From 67b485cd4c62e8a5c69d4000ff665653d1127d9f Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Wed, 27 May 2015 07:37:39 -0400 Subject: [PATCH 1/3] add .gitignore and configure/ExampleRELEASE.local --- .gitignore | 13 +++++++++++++ configure/ExampleRELEASE.local | 7 +++++++ 2 files changed, 20 insertions(+) create mode 100644 .gitignore create mode 100644 configure/ExampleRELEASE.local diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cde41de --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +QtC- +bin/ +lib/ +doc/ +include/ +db/ +dbd/ +documentation/html +documentation/*.tag +envPaths +configure/*.local +!configure/ExampleRELEASE.local +**/O.* diff --git a/configure/ExampleRELEASE.local b/configure/ExampleRELEASE.local new file mode 100644 index 0000000..403d72f --- /dev/null +++ b/configure/ExampleRELEASE.local @@ -0,0 +1,7 @@ +EPICS_BASE=/home/install/epics/base + +EPICS4_DIR=/home/epicsv4 +PVCOMMON=${EPICS4_DIR}/pvCommonCPP +PVDATA=${EPICS4_DIR}/pvDataCPP + + From b1299c60fe20f3f590c31da69f81c5a0a2359d97 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Fri, 29 May 2015 08:36:13 -0400 Subject: [PATCH 2/3] moved easyPVACPP to pvAccessCPP and renamed to Pva --- Doxyfile | 2 +- Makefile | 25 +- documentation/pva.html | 202 +++ documentation/pvaOverview.html | 321 ++++ documentation/pva_20150529.html | 202 +++ exampleDatabasePVA.zip | Bin 0 -> 23039 bytes pvaExample/Makefile | 13 + pvaExample/configure/CONFIG | 29 + pvaExample/configure/CONFIG_SITE | 27 + pvaExample/configure/ExampleRELEASE.local | 6 + pvaExample/configure/Makefile | 8 + pvaExample/configure/RELEASE | 41 + pvaExample/configure/RULES | 6 + pvaExample/configure/RULES.ioc | 2 + pvaExample/configure/RULES_DIRS | 2 + pvaExample/configure/RULES_TOP | 3 + pvaExample/src/Makefile | 72 + pvaExample/src/examplePvaGet.cpp | 146 ++ pvaExample/src/examplePvaMonitor.cpp | 46 + pvaExample/src/examplePvaMultiDouble.cpp | 84 + pvaExample/src/examplePvaNTMultiChannel.cpp | 101 ++ pvaExample/src/examplePvaProcess.cpp | 44 + pvaExample/src/examplePvaPut.cpp | 45 + pvaExample/src/helloWorldPutGet.cpp | 48 + pvaExample/src/helloWorldRPC.cpp | 77 + pvaSrc/Makefile | 34 + pvaSrc/pva.cpp | 199 +++ pvaSrc/pva.h | 1662 +++++++++++++++++++ pvaSrc/pvaChannel.cpp | 495 ++++++ pvaSrc/pvaGet.cpp | 230 +++ pvaSrc/pvaGetData.cpp | 200 +++ pvaSrc/pvaMonitor.cpp | 250 +++ pvaSrc/pvaMonitorData.cpp | 226 +++ pvaSrc/pvaMultiChannel.cpp | 165 ++ pvaSrc/pvaMultiDouble.cpp | 139 ++ pvaSrc/pvaMultiDouble.h | 81 + pvaSrc/pvaNTMultiChannel.cpp | 268 +++ pvaSrc/pvaNTMultiChannel.h | 103 ++ pvaSrc/pvaProcess.cpp | 212 +++ pvaSrc/pvaPut.cpp | 292 ++++ pvaSrc/pvaPutData.cpp | 267 +++ pvaSrc/pvaPutGet.cpp | 378 +++++ pvaSrc/temp | 120 ++ pvaTest/Makefile | 13 + pvaTest/configure/CONFIG | 29 + pvaTest/configure/CONFIG_SITE | 27 + pvaTest/configure/ExampleRELEASE.local | 6 + pvaTest/configure/Makefile | 8 + pvaTest/configure/RELEASE | 41 + pvaTest/configure/RULES | 6 + pvaTest/configure/RULES.ioc | 2 + pvaTest/configure/RULES_DIRS | 2 + pvaTest/configure/RULES_TOP | 3 + pvaTest/src/Makefile | 57 + pvaTest/src/pvaAllTests.c | 31 + pvaTest/src/testPvaGetData.cpp | 155 ++ pvaTest/src/testPvaMonitorData.cpp | 153 ++ pvaTest/src/testPvaMultiDouble.cpp | 156 ++ pvaTest/src/testPvaNTMultiChannel.cpp | 132 ++ pvaTest/src/testPvaPutData.cpp | 229 +++ pvaTest/src/testPvaPutGet.cpp | 66 + pvaTest/src/testPvaPutGetMonitor.cpp | 89 + 62 files changed, 8069 insertions(+), 9 deletions(-) create mode 100644 documentation/pva.html create mode 100644 documentation/pvaOverview.html create mode 100644 documentation/pva_20150529.html create mode 100644 exampleDatabasePVA.zip create mode 100644 pvaExample/Makefile create mode 100644 pvaExample/configure/CONFIG create mode 100644 pvaExample/configure/CONFIG_SITE create mode 100644 pvaExample/configure/ExampleRELEASE.local create mode 100644 pvaExample/configure/Makefile create mode 100644 pvaExample/configure/RELEASE create mode 100644 pvaExample/configure/RULES create mode 100644 pvaExample/configure/RULES.ioc create mode 100644 pvaExample/configure/RULES_DIRS create mode 100644 pvaExample/configure/RULES_TOP create mode 100644 pvaExample/src/Makefile create mode 100644 pvaExample/src/examplePvaGet.cpp create mode 100644 pvaExample/src/examplePvaMonitor.cpp create mode 100644 pvaExample/src/examplePvaMultiDouble.cpp create mode 100644 pvaExample/src/examplePvaNTMultiChannel.cpp create mode 100644 pvaExample/src/examplePvaProcess.cpp create mode 100644 pvaExample/src/examplePvaPut.cpp create mode 100644 pvaExample/src/helloWorldPutGet.cpp create mode 100644 pvaExample/src/helloWorldRPC.cpp create mode 100644 pvaSrc/Makefile create mode 100644 pvaSrc/pva.cpp create mode 100644 pvaSrc/pva.h create mode 100644 pvaSrc/pvaChannel.cpp create mode 100644 pvaSrc/pvaGet.cpp create mode 100644 pvaSrc/pvaGetData.cpp create mode 100644 pvaSrc/pvaMonitor.cpp create mode 100644 pvaSrc/pvaMonitorData.cpp create mode 100644 pvaSrc/pvaMultiChannel.cpp create mode 100644 pvaSrc/pvaMultiDouble.cpp create mode 100644 pvaSrc/pvaMultiDouble.h create mode 100644 pvaSrc/pvaNTMultiChannel.cpp create mode 100644 pvaSrc/pvaNTMultiChannel.h create mode 100644 pvaSrc/pvaProcess.cpp create mode 100644 pvaSrc/pvaPut.cpp create mode 100644 pvaSrc/pvaPutData.cpp create mode 100644 pvaSrc/pvaPutGet.cpp create mode 100644 pvaSrc/temp create mode 100644 pvaTest/Makefile create mode 100644 pvaTest/configure/CONFIG create mode 100644 pvaTest/configure/CONFIG_SITE create mode 100644 pvaTest/configure/ExampleRELEASE.local create mode 100644 pvaTest/configure/Makefile create mode 100644 pvaTest/configure/RELEASE create mode 100644 pvaTest/configure/RULES create mode 100644 pvaTest/configure/RULES.ioc create mode 100644 pvaTest/configure/RULES_DIRS create mode 100644 pvaTest/configure/RULES_TOP create mode 100644 pvaTest/src/Makefile create mode 100644 pvaTest/src/pvaAllTests.c create mode 100644 pvaTest/src/testPvaGetData.cpp create mode 100644 pvaTest/src/testPvaMonitorData.cpp create mode 100644 pvaTest/src/testPvaMultiDouble.cpp create mode 100644 pvaTest/src/testPvaNTMultiChannel.cpp create mode 100644 pvaTest/src/testPvaPutData.cpp create mode 100644 pvaTest/src/testPvaPutGet.cpp create mode 100644 pvaTest/src/testPvaPutGetMonitor.cpp diff --git a/Doxyfile b/Doxyfile index c853574..4faffdc 100644 --- a/Doxyfile +++ b/Doxyfile @@ -908,7 +908,7 @@ HTML_STYLESHEET = # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = documentation/pvaOverview.html # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images diff --git a/Makefile b/Makefile index c005d8f..f5e3f4a 100644 --- a/Makefile +++ b/Makefile @@ -2,16 +2,25 @@ TOP = . include $(TOP)/configure/CONFIG +DIRS := $(DIRS) $(filter-out $(DIRS), configure) +DIRS := $(DIRS) $(filter-out $(DIRS), src) +DIRS := $(DIRS) $(filter-out $(DIRS), pvaSrc) +DIRS := $(DIRS) $(filter-out $(DIRS), pvtoolsSrc) +DIRS := $(DIRS) $(filter-out $(DIRS), testApp) +DIRS := $(DIRS) $(filter-out $(DIRS), pvaExample) +DIRS := $(DIRS) $(filter-out $(DIRS), pvaTest) -DIRS := configure +EMBEDDED_TOPS := $(EMBEDDED_TOPS) $(filter-out $(EMBEDDED_TOPS), pvaExample) +EMBEDDED_TOPS := $(EMBEDDED_TOPS) $(filter-out $(EMBEDDED_TOPS), pvaTest) -DIRS += src -src_DEPEND_DIRS = configure +define DIR_template + $(1)_DEPEND_DIRS = configure +endef +$(foreach dir, $(filter-out configure,$(DIRS)),$(eval $(call DIR_template,$(dir)))) -DIRS += pvtoolsSrc -pvtoolsSrc_DEPEND_DIRS = src - -DIRS += testApp -testApp_DEPEND_DIRS = src +define EMB_template + $(1)_DEPEND_DIRS = src pvaSrc +endef +$(foreach dir, $(EMBEDDED_TOPS),$(eval $(call EMB_template,$(dir)))) include $(TOP)/configure/RULES_TOP diff --git a/documentation/pva.html b/documentation/pva.html new file mode 100644 index 0000000..42c9001 --- /dev/null +++ b/documentation/pva.html @@ -0,0 +1,202 @@ + + + + + + EPICS pva + + + + + + + + + + + +
+

EPICS pva

+ +

EPICS V4 Working Group, Working Draft, +29-May-2015

+
+
This version:
+
pva.html +
+
Latest version:
+
pva_20150529.html +
+
Previous version:
+
none
+
Editors:
+
Marty Kraimer, BNL
+
Matej Sekoranja, Cosylab
+
+ +

Abstract

+ +

Pva (Pva PVAccess) is a software library that provides to an EPICS client programmer, a friendly +client side programming interface to the data of an EPICS based control system. It is intended +for such uses as rapid development of ad hoc programs by controls engineers, or to provide +scientists a way to directly develop analytical applications.

+ +

Specifically, pva provides a synchronous interface for pvAccess, which is the +software support for high speed controls network communications used in EPICS version 4. +PvAccess provides a callback based interface, which can be hard to use. +Pva provides an interface that does not require callbacks even for monitors. +

+

+PvaChannel provides many "convenience" methods to directly get and put +scalar and scalarArray data types. +Additional methods provide access to the full features of pvAccess. +

+

+PvaMultiChannel provides access to data from multiple channels. +It can be used directly by a client or via PvaMultiDouble or PvaNTMultiChannel. +PvaMultiDouble allows the client to get and put data to multiple channels. +But each channel must have a value field that is a numeric scalar. +PvaNTMultiChannel allows the client to get and put data to multiple channels. +Each channel must have a value field. +The data for the channels is presented via normative type NTMultiChannel. +

+ +

For more information about EPICS generally, please refer to the home page of the Experimental Physics and Industrial + Control System.

+ + + +

Status of this Document and of the Pva Software

+ +

PvaCPP is ready for use.

+ +
+ +
+

Table of Contents

+
+ + +
+
+ +

Introduction

+ +

Pva is a synchronous API for accessing PVData via PVAccess. It provides +an interface to many of the features provided by pvData and pvAccess.

+ +

This document describes the layout of the source files in this project.

+

+A user overview is available via +pvaOverview.html + +

+

+Doxygen documentation is available at +doxygenDoc + +

+

Example and Test Database

+

The examples and tests require that an example pvAccess server is runnimg. +This distribution has a file exampleDatabasePva.zip. +When unzipped this is used to create an example IOC database. +The database has the record used by the examples are tests that come with pvaJava. +It uses pvDatabaseCPP to build the database. +

+

+After unzipping the file: +

+
+cd configure
+cp ExampleRELEASE.local RELEASE.local
+edit RELEASE.local
+cd ..
+make
+cd iocBoot/exampleDatabase
+../../bin/<arch:>/exampleDatabase st.cmd
+
+

Testing

+

The tests will fail unless the example database is running.

+

Once it is running:

+
+make runtests
+
+

Examples

+

Examples are in directory pvaExample/src. +An example of how to run them is:

+
+mrk> pwd
+/home/epicsv4/pvAccessCPP/pvaExample
+mrk> bin/linux-x86_64/examplePvaGet 
+
+

The following is a brief description of each example. +In order to understand each example it +helps to also look at the source for the example.

+

examplePvaGet

+

This has a number of examples:

+
+
exampleDouble
+
+ This shows two methods for getting data from a channel that has a numeric + scalar value field. +
+
exampleDoubleArray
+
+ This shows two methods for getting data from a channel that has a + double array value field. +
+
exampleCADouble
+
+ This is like exampleDouble except it uses provider ca. +
+
exampleCADoubleArray
+
+ This is like exampleDoubleArray except it uses provider ca. +
+
examplePowerSupply
+
+ This is an example of getting data from a channel that does not + have a value field. +
+
+

examplePvaMonitor

+

This is an example of creating a monitor on a channel. +It monitors a channel that models a powerSupply, i. e. it is not a "standard" record. +It does not have a value field. +

+

After starting the example a change can be made to the powerSupply by issuing:

+
+pvput -r "power.value,voltage.value" examplePowerSupply 6 6
+
+

examplePvaPut

+

This example gets and puts to channel exampleDouble.

+

examplePvaProcess

+

This example makes a process request to channel exampleDouble.

+

helloWorldPutGet

+

This is an example of issuing a channelPutGet.

+

examplePvaMultiDouble

+

This is an example of issuing gets and puts to multiple channels where each +channel has a numeric scalar value field.

+

examplePvaNTMultiChannel

+

This is an example of using NDMultiChannel to obtain data from multiple channels. +

+

helloWorldRPC

+

This is an example of issuing a channelRPC request. +It does not use pva.

+
+ + diff --git a/documentation/pvaOverview.html b/documentation/pvaOverview.html new file mode 100644 index 0000000..ae851c2 --- /dev/null +++ b/documentation/pvaOverview.html @@ -0,0 +1,321 @@ + + + + + + pva C++ Overview + + + + + + + + + + + +
+

Pva C++ Overview

+ +
+ +
+

Table of Contents

+
+ + +
+
+ +

Introduction

+ +

Pva 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 if a request fails. +A client can also check for failues and thus prevent exceptions.

+ +

The Pva API has the following features:

+
    +
  1. Provides a synchronous API rather than the callback API provided by pvAccess.
  2. +
  3. Makes common requests pva.
  4. +
  5. Provides full access to the pvAccess API for more demanding + applications
  6. +
  7. Allows efficient client side programs.
  8. +
  9. Takes care of most object resource management problems.
  10. +
+

Simple examples of using pva:

+
+// pvaGet
+PvaPtr pva = Pva::create();
+double value = pva->channel("exampleDouble")->get()->getData()->getDouble();
+
+// pvaPut
+PvaChannelPtr channel = pva->channel("exampleDouble");
+PvaPutPtr put = channel->put();
+PvaPutDataPtr putData = put->getData();
+putData->putDouble(3.0); put->put();
+
+// pvaMonitor
+PvaMonitorPtr monitor = pva->channel("examplePowerSupply")->monitor("");
+PvaMonitorDataPtr pvaData = monitor->getData();
+while(true) {
+    monitor->waitEvent();
+    cout << "changed\n";
+    pvaData->showChanged(cout);
+    cout << "overrun\n";
+    pvaData->showOverrun(cout);
+    monitor->releaseEvent();
+}
+
+// pvaProcess
+PvaChannelPtr channel = pva->channel("exampleDouble");
+PvaProcessPtr process = channel->createProcess();
+process->process();
+
+
+

pvaExample includes a number of examples.

+

pva does not provide support for:

+
+
ChannelArray
+
TBD
+
ChannelRPC
+
pvAccess itself already provides a synchronous interface. + The examples include helloWorldRPC, which is an example of using channelRP. +
+
+ +

Pva

+

An instance of Pva is obtained via the call:

+
+PvaPtr pva = Pva::create();
+
+ +

Pva has methods to create instances of PvaChannel. +The client can specify the provider name or use the default provider. +The client can manage it's own channels or can let pva cache channels. +An example of using the cached method is:

+
+PvaChannelPtr pvaChannel = pva->channel("exampleDouble");
+
+

This will attempt to connect to channel exampleDouble. +Since the client did not specify a timeout an exception wll be thrown if +the connection request fails. +The client will block until the connection is made or an exception is thrown. +If the request succeeds, pva caches the pvaChannel so that if the +client makes another request for the same channel the cached object is +returned to the client. +

+

An example of using a non cached method is:

+
+PvaChannelPtr pvaChannel = pva->createChannel("exampleDouble");
+
+

This will create an PvaChannel and return it to the client. +The client must itself connect. +This is useful if the client wants to connect to multiple channels in parallel. +

+ +

PvaChannel - Wrapper For Single Channel

+

PvaChannel

+

This provides methods for connecting to a channel and for creating instances of +PvaField, PvaProcess, ..., PvaPutGet.

+

Connection must be made before any create method is called or +an exception is raised. +The following is a synchronous connection request:

+
+pvaChannel->connect(5.0); // BLOCKS AND THROWS IF NO CONNECT
+
+

This blocks until then connection is made or until timout occurs. +An exception is raised if the connection request fails. +

+

The same request can be made without blocking and without exceptions.

+
+pvaChannel->issueConnect(); // DOES NOT BLOCK
+.....
+Status status =pvaChannel->waitConnect(5.0);  // BLOCKS DOES NOT THROW
+if(!status.isOK()) {
+   // failure do something
+}
+
+

Once the channel is connected other Pva objects can be created. +For example:

+
+PvaGetPtr pvaGet = pvaChannel->get(); // DOES BLOCK
+
+

This is a caching request. +If the client already has made an identical request the client will receive the +cached object. +If a new pvaGet is created than it is connected before it is returned to the client. +

+

The client can also managed it's own objects:

+
+PvaGetPtr pvaGet = pvaChannel->createGet(); // DOES NOT BLOCK
+
+

The client must connect the pvaGet.

+ +

PvaGetData

+

This provides the data returned by pvaGet and pvaPutGet. +It is obtained via:

+
+PvaGetDataPtr pvaData = pvaGet->getData();
+
+

It provides methods to get everything returned by channelGet. +In addition there are methods that make it easier to handle a value +field that is a scalar or a scalarArray. +Also for a scalar that is a double or a scalarArray with element type double. +

+

An example is:

+
+double value = pvaData->getDouble();
+
+

It also keeps a bitSet showing which fields have changed since the last channelGet or channelPutGet.

+ +

PvaMonitorData

+

To the client this looks identical to PvaGetData except that +it provides two BitSets: changedBitSet and overrrunBitSet. +It is used by pvaMonitor. +

+

PvaPutData

+

This is used to provided data for pvaPut and pvaPutGet. +It has many of the same methods as pvaGetData. +It does not have a bitSet. +It also has put methods like:

+
+void pvaData->putDouble(5.0);
+
+

PvaGet

+

This provides methods to connect to channelGet and to issue get request. +To connect via a single synchronous call:

+
+eastGet->connect();  // BLOCKS AND CAN THROW
+
+

This can also be done in two steps:

+
+pvaGet->issueConnect(); // DOES NOT BLOCK
+...
+Status status = pvaGet->waitConnect(); // BLOCKS AND DOES NOT HROW
+
+

Once connected gets are issued via either:

+
+void pvaGet->get(); // BLOCKS AND CAN THROW
+
+or +
+pvaGet->issueGet(); // DOES NOT BLOCK
+...
+Status status = pvaGet->waitGet(); // BLOCKS AND DOES NOT THROW
+
+

PvaPut

+

This is similar to pvaGet except that it wraps channelPut instead of channelGet. +

+

Once connected puts are issued via either:

+
+void pvaPut->put(); // BLOCKS AND CAN THROW
+
+or +
+pvaPut->issuePut(); // DOES NOT BLOCK
+...
+Status status = pvaPut->waitPut(); // BLOCKS AND DOES NOT THROW
+
+

PvaMonitor

+

Connecting is similar to pvaGet and pvaPut. +The other methods are:

+
+
start
+
Starts monitoring
+
stop
+
Stops monitoring
+
poll
+
polls for a monitorEvent. + The data is avalable via pvaMonitorData. +
+
releaseEvent
+
Release the data from the last poll. + Note that this must be called before another poll is requested. +
+
waitEvent
+
Block until a monitorEvent is available. + If true is returned a poll has already been issued. +
+
setRequester
+
A client callback is registered to receive notice of monitorEvents.
+
+

PvaProcess

+

Connecting is similar to pvaGet. +It has methods:

+
+
process
+
call issueProcess and waitProcess.
+
issueProcess
+
call channelProcess->process() and return immediately. +
+
waitProcess
+
Wait for process to complete.
+
+

PvaPutGet

+

Connecting is similar to pvaGet. +It has methods:

+
+
putGet
+
calls issuePutGet and waitPutGet. + throws an exception if not successfull. +
+
issuePutGet
+
+ Calls channel->putGet() and returns. +
+
waitPutGet
+
+ Waits until putGet completes and returns status. +
+
getGet,issueGetGet, and waitGetGet
+
Gets the data for the get part of channelPutGet.
+
getPut,issueGetPut,and waitGetPut
+
Gets the data for the put part of channelPutGet.
+
getPutData
+
+ Returns the PvaData for the put part of channelPutGet. +
+
getGetData
+
+ Returns the PvaData for the get part of channelPutGet. +
+
+

Look at javaDoc for details.

+ +

PvaMultiChannel - Wrapper For Multiple Channels

+

PvaMultiChannel

+

This provides methods for connecting to multiple channels. +A client can either use PvaMultiChannel directly or use PvaMultiDouble or PvaNTMultiChannel. +But both impose restrictions on what can be accessed. +

+

PvaMultiDouble

+

This provides support for gets and puts to the value field of multiple channels. +Each channel must have a value field that is a numeric scalar. +The client always sees the data as a PVDoubleArray. +All channels must connect. +If any problems occur an exception is thrown. +

+

PvaNTMultiChannel

+

This provides support for gets and puts to the value field of multiple channels. +Each channel must have a value field. +The client always sees the data as a NTMultiChannel, which is one +of the types provided by normativeTypesCPP. +All channels must connect. +If any problems occur an exception is thrown. +

+ +
+ + diff --git a/documentation/pva_20150529.html b/documentation/pva_20150529.html new file mode 100644 index 0000000..42c9001 --- /dev/null +++ b/documentation/pva_20150529.html @@ -0,0 +1,202 @@ + + + + + + EPICS pva + + + + + + + + + + + +
+

EPICS pva

+ +

EPICS V4 Working Group, Working Draft, +29-May-2015

+
+
This version:
+
pva.html +
+
Latest version:
+
pva_20150529.html +
+
Previous version:
+
none
+
Editors:
+
Marty Kraimer, BNL
+
Matej Sekoranja, Cosylab
+
+ +

Abstract

+ +

Pva (Pva PVAccess) is a software library that provides to an EPICS client programmer, a friendly +client side programming interface to the data of an EPICS based control system. It is intended +for such uses as rapid development of ad hoc programs by controls engineers, or to provide +scientists a way to directly develop analytical applications.

+ +

Specifically, pva provides a synchronous interface for pvAccess, which is the +software support for high speed controls network communications used in EPICS version 4. +PvAccess provides a callback based interface, which can be hard to use. +Pva provides an interface that does not require callbacks even for monitors. +

+

+PvaChannel provides many "convenience" methods to directly get and put +scalar and scalarArray data types. +Additional methods provide access to the full features of pvAccess. +

+

+PvaMultiChannel provides access to data from multiple channels. +It can be used directly by a client or via PvaMultiDouble or PvaNTMultiChannel. +PvaMultiDouble allows the client to get and put data to multiple channels. +But each channel must have a value field that is a numeric scalar. +PvaNTMultiChannel allows the client to get and put data to multiple channels. +Each channel must have a value field. +The data for the channels is presented via normative type NTMultiChannel. +

+ +

For more information about EPICS generally, please refer to the home page of the Experimental Physics and Industrial + Control System.

+ + + +

Status of this Document and of the Pva Software

+ +

PvaCPP is ready for use.

+ +
+ +
+

Table of Contents

+
+ + +
+
+ +

Introduction

+ +

Pva is a synchronous API for accessing PVData via PVAccess. It provides +an interface to many of the features provided by pvData and pvAccess.

+ +

This document describes the layout of the source files in this project.

+

+A user overview is available via +pvaOverview.html + +

+

+Doxygen documentation is available at +doxygenDoc + +

+

Example and Test Database

+

The examples and tests require that an example pvAccess server is runnimg. +This distribution has a file exampleDatabasePva.zip. +When unzipped this is used to create an example IOC database. +The database has the record used by the examples are tests that come with pvaJava. +It uses pvDatabaseCPP to build the database. +

+

+After unzipping the file: +

+
+cd configure
+cp ExampleRELEASE.local RELEASE.local
+edit RELEASE.local
+cd ..
+make
+cd iocBoot/exampleDatabase
+../../bin/<arch:>/exampleDatabase st.cmd
+
+

Testing

+

The tests will fail unless the example database is running.

+

Once it is running:

+
+make runtests
+
+

Examples

+

Examples are in directory pvaExample/src. +An example of how to run them is:

+
+mrk> pwd
+/home/epicsv4/pvAccessCPP/pvaExample
+mrk> bin/linux-x86_64/examplePvaGet 
+
+

The following is a brief description of each example. +In order to understand each example it +helps to also look at the source for the example.

+

examplePvaGet

+

This has a number of examples:

+
+
exampleDouble
+
+ This shows two methods for getting data from a channel that has a numeric + scalar value field. +
+
exampleDoubleArray
+
+ This shows two methods for getting data from a channel that has a + double array value field. +
+
exampleCADouble
+
+ This is like exampleDouble except it uses provider ca. +
+
exampleCADoubleArray
+
+ This is like exampleDoubleArray except it uses provider ca. +
+
examplePowerSupply
+
+ This is an example of getting data from a channel that does not + have a value field. +
+
+

examplePvaMonitor

+

This is an example of creating a monitor on a channel. +It monitors a channel that models a powerSupply, i. e. it is not a "standard" record. +It does not have a value field. +

+

After starting the example a change can be made to the powerSupply by issuing:

+
+pvput -r "power.value,voltage.value" examplePowerSupply 6 6
+
+

examplePvaPut

+

This example gets and puts to channel exampleDouble.

+

examplePvaProcess

+

This example makes a process request to channel exampleDouble.

+

helloWorldPutGet

+

This is an example of issuing a channelPutGet.

+

examplePvaMultiDouble

+

This is an example of issuing gets and puts to multiple channels where each +channel has a numeric scalar value field.

+

examplePvaNTMultiChannel

+

This is an example of using NDMultiChannel to obtain data from multiple channels. +

+

helloWorldRPC

+

This is an example of issuing a channelRPC request. +It does not use pva.

+
+ + diff --git a/exampleDatabasePVA.zip b/exampleDatabasePVA.zip new file mode 100644 index 0000000000000000000000000000000000000000..9f7e582cf018fdcdeefe81c61d23052f0b425208 GIT binary patch literal 23039 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 literal 0 HcmV?d00001 diff --git a/pvaExample/Makefile b/pvaExample/Makefile new file mode 100644 index 0000000..0a9fd57 --- /dev/null +++ b/pvaExample/Makefile @@ -0,0 +1,13 @@ +# Makefile at top of application tree + +TOP = . +include $(TOP)/configure/CONFIG + +DIRS += configure + +DIRS += src +src_DEPEND_DIRS = configure + +include $(TOP)/configure/RULES_TOP + + diff --git a/pvaExample/configure/CONFIG b/pvaExample/configure/CONFIG new file mode 100644 index 0000000..c1a4703 --- /dev/null +++ b/pvaExample/configure/CONFIG @@ -0,0 +1,29 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common +ifdef T_A +-include $(TOP)/configure/RELEASE.Common.$(T_A) +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain other build configuration settings +include $(TOP)/configure/CONFIG_SITE +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +ifdef T_A + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/pvaExample/configure/CONFIG_SITE b/pvaExample/configure/CONFIG_SITE new file mode 100644 index 0000000..6648852 --- /dev/null +++ b/pvaExample/configure/CONFIG_SITE @@ -0,0 +1,27 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building anyway if conflicts are found. +CHECK_RELEASE = WARN + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv +USR_INCLUDES += -I $(INSTALL_LOCATION)/include + +-include $(TOP)/../../CONFIG_SITE.local +-include $(TOP)/../configure/CONFIG_SITE.local diff --git a/pvaExample/configure/ExampleRELEASE.local b/pvaExample/configure/ExampleRELEASE.local new file mode 100644 index 0000000..3c70d98 --- /dev/null +++ b/pvaExample/configure/ExampleRELEASE.local @@ -0,0 +1,6 @@ +EPICS_BASE=/home/install/epics/base +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top +EPICSV4HOME=/home/epicsv4 +PVCOMMON=${EPICSV4HOME}/pvCommonCPP +PVDATA=${EPICSV4HOME}/pvDataCPP +PVACCESS=${EPICSV4HOME}/pvAccessCPP diff --git a/pvaExample/configure/Makefile b/pvaExample/configure/Makefile new file mode 100644 index 0000000..9254309 --- /dev/null +++ b/pvaExample/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/pvaExample/configure/RELEASE b/pvaExample/configure/RELEASE new file mode 100644 index 0000000..56e5b8b --- /dev/null +++ b/pvaExample/configure/RELEASE @@ -0,0 +1,41 @@ +# pvDatabaseCPP/example RELEASE - Location of external support modules +# +# IF YOU CHANGE this file or any file it includes you must +# subsequently do a "gnumake rebuild" in the application's +# top level directory. +# +# The build process does not check dependencies against files +# that are outside this application, thus you should also do a +# "gnumake rebuild" in the top level directory after EPICS_BASE +# or any other external module pointed to below is rebuilt. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) + +# EPICS V4 Developers: Do not edit the locations in this file! +# +# Create a file RELEASE.local pointing to your PVASRV, PVACCESS, +# PVDATA, PVCOMMON and EPICS_BASE build directories, e.g. +# PVASRV = /path/to/epics/pvaSrvCPP +# PVACCESS = /path/to/epics/pvAccessCPP +# PVDATA = /path/to/epics/pvDataCPP +# PVCOMMON = /path/to/epics/pvCommonCPP +# EPICS_BASE = /path/to/epics/base + +# If this example is built in a directory under pvDatabaseCPP, +# use the following definitions: + +EASYPVA = $(TOP)/.. + +-include $(TOP)/../configure/RELEASE.local +-include $(TOP)/../../RELEASE.local + +# If you copied this example from pvDatabaseCPP to be built as a +# standalone TOP, adjust and use the following definitions: + +#EASYPVA = /path/to/epics/easyPVACPP + +#-include $(TOP)/../RELEASE.local +#-include $(TOP)/configure/RELEASE.local diff --git a/pvaExample/configure/RULES b/pvaExample/configure/RULES new file mode 100644 index 0000000..6d56e14 --- /dev/null +++ b/pvaExample/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/pvaExample/configure/RULES.ioc b/pvaExample/configure/RULES.ioc new file mode 100644 index 0000000..901987c --- /dev/null +++ b/pvaExample/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/pvaExample/configure/RULES_DIRS b/pvaExample/configure/RULES_DIRS new file mode 100644 index 0000000..3ba269d --- /dev/null +++ b/pvaExample/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/pvaExample/configure/RULES_TOP b/pvaExample/configure/RULES_TOP new file mode 100644 index 0000000..d09d668 --- /dev/null +++ b/pvaExample/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/pvaExample/src/Makefile b/pvaExample/src/Makefile new file mode 100644 index 0000000..f7758d3 --- /dev/null +++ b/pvaExample/src/Makefile @@ -0,0 +1,72 @@ +TOP=.. + +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE + + +PROD_HOST += examplePvaProcess +examplePvaProcess_SRCS += examplePvaProcess.cpp +examplePvaProcess_LIBS += pva +examplePvaProcess_LIBS += pvAccess +examplePvaProcess_LIBS += pvData +examplePvaProcess_LIBS += Com + +PROD_HOST += examplePvaGet +examplePvaGet_SRCS += examplePvaGet.cpp +examplePvaGet_LIBS += pva +examplePvaGet_LIBS += pvAccess +examplePvaGet_LIBS += pvData +examplePvaGet_LIBS += Com + +PROD_HOST += examplePvaPut +examplePvaPut_SRCS += examplePvaPut.cpp +examplePvaPut_LIBS += pva +examplePvaPut_LIBS += pvAccess +examplePvaPut_LIBS += pvData +examplePvaPut_LIBS += Com + +PROD_HOST += examplePvaMonitor +examplePvaMonitor_SRCS += examplePvaMonitor.cpp +examplePvaMonitor_LIBS += pva +examplePvaMonitor_LIBS += pvAccess +examplePvaMonitor_LIBS += pvData +examplePvaMonitor_LIBS += Com + +PROD_HOST += examplePvaMultiDouble +examplePvaMultiDouble_SRCS += examplePvaMultiDouble.cpp +examplePvaMultiDouble_LIBS += pva +examplePvaMultiDouble_LIBS += pvAccess +examplePvaMultiDouble_LIBS += pvData +examplePvaMultiDouble_LIBS += Com + +PROD_HOST += examplePvaNTMultiChannel +examplePvaNTMultiChannel_SRCS += examplePvaNTMultiChannel.cpp +examplePvaNTMultiChannel_LIBS += pva +examplePvaNTMultiChannel_LIBS += pvAccess +examplePvaNTMultiChannel_LIBS += nt +examplePvaNTMultiChannel_LIBS += pvData +examplePvaNTMultiChannel_LIBS += Com + +PROD_HOST += helloWorldRPC +helloWorldRPC_SRCS += helloWorldRPC.cpp +helloWorldRPC_LIBS += pva +helloWorldRPC_LIBS += pvAccess +helloWorldRPC_LIBS += nt +helloWorldRPC_LIBS += pvData +helloWorldRPC_LIBS += Com + +PROD_HOST += helloWorldPutGet +helloWorldPutGet_SRCS += helloWorldPutGet.cpp +helloWorldPutGet_LIBS += pva +helloWorldPutGet_LIBS += pvAccess +helloWorldPutGet_LIBS += nt +helloWorldPutGet_LIBS += pvData +helloWorldPutGet_LIBS += Com + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/pvaExample/src/examplePvaGet.cpp b/pvaExample/src/examplePvaGet.cpp new file mode 100644 index 0000000..c93667b --- /dev/null +++ b/pvaExample/src/examplePvaGet.cpp @@ -0,0 +1,146 @@ +/*examplePvaGet.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void exampleDouble(PvaPtr const &pva) +{ + cout << "example double scalar\n"; + double value; + try { + cout << "short way\n"; + value = pva->channel("exampleDouble")->get()->getData()->getDouble(); + cout << "as double " << value << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + cout << "long way\n"; + PvaChannelPtr pvaChannel = pva->createChannel("exampleDouble"); + pvaChannel->issueConnect(); + Status status = pvaChannel->waitConnect(2.0); + if(!status.isOK()) {cout << " connect failed\n"; return;} + PvaGetPtr pvaGet = pvaChannel->createGet(); + pvaGet->issueConnect(); + status = pvaGet->waitConnect(); + if(!status.isOK()) {cout << " createGet failed\n"; return;} + PvaGetDataPtr pvaData = pvaGet->getData(); + value = pvaData->getDouble(); + cout << "as double " << value << endl; +} + +static void exampleDoubleArray(PvaPtr const &pva) +{ + cout << "example double array\n"; + shared_vector value; + try { + cout << "short way\n"; + value = pva->channel("exampleDoubleArray")->get()->getData()->getDoubleArray(); + cout << "as doubleArray " << value << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + try { + cout << "long way\n"; + PvaChannelPtr pvaChannel = pva->createChannel("exampleDoubleArray"); + pvaChannel->connect(2.0); + PvaGetPtr pvaGet = pvaChannel->createGet(); + PvaGetDataPtr pvaData = pvaGet->getData(); + value = pvaData->getDoubleArray(); + cout << "as doubleArray " << value << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + +static void examplePowerSupply(PvaPtr const &pva) +{ + cout << "example powerSupply\n"; + PVStructurePtr pvStructure; + try { + cout << "short way\n"; + pvStructure = pva->channel("examplePowerSupply")-> + get("field()")->getData()->getPVStructure(); + cout << pvStructure << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + +} + +static void exampleCADouble(PvaPtr const &pva) +{ + cout << "example double scalar\n"; + double value; + try { + cout << "short way\n"; + value = pva->channel("double00","ca",5.0)->get()->getData()->getDouble(); + cout << "as double " << value << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + cout << "long way\n"; + PvaChannelPtr pvaChannel = pva->createChannel("double00","ca"); + pvaChannel->issueConnect(); + Status status = pvaChannel->waitConnect(2.0); + if(!status.isOK()) {cout << " connect failed\n"; return;} + PvaGetPtr pvaGet = pvaChannel->createGet(); + pvaGet->issueConnect(); + status = pvaGet->waitConnect(); + if(!status.isOK()) {cout << " createGet failed\n"; return;} + PvaGetDataPtr pvaData = pvaGet->getData(); + value = pvaData->getDouble(); + cout << "as double " << value << endl; +} + +static void exampleCADoubleArray(PvaPtr const &pva) +{ + cout << "example double array\n"; + shared_vector value; + try { + cout << "short way\n"; + value = pva->channel("doubleArray","ca",5.0)->get()->getData()->getDoubleArray(); + cout << "as doubleArray " << value << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + try { + cout << "long way\n"; + PvaChannelPtr pvaChannel = pva->createChannel("doubleArray","ca"); + pvaChannel->connect(2.0); + PvaGetPtr pvaGet = pvaChannel->createGet(); + PvaGetDataPtr pvaData = pvaGet->getData(); + value = pvaData->getDoubleArray(); + cout << "as doubleArray " << value << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + +int main(int argc,char *argv[]) +{ + PvaPtr pva = Pva::create(); + exampleDouble(pva); + exampleDoubleArray(pva); + examplePowerSupply(pva); + exampleCADouble(pva); + exampleCADoubleArray(pva); + cout << "done\n"; + return 0; +} diff --git a/pvaExample/src/examplePvaMonitor.cpp b/pvaExample/src/examplePvaMonitor.cpp new file mode 100644 index 0000000..a305e89 --- /dev/null +++ b/pvaExample/src/examplePvaMonitor.cpp @@ -0,0 +1,46 @@ +/*monitorPowerSupply.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include + +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void exampleMonitor(PvaPtr const &pva) +{ + PvaMonitorPtr monitor = pva->channel("examplePowerSupply")->monitor(""); + PvaMonitorDataPtr pvaData = monitor->getData(); + while(true) { + monitor->waitEvent(); + cout << "changed\n"; + pvaData->showChanged(cout); + cout << "overrun\n"; + pvaData->showOverrun(cout); + monitor->releaseEvent(); + } +} + + +int main(int argc,char *argv[]) +{ + PvaPtr pva = Pva::create(); + exampleMonitor(pva); + cout << "done\n"; + return 0; +} diff --git a/pvaExample/src/examplePvaMultiDouble.cpp b/pvaExample/src/examplePvaMultiDouble.cpp new file mode 100644 index 0000000..e517857 --- /dev/null +++ b/pvaExample/src/examplePvaMultiDouble.cpp @@ -0,0 +1,84 @@ +/*examplePvaMultiDouble.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void example(PvaPtr const &pva) +{ + cout << "example multiDouble\n"; + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "exampleDouble04"; + channelNames[4] = "exampleDouble05"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + PvaMultiDoublePtr multiDouble(PvaMultiDouble::create(pva,pvNames)); + try { + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + +} + +static void exampleCA(PvaPtr const &pva) +{ + cout << "example multiDouble\n"; + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "double01"; + channelNames[1] = "double02"; + channelNames[2] = "double03"; + channelNames[3] = "double04"; + channelNames[4] = "double05"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + PvaMultiDoublePtr multiDouble(PvaMultiDouble::create(pva,pvNames,5.0,"ca")); + try { + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + +} + + +int main(int argc,char *argv[]) +{ + PvaPtr pva = Pva::create(); + example(pva); + exampleCA(pva); + return 0; +} diff --git a/pvaExample/src/examplePvaNTMultiChannel.cpp b/pvaExample/src/examplePvaNTMultiChannel.cpp new file mode 100644 index 0000000..4c038a5 --- /dev/null +++ b/pvaExample/src/examplePvaNTMultiChannel.cpp @@ -0,0 +1,101 @@ +/*examplePvaNTMultiChannel.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; +using namespace epics::nt; + + +static void example(PvaPtr const &pva) +{ + cout << "example ntMultiChannel\n"; + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble"; + channelNames[1] = "exampleDoubleArray"; + channelNames[2] = "exampleString"; + channelNames[3] = "exampleBoolean"; + channelNames[4] = "exampleEnum"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + StructureConstPtr structure = builder-> + addTimeStamp()-> + addSeverity() -> + addStatus() -> + addMessage() -> + addSecondsPastEpoch() -> + addNanoseconds() -> + addUserTag() -> + createStructure(); + PvaNTMultiChannelPtr multi = PvaNTMultiChannel::create( + pva,pvNames,structure); + try { + NTMultiChannelPtr nt = multi->get(); + cout << "initial\n" << nt->getPVStructure() << endl; + + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + +} + +static void exampleCA(PvaPtr const &pva) +{ + cout << "example ntMultiChannel\n"; + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "double00"; + channelNames[1] = "doubleArray"; + channelNames[2] = "string00"; + channelNames[3] = "mbbiwierd"; + channelNames[4] = "enum01"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + StructureConstPtr structure = builder-> + addTimeStamp()-> + addSeverity() -> + addStatus() -> + addMessage() -> + addSecondsPastEpoch() -> + addNanoseconds() -> + addUserTag() -> + createStructure(); + PvaNTMultiChannelPtr multi = PvaNTMultiChannel::create( + pva,pvNames,structure,5.0,"ca"); + try { + NTMultiChannelPtr nt = multi->get(); + cout << "initial\n" << nt->getPVStructure() << endl; + + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + +} + + +int main(int argc,char *argv[]) +{ + PvaPtr pva = Pva::create(); + example(pva); + exampleCA(pva); + return 0; +} diff --git a/pvaExample/src/examplePvaProcess.cpp b/pvaExample/src/examplePvaProcess.cpp new file mode 100644 index 0000000..dedc019 --- /dev/null +++ b/pvaExample/src/examplePvaProcess.cpp @@ -0,0 +1,44 @@ +/*examplePvaProcess.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void exampleProcess(PvaPtr const &pva) +{ + cout << "example process\n"; + PvaChannelPtr channel = pva->channel("exampleDouble"); + PvaProcessPtr process = channel->createProcess(); + try { + process->process(); + cout << channel->get("field()")->getData()->showChanged(cout) << endl; + process->process(); + cout << channel->get("field()")->getData()->showChanged(cout) << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + + +int main(int argc,char *argv[]) +{ + PvaPtr pva = Pva::create(); + exampleProcess(pva); + return 0; +} diff --git a/pvaExample/src/examplePvaPut.cpp b/pvaExample/src/examplePvaPut.cpp new file mode 100644 index 0000000..aa59f63 --- /dev/null +++ b/pvaExample/src/examplePvaPut.cpp @@ -0,0 +1,45 @@ +/*examplePvaPut.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void examplePut(PvaPtr const &pva) +{ + cout << "example put\n"; + PvaChannelPtr channel = pva->channel("exampleDouble"); + PvaPutPtr put = channel->put(); + PvaPutDataPtr putData = put->getData(); + try { + putData->putDouble(3.0); put->put(); + cout << channel->get("field()")->getData()->showChanged(cout) << endl; + putData->putDouble(4.0); put->put(); + cout << channel->get("field()")->getData()->showChanged(cout) << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + + +int main(int argc,char *argv[]) +{ + PvaPtr pva = Pva::create(); + examplePut(pva); + return 0; +} diff --git a/pvaExample/src/helloWorldPutGet.cpp b/pvaExample/src/helloWorldPutGet.cpp new file mode 100644 index 0000000..d1f3022 --- /dev/null +++ b/pvaExample/src/helloWorldPutGet.cpp @@ -0,0 +1,48 @@ +/*helloWorldPutGet.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void example(PvaPtr const &pva) +{ + cout << "helloWorldPutGet\n"; + try { + PvaChannelPtr channel = pva->channel("exampleHello"); + PvaPutGetPtr putGet = channel->createPutGet(); + putGet->connect(); + PvaPutDataPtr putData = putGet->getPutData(); + PVStructurePtr arg = putData->getPVStructure(); + PVStringPtr pvValue = arg->getSubField("argument.value"); + pvValue->put("World"); + putGet->putGet(); + PvaGetDataPtr getData = putGet->getGetData(); + cout << getData->getPVStructure() << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + + +int main(int argc,char *argv[]) +{ + PvaPtr pva = Pva::create(); + example(pva); + return 0; +} diff --git a/pvaExample/src/helloWorldRPC.cpp b/pvaExample/src/helloWorldRPC.cpp new file mode 100644 index 0000000..9106842 --- /dev/null +++ b/pvaExample/src/helloWorldRPC.cpp @@ -0,0 +1,77 @@ +/*exampleChannelRPC.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; + +static FieldCreatePtr fieldCreate = getFieldCreate(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); + + +static void exampleSimple() +{ + StructureConstPtr topStructure = fieldCreate->createFieldBuilder()-> + add("value",pvString)-> + createStructure(); + PVStructurePtr pvRequest = pvDataCreate->createPVStructure(topStructure); + PVStringPtr pvArgument = pvRequest->getSubField("value"); + pvArgument->put("World"); + cout << "example channeRPC simple\n"; + try { + PVStructurePtr pvResult = + RPCClient::sendRequest("exampleHelloRPC", pvRequest); + cout << "result\n" << pvResult << endl; + } catch (RPCRequestException &e) { + cout << e.what() << endl; + } +} + +void exampleMore() +{ + StructureConstPtr topStructure = fieldCreate->createFieldBuilder()-> + add("value",pvString)-> + createStructure(); + PVStructurePtr pvRequest = pvDataCreate->createPVStructure(topStructure); + PVStringPtr pvArgument = pvRequest->getSubField("value"); + pvArgument->put("World"); + cout << "example channeRPC more\n"; + try { + RPCClient::shared_pointer client = RPCClient::create("exampleHelloRPC"); + client->issueConnect(); + if (client->waitConnect()) + { + client->issueRequest(pvRequest); + PVStructure::shared_pointer result = client->waitResponse(); + std::cout << *result << std::endl; + } + else { + cout << "waitConnect timeout\n"; + return; + } + } catch (RPCRequestException &e) { + cout << e.what() << endl; + } +} + + +int main(int argc,char *argv[]) +{ + exampleSimple(); + exampleMore(); + return 0; +} diff --git a/pvaSrc/Makefile b/pvaSrc/Makefile new file mode 100644 index 0000000..8e876df --- /dev/null +++ b/pvaSrc/Makefile @@ -0,0 +1,34 @@ +# This is a Makefile fragment, see ../Makefile + +TOP = .. +include $(TOP)/configure/CONFIG + +INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv +USR_INCLUDES += -I$(INSTALL_LOCATION)/include + +LIBRARY += pva + +INC += pva.h +INC += pvaMultiDouble.h +INC += pvaNTMultiChannel.h + +LIBSRCS += pva.cpp +LIBSRCS += pvaPutData.cpp +LIBSRCS += pvaGetData.cpp +LIBSRCS += pvaMonitorData.cpp +LIBSRCS += pvaChannel.cpp +LIBSRCS += pvaProcess.cpp +LIBSRCS += pvaGet.cpp +LIBSRCS += pvaPut.cpp +LIBSRCS += pvaMonitor.cpp +LIBSRCS += pvaPutGet.cpp +LIBSRCS += pvaMultiChannel.cpp +LIBSRCS += pvaMultiDouble.cpp +LIBSRCS += pvaNTMultiChannel.cpp +#LIBSRCS += pvaRPC.cpp + +pva_LIBS += pvAccess pvData nt Com +pva_LIBS += $(EPICS_BASE_IOC_LIBS) + +include $(TOP)/configure/RULES + diff --git a/pvaSrc/pva.cpp b/pvaSrc/pva.cpp new file mode 100644 index 0000000..9544dd7 --- /dev/null +++ b/pvaSrc/pva.cpp @@ -0,0 +1,199 @@ +/* pva.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ + +#define epicsExportSharedSymbols +#include +#include +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvAccess::ca; +using namespace std; + +namespace epics { namespace pva { + +static FieldCreatePtr fieldCreate = getFieldCreate(); +static const string pvaName = "pva"; +static const string defaultProvider = "pva"; +static UnionConstPtr variantUnion = fieldCreate->createVariantUnion(); + +namespace pvaPvt { + + static size_t numberPva = 0; + static bool firstTime = true; + static Mutex mutex; + + class StartStopClientFactory { + public: + static void PvaBeingConstructed() + { + bool saveFirst = false; + { + Lock xx(mutex); + ++numberPva; + saveFirst = firstTime; + firstTime = false; + } + if(saveFirst) { + ClientFactory::start(); + CAClientFactory::start(); + } + } + + static void PvaBeingDestroyed() { + size_t numLeft = 0; + { + Lock xx(mutex); + --numberPva; + numLeft = numberPva; + } + if(numLeft<=0) { + ClientFactory::stop(); + CAClientFactory::stop(); + } + } + }; + +} // namespace pvaPvt + +class PvaChannelCache +{ +public: + PvaChannelCache(){} + ~PvaChannelCache(){ + destroy(); + } + void destroy() { + pvaChannelMap.clear(); + } + PvaChannelPtr getChannel(string const & channelName); + void addChannel(PvaChannelPtr const & pvaChannel); + void removeChannel(string const & channelName); +private: + map pvaChannelMap; +}; + +PvaChannelPtr PvaChannelCache::getChannel(string const & channelName) +{ + map::iterator iter = pvaChannelMap.find(channelName); + if(iter!=pvaChannelMap.end()) return iter->second; + return PvaChannelPtr(); +} + +void PvaChannelCache::addChannel(PvaChannelPtr const & pvaChannel) +{ + pvaChannelMap.insert(std::pair( + pvaChannel->getChannelName(),pvaChannel)); +} + +void PvaChannelCache::removeChannel(string const & channelName) +{ + map::iterator iter = pvaChannelMap.find(channelName); + if(iter!=pvaChannelMap.end()) pvaChannelMap.erase(iter); +} + +using namespace epics::pva::pvaPvt; + +PvaPtr Pva::create() +{ + PvaPtr xx(new Pva()); + StartStopClientFactory::PvaBeingConstructed(); + return xx; +} + +PVStructurePtr Pva::createRequest(string const &request) +{ + CreateRequest::shared_pointer createRequest = CreateRequest::create(); + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + throw std::invalid_argument("invalid pvRequest: " + createRequest->getMessage()); + } + return pvRequest; +} + +Pva::Pva() +: pvaChannelCache(new PvaChannelCache()), + isDestroyed(false) +{ +} + +Pva::~Pva() { + destroy(); +} + +void Pva::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaChannelCache.reset(); + channelList.clear(); + multiChannelList.clear(); + StartStopClientFactory::PvaBeingDestroyed(); +} + +string Pva:: getRequesterName() +{ + static string name("pva"); + return name; +} + +void Pva::message( + string const & message, + MessageType messageType) +{ + cout << getMessageTypeName(messageType) << " " << message << endl; +} + +PvaChannelPtr Pva::channel( + std::string const & channelName, + std::string const & providerName, + double timeOut) +{ + PvaChannelPtr pvaChannel = pvaChannelCache->getChannel(channelName); + if(pvaChannel) return pvaChannel; + pvaChannel = createChannel(channelName,providerName); + pvaChannel->connect(timeOut); + pvaChannelCache->addChannel(pvaChannel); + return pvaChannel; +} + +PvaChannelPtr Pva::createChannel(string const & channelName) +{ + return PvaChannel::create(getPtrSelf(),channelName); +} + +PvaChannelPtr Pva::createChannel(string const & channelName, string const & providerName) +{ + return PvaChannel::create(getPtrSelf(),channelName,providerName); +} + +PvaMultiChannelPtr Pva::createMultiChannel( + epics::pvData::PVStringArrayPtr const & channelNames) +{ + return createMultiChannel(channelNames,"pva"); +} + +PvaMultiChannelPtr Pva::createMultiChannel( + epics::pvData::PVStringArrayPtr const & channelNames, + std::string const & providerName) +{ + return PvaMultiChannel::create(getPtrSelf(),channelNames,providerName); +} + +}} + diff --git a/pvaSrc/pva.h b/pvaSrc/pva.h new file mode 100644 index 0000000..1924551 --- /dev/null +++ b/pvaSrc/pva.h @@ -0,0 +1,1662 @@ +/* pva.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#ifndef PVA_H +#define PVA_H + +#ifdef epicsExportSharedSymbols +# define pvaEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef pvaEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef pvaEpicsExportSharedSymbols +#endif + +#include + + +namespace epics { namespace pva { + +class Pva; +typedef std::tr1::shared_ptr PvaPtr; +class PvaGetData; +typedef std::tr1::shared_ptr PvaGetDataPtr; +class PvaPutData; +typedef std::tr1::shared_ptr PvaPutDataPtr; +class PvaMonitorData; +typedef std::tr1::shared_ptr PvaMonitorDataPtr; +class PvaChannel; +typedef std::tr1::shared_ptr PvaChannelPtr; +class PvaField; +typedef std::tr1::shared_ptr PvaFieldPtr; +class PvaProcess; +typedef std::tr1::shared_ptr PvaProcessPtr; +class PvaGet; +typedef std::tr1::shared_ptr PvaGetPtr; +class PvaPut; +typedef std::tr1::shared_ptr PvaPutPtr; +class PvaPutGet; +typedef std::tr1::shared_ptr PvaPutGetPtr; +class PvaMonitor; +typedef std::tr1::shared_ptr PvaMonitorPtr; +class PvaMonitorRequester; +typedef std::tr1::shared_ptr PvaMonitorRequesterPtr; +class PvaArray; +typedef std::tr1::shared_ptr PvaArrayPtr; +class PvaRPC; +typedef std::tr1::shared_ptr PvaRPCPtr; + +typedef epics::pvData::shared_vector PvaChannelArray; +typedef std::tr1::shared_ptr PvaChannelArrayPtr; +typedef std::tr1::weak_ptr PvaChannelArrayWPtr; + +class PvaMultiChannel; +typedef std::tr1::shared_ptr PvaMultiChannelPtr; +class PvaMultiChannelGet; + +// following are private to pva +class PvaChannelCache; +typedef std::tr1::shared_ptr PvaChannelCachePtr; + +/** + * @brief Pva is a synchronous interface to pvAccess plus convenience methods. + * + * @author mrk + */ +class epicsShareClass Pva : + public epics::pvData::Requester, + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(Pva); + + /** + * Destructor + */ + ~Pva(); + /** + * @brief Create an instance of Pva + * @return shared_ptr to new instance. + */ + static PvaPtr create(); + /** @brief get the requester name. + * @return The name. + */ + std::string getRequesterName(); + /** + * @brief A new message. + * If a requester is set then it is called otherwise message is displayed + * on standard out. + * @param message The message. + * @param messageType The type. + */ + void message( + std::string const & message, + epics::pvData::MessageType messageType); + /** + * @brief Destroy all the channels and multiChannels. + */ + void destroy(); + /** + * @brief get a cached channel or create and connect to a new channel. + * The provider is pva. The timeout is 5 seconds. + * If connection can not be made an exception is thrown. + * @param channelName The channelName. + * @return The interface. + */ + PvaChannelPtr channel(std::string const & channelName) + { return channel(channelName,"pva", 5.0); } + /** + * @brief get a cached channel or create and connect to a new channel. + * If connection can not be made an exception is thrown. + * @param channelName The channelName. + * @return The interface. + */ + PvaChannelPtr channel( + std::string const & channelName, + std::string const &providerName, + double timeOut); + /** + * @brief Create an PvaChannel. The provider is pva. + * @param channelName The channelName. + * @return The interface. + */ + PvaChannelPtr createChannel(std::string const & channelName); + /** + * @brief Create an PvaChannel with the specified provider. + * @param channelName The channelName. + * @param providerName The provider. + * @return The interface or null if the provider does not exist. + */ + PvaChannelPtr createChannel( + std::string const & channelName, + std::string const & providerName); + /** + * @brief Create an PvaMultiChannel. The provider is pvAccess. + * @param channelName The channelName array. + * @return The interface. + */ + PvaMultiChannelPtr createMultiChannel( + epics::pvData::PVStringArrayPtr const & channelNames); + /** + * @brief Create an PvaMultiChannel with the specified provider. + * @param channelName The channelName array. + * @param providerName The provider. + * @return The interface. + */ + PvaMultiChannelPtr createMultiChannel( + epics::pvData::PVStringArrayPtr const & channelNames, + std::string const & providerName); + /** + * @brief Set a requester. + * The default is for Pva to handle messages by printing to System.out. + * @param requester The requester. + */ + void setRequester(epics::pvData::RequesterPtr const & requester); + /** + * @brief Clear the requester. Pva will handle messages. + */ + void clearRequester(); + /** + * @brief get shared pointer to this + */ + PvaPtr getPtrSelf() + { + return shared_from_this(); + } +private: + Pva(); + PvaChannelCachePtr pvaChannelCache; + + epics::pvData::PVStructurePtr createRequest(std::string const &request); + std::list channelList; + std::list multiChannelList; + epics::pvData::Requester::weak_pointer requester; + bool isDestroyed; + epics::pvData::Mutex mutex; +}; + +// folowing private to PvaChannel +class PvaGetCache; +typedef std::tr1::shared_ptr PvaGetCachePtr; +class PvaPutCache; +typedef std::tr1::shared_ptr PvaPutCachePtr; +class ChannelRequesterImpl; +/** + * @brief An easy to use alternative to directly calling the Channel methods of pvAccess. + * + * @author mrk + */ +class epicsShareClass PvaChannel : + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(PvaChannel); + /** + * @brief Create a PvaChannel. + * @param pva Interface to Pva + * @param channelName The name of the channel. + * @return The interface. + */ + static PvaChannelPtr create( + PvaPtr const &pva, + std::string const & channelName) + {return create(pva,channelName,"pva");} + /** + * @brief Create a PvaChannel. + * @param channelName The name of the channel. + * @param providerName The name of the provider. + * @return The interface to the PvaStructure. + */ + static PvaChannelPtr create( + PvaPtr const &pva, + std::string const & channelName, + std::string const & providerName); + ~PvaChannel(); + /** + * @brief Destroy the pvAccess connection. + */ + void destroy(); + /** + * @brief Get the name of the channel to which PvaChannel is connected. + * @return The channel name. + */ + std::string getChannelName(); + /** + * @brief Get the the channel to which PvaChannel is connected. + * @return The channel interface. + */ + epics::pvAccess::Channel::shared_pointer getChannel(); + /** + * @brief Connect to the channel. + * This calls issueConnect and waitConnect. + * An exception is thrown if connect fails. + * @param timeout The time to wait for connecting to the channel. + */ + void connect(double timeout=5.0); + /** + * @brief Issue a connect request and return immediately. + */ + void issueConnect(); + /** + * @brief Wait until the connection completes or for timeout. + * @param timeout The time in second to wait. + * @return status. + */ + epics::pvData::Status waitConnect(double timeout); + /** + * @brief Calls the next method with subField = ""; + * @return The interface. + */ + PvaFieldPtr createField(); + /** + * @brief Create an PvaField for the specified subField. + * @param subField The syntax for subField is defined in package org.epics.pvdata.copy + * @return The interface. + */ + PvaFieldPtr createField(std::string const & subField); + /** + * @brief Calls the next method with request = ""; + * @return The interface. + */ + PvaProcessPtr createProcess(); + /** + * @brief First call createRequest as implemented by pvDataJava and then calls the next method. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaProcessPtr createProcess(std::string const & request); + /** + * @brief Creates an PvaProcess. + * @param pvRequest The syntax of pvRequest is described in package org.epics.pvdata.copy. + * @return The interface. + */ + PvaProcessPtr createProcess(epics::pvData::PVStructurePtr const & pvRequest); + /** + * @brief Call the next method with request = "field(value,alarm,timeStamp)" + * @return The interface. + */ + PvaGetPtr get(); + /** + * @brief get a cached PvaGet or create and connect to a new PvaGet. + * Then call it's get method. + * If connection can not be made an exception is thrown. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaGetPtr get(std::string const & request); + /** + * @brief Call the next method with request = "field(value,alarm,timeStamp)" + * @return The interface. + */ + PvaGetPtr createGet(); + /** + * @brief First call createRequest as implemented by pvDataJava and then call the next method. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaGetPtr createGet(std::string const & request); + /** + * @brief Creates an PvaGet. + * @param pvRequest The syntax of pvRequest is described in package org.epics.pvdata.copy. + * @return The interface. + */ + PvaGetPtr createGet(epics::pvData::PVStructurePtr const & pvRequest); + /** + * @brief Call the next method with request = "field(value)" + * @return The interface. + */ + PvaPutPtr put(); + /** + * @brief get a cached PvaPut or create and connect to a new PvaPut. + * Then call it's get method. + * If connection can not be made an exception is thrown. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaPutPtr put(std::string const & request); + /** + * @brief Call the next method with request = "field(value)" + * @return The interface. + */ + PvaPutPtr createPut(); + /** + * @brief First call createRequest as implemented by pvDataJava and then calls the next method. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaPutPtr createPut(std::string const & request); + /** + * @brief Create an PvaPut. + * @param pvRequest The syntax of pvRequest is described in package org.epics.pvdata.copy. + * @return The interface. + */ + PvaPutPtr createPut(epics::pvData::PVStructurePtr const & pvRequest); + /** + * @brief Call the next method with request = "record[process=true]putField(argument)getField(result)". + * @return The interface. + */ + PvaPutGetPtr createPutGet(); + /** + * @brief First call createRequest as implemented by pvDataJava and then calls the next method. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaPutGetPtr createPutGet(std::string const & request); + /** + * @brief Create an PvaPutGet. + * @param pvRequest The syntax of pvRequest is described in package org.epics.pvdata.copy. + * @return The interface. + */ + PvaPutGetPtr createPutGet(epics::pvData::PVStructurePtr const & pvRequest); + /** + * @brief Call createRPC(PVStructure(null)) + * @return The interface. + */ + PvaRPCPtr createRPC(); + /** + * @brief First call createRequest as implemented by pvDataJava and then calls the next method. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaRPCPtr createRPC(std::string const & request); + /** + * @brief Create an PvaRPC. + * @param pvRequest The syntax of pvRequest is described in package org.epics.pvdata.copy. + * @return The interface. + */ + PvaRPCPtr createRPC(epics::pvData::PVStructurePtr const & pvRequest); + /** + * @brief Call the next method with request = "field(value)"; + * @return The interface. + */ + PvaArrayPtr createArray(); + /** + * @brief First call createRequest as implemented by pvDataJava and then calls the next method. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaArrayPtr createArray(std::string const & request); + /** + * @brief Create an PvaArray. + * @param pvRequest The syntax of pvRequest is described in package org.epics.pvdata.copy. + * @return The interface. + */ + PvaArrayPtr createArray(epics::pvData::PVStructurePtr const & pvRequest); + /** + * @brief Call the next method with request = "field(value,alarm,timeStamp)" + * @return The interface. + */ + PvaMonitorPtr monitor(); + /** + * @brief get a cached PvaMonitor or create and connect to a new PvaMonitor. + * Then call it's start method. + * If connection can not be made an exception is thrown. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaMonitorPtr monitor(std::string const & request); + /** + * @brief Call the next method with request = "field(value,alarm,timeStamp)" + * @param pvaMonitorRequester The client callback. + * @return The interface. + */ + PvaMonitorPtr monitor(PvaMonitorRequesterPtr const & pvaMonitorRequester); + + /** + * @brief get a cached PvaMonitor or create and connect to a new PvaMonitor. + * Then call it's start method. + * If connection can not be made an exception is thrown. + * @param request The request as described in package org.epics.pvdata.copy + * @param pvaMonitorRequester The client callback. + * @return The interface. + */ + PvaMonitorPtr monitor( + std::string const & request, + PvaMonitorRequesterPtr const & pvaMonitorRequester); + /** + * @brief Call the next method with request = "field(value.alarm,timeStamp)" + * @return The interface. + */ + PvaMonitorPtr createMonitor(); + /** + * @brief First call createRequest as implemented by pvDataJava and then calls the next method. + * @param request The request as described in package org.epics.pvdata.copy + * @return The interface. + */ + PvaMonitorPtr createMonitor(std::string const & request); + /** + * @brief Create an PvaMonitor. + * @param pvRequest The syntax of pvRequest is described in package org.epics.pvdata.copy. + * @return The interface. + */ + PvaMonitorPtr createMonitor(epics::pvData::PVStructurePtr const & pvRequest); + PvaChannelPtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaChannel( + PvaPtr const &pva, + std::string const & channelName, + std::string const & providerName); + void channelCreated( + const epics::pvData::Status& status, + epics::pvAccess::Channel::shared_pointer const & channel); + void channelStateChange( + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvAccess::Channel::ConnectionState connectionState); + std::string getRequesterName(); + void message( + std::string const & message, + epics::pvData::MessageType messageType); + + enum ConnectState {connectIdle,connectActive,notConnected,connected}; + + Pva::weak_pointer pva; + std::string channelName; + std::string providerName; + ConnectState connectState; + bool isDestroyed; + epics::pvData::CreateRequest::shared_pointer createRequest; + PvaGetCachePtr pvaGetCache; + PvaPutCachePtr pvaPutCache; + + epics::pvData::Status channelConnectStatus; + epics::pvData::Mutex mutex; + epics::pvData::Event waitForConnect; + epics::pvAccess::Channel::shared_pointer channel; + epics::pvAccess::ChannelRequester::shared_pointer channelRequester; + friend class ChannelRequesterImpl; +}; + +/** + * @brief This is a class that holds data returned by PvaGet or PvaPutGet + * + */ +class epicsShareClass PvaGetData +{ +public: + POINTER_DEFINITIONS(PvaGetData); + /** + * @brief Factory method for creating an instance of PvaGetData. + */ + static PvaGetDataPtr create(epics::pvData::StructureConstPtr const & structure); + ~PvaGetData() {} + /** + * @brief Set a prefix for throw messages. + * @param value The prefix. + */ + void setMessagePrefix(std::string const & value); + /** @brief Get the structure. + * @return the structure. + */ + epics::pvData::StructureConstPtr getStructure(); + /** @brief Get the pvStructure. + * @return the pvStructure. + */ + epics::pvData::PVStructurePtr getPVStructure(); + /** @brief Get the BitSet for the pvStructure + * This shows which fields have changed value. + * @return The bitSet + */ + epics::pvData::BitSetPtr getBitSet(); + /** @brief show the fields that have changed. + * @param out The stream that shows the changed fields. + * @return The stream that was input + */ + std::ostream & showChanged(std::ostream & out); + /** + * @brief New data is present. + * @param pvStructureFrom The new data. + * @param bitSetFrom the bitSet showing which values have changed. + */ + void setData( + epics::pvData::PVStructurePtr const & pvStructureFrom, + epics::pvData::BitSetPtr const & bitSetFrom); + /** + * @brief Is there a top level field named value. + * @return The answer. + */ + bool hasValue(); + /** + * @brief Is the value field a scalar? + * @return The answer. + */ + bool isValueScalar(); + /** + * @brief Is the value field a scalar array? + * @return The answer. + */ + bool isValueScalarArray(); + /** + * @brief Return the interface to the value field. + * @return The interface. an excetion is thrown if a value field does not exist. + */ + epics::pvData::PVFieldPtr getValue(); + /** + * @brief Return the interface to a scalar value field. + * @return The interface for a scalar value field. + * An exception is thown if no scalar value field. + */ + epics::pvData::PVScalarPtr getScalarValue(); + /** + * @brief Return the interface to an array value field. + * @return The interface. + * An exception is thown if no array value field. + */ + std::tr1::shared_ptr getArrayValue(); + /** + * @brief Return the interface to a scalar array value field. + * @return Return the interface. + * An exception is thown if no scalar array value field. + */ + std::tr1::shared_ptr getScalarArrayValue(); + /** + * @brief Get the value as a double. + * If value is not a numeric scalar an exception is thrown. + * @return The value. + */ + double getDouble(); + /** + * @brief Get the value as a string. + * If value is not a scalar an exception is thrown + * @return The value. + */ + std::string getString(); + /** + * @brief Get the value as a double array. + * If the value is not a numeric array an exception is thrown. + * @return The value. + */ + epics::pvData::shared_vector getDoubleArray(); + /** + * @brief Get the value as a string array. + * If the value is not a string array an exception is thrown. + * @return The value. + */ + epics::pvData::shared_vector getStringArray(); + /** + * @brief Get the alarm. + * If the pvStructure as an alarm field it's values are returned. + * If no then alarm shows that not alarm defined. + * @return The alarm. + */ + epics::pvData::Alarm getAlarm(); + /** + * @brief Get the timeStamp. + * If the pvStructure as a timeStamp field, it's values are returned. + * If no then all fields are 0. + * @return The timeStamp. + */ + epics::pvData::TimeStamp getTimeStamp(); +private: + PvaGetData(epics::pvData::StructureConstPtr const & structure); + void checkValue(); + epics::pvData::StructureConstPtr structure; + epics::pvData::PVStructurePtr pvStructure; + epics::pvData::BitSetPtr bitSet; + + std::string messagePrefix; + epics::pvData::PVFieldPtr pvValue; + epics::pvData::PVAlarm pvAlarm; + epics::pvData::PVTimeStamp pvTimeStamp; +}; + +class PvaPostHandlerPvt; // private to PvaPutData +/** + * @brief This is a class that holds data given to by PvaPut or PvaPutGet + * + */ +class epicsShareClass PvaPutData +{ +public: + POINTER_DEFINITIONS(PvaPutData); + /** + * @brief Factory method for creating an instance of PvaPutData. + */ + static PvaPutDataPtr create(epics::pvData::StructureConstPtr const & structure); + ~PvaPutData() {} + /** + * @brief Set a prefix for throw messages. + * @param value The prefix. + */ + void setMessagePrefix(std::string const & value); + /** @brief Get the structure. + * @return the structure. + */ + epics::pvData::StructureConstPtr getStructure(); + /** @brief Get the pvStructure. + * @return the pvStructure. + */ + epics::pvData::PVStructurePtr getPVStructure(); + /** @brief Get the BitSet for the pvStructure + * This shows which fields have changed value. + * @return The bitSet + */ + epics::pvData::BitSetPtr getBitSet(); + /** @brief show the fields that have changed. + * @param out The stream that shows the changed fields. + * @return The stream that was input + */ + std::ostream & showChanged(std::ostream & out); + /** + * @brief Is there a top level field named value. + * @return The answer. + */ + bool hasValue(); + /** + * @brief Is the value field a scalar? + * @return The answer. + */ + bool isValueScalar(); + /** + * @brief Is the value field a scalar array? + * @return The answer. + */ + bool isValueScalarArray(); + /** + * @brief Return the interface to the value field. + * @return The interface. an excetion is thrown if a value field does not exist. + */ + epics::pvData::PVFieldPtr getValue(); + /** + * @brief Return the interface to a scalar value field. + * @return The interface for a scalar value field. + * An exception is thown if no scalar value field. + */ + epics::pvData::PVScalarPtr getScalarValue(); + /** + * @brief Return the interface to an array value field. + * @return The interface. + * An exception is thown if no array value field. + */ + std::tr1::shared_ptr getArrayValue(); + /** + * @brief Return the interface to a scalar array value field. + * @return Return the interface. + * An exception is thown if no scalar array value field. + */ + std::tr1::shared_ptr getScalarArrayValue(); + /** + * @brief Get the value as a double. + * If value is not a numeric scalar an exception is thrown. + * @return The value. + */ + double getDouble(); + /** + * @brief Get the value as a string. + * If value is not a string an exception is thrown + * @return The value. + */ + std::string getString(); + /** + * @brief Get the value as a double array. + * If the value is not a numeric array an exception is thrown. + * @return The value. + */ + epics::pvData::shared_vector getDoubleArray(); + /** + * @brief Get the value as a string array. + * If the value is not a string array an exception is thrown. + * @return The value. + */ + epics::pvData::shared_vector getStringArray(); + /** + * Put the value as a double. + * An exception is also thrown if the actualy type can cause an overflow. + * If value is not a numeric scalar an exception is thrown. + */ + void putDouble(double value); + /** + * Put the value as a string. + * If value is not a scalar an exception is thrown. + */ + void putString(std::string const & value); + /** + * Copy the array to the value field. + * If the value field is not a double array field an exception is thrown. + * @param value The place where data is copied. + */ + void putDoubleArray(epics::pvData::shared_vector const & value); + /** + * Copy array to the value field. + * If the value field is not a string array field an exception is thrown. + * @param value data source + */ + void putStringArray(epics::pvData::shared_vector const & value); + /** + * Copy array to the value field. + * If the value field is not a scalarArray field an exception is thrown. + * @param value data source + */ + void putStringArray(std::vector const & value); +private: + PvaPutData(epics::pvData::StructureConstPtr const &structure); + void checkValue(); + void postPut(size_t fieldNumber); + + std::vector postHandler; + epics::pvData::StructureConstPtr structure; + epics::pvData::PVStructurePtr pvStructure; + epics::pvData::BitSetPtr bitSet; + friend class PvaPostHandlerPvt; + + std::string messagePrefix; + epics::pvData::PVFieldPtr pvValue; +}; + +/** + * @brief This is a class that holds data returned by PvaMonitor + * + */ +class epicsShareClass PvaMonitorData +{ +public: + POINTER_DEFINITIONS(PvaMonitorData); + /** + * @brief Factory method for creating an instance of PvaMonitorData. + */ + static PvaMonitorDataPtr create(epics::pvData::StructureConstPtr const & structure); + ~PvaMonitorData() {} + /** + * @brief Set a prefix for throw messages. + * @param value The prefix. + */ + void setMessagePrefix(std::string const & value); + /** @brief Get the structure. + * @return the structure. + */ + epics::pvData::StructureConstPtr getStructure(); + /** @brief Get the pvStructure. + * @return the pvStructure. + */ + epics::pvData::PVStructurePtr getPVStructure(); + /** @brief Get the BitSet for the pvStructure + * This shows which fields have changed value. + * @return The bitSet + */ + epics::pvData::BitSetPtr getChangedBitSet(); + /** @brief Get the overrun BitSet for the pvStructure + * This shows which fields have had more than one change. + * @return The bitSet + */ + epics::pvData::BitSetPtr getOverrunBitSet(); + /** @brief show the fields that have changed. + * @param out The stream that shows the changed fields. + * @return The stream that was input + */ + std::ostream & showChanged(std::ostream & out); + /** @brief show the fields that have overrun. + * @param out The stream that shows the overrun fields. + * @return The stream that was input + */ + std::ostream & showOverrun(std::ostream & out); + /** + * @brief New data is present. + * @param monitorElement The new data. + */ + void setData(epics::pvData::MonitorElementPtr const & monitorElement); + /** + * @brief Is there a top level field named value. + * @return The answer. + */ + bool hasValue(); + /** + * @brief Is the value field a scalar? + * @return The answer. + */ + bool isValueScalar(); + /** + * @brief Is the value field a scalar array? + * @return The answer. + */ + bool isValueScalarArray(); + /** + * @brief Return the interface to the value field. + * @return The interface. an excetion is thrown if a value field does not exist. + */ + epics::pvData::PVFieldPtr getValue(); + /** + * @brief Return the interface to a scalar value field. + * @return The interface for a scalar value field. + * An exception is thown if no scalar value field. + */ + epics::pvData::PVScalarPtr getScalarValue(); + /** + * @brief Return the interface to an array value field. + * @return The interface. + * An exception is thown if no array value field. + */ + std::tr1::shared_ptr getArrayValue(); + /** + * @brief Return the interface to a scalar array value field. + * @return Return the interface. + * An exception is thown if no scalar array value field. + */ + std::tr1::shared_ptr getScalarArrayValue(); + /** + * @brief Get the value as a double. + * If value is not a numeric scalar an exception is thrown. + * @return The value. + */ + double getDouble(); + /** + * @brief Get the value as a string. + * If value is not a scalar an exception is thrown + * @return The value. + */ + std::string getString(); + /** + * @brief Get the value as a double array. + * If the value is not a numeric array an exception is thrown. + * @return The value. + */ + epics::pvData::shared_vector getDoubleArray(); + /** + * @brief Get the value as a string array. + * If the value is not a string array an exception is thrown. + * @return The value. + */ + epics::pvData::shared_vector getStringArray(); + /** + * @brief Get the alarm. + * If the pvStructure as an alarm field it's values are returned. + * If no then alarm shows that not alarm defined. + * @return The alarm. + */ + epics::pvData::Alarm getAlarm(); + /** + * @brief Get the timeStamp. + * If the pvStructure as a timeStamp field, it's values are returned. + * If no then all fields are 0. + * @return The timeStamp. + */ + epics::pvData::TimeStamp getTimeStamp(); +private: + PvaMonitorData(epics::pvData::StructureConstPtr const & structure); + void checkValue(); + + epics::pvData::StructureConstPtr structure; + epics::pvData::PVStructurePtr pvStructure; + epics::pvData::BitSetPtr changedBitSet; + epics::pvData::BitSetPtr overrunBitSet; + + std::string messagePrefix; + epics::pvData::PVFieldPtr pvValue; + epics::pvData::PVAlarm pvAlarm; + epics::pvData::PVTimeStamp pvTimeStamp; +}; + +class ChannelProcessRequesterImpl; // private to PvaProcess +/** + * @brief An easy to use alternative to ChannelProcess. + * + * @author mrk + */ +class epicsShareClass PvaProcess +{ +public: + POINTER_DEFINITIONS(PvaProcess); + /** + * @brief Create a PvaProcess. + * @param &pva Interface to Pva + * @param pvaChannel Interface to PvaChannel + * @param channel Interface to Channel + * @param pvRequest The request structure. + * @return The interface to the PvaStructure. + */ + static PvaProcessPtr create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest + ); + /** + * @brief destructor + */ + ~PvaProcess(); + /** + * @brief destroy an resources used. + */ + void destroy(); + /** + * @brief call issueConnect and then waitConnect. + * An exception is thrown if connect fails. + */ + void connect(); + /** + * @brief create the channelProcess connection to the channel. + * This can only be called once. + */ + void issueConnect(); + /** + * @brief wait until the channelProcess connection to the channel is complete. + * @return status; + */ + epics::pvData::Status waitConnect(); + /** + * @brief Call issueProcess and then waitProcess. + * An exception is thrown if get fails. + */ + void process(); + /** + * @brief Issue a get and return immediately. + */ + void issueProcess(); + /** + * @brief Wait until get completes. + * @return status. + */ + epics::pvData::Status waitProcess(); +private: + PvaProcess( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest); + std::string getRequesterName(); + void message(std::string const & message,epics::pvData::MessageType messageType); + void channelProcessConnect( + const epics::pvData::Status& status, + epics::pvAccess::ChannelProcess::shared_pointer const & channelProcess); + void processDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelProcess::shared_pointer const & channelProcess); + void checkProcessState(); + enum ProcessConnectState {connectIdle,connectActive,connected}; + + Pva::weak_pointer pva; + PvaChannel::weak_pointer pvaChannel; + epics::pvAccess::Channel::shared_pointer channel; + epics::pvAccess::ChannelProcessRequester::shared_pointer processRequester; + epics::pvData::PVStructurePtr pvRequest; + epics::pvData::Mutex mutex; + epics::pvData::Event waitForConnect; + epics::pvData::Event waitForProcess; + std::string messagePrefix; + + bool isDestroyed; + epics::pvData::Status channelProcessConnectStatus; + epics::pvData::Status channelProcessStatus; + epics::pvAccess::ChannelProcess::shared_pointer channelProcess; + + ProcessConnectState connectState; + + enum ProcessState {processIdle,processActive,processComplete}; + ProcessState processState; + friend class ChannelProcessRequesterImpl; +}; + +class ChannelGetRequesterImpl; // private to PvaGet +/** + * @brief An easy to use alternative to ChannelGet. + * + * @author mrk + */ +class epicsShareClass PvaGet +{ +public: + POINTER_DEFINITIONS(PvaGet); + /** + * @brief Create a PvaGet. + * @param &pva Interface to Pva + * @param pvaChannel Interface to PvaChannel + * @param channel Interface to Channel + * @param pvRequest The request structure. + * @return The interface to the PvaStructure. + */ + static PvaGetPtr create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest + ); + /** + * @brief destructor + */ + ~PvaGet(); + /** + * @brief destroy an resources used. + */ + void destroy(); + /** + * @brief call issueConnect and then waitConnect. + * An exception is thrown if connect fails. + */ + void connect(); + /** + * @brief create the channelGet connection to the channel. + * This can only be called once. + */ + void issueConnect(); + /** + * @brief wait until the channelGet connection to the channel is complete. + * @return status; + */ + epics::pvData::Status waitConnect(); + /** + * @brief Call issueGet and then waitGet. + * An exception is thrown if get fails. + */ + void get(); + /** + * @brief Issue a get and return immediately. + */ + void issueGet(); + /** + * @brief Wait until get completes. + * @return status; + */ + epics::pvData::Status waitGet(); + /** + * @brief Get the data/ + * @return The interface. + */ + PvaGetDataPtr getData(); +private: + PvaGet( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest); + std::string getRequesterName(); + void message(std::string const & message,epics::pvData::MessageType messageType); + void channelGetConnect( + const epics::pvData::Status& status, + epics::pvAccess::ChannelGet::shared_pointer const & channelGet, + epics::pvData::StructureConstPtr const & structure); + void getDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelGet::shared_pointer const & channelGet, + epics::pvData::PVStructurePtr const & pvStructure, + epics::pvData::BitSetPtr const & bitSet); + void checkGetState(); + enum GetConnectState {connectIdle,connectActive,connected}; + + Pva::weak_pointer pva; + PvaChannel::weak_pointer pvaChannel; + epics::pvAccess::Channel::shared_pointer channel; + epics::pvAccess::ChannelGetRequester::shared_pointer getRequester; + epics::pvData::PVStructurePtr pvRequest; + epics::pvData::Mutex mutex; + epics::pvData::Event waitForConnect; + epics::pvData::Event waitForGet; + PvaGetDataPtr pvaData; + std::string messagePrefix; + + bool isDestroyed; + epics::pvData::Status channelGetConnectStatus; + epics::pvData::Status channelGetStatus; + epics::pvAccess::ChannelGet::shared_pointer channelGet; + + GetConnectState connectState; + + enum GetState {getIdle,getActive,getComplete}; + GetState getState; + friend class ChannelGetRequesterImpl; +}; + +class ChannelPutRequesterImpl; // private to PvaPut +/** + * @brief An easy to use alternative to ChannelPut. + * + * @author mrk + */ +class epicsShareClass PvaPut +{ +public: + POINTER_DEFINITIONS(PvaPut); + /** + * @brief Create a PvaPut. + * @param &pva Interface to Pva + * @param pvaChannel Interface to PvaChannel + * @param channel Interface to Channel + * @param pvRequest The request structure. + * @return The interface to the PvaStructure. + */ + static PvaPutPtr create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest + ); + /** + * @brief destructor + */ + ~PvaPut(); + /** + * @brief destroy an resources used. + */ + void destroy(); + /** + * @brief call issueConnect and then waitConnect. + * An exception is thrown if connect fails. + */ + void connect(); + /** + * @brief create the channelPut connection to the channel. + * This can only be called once. + */ + void issueConnect(); + /** + * @brief wait until the channelPut connection to the channel is complete. + * @return status; + */ + epics::pvData::Status waitConnect(); + /** + * @brief Call issueGet and then waitGet. + * An exception is thrown if get fails. + */ + void get(); + /** + * @brief Issue a get and return immediately. + */ + void issueGet(); + /** + * @brief Wait until get completes. + * @return status + */ + epics::pvData::Status waitGet(); + /** + * @brief Call issuePut and then waitPut. + * An exception is thrown if get fails. + */ + void put(); + /** + * @brief Issue a put and return immediately. + */ + void issuePut(); + /** + * @brief Wait until put completes. + * @return status + */ + epics::pvData::Status waitPut(); + /** + * @brief Get the data/ + * @return The interface. + */ + PvaPutDataPtr getData(); +private : + PvaPut( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest); + std::string getRequesterName(); + void message(std::string const & message,epics::pvData::MessageType messageType); + void channelPutConnect( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut, + epics::pvData::StructureConstPtr const & structure); + void getDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut, + epics::pvData::PVStructurePtr const & pvStructure, + epics::pvData::BitSetPtr const & bitSet); + void putDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut); + void checkPutState(); + enum PutConnectState {connectIdle,connectActive,connected}; + + Pva::weak_pointer pva; + PvaChannel::weak_pointer pvaChannel; + epics::pvAccess::Channel::shared_pointer channel; + epics::pvAccess::ChannelPutRequester::shared_pointer putRequester; + epics::pvData::PVStructurePtr pvRequest; + epics::pvData::Mutex mutex; + epics::pvData::Event waitForConnect; + epics::pvData::Event waitForGetPut; + PvaPutDataPtr pvaData; + std::string messagePrefix; + + bool isDestroyed; + epics::pvData::Status channelPutConnectStatus; + epics::pvData::Status channelGetPutStatus; + epics::pvAccess::ChannelPut::shared_pointer channelPut; + + PutConnectState connectState; + + enum PutState {putIdle,getActive,putActive,putComplete}; + PutState putState; + friend class ChannelPutRequesterImpl; +}; + +class ChannelPutGetRequesterImpl; // private to PvaPutGet +/** + * @brief An easy to use alternative to ChannelPutGet. + * + * @author mrk + */ +class epicsShareClass PvaPutGet +{ +public: + POINTER_DEFINITIONS(PvaPutGet); + /** + * @brief Create a PvaPutGet. + * @param &pva Interface to Pva + * @param pvaChannel Interface to PvaChannel + * @param channel Interface to Channel + * @param pvRequest The request structure. + * @return The interface to the PvaStructure. + */ + static PvaPutGetPtr create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest + ); + /** + * @brief destructor + */ + ~PvaPutGet(); + /** + * @brief destroy an resources used. + */ + void destroy(); + /** + * @brief call issueConnect and then waitConnect. + * An exception is thrown if connect fails. + */ + void connect(); + /** + * @brief create the channelPutGet connection to the channel. + * This can only be called once. + * An exception is thrown if connect fails. + */ + void issueConnect(); + /** + * @brief wait until the channelPutGet connection to the channel is complete. + * @return status; + */ + epics::pvData::Status waitConnect(); + /** + * @brief Call issuePutGet and then waitPutGet. + * An exception is thrown if putGet fails. + */ + void putGet(); + /** + * @brief Issue a putGet and return immediately. + */ + void issuePutGet(); + /** + * @brief Wait until putGet completes. + * If failure getStatus can be called to get reason. + * @return status + */ + epics::pvData::Status waitPutGet(); + /** + * @brief Call issueGet and then waitGetGet. + * An exception is thrown if get fails. + */ + void getGet(); + /** + * @brief Issue a getGet and return immediately. + */ + void issueGetGet(); + /** + * @brief Wait until getGet completes. + * If failure getStatus can be called to get reason. + * @return status + */ + epics::pvData::Status waitGetGet(); + /** + * @brief Call issuePut and then waitGetPut. + * An exception is thrown if getPut fails. + */ + void getPut(); + /** + * @brief Issue a getPut and return immediately. + */ + void issueGetPut(); + /** + * @brief Wait until getPut completes. + * @return status + */ + epics::pvData::Status waitGetPut(); + /** + * @brief Get the put data. + * @return The interface. + */ + PvaPutDataPtr getPutData(); + /** + * @brief Get the get data. + * @return The interface. + */ + PvaGetDataPtr getGetData(); +private : + PvaPutGet( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest); + std::string getRequesterName(); + void message(std::string const & message,epics::pvData::MessageType messageType); + void channelPutGetConnect( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::StructureConstPtr const & putStructure, + epics::pvData::StructureConstPtr const & getStructure); + void putGetDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructurePtr const & getPVStructure, + epics::pvData::BitSetPtr const & getBitSet); + void getPutDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructurePtr const & putPVStructure, + epics::pvData::BitSet::shared_pointer const & putBitSet); + void getGetDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructurePtr const & getPVStructure, + epics::pvData::BitSet::shared_pointer const & getBitSet); + void checkPutGetState(); + enum PutGetConnectState {connectIdle,connectActive,connected}; + + Pva::weak_pointer pva; + PvaChannel::weak_pointer pvaChannel; + epics::pvAccess::Channel::shared_pointer channel; + epics::pvAccess::ChannelPutGetRequester::shared_pointer putGetRequester; + epics::pvData::PVStructurePtr pvRequest; + epics::pvData::Mutex mutex; + epics::pvData::Event waitForConnect; + epics::pvData::Event waitForPutGet; + PvaGetDataPtr pvaGetData; + PvaPutDataPtr pvaPutData; + std::string messagePrefix; + + bool isDestroyed; + epics::pvData::Status channelPutGetConnectStatus; + epics::pvData::Status channelGetPutGetStatus; + epics::pvAccess::ChannelPutGet::shared_pointer channelPutGet; + + PutGetConnectState connectState; + epics::pvData::Status channelPutGetStatus; + + enum PutGetState {putGetIdle,putGetActive,putGetComplete}; + PutGetState putGetState; + friend class ChannelPutGetRequesterImpl; +}; + +class ChannelMonitorRequester; // private to PvaMonitor +/** + * @brief Optional client callback. + * + */ +class epicsShareClass PvaMonitorRequester +{ +public: + POINTER_DEFINITIONS(PvaMonitorRequester); + /** + * @brief destructor + */ + virtual ~PvaMonitorRequester(){} + /** + * @brief A monitor event has occurred. + * @param monitor The PvaMonitor that received the event. + */ + virtual void event(PvaMonitorPtr monitor) = 0; +}; + +/** + * @brief An easy to use alternative to Monitor. + * + */ +class epicsShareClass PvaMonitor : + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(PvaMonitor); + /** + * @brief Create a PvaMonitor. + * @param &pva Interface to Pva + * @param pvaChannel Interface to PvaChannel + * @param channel Interface to Channel + * @param pvRequest The request structure. + * @return The interface to the PvaStructure. + */ + static PvaMonitorPtr create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest + ); + /** + * @brief destructor + */ + ~PvaMonitor(); + /** + * @brief destroy an resources used. + */ + void destroy(); + /** + * @brief call issueConnect and then waitConnect. + * An exception is thrown if connect fails. + */ + void connect(); + /** + * @brief create the channelMonitor connection to the channel. + * This can only be called once. + * An exception is thrown if connect fails. + */ + void issueConnect(); + /** + * @brief wait until the channelMonitor connection to the channel is complete. + * @return status; + */ + epics::pvData::Status waitConnect(); + /** + * @brief Set a user callback. + * @param pvaMonitorrRequester The requester which must be implemented by the caller. + */ + void setRequester(PvaMonitorRequesterPtr const & pvaMonitorrRequester); + /** + * @brief Start monitoring. + */ + void start(); + /** + * @brief Stop monitoring. + */ + void stop(); + /** + * @brief poll for a monitor event. + * The data will be in PvaData. + * @return (false,true) means event (did not, did) occur. + */ + bool poll(); + /** + * @brief wait for a monitor event. + * The data will be in PvaData. + * @param secondsToWait Time to wait for event. + * @return (false,true) means event (did not, did) occur. + */ + bool waitEvent(double secondsToWait = 0.0); + /** + * @brief Release the monitorElement returned by poll + */ + void releaseEvent(); + /** + * @brief The data in which monitor events are placed. + * @return The interface. + */ + PvaMonitorDataPtr getData(); + /** + * @brief get shared pointer to this + */ + PvaMonitorPtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaMonitor( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + epics::pvAccess::Channel::shared_pointer const & channel, + epics::pvData::PVStructurePtr const &pvRequest); + std::string getRequesterName(); + void message(std::string const & message,epics::pvData::MessageType messageType); + void monitorConnect( + const epics::pvData::Status& status, + epics::pvData::MonitorPtr const & monitor, + epics::pvData::StructureConstPtr const & structure); + void monitorEvent(epics::pvData::MonitorPtr const & monitor); + void unlisten(); + void checkMonitorState(); + enum MonitorConnectState {connectIdle,connectActive,connected,monitorStarted}; + + Pva::weak_pointer pva; + PvaChannel::weak_pointer pvaChannel; + epics::pvAccess::Channel::shared_pointer channel; + epics::pvData::PVStructurePtr pvRequest; + epics::pvData::MonitorRequester::shared_pointer monitorRequester; + epics::pvData::Mutex mutex; + epics::pvData::Event waitForConnect; + epics::pvData::Event waitForEvent; + PvaMonitorDataPtr pvaData; + std::string messagePrefix; + + bool isDestroyed; + epics::pvData::Status connectStatus; + epics::pvData::MonitorPtr monitor; + epics::pvData::MonitorElementPtr monitorElement; + PvaMonitorRequester::weak_pointer pvaMonitorRequester; + + MonitorConnectState connectState; + bool userPoll; + bool userWait; + friend class ChannelMonitorRequester; +}; + +/** + * @brief Provides access to multiple channels. + * + * @author mrk + */ +class epicsShareClass PvaMultiChannel : + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(PvaMultiChannel); + /** + * @brief Create a PvaMultiChannel. + * @param channelNames The name. of the channel.. + * @param providerName The name of the provider. + * @return The interface to the PvaStructure. + */ + static PvaMultiChannelPtr create( + PvaPtr const &pva, + epics::pvData::PVStringArrayPtr const & channelNames, + std::string const & providerName = "pva"); + ~PvaMultiChannel(); + /** + * @brief Destroy the pvAccess connection. + */ + void destroy(); + /** + * @brief Get the channelNames. + * @return The names. + */ + epics::pvData::PVStringArrayPtr getChannelNames(); + /** + * @brief Connect to the channel. + * This calls issueConnect and waitConnect. + * An exception is thrown if connect fails. + * @param timeout The time to wait for connecting to the channel. + * @param maxNotConnected Maximum number of channels that do not connect. + * @return status of request + */ + epics::pvData::Status connect( + double timeout=5, + size_t maxNotConnected=0); + /** + * Are all channels connected? + * @return if all are connected. + */ + bool allConnected(); + /** + * Has a connection state change occured? + * @return (true, false) if (at least one, no) channel has changed state. + */ + bool connectionChange(); + /** + * Get the connection state of each channel. + * @return The state of each channel. + */ + epics::pvData::PVBooleanArrayPtr getIsConnected(); + /** + * Get the pvaChannelArray. + * @return The weak shared pointer. + */ + PvaChannelArrayWPtr getPvaChannelArray(); + /** + * Get pva. + * @return The weak shared pointer. + */ + Pva::weak_pointer getPva(); + /** + * Get the shared pointer to self. + * @return The shared pointer. + */ + PvaMultiChannelPtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaMultiChannel( + PvaPtr const &pva, + epics::pvData::PVStringArrayPtr const & channelName, + std::string const & providerName); + + Pva::weak_pointer pva; + epics::pvData::PVStringArrayPtr channelName; + std::string providerName; + size_t numChannel; + epics::pvData::Mutex mutex; + + size_t numConnected; + PvaChannelArrayPtr pvaChannelArray; + epics::pvData::PVBooleanArrayPtr isConnected; + bool isDestroyed; +}; + + +}} + +#endif /* PVA_H */ + +/** @page Overview Documentation + * + * pvaOverview.html + * + */ + diff --git a/pvaSrc/pvaChannel.cpp b/pvaSrc/pvaChannel.cpp new file mode 100644 index 0000000..25ecffa --- /dev/null +++ b/pvaSrc/pvaChannel.cpp @@ -0,0 +1,495 @@ +/* pvaChannel.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include +#include +#include +#include +#include +#include + + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + + +class PvaGetCache +{ +public: + PvaGetCache(){} + ~PvaGetCache(); + void destroy() { + pvaGetMap.clear(); + } + PvaGetPtr getGet(string const & request); + void addGet(string const & request,PvaGetPtr const & pvaGet); +private: + map pvaGetMap; +}; + +PvaGetCache::~PvaGetCache() +{ + destroy(); +} + +PvaGetPtr PvaGetCache::getGet(string const & request) +{ + map::iterator iter = pvaGetMap.find(request); + if(iter!=pvaGetMap.end()) return iter->second; + return PvaGetPtr(); +} + +void PvaGetCache::addGet(string const & request,PvaGetPtr const & pvaGet) +{ + pvaGetMap.insert(std::pair( + request,pvaGet)); +} + + +class PvaPutCache +{ +public: + PvaPutCache(){} + ~PvaPutCache(); + void destroy() { + pvaPutMap.clear(); + } + PvaPutPtr getPut(string const & request); + void addPut(string const & request,PvaPutPtr const & pvaPut); +private: + map pvaPutMap; +}; + +PvaPutCache::~PvaPutCache() +{ + destroy(); +} + +PvaPutPtr PvaPutCache::getPut(string const & request) +{ + map::iterator iter = pvaPutMap.find(request); + if(iter!=pvaPutMap.end()) return iter->second; + return PvaPutPtr(); +} + +void PvaPutCache::addPut(string const & request,PvaPutPtr const & pvaPut) +{ + pvaPutMap.insert(std::pair( + request,pvaPut)); +} + +class ChannelRequesterImpl : public ChannelRequester +{ + PvaChannel *pvaChannel; +public: + ChannelRequesterImpl(PvaChannel *pvaChannel) + : pvaChannel(pvaChannel) {} + void channelCreated( + const Status& status, + Channel::shared_pointer const & channel) + { pvaChannel->channelCreated(status,channel); } + void channelStateChange( + Channel::shared_pointer const & channel, + Channel::ConnectionState connectionState) + {pvaChannel->channelStateChange(channel,connectionState);} + tr1::shared_ptr getChannel() {return pvaChannel->getChannel();} + string getRequesterName() + {return pvaChannel->getRequesterName();} + void message( + string const & message, + MessageType messageType) + { pvaChannel->message(message,messageType); } + void destroy() {pvaChannel->destroy();} +}; + + +PvaChannel::PvaChannel( + PvaPtr const &pva, + string const & channelName, + string const & providerName) +: pva(pva), + channelName(channelName), + providerName(providerName), + connectState(connectIdle), + isDestroyed(false), + createRequest(CreateRequest::create()), + pvaGetCache(new PvaGetCache()), + pvaPutCache(new PvaPutCache()) +{} + +PvaChannel::~PvaChannel() +{ + destroy(); +} + +void PvaChannel::channelCreated(const Status& status, Channel::shared_pointer const & channel) +{ + if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed"); + if(status.isOK()) { + this->channel = channel; + return; + } + cout << "PvaChannel::channelCreated status " << status.getMessage() << " why??\n"; +} + +void PvaChannel::channelStateChange( + Channel::shared_pointer const & channel, + Channel::ConnectionState connectionState) +{ + if(isDestroyed) return; + bool waitingForConnect = false; + if(connectState==connectActive) waitingForConnect = true; + if(connectionState!=Channel::CONNECTED) { + string mess(channelName + + " connection state " + Channel::ConnectionStateNames[connectionState]); + message(mess,errorMessage); + channelConnectStatus = Status(Status::STATUSTYPE_ERROR,mess); + connectState = notConnected; + } else { + connectState = connected; + } + if(waitingForConnect) waitForConnect.signal(); +} + +string PvaChannel::getRequesterName() +{ + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("Pva was destroyed"); + return yyy->getRequesterName(); +} + +void PvaChannel::message( + string const & message, + MessageType messageType) +{ + if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("Pva was destroyed"); + yyy->message(message, messageType); +} + +void PvaChannel::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + if(channel) channel->destroy(); + channel.reset(); + pvaGetCache.reset(); + pvaPutCache.reset(); +} + +string PvaChannel::getChannelName() +{ + if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed"); + return channelName; +} + +Channel::shared_pointer PvaChannel::getChannel() +{ + if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed"); + return channel; +} + +void PvaChannel::connect(double timeout) +{ + if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed"); + issueConnect(); + Status status = waitConnect(timeout); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << getChannelName() << " PvaChannel::connect " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaChannel::issueConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed"); + if(connectState!=connectIdle) { + throw std::runtime_error("pvaChannel already connected"); + } + channelRequester = ChannelRequester::shared_pointer(new ChannelRequesterImpl(this)); + + channelConnectStatus = Status( + Status::STATUSTYPE_ERROR, + getChannelName() + " createChannel failed"); + connectState = connectActive; + ChannelProviderRegistry::shared_pointer reg = getChannelProviderRegistry(); + ChannelProvider::shared_pointer provider = reg->getProvider(providerName); + if(!provider) { + throw std::runtime_error(getChannelName() + " provider " + providerName + " not registered"); + } + channel = provider->createChannel(channelName,channelRequester,ChannelProvider::PRIORITY_DEFAULT); + if(!channel) { + throw std::runtime_error(channelConnectStatus.getMessage()); + } +} + +Status PvaChannel::waitConnect(double timeout) +{ + if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed"); + waitForConnect.wait(timeout); + if(connectState==connected) return Status::Ok; + return Status(Status::STATUSTYPE_ERROR,channelConnectStatus.getMessage()); +} + +PvaFieldPtr PvaChannel::createField() +{ + return createField(""); +} + +PvaFieldPtr PvaChannel::createField(string const & subField) +{ + throw std::runtime_error("PvaChannel::createField not implemented"); +} + +PvaProcessPtr PvaChannel::createProcess() +{ + return createProcess(""); +} + +PvaProcessPtr PvaChannel::createProcess(string const & request) +{ + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << "channel " << getChannelName(); + ss << " PvaChannel::createProcess invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return createProcess(pvRequest); +} + +PvaProcessPtr PvaChannel::createProcess(PVStructurePtr const & pvRequest) +{ + if(connectState!=connected) connect(5.0); + if(connectState!=connected) throw std::runtime_error("PvaChannel::creatProcess not connected"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("Pva was destroyed"); + return PvaProcess::create(yyy,getPtrSelf(),channel,pvRequest); +} + +PvaGetPtr PvaChannel::get() {return get("value,alarm,timeStamp");} + +PvaGetPtr PvaChannel::get(string const & request) +{ + PvaGetPtr pvaGet = pvaGetCache->getGet(request); + if(pvaGet) return pvaGet; + pvaGet = createGet(request); + pvaGet->connect(); + pvaGetCache->addGet(request,pvaGet); + return pvaGet; +} + +PvaGetPtr PvaChannel::createGet() +{ + return PvaChannel::createGet("value,alarm,timeStamp"); +} + +PvaGetPtr PvaChannel::createGet(string const & request) +{ + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << "channel " << getChannelName(); + ss << " PvaChannel::createGet invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return createGet(pvRequest); +} + +PvaGetPtr PvaChannel::createGet(PVStructurePtr const & pvRequest) +{ + if(connectState!=connected) connect(5.0); + if(connectState!=connected) throw std::runtime_error("PvaChannel::creatGet not connected"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("Pva was destroyed"); + return PvaGet::create(yyy,getPtrSelf(),channel,pvRequest); +} + +PvaPutPtr PvaChannel::put() {return put("value");} + +PvaPutPtr PvaChannel::put(string const & request) +{ + PvaPutPtr pvaPut = pvaPutCache->getPut(request); + if(pvaPut) return pvaPut; + pvaPut = createPut(request); + pvaPut->connect(); + pvaPut->get(); + pvaPutCache->addPut(request,pvaPut); + return pvaPut; +} + +PvaPutPtr PvaChannel::createPut() +{ + return createPut("value"); +} + +PvaPutPtr PvaChannel::createPut(string const & request) +{ + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << "channel " << getChannelName(); + ss << " PvaChannel::createPut invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return createPut(pvRequest); +} + +PvaPutPtr PvaChannel::createPut(PVStructurePtr const & pvRequest) +{ + if(connectState!=connected) connect(5.0); + if(connectState!=connected) throw std::runtime_error("PvaChannel::creatPut not connected"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("Pva was destroyed"); + return PvaPut::create(yyy,getPtrSelf(),channel,pvRequest); +} + +PvaPutGetPtr PvaChannel::createPutGet() +{ + return createPutGet("putField(argument)getField(result)"); +} + +PvaPutGetPtr PvaChannel::createPutGet(string const & request) +{ + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << "channel " << getChannelName(); + ss << " PvaChannel::createPutGet invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return createPutGet(pvRequest); +} + +PvaPutGetPtr PvaChannel::createPutGet(PVStructurePtr const & pvRequest) +{ + if(connectState!=connected) connect(5.0); + if(connectState!=connected) throw std::runtime_error("PvaChannel::creatPutGet not connected"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("Pva was destroyed"); + return PvaPutGet::create(yyy,getPtrSelf(),channel,pvRequest); +} + +PvaRPCPtr PvaChannel::createRPC() +{ + return createRPC(""); +} + +PvaRPCPtr PvaChannel::createRPC(string const & request) +{ + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << "channel " << getChannelName(); + ss << " PvaChannel::createRPC invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return createRPC(pvRequest); +} + +PvaRPCPtr PvaChannel::createRPC(PVStructurePtr const & pvRequest) +{ + throw std::runtime_error("PvaChannel::createRPC not implemented"); +} + +PvaArrayPtr PvaChannel::createArray() +{ + return createArray("value"); +} + +PvaArrayPtr PvaChannel::createArray(string const & request) +{ + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << "channel " << getChannelName(); + ss << " PvaChannel::createArray invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return createArray(pvRequest); +} + +PvaArrayPtr PvaChannel::createArray(PVStructurePtr const & pvRequest) +{ + throw std::runtime_error("PvaChannel::createArray not implemented"); +} + + +PvaMonitorPtr PvaChannel::monitor() {return monitor("value,alarm,timeStamp");} + +PvaMonitorPtr PvaChannel::monitor(string const & request) +{ + PvaMonitorPtr pvaMonitor = createMonitor(request); + pvaMonitor->connect(); + pvaMonitor->start(); + return pvaMonitor; +} + +PvaMonitorPtr PvaChannel::monitor(PvaMonitorRequesterPtr const & pvaMonitorRequester) +{ return monitor("value,alarm,timeStamp",pvaMonitorRequester); +} + +PvaMonitorPtr PvaChannel::monitor(string const & request, + PvaMonitorRequesterPtr const & pvaMonitorRequester) +{ + PvaMonitorPtr pvaMonitor = createMonitor(request); + pvaMonitor->connect(); + pvaMonitor->setRequester(pvaMonitorRequester); + pvaMonitor->start(); + return pvaMonitor; +} + +PvaMonitorPtr PvaChannel::createMonitor() +{ + return createMonitor("value,alarm,timeStamp"); +} + +PvaMonitorPtr PvaChannel::createMonitor(string const & request) +{ + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << "channel " << getChannelName(); + ss << " PvaChannel::createMonitor invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return createMonitor(pvRequest); +} + +PvaMonitorPtr PvaChannel::createMonitor(PVStructurePtr const & pvRequest) +{ + if(connectState!=connected) connect(5.0); + if(connectState!=connected) throw std::runtime_error("PvaChannel::createMonitor not connected"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("Pva was destroyed"); + return PvaMonitor::create(yyy,getPtrSelf(),channel,pvRequest); +} + + +PvaChannelPtr PvaChannel::create( + PvaPtr const &pva, + string const & channelName, + string const & providerName) +{ + PvaChannelPtr channel(new PvaChannel(pva,channelName,providerName)); + return channel; +} + +}} diff --git a/pvaSrc/pvaGet.cpp b/pvaSrc/pvaGet.cpp new file mode 100644 index 0000000..dff7e14 --- /dev/null +++ b/pvaSrc/pvaGet.cpp @@ -0,0 +1,230 @@ +/* pvaGet.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + + +class ChannelGetRequesterImpl : public ChannelGetRequester +{ + PvaGet * pvaGet; +public: + ChannelGetRequesterImpl(PvaGet * pvaGet) + : pvaGet(pvaGet) {} + string getRequesterName() + {return pvaGet->getRequesterName();} + void message(string const & message,MessageType messageType) + {pvaGet->message(message,messageType);} + void channelGetConnect( + const Status& status, + ChannelGet::shared_pointer const & channelGet, + StructureConstPtr const & structure) + {pvaGet->channelGetConnect(status,channelGet,structure);} + void getDone( + const Status& status, + ChannelGet::shared_pointer const & channelGet, + PVStructurePtr const & pvStructure, + BitSetPtr const & bitSet) + {pvaGet->getDone(status,channelGet,pvStructure,bitSet);} +}; + +PvaGet::PvaGet( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +: pva(pva), + pvaChannel(pvaChannel), + channel(channel), + pvRequest(pvRequest), + isDestroyed(false), + connectState(connectIdle), + getState(getIdle) +{ +} + +PvaGet::~PvaGet() +{ + destroy(); +} + +void PvaGet::checkGetState() +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + if(connectState==connectIdle) connect(); + if(getState==getIdle) get(); +} + +// from ChannelGetRequester +string PvaGet::getRequesterName() +{ + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + return yyy->getRequesterName(); +} + +void PvaGet::message(string const & message,MessageType messageType) +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + yyy->message(message, messageType); +} + +void PvaGet::channelGetConnect( + const Status& status, + ChannelGet::shared_pointer const & channelGet, + StructureConstPtr const & structure) +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + channelGetConnectStatus = status; + this->channelGet = channelGet; + if(status.isOK()) { + pvaData = PvaGetData::create(structure); + pvaData->setMessagePrefix(channel->getChannelName()); + } + waitForConnect.signal(); + +} + +void PvaGet::getDone( + const Status& status, + ChannelGet::shared_pointer const & channelGet, + PVStructurePtr const & pvStructure, + BitSetPtr const & bitSet) +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + channelGetStatus = status; + if(status.isOK()) { + pvaData->setData(pvStructure,bitSet); + } + waitForGet.signal(); +} + + +// from PvaGet +void PvaGet::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + if(channelGet) channelGet->destroy(); + channelGet.reset(); +} + +void PvaGet::connect() +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + issueConnect(); + Status status = waitConnect(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaGet::connect " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaGet::issueConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + if(connectState!=connectIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaGet already connected "; + throw std::runtime_error(ss.str()); + } + getRequester = ChannelGetRequester::shared_pointer(new ChannelGetRequesterImpl(this)); + connectState = connectActive; + channelGet = channel->createChannelGet(getRequester,pvRequest); +} + +Status PvaGet::waitConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + if(connectState!=connectActive) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaGet illegal connect state "; + throw std::runtime_error(ss.str()); + } + waitForConnect.wait(); + if(channelGetConnectStatus.isOK()){ + connectState = connected; + return Status::Ok; + } + connectState = connectIdle; + return Status(Status::STATUSTYPE_ERROR,channelGetConnectStatus.getMessage()); +} + +void PvaGet::get() +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + issueGet(); + Status status = waitGet(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaGet::get " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaGet::issueGet() +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + if(connectState==connectIdle) connect(); + if(getState!=getIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaGet::issueGet get aleady active "; + throw std::runtime_error(ss.str()); + } + getState = getActive; + channelGet->get(); +} + +Status PvaGet::waitGet() +{ + if(isDestroyed) throw std::runtime_error("pvaGet was destroyed"); + if(getState!=getActive){ + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaGet::waitGet llegal get state"; + throw std::runtime_error(ss.str()); + } + waitForGet.wait(); + getState = getIdle; + if(channelGetStatus.isOK()) { + return Status::Ok; + } + return Status(Status::STATUSTYPE_ERROR,channelGetStatus.getMessage()); +} +PvaGetDataPtr PvaGet::getData() +{ + checkGetState(); + return pvaData; +} + +PvaGetPtr PvaGet::create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +{ + PvaGetPtr epv(new PvaGet(pva,pvaChannel,channel,pvRequest)); + return epv; +} + +}} diff --git a/pvaSrc/pvaGetData.cpp b/pvaSrc/pvaGetData.cpp new file mode 100644 index 0000000..6412e83 --- /dev/null +++ b/pvaSrc/pvaGetData.cpp @@ -0,0 +1,200 @@ +/* pvaGetData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include + +#include +#include +#include +#include + + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + + +typedef std::tr1::shared_ptr PVArrayPtr; +static ConvertPtr convert = getConvert(); +static string noStructure("no pvStructure "); +static string noValue("no value field"); +static string noScalar("value is not a scalar"); +static string notCompatibleScalar("value is not a compatible scalar"); +static string noArray("value is not an array"); +static string noScalarArray("value is not a scalarArray"); +static string notDoubleArray("value is not a doubleArray"); +static string notStringArray("value is not a stringArray"); + +PvaGetDataPtr PvaGetData::create(StructureConstPtr const & structure) +{ + PvaGetDataPtr epv(new PvaGetData(structure)); + return epv; +} + +PvaGetData::PvaGetData(StructureConstPtr const & structure) +: structure(structure) +{} + +void PvaGetData::checkValue() +{ + if(pvValue) return; + throw std::runtime_error(messagePrefix + noValue); +} + +void PvaGetData::setMessagePrefix(std::string const & value) +{ + messagePrefix = value + " "; +} + +StructureConstPtr PvaGetData::getStructure() +{return structure;} + +PVStructurePtr PvaGetData::getPVStructure() +{ + if(pvStructure) return pvStructure; + throw std::runtime_error(messagePrefix + noStructure); +} + +BitSetPtr PvaGetData::getBitSet() +{ + if(bitSet)return bitSet; + throw std::runtime_error(messagePrefix + noStructure); +} + +std::ostream & PvaGetData::showChanged(std::ostream & out) +{ + if(!bitSet) throw std::runtime_error(messagePrefix + noStructure); + size_t nextSet = bitSet->nextSetBit(0); + PVFieldPtr pvField; + while(nextSet!=string::npos) { + if(nextSet==0) { + pvField = pvStructure; + } else { + pvField = pvStructure->getSubField(nextSet); + } + string name = pvField->getFullName(); + out << name << " = " << pvField << endl; + nextSet = bitSet->nextSetBit(nextSet+1); + } + return out; +} + +void PvaGetData::setData( + PVStructurePtr const & pvStructureFrom, + BitSetPtr const & bitSetFrom) +{ + pvStructure = pvStructureFrom; + bitSet = bitSetFrom; + pvValue = pvStructure->getSubField("value"); +} + +bool PvaGetData::hasValue() +{ + if(!pvValue) return false; + return true; +} + +bool PvaGetData::isValueScalar() +{ + if(!pvValue) return false; + if(pvValue->getField()->getType()==scalar) return true; + return false; +} + +bool PvaGetData::isValueScalarArray() +{ + if(!pvValue) return false; + if(pvValue->getField()->getType()==scalarArray) return true; + return false; +} + +PVFieldPtr PvaGetData::getValue() +{ + checkValue(); + return pvValue; +} + +PVScalarPtr PvaGetData::getScalarValue() +{ + checkValue(); + PVScalarPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + noScalar); + } + return pv; +} + +PVArrayPtr PvaGetData::getArrayValue() +{ + checkValue(); + PVArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + noArray); + } + return pv; +} + +PVScalarArrayPtr PvaGetData::getScalarArrayValue() +{ + checkValue(); + PVScalarArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + noScalarArray); + } + return pv; +} + +double PvaGetData::getDouble() +{ + PVScalarPtr pvScalar = getScalarValue(); + ScalarType scalarType = pvScalar->getScalar()->getScalarType(); + if(scalarType==pvDouble) { + PVDoublePtr pvDouble = static_pointer_cast(pvScalar); + return pvDouble->get(); + } + if(!ScalarTypeFunc::isNumeric(scalarType)) { + throw std::runtime_error(messagePrefix + notCompatibleScalar); + } + return convert->toDouble(pvScalar); +} + +string PvaGetData::getString() +{ + PVScalarPtr pvScalar = getScalarValue(); + return convert->toString(pvScalar); +} + +shared_vector PvaGetData::getDoubleArray() +{ + checkValue(); + PVDoubleArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notDoubleArray); + } + return pv->view(); +} + +shared_vector PvaGetData::getStringArray() +{ + checkValue(); + PVStringArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notStringArray); + } + return pv->view(); + +} + +}} diff --git a/pvaSrc/pvaMonitor.cpp b/pvaSrc/pvaMonitor.cpp new file mode 100644 index 0000000..0c0344e --- /dev/null +++ b/pvaSrc/pvaMonitor.cpp @@ -0,0 +1,250 @@ +/* pvaMonitor.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ +#define epicsExportSharedSymbols + +#include +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + + +class ChannelMonitorRequester : public MonitorRequester +{ + PvaMonitor * pvaMonitor; +public: + ChannelMonitorRequester(PvaMonitor * pvaMonitor) + : pvaMonitor(pvaMonitor) {} + string getRequesterName() + {return pvaMonitor->getRequesterName();} + void message(string const & message,MessageType messageType) + {pvaMonitor->message(message,messageType);} + void monitorConnect( + const Status& status, + Monitor::shared_pointer const & monitor, + StructureConstPtr const & structure) + {pvaMonitor->monitorConnect(status,monitor,structure);} + void monitorEvent(MonitorPtr const & monitor) + { + pvaMonitor->monitorEvent(monitor); + } + void unlisten(MonitorPtr const & monitor) + {pvaMonitor->unlisten();} +}; + +PvaMonitor::PvaMonitor( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +: pva(pva), + pvaChannel(pvaChannel), + channel(channel), + pvRequest(pvRequest), + isDestroyed(false), + connectState(connectIdle), + userPoll(false), + userWait(false) +{ +} + +PvaMonitor::~PvaMonitor() +{ + destroy(); +} + +void PvaMonitor::checkMonitorState() +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + if(connectState==connectIdle) connect(); + if(connectState==connected) start(); +} + +// from MonitorRequester +string PvaMonitor::getRequesterName() +{ + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + return yyy->getRequesterName(); +} + +void PvaMonitor::message(string const & message,MessageType messageType) +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + yyy->message(message, messageType); +} + +void PvaMonitor::monitorConnect( + const Status& status, + Monitor::shared_pointer const & monitor, + StructureConstPtr const & structure) +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + connectStatus = status; + this->monitor = monitor; + if(status.isOK()) { + pvaData = PvaMonitorData::create(structure); + pvaData->setMessagePrefix(channel->getChannelName()); + } + waitForConnect.signal(); + +} + +void PvaMonitor::monitorEvent(MonitorPtr const & monitor) +{ + PvaMonitorRequesterPtr req = pvaMonitorRequester.lock(); + if(req) req->event(getPtrSelf()); + if(userWait) waitForEvent.signal(); +} + +void PvaMonitor::unlisten() +{ + destroy(); +} + +// from PvaMonitor +void PvaMonitor::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + if(monitor) monitor->destroy(); + monitor.reset(); +} + +void PvaMonitor::connect() +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + issueConnect(); + Status status = waitConnect(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaMonitor::connect " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaMonitor::issueConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + if(connectState!=connectIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaMonitor already connected "; + throw std::runtime_error(ss.str()); + } + monitorRequester = ChannelMonitorRequester::shared_pointer(new ChannelMonitorRequester(this)); + connectState = connectActive; + monitor = channel->createMonitor(monitorRequester,pvRequest); +} + +Status PvaMonitor::waitConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + if(connectState!=connectActive) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaMonitor illegal connect state "; + throw std::runtime_error(ss.str()); + } + waitForConnect.wait(); + if(connectStatus.isOK()){ + connectState = connected; + return Status::Ok; + } + connectState = connectIdle; + return Status(Status::STATUSTYPE_ERROR,connectStatus.getMessage()); +} + +void PvaMonitor::setRequester(PvaMonitorRequesterPtr const & pvaMonitorrRequester) +{ + this->pvaMonitorRequester = pvaMonitorrRequester; +} + +void PvaMonitor::start() +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + if(connectState==monitorStarted) return; + if(connectState==connectIdle) connect(); + if(connectState!=connected) throw std::runtime_error("PvaMonitor::start illegal state"); + connectState = monitorStarted; + monitor->start(); +} + + +void PvaMonitor::stop() +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + if(connectState!=monitorStarted) return; + connectState = connected; + monitor->stop(); +} + +bool PvaMonitor::poll() +{ + checkMonitorState(); + if(connectState!=monitorStarted) throw std::runtime_error("PvaMonitor::poll illegal state"); + if(userPoll) throw std::runtime_error("PvaMonitor::poll did not release last"); + monitorElement = monitor->poll(); + if(!monitorElement) return false; + userPoll = true; + pvaData->setData(monitorElement); + return true; +} + +bool PvaMonitor::waitEvent(double secondsToWait) +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + if(connectState!=monitorStarted) throw std::runtime_error("PvaMonitor::poll illegal state"); + if(poll()) return true; + userWait = true; + if(secondsToWait==0.0) { + waitForEvent.wait(); + } else { + waitForEvent.wait(secondsToWait); + } + userWait = false; + return poll(); +} + +void PvaMonitor::releaseEvent() +{ + if(isDestroyed) throw std::runtime_error("pvaMonitor was destroyed"); + if(connectState!=monitorStarted) throw std::runtime_error("PvaMonitor::poll illegal state"); + if(!userPoll) throw std::runtime_error("PvaMonitor::releaseEvent did not call poll"); + userPoll = false; + monitor->release(monitorElement); +} + +PvaMonitorDataPtr PvaMonitor::getData() +{ + checkMonitorState(); + return pvaData; +} + +PvaMonitorPtr PvaMonitor::create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +{ + PvaMonitorPtr epv(new PvaMonitor(pva,pvaChannel,channel,pvRequest)); + return epv; +} + +}} diff --git a/pvaSrc/pvaMonitorData.cpp b/pvaSrc/pvaMonitorData.cpp new file mode 100644 index 0000000..dcbb15c --- /dev/null +++ b/pvaSrc/pvaMonitorData.cpp @@ -0,0 +1,226 @@ +/* pvaMonitorData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include + +#include +#include +#include +#include + + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + + +typedef std::tr1::shared_ptr PVArrayPtr; +static StructureConstPtr nullStructure; +static PVStructurePtr nullPVStructure; +static ConvertPtr convert = getConvert(); +static string noStructure("no pvStructure "); +static string noValue("no value field"); +static string noScalar("value is not a scalar"); +static string notCompatibleScalar("value is not a compatible scalar"); +static string noArray("value is not an array"); +static string noScalarArray("value is not a scalarArray"); +static string notDoubleArray("value is not a doubleArray"); +static string notStringArray("value is not a stringArray"); + +PvaMonitorDataPtr PvaMonitorData::create(StructureConstPtr const & structure) +{ + PvaMonitorDataPtr epv(new PvaMonitorData(structure)); + return epv; +} + +PvaMonitorData::PvaMonitorData(StructureConstPtr const & structure) +: structure(structure) +{} + + +void PvaMonitorData::checkValue() +{ + if(pvValue) return; + throw std::runtime_error(messagePrefix + noValue); +} + +void PvaMonitorData::setMessagePrefix(std::string const & value) +{ + messagePrefix = value + " "; +} + +StructureConstPtr PvaMonitorData::getStructure() +{return structure;} + +PVStructurePtr PvaMonitorData::getPVStructure() +{ + if(pvStructure) return pvStructure; + throw std::runtime_error(messagePrefix + noStructure); +} + +BitSetPtr PvaMonitorData::getChangedBitSet() +{ + if(!changedBitSet) throw std::runtime_error(messagePrefix + noStructure); + return changedBitSet; +} + +BitSetPtr PvaMonitorData::getOverrunBitSet() +{ + if(!overrunBitSet) throw std::runtime_error(messagePrefix + noStructure); + return overrunBitSet; +} + +std::ostream & PvaMonitorData::showChanged(std::ostream & out) +{ + if(!changedBitSet) throw std::runtime_error(messagePrefix + noStructure); + size_t nextSet = changedBitSet->nextSetBit(0); + PVFieldPtr pvField; + while(nextSet!=string::npos) { + if(nextSet==0) { + pvField = pvStructure; + } else { + pvField = pvStructure->getSubField(nextSet); + } + string name = pvField->getFullName(); + out << name << " = " << pvField << endl; + nextSet = changedBitSet->nextSetBit(nextSet+1); + } + return out; +} + +std::ostream & PvaMonitorData::showOverrun(std::ostream & out) +{ + if(!overrunBitSet) throw std::runtime_error(messagePrefix + noStructure); + size_t nextSet = overrunBitSet->nextSetBit(0); + PVFieldPtr pvField; + while(nextSet!=string::npos) { + if(nextSet==0) { + pvField = pvStructure; + } else { + pvField = pvStructure->getSubField(nextSet); + } + string name = pvField->getFullName(); + out << name << " = " << pvField << endl; + nextSet = overrunBitSet->nextSetBit(nextSet+1); + } + return out; +} + +void PvaMonitorData::setData(MonitorElementPtr const & monitorElement) +{ + pvStructure = monitorElement->pvStructurePtr; + changedBitSet = monitorElement->changedBitSet; + overrunBitSet = monitorElement->overrunBitSet; + pvValue = pvStructure->getSubField("value"); +} + +bool PvaMonitorData::hasValue() +{ + if(!pvValue) return false; + return true; +} + +bool PvaMonitorData::isValueScalar() +{ + if(!pvValue) return false; + if(pvValue->getField()->getType()==scalar) return true; + return false; +} + +bool PvaMonitorData::isValueScalarArray() +{ + if(!pvValue) return false; + if(pvValue->getField()->getType()==scalarArray) return true; + return false; +} + +PVFieldPtr PvaMonitorData::getValue() +{ + checkValue(); + return pvValue; +} + +PVScalarPtr PvaMonitorData::getScalarValue() +{ + checkValue(); + PVScalarPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + noScalar); + } + return pv; +} + +PVArrayPtr PvaMonitorData::getArrayValue() +{ + checkValue(); + PVArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + noArray); + } + return pv; +} + +PVScalarArrayPtr PvaMonitorData::getScalarArrayValue() +{ + checkValue(); + PVScalarArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + noScalarArray); + } + return pv; +} + +double PvaMonitorData::getDouble() +{ + PVScalarPtr pvScalar = getScalarValue(); + ScalarType scalarType = pvScalar->getScalar()->getScalarType(); + if(scalarType==pvDouble) { + PVDoublePtr pvDouble = static_pointer_cast(pvScalar); + return pvDouble->get(); + } + if(!ScalarTypeFunc::isNumeric(scalarType)) { + throw std::runtime_error(messagePrefix + notCompatibleScalar); + } + return convert->toDouble(pvScalar); +} + +string PvaMonitorData::getString() +{ + PVScalarPtr pvScalar = getScalarValue(); + return convert->toString(pvScalar); +} + +shared_vector PvaMonitorData::getDoubleArray() +{ + checkValue(); + PVDoubleArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notDoubleArray); + } + return pv->view(); +} + +shared_vector PvaMonitorData::getStringArray() +{ + checkValue(); + PVStringArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notStringArray); + } + return pv->view(); + +} + +}} diff --git a/pvaSrc/pvaMultiChannel.cpp b/pvaSrc/pvaMultiChannel.cpp new file mode 100644 index 0000000..f2c8ece --- /dev/null +++ b/pvaSrc/pvaMultiChannel.cpp @@ -0,0 +1,165 @@ +/* pvaMultiChannel.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include +#include +#include +#include +#include +#include + + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + + + +PvaMultiChannel::PvaMultiChannel( + PvaPtr const &pva, + PVStringArrayPtr const & channelName, + string const & providerName) +: pva(pva), + channelName(channelName), + providerName(providerName), + numChannel(channelName->getLength()), + isConnected(getPVDataCreate()->createPVScalarArray()), + isDestroyed(false) +{ +} + +PvaMultiChannel::~PvaMultiChannel() +{ + destroy(); +} + +void PvaMultiChannel::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaChannelArray.reset(); +} + +PVStringArrayPtr PvaMultiChannel::getChannelNames() +{ + if(isDestroyed) throw std::runtime_error("pvaMultiChannel was destroyed"); + return channelName; +} + +Status PvaMultiChannel::connect(double timeout,size_t maxNotConnected) +{ + if(isDestroyed) throw std::runtime_error("pvaMultiChannel was destroyed"); + if(pvaChannelArray) throw std::runtime_error("pvaMultiChannel already connected"); + PvaPtr pva = this->pva.lock(); + if(!pva) return Status(Status::STATUSTYPE_ERROR,"pva is gone"); + shared_vector pvaChannel(numChannel,PvaChannelPtr()); + PVStringArray::const_svector channelNames = channelName->view(); + shared_vector isConnected(numChannel,false); + for(size_t i=0; i< numChannel; ++i) { + pvaChannel[i] = pva->createChannel(channelNames[i],providerName); + pvaChannel[i]->issueConnect(); + } + Status returnStatus = Status::Ok; + Status status = Status::Ok; + size_t numBad = 0; + for(size_t i=0; i< numChannel; ++i) { + if(numBad==0) { + status = pvaChannel[i]->waitConnect(timeout); + } else { + status = pvaChannel[i]->waitConnect(.001); + } + if(status.isOK()) { + ++numConnected; + isConnected[i] = true; + continue; + } + if(returnStatus.isOK()) returnStatus = status; + ++numBad; + if(numBad>maxNotConnected) break; + } + pvaChannelArray = PvaChannelArrayPtr(new PvaChannelArray(freeze(pvaChannel))); + this->isConnected->replace(freeze(isConnected)); + return numBad>maxNotConnected ? returnStatus : Status::Ok; +} + + +bool PvaMultiChannel::allConnected() +{ + if(isDestroyed) throw std::runtime_error("pvaMultiChannel was destroyed"); + if(!pvaChannelArray) throw std::runtime_error("pvaMultiChannel not connected"); + if(numConnected==numChannel) return true; + return (numConnected==numChannel) ? true : false; +} + +bool PvaMultiChannel::connectionChange() +{ + if(isDestroyed) throw std::runtime_error("pvaMultiChannel was destroyed"); + if(!pvaChannelArray) throw std::runtime_error("pvaMultiChannel not connected"); + if(numConnected==numChannel) return true; + PVBooleanArray::const_svector isConnected = this->isConnected->view(); + shared_vector channels = *pvaChannelArray.get(); + for(size_t i=0; igetChannel(); + Channel::ConnectionState stateNow = channel->getConnectionState(); + bool connectedNow = stateNow==Channel::CONNECTED ? true : false; + if(connectedNow!=isConnected[i]) return true; + } + return false; +} + +PVBooleanArrayPtr PvaMultiChannel::getIsConnected() +{ + if(isDestroyed) throw std::runtime_error("pvaMultiChannel was destroyed"); + if(!pvaChannelArray) throw std::runtime_error("pvaMultiChannel not connected"); + if(!connectionChange()) return isConnected; + shared_vector isConnected(numChannel,false); + shared_vector channels = *pvaChannelArray.get(); + for(size_t i=0; igetChannel(); + Channel::ConnectionState stateNow = channel->getConnectionState(); + if(stateNow==Channel::CONNECTED) isConnected[i] = true; + } + this->isConnected->replace(freeze(isConnected)); + return this->isConnected; +} + +PvaChannelArrayWPtr PvaMultiChannel::getPvaChannelArray() +{ + if(isDestroyed) throw std::runtime_error("pvaMultiChannel was destroyed"); + if(!pvaChannelArray) throw std::runtime_error("pvaMultiChannel not connected"); + return pvaChannelArray; +} + +Pva::weak_pointer PvaMultiChannel::getPva() +{ + if(isDestroyed) throw std::runtime_error("pvaMultiChannel was destroyed"); + return pva; +} + +PvaMultiChannelPtr PvaMultiChannel::create( + PvaPtr const &pva, + PVStringArrayPtr const & channelNames, + string const & providerName) +{ + PvaMultiChannelPtr channel(new PvaMultiChannel(pva,channelNames,providerName)); + return channel; +} + +}} diff --git a/pvaSrc/pvaMultiDouble.cpp b/pvaSrc/pvaMultiDouble.cpp new file mode 100644 index 0000000..4871928 --- /dev/null +++ b/pvaSrc/pvaMultiDouble.cpp @@ -0,0 +1,139 @@ +/* pvaMultiDouble.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ + +#define epicsExportSharedSymbols +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + +PvaMultiDoublePtr PvaMultiDouble::create( + PvaPtr const & pva, + PVStringArrayPtr const & channelName, + double timeout, + std::string const & providerName) +{ + PvaMultiChannelPtr pvaMultiChannel( + PvaMultiChannel::create(pva,channelName,providerName)); + Status status = pvaMultiChannel->connect(timeout,0); + if(!status.isOK()) throw std::runtime_error(status.getMessage()); + return PvaMultiDoublePtr(new PvaMultiDouble(pvaMultiChannel)); +} + +PvaMultiDouble::PvaMultiDouble(PvaMultiChannelPtr const &pvaMultiChannel) +: + pvaMultiChannel(pvaMultiChannel) +{} + +PvaMultiDouble::~PvaMultiDouble() +{ +} + +void PvaMultiDouble::createGet() +{ + PvaChannelArrayPtr pvaChannelArray = pvaMultiChannel->getPvaChannelArray().lock(); + if(!pvaChannelArray) throw std::runtime_error("pvaChannelArray is gone"); + shared_vector pvaChannels = *pvaChannelArray; + size_t numChannel = pvaChannels.size(); + pvaGet = std::vector(numChannel,PvaGetPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreateGet("value"); + pvaGet[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); +} + +void PvaMultiDouble::createPut() +{ + PvaChannelArrayPtr pvaChannelArray = pvaMultiChannel->getPvaChannelArray().lock(); + if(!pvaChannelArray) throw std::runtime_error("pvaChannelArray is gone"); + shared_vector pvaChannels = *pvaChannelArray; + size_t numChannel = pvaChannels.size(); + pvaPut = std::vector(numChannel,PvaPutPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreatePut("value"); + pvaPut[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); +} + +epics::pvData::shared_vector PvaMultiDouble::get() +{ + if(pvaGet.empty()) createGet(); + shared_vector channelNames = pvaMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + epics::pvData::shared_vector data(channelNames.size()); + for(size_t i=0; iissueGet(); + } + for(size_t i=0; iwaitGet(); + if(!status.isOK()) { + string message = channelNames[i] + " " + status.getMessage(); + throw std::runtime_error(message); + } + data[i] = pvaGet[i]->getData()->getDouble(); + } + return data; +} + +void PvaMultiDouble::put(shared_vector const &value) +{ + if(pvaPut.empty()) createPut(); + shared_vector channelNames = pvaMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + for(size_t i=0; igetData()->putDouble(value[i]); + pvaPut[i]->issuePut(); + } + for(size_t i=0; iwaitPut(); + if(!status.isOK()) { + string message = channelNames[i] + " " + status.getMessage(); + throw std::runtime_error(message); + } + } +} + + +}} diff --git a/pvaSrc/pvaMultiDouble.h b/pvaSrc/pvaMultiDouble.h new file mode 100644 index 0000000..84394aa --- /dev/null +++ b/pvaSrc/pvaMultiDouble.h @@ -0,0 +1,81 @@ +/* pvaMultiDouble.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#ifndef PVAMULTIDOUBLE_H +#define PVAMULTIDOUBLE_H + +#ifdef epicsExportSharedSymbols +# define pvaEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#include + +namespace epics { namespace pva { + +class PvaMultiDouble; +typedef std::tr1::shared_ptr PvaMultiDoublePtr; + +/** + * @brief Support for multiple channels where each channel has a value field that is a scalar double. + * If any problems arise an exception is thrown. + * + * @author mrk + */ +class epicsShareClass PvaMultiDouble +{ +public: + POINTER_DEFINITIONS(PvaMultiDouble); + /** + * @brief Create a PvaMultiDouble. + * @param &pva Interface to Pva + * @param channelName PVStringArray of channelNames. + * @param timeout The timeout in seconds for connecting. + * @param providerName The name of the channelProvider for each channel. + * @return The interface to PvaMultiDouble. + */ + static PvaMultiDoublePtr create( + PvaPtr const & pva, + epics::pvData::PVStringArrayPtr const & channelName, + double timeout = 5.0, + std::string const & providerName = "pva"); + /** + * @brief destructor + */ + ~PvaMultiDouble(); + /** + * @brief destroy any resources used. + */ + void destroy(); + /** + * @brief get the value of all the channels. + * @return The data. + */ + epics::pvData::shared_vector get(); + /** + * @brief put a new value to each channel. + * @param value The data. + */ + void put(epics::pvData::shared_vector const &value); + PvaMultiChannelPtr getPvaMultiChannel(); +private: + PvaMultiDouble( + PvaMultiChannelPtr const & channelName); + void createGet(); + void createPut(); + + PvaMultiChannelPtr pvaMultiChannel; + std::vector pvaGet; + std::vector pvaPut; +}; + +}} + +#endif // PVAMULTIDOUBLE_H diff --git a/pvaSrc/pvaNTMultiChannel.cpp b/pvaSrc/pvaNTMultiChannel.cpp new file mode 100644 index 0000000..4d00613 --- /dev/null +++ b/pvaSrc/pvaNTMultiChannel.cpp @@ -0,0 +1,268 @@ +/* pvaNTMultiChannel.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ + +#define epicsExportSharedSymbols +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::nt; +using namespace std; + +namespace epics { namespace pva { + +PvaNTMultiChannelPtr PvaNTMultiChannel::create( + PvaPtr const & pva, + PVStringArrayPtr const & channelName, + StructureConstPtr const &structure, + double timeout, + std::string const & providerName) +{ + PvaMultiChannelPtr pvaMultiChannel( + PvaMultiChannel::create(pva,channelName,providerName)); + Status status = pvaMultiChannel->connect(timeout,0); + if(!status.isOK()) throw std::runtime_error(status.getMessage()); + if(!NTMultiChannel::is_a(structure)) throw std::runtime_error("structure is not valid"); + PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure); + pvStructure->getSubField("channelName")-> + replace(pvaMultiChannel->getChannelNames()->view()); + pvStructure->getSubField("isConnected")-> + replace(pvaMultiChannel->getIsConnected()->view()); + NTMultiChannelPtr ntMultiChannel(NTMultiChannel::wrap(pvStructure)); + return PvaNTMultiChannelPtr(new PvaNTMultiChannel(pvaMultiChannel,ntMultiChannel)); +} + +PvaNTMultiChannel::PvaNTMultiChannel( + PvaMultiChannelPtr const &pvaMultiChannel, + NTMultiChannelPtr const &ntMultiChannel) +: + pvaMultiChannel(pvaMultiChannel), + ntMultiChannel(ntMultiChannel), + pvUnionArray(ntMultiChannel->getPVStructure()->getSubField("value")), + pvDataCreate(getPVDataCreate()) +{} + +PvaNTMultiChannel::~PvaNTMultiChannel() +{ +} + +void PvaNTMultiChannel::createGet() +{ + PVStructurePtr pvStructure = ntMultiChannel->getPVStructure(); + bool getAlarm = false; + if(pvStructure->getSubField("severity")) getAlarm = true; + if(pvStructure->getSubField("status")) getAlarm = true; + if(pvStructure->getSubField("severity")) getAlarm = true; + bool getTimeStamp = false; + if(pvStructure->getSubField("secondsPastEpoch")) getTimeStamp = true; + if(pvStructure->getSubField("nanoseconds")) getTimeStamp = true; + if(pvStructure->getSubField("userTag")) getTimeStamp = true; + string request = "value"; + if(getAlarm) request += ",alarm"; + if(getTimeStamp) request += ",timeStamp"; + PvaChannelArrayPtr pvaChannelArray = pvaMultiChannel->getPvaChannelArray().lock(); + if(!pvaChannelArray) throw std::runtime_error("pvaChannelArray is gone"); + shared_vector pvaChannels = *pvaChannelArray; + size_t numChannel = pvaChannels.size(); + pvaGet = std::vector(numChannel,PvaGetPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreateGet(request); + pvaGet[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); + +} + +void PvaNTMultiChannel::createPut() +{ + PvaChannelArrayPtr pvaChannelArray = pvaMultiChannel->getPvaChannelArray().lock(); + if(!pvaChannelArray) throw std::runtime_error("pvaChannelArray is gone"); + shared_vector pvaChannels = *pvaChannelArray; + size_t numChannel = pvaChannels.size(); + pvaPut = std::vector(numChannel,PvaPutPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreatePut("value"); + pvaPut[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); +} + +NTMultiChannelPtr PvaNTMultiChannel::get() +{ + if(pvaGet.empty()) createGet(); + PVStructurePtr pvStructure = ntMultiChannel->getPVStructure(); + shared_vector channelNames = pvaMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + bool severityExists = false; + bool statusExists = false; + bool messageExists = false; + bool secondsPastEpochExists = false; + bool nanosecondsExists = false; + bool userTagExists = false; + if(pvStructure->getSubField("severity")) { + severity.resize(numChannel); + severityExists = true; + } + if(pvStructure->getSubField("status")) { + status.resize(numChannel); + statusExists = true; + } + if(pvStructure->getSubField("message")) { + message.resize(numChannel); + messageExists = true; + } + if(pvStructure->getSubField("secondsPastEpoch")) { + secondsPastEpoch.resize(numChannel); + secondsPastEpochExists = true; + } + if(pvStructure->getSubField("nanoseconds")) { + nanoseconds.resize(numChannel); + nanosecondsExists = true; + } + if(pvStructure->getSubField("userTag")) { + userTag.resize(numChannel); + userTagExists = true; + } + shared_vector valueVector(numChannel); + for(size_t i=0; iissueGet(); + } + for(size_t i=0; iwaitGet(); + if(!stat.isOK()) { + string message = channelNames[i] + " " + stat.getMessage(); + throw std::runtime_error(message); + } + PVStructurePtr pvStructure = pvaGet[i]->getData()->getPVStructure(); + PVFieldPtr pvField = pvStructure->getSubField("value"); + if(!pvField) { + string message = channelNames[i] + " no value field"; + throw std::runtime_error(message); + } + UnionConstPtr u = pvUnionArray->getUnionArray()->getUnion(); + if(u->isVariant()) { + PVUnionPtr pvUnion = pvDataCreate->createPVVariantUnion(); + pvUnion->set(pvDataCreate->createPVField(pvField)); + valueVector[i] = pvUnion; + } else { + PVUnionPtr pvUnion = pvDataCreate->createPVUnion(u); + pvUnion->set(pvField); + valueVector[i] = pvUnion; + } + pvField = pvStructure->getSubField("alarm"); + if(pvField) { + if(pvAlarm.attach(pvField)) { + pvAlarm.get(alarm); + if(severityExists) severity[i] = alarm.getSeverity(); + if(statusExists) status[i] = alarm.getStatus(); + if(messageExists) message[i] = alarm.getMessage(); + } + } + pvField = pvStructure->getSubField("timeStamp"); + if(pvField) { + if(pvTimeStamp.attach(pvField)) { + pvTimeStamp.get(timeStamp); + if(secondsPastEpochExists) secondsPastEpoch[i] = + timeStamp.getSecondsPastEpoch(); + if(nanosecondsExists) nanoseconds[i] = + timeStamp.getNanoseconds(); + if(userTagExists) userTag[i] = timeStamp.getUserTag(); + } + } + } + pvUnionArray->replace(freeze(valueVector)); + if(severityExists) { + pvStructure->getSubField("severity")->replace( + freeze(severity)); + } + if(statusExists) { + pvStructure->getSubField("status")->replace( + freeze(status)); + } + if(messageExists) { + pvStructure->getSubField("message")->replace(freeze(message)); + } + if(secondsPastEpochExists) { + pvStructure->getSubField("secondsPastEpoch")->replace(freeze(secondsPastEpoch)); + } + if(nanosecondsExists) { + pvStructure->getSubField("nanoseconds")->replace(freeze(nanoseconds)); + } + if(userTagExists) { + pvStructure->getSubField("userTag")->replace(freeze(userTag)); + } + return ntMultiChannel; +} + +void PvaNTMultiChannel::put(NTMultiChannelPtr const &value) +{ + if(pvaPut.empty()) createPut(); + shared_vector channelNames = pvaMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + PVUnionArrayPtr pvValue = value->getPVStructure()-> + getSubField("value"); + shared_vector valueVector = pvValue->view(); + for(size_t i=0; iget(); + PVFieldPtr pvTo = pvaPut[i]->getData()->getValue(); + Type typeFrom = pvFrom->getField()->getType(); + Type typeTo = pvTo->getField()->getType(); + if(typeFrom==typeTo) { + if(typeFrom==scalar || typeFrom==scalarArray) { + pvTo->copy(*pvFrom); + } + } + pvaPut[i]->issuePut(); + } catch (std::exception e) { + string message = channelNames[i] + " " + e.what(); + throw std::runtime_error(message); + } + } + for(size_t i=0; iwaitPut(); + if(!status.isOK()) { + string message = channelNames[i] + " " + status.getMessage(); + throw std::runtime_error(message); + } + } +} + +}} diff --git a/pvaSrc/pvaNTMultiChannel.h b/pvaSrc/pvaNTMultiChannel.h new file mode 100644 index 0000000..31efef7 --- /dev/null +++ b/pvaSrc/pvaNTMultiChannel.h @@ -0,0 +1,103 @@ +/* pvaNTMultiChannel.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#ifndef PVANTMULTIChannel_H +#define PVANTMULTIChannel_H + +#ifdef epicsExportSharedSymbols +# define pvaEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#include + +namespace epics { namespace pva { + +class PvaNTMultiChannel; +typedef std::tr1::shared_ptr PvaNTMultiChannelPtr; + +/** + * @brief Support for multiple channels where each channel has a value field that + * is a scalar, scalarArray, or enumerated structure. + * The data is provided via normativeType NTMultiChannel. + * If any problems arise an exception is thrown. + * + * @author mrk + */ +class epicsShareClass PvaNTMultiChannel +{ +public: + POINTER_DEFINITIONS(PvaNTMultiChannel); + /** + * @brief Create a PvaNTMultiChannel. + * @param &pva Interface to Pva + * @param channelName PVStringArray of channelNames. + * @param structure valid NTMultiChannel structure. + * @param timeout Timeout for connecting. + * @param providerName The provider for each channel. + * @return The interface to PvaNTMultiChannel. + */ + static PvaNTMultiChannelPtr create( + PvaPtr const & pva, + epics::pvData::PVStringArrayPtr const & channelName, + epics::pvData::StructureConstPtr const & structure, + double timeout = 5.0, + std::string const & providerName = "pva"); + /** + * @brief destructor + */ + ~PvaNTMultiChannel(); + /** + * @brief destroy any resources used. + */ + void destroy(); + /** + * @brief get the value of all the channels. + * @return The data. + */ + epics::nt::NTMultiChannelPtr get(); + /** + * @brief put a new value to each channel. + * @param value The data. + */ + void put(epics::nt::NTMultiChannelPtr const &value); + /** + * @brief Get the PvaMultiChannel. + * @return The interface. + */ + PvaMultiChannelPtr getPvaMultiChannel(); +private: + PvaNTMultiChannel( + PvaMultiChannelPtr const & channelName, + epics::nt::NTMultiChannelPtr const &ntMultiChannel); + void createGet(); + void createPut(); + + PvaMultiChannelPtr pvaMultiChannel; + epics::nt::NTMultiChannelPtr ntMultiChannel; + epics::pvData::PVUnionArrayPtr pvUnionArray; + epics::pvData::PVDataCreatePtr pvDataCreate; + std::vector pvaGet; + std::vector pvaPut; + epics::pvData::shared_vector severity; + epics::pvData::shared_vector status; + epics::pvData::shared_vector message; + epics::pvData::shared_vector secondsPastEpoch; + epics::pvData::shared_vector nanoseconds; + epics::pvData::shared_vector userTag; + epics::pvData::Alarm alarm; + epics::pvData::PVAlarm pvAlarm; + epics::pvData::TimeStamp timeStamp;; + epics::pvData::PVTimeStamp pvTimeStamp; +}; + +}} + +#endif // PVANTMULTIChannel_H diff --git a/pvaSrc/pvaProcess.cpp b/pvaSrc/pvaProcess.cpp new file mode 100644 index 0000000..342161d --- /dev/null +++ b/pvaSrc/pvaProcess.cpp @@ -0,0 +1,212 @@ +/* pvaProcess.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + + +class ChannelProcessRequesterImpl : public ChannelProcessRequester +{ + PvaProcess * pvaProcess; +public: + ChannelProcessRequesterImpl(PvaProcess * pvaProcess) + : pvaProcess(pvaProcess) {} + string getRequesterName() + {return pvaProcess->getRequesterName();} + void message(string const & message,MessageType messageType) + {pvaProcess->message(message,messageType);} + void channelProcessConnect( + const Status& status, + ChannelProcess::shared_pointer const & channelProcess) + {pvaProcess->channelProcessConnect(status,channelProcess);} + void processDone( + const Status& status, + ChannelProcess::shared_pointer const & channelProcess) + {pvaProcess->processDone(status,channelProcess);} +}; + +PvaProcess::PvaProcess( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +: pva(pva), + pvaChannel(pvaChannel), + channel(channel), + pvRequest(pvRequest), + isDestroyed(false), + connectState(connectIdle), + processState(processIdle) +{ +} + +PvaProcess::~PvaProcess() +{ + destroy(); +} + +void PvaProcess::checkProcessState() +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + if(connectState==connectIdle) connect(); + if(processState==processIdle) process(); +} + +// from ChannelProcessRequester +string PvaProcess::getRequesterName() +{ + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + return yyy->getRequesterName(); +} + +void PvaProcess::message(string const & message,MessageType messageType) +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + yyy->message(message, messageType); +} + +void PvaProcess::channelProcessConnect( + const Status& status, + ChannelProcess::shared_pointer const & channelProcess) +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + channelProcessConnectStatus = status; + this->channelProcess = channelProcess; + waitForConnect.signal(); + +} + +void PvaProcess::processDone( + const Status& status, + ChannelProcess::shared_pointer const & channelProcess) +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + channelProcessStatus = status; + waitForProcess.signal(); +} + + +// from PvaProcess +void PvaProcess::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + if(channelProcess) channelProcess->destroy(); + channelProcess.reset(); +} + +void PvaProcess::connect() +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + issueConnect(); + Status status = waitConnect(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaProcess::connect " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaProcess::issueConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + if(connectState!=connectIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaProcess already connected "; + throw std::runtime_error(ss.str()); + } + processRequester = ChannelProcessRequester::shared_pointer(new ChannelProcessRequesterImpl(this)); + connectState = connectActive; + channelProcess = channel->createChannelProcess(processRequester,pvRequest); +} + +Status PvaProcess::waitConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + if(connectState!=connectActive) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaProcess illegal connect state "; + throw std::runtime_error(ss.str()); + } + waitForConnect.wait(); + if(channelProcessConnectStatus.isOK()){ + connectState = connected; + return Status::Ok; + } + connectState = connectIdle; + return Status(Status::STATUSTYPE_ERROR,channelProcessConnectStatus.getMessage()); +} + +void PvaProcess::process() +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + issueProcess(); + Status status = waitProcess(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaProcess::process " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaProcess::issueProcess() +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + if(connectState==connectIdle) connect(); + if(processState!=processIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaProcess::issueProcess process aleady active "; + throw std::runtime_error(ss.str()); + } + processState = processActive; + channelProcess->process(); +} + +Status PvaProcess::waitProcess() +{ + if(isDestroyed) throw std::runtime_error("pvaProcess was destroyed"); + if(processState!=processActive){ + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaProcess::waitProcess llegal process state"; + throw std::runtime_error(ss.str()); + } + waitForProcess.wait(); + processState = processIdle; + if(channelProcessStatus.isOK()) { + return Status::Ok; + } + return Status(Status::STATUSTYPE_ERROR,channelProcessStatus.getMessage()); +} + +PvaProcessPtr PvaProcess::create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +{ + PvaProcessPtr epv(new PvaProcess(pva,pvaChannel,channel,pvRequest)); + return epv; +} + +}} diff --git a/pvaSrc/pvaPut.cpp b/pvaSrc/pvaPut.cpp new file mode 100644 index 0000000..d975bbe --- /dev/null +++ b/pvaSrc/pvaPut.cpp @@ -0,0 +1,292 @@ +/* pvaPut.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + +class ChannelPutRequesterImpl : public ChannelPutRequester +{ + PvaPut * pvaPut; +public: + ChannelPutRequesterImpl(PvaPut * pvaPut) + : pvaPut(pvaPut) {} + string getRequesterName() + {return pvaPut->getRequesterName();} + void message(string const & message,MessageType messageType) + {pvaPut->message(message,messageType);} + void channelPutConnect( + const Status& status, + ChannelPut::shared_pointer const & channelPut, + StructureConstPtr const & structure) + {pvaPut->channelPutConnect(status,channelPut,structure);} + void getDone( + const Status& status, + ChannelPut::shared_pointer const & channelPut, + PVStructurePtr const & pvStructure, + BitSetPtr const & bitSet) + {pvaPut->getDone(status,channelPut,pvStructure,bitSet);} + void putDone( + const Status& status, + ChannelPut::shared_pointer const & channelPut) + {pvaPut->putDone(status,channelPut);} +}; + +PvaPut::PvaPut( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +: pva(pva), + pvaChannel(pvaChannel), + channel(channel), + pvRequest(pvRequest), + isDestroyed(false), + connectState(connectIdle), + putState(putIdle) +{ +} + +PvaPut::~PvaPut() +{ + destroy(); +} + +void PvaPut::checkPutState() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + if(connectState==connectIdle){ + connect(); + get(); + } +} + +// from ChannelPutRequester +string PvaPut::getRequesterName() +{ + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + return yyy->getRequesterName(); +} + +void PvaPut::message(string const & message,MessageType messageType) +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + yyy->message(message, messageType); +} + +void PvaPut::channelPutConnect( + const Status& status, + ChannelPut::shared_pointer const & channelPut, + StructureConstPtr const & structure) +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + channelPutConnectStatus = status; + this->channelPut = channelPut; + if(status.isOK()) { + pvaData = PvaPutData::create(structure); + pvaData->setMessagePrefix(pvaChannel.lock()->getChannelName()); + } + waitForConnect.signal(); + +} + +void PvaPut::getDone( + const Status& status, + ChannelPut::shared_pointer const & channelPut, + PVStructurePtr const & pvStructure, + BitSetPtr const & bitSet) +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + channelGetPutStatus = status; + if(status.isOK()) { + PVStructurePtr pvs = pvaData->getPVStructure(); + pvs->copyUnchecked(*pvStructure,*bitSet); + BitSetPtr bs = pvaData->getBitSet(); + bs->clear(); + *bs |= *bitSet; + } + waitForGetPut.signal(); +} + +void PvaPut::putDone( + const Status& status, + ChannelPut::shared_pointer const & channelPut) +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + channelGetPutStatus = status; + waitForGetPut.signal(); +} + + +// from PvaPut +void PvaPut::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + if(channelPut) channelPut->destroy(); + channelPut.reset(); +} + +void PvaPut::connect() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + issueConnect(); + Status status = waitConnect(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPut::connect " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaPut::issueConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + if(connectState!=connectIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaPut already connected "; + throw std::runtime_error(ss.str()); + } + putRequester = ChannelPutRequester::shared_pointer(new ChannelPutRequesterImpl(this)); + connectState = connectActive; + channelPut = channel->createChannelPut(putRequester,pvRequest); +} + +Status PvaPut::waitConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + if(connectState!=connectActive) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaPut illegal connect state "; + throw std::runtime_error(ss.str()); + } + waitForConnect.wait(); + if(channelPutConnectStatus.isOK()) { + connectState = connected; + return Status::Ok; + } + connectState = connectIdle; + return Status(Status::STATUSTYPE_ERROR,channelPutConnectStatus.getMessage()); +} + +void PvaPut::get() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + issueGet(); + Status status = waitGet(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPut::get " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaPut::issueGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + if(connectState==connectIdle) connect(); + if(putState!=putIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPut::issueGet get or put aleady active "; + throw std::runtime_error(ss.str()); + } + putState = getActive; + pvaData->getBitSet()->clear(); + channelPut->get(); +} + +Status PvaPut::waitGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + if(putState!=getActive){ + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPut::waitGet llegal put state"; + throw std::runtime_error(ss.str()); + } + waitForGetPut.wait(); + putState = putIdle; + if(channelGetPutStatus.isOK()) { + return Status::Ok; + } + return Status(Status::STATUSTYPE_ERROR,channelGetPutStatus.getMessage()); +} + +void PvaPut::put() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + issuePut(); + Status status = waitPut(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPut::put " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaPut::issuePut() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + if(connectState==connectIdle) connect(); + if(putState!=putIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPut::issueGet get or put aleady active "; + throw std::runtime_error(ss.str()); + } + putState = putActive; + channelPut->put(pvaData->getPVStructure(),pvaData->getBitSet()); +} + +Status PvaPut::waitPut() +{ + if(isDestroyed) throw std::runtime_error("pvaPut was destroyed"); + if(putState!=putActive){ + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPut::waitPut llegal put state"; + throw std::runtime_error(ss.str()); + } + waitForGetPut.wait(); + putState = putIdle; + if(channelGetPutStatus.isOK()) { + pvaData->getBitSet()->clear(); + return Status::Ok; + } + return Status(Status::STATUSTYPE_ERROR,channelGetPutStatus.getMessage()); +} + +PvaPutDataPtr PvaPut::getData() +{ + checkPutState(); + return pvaData; +} + +PvaPutPtr PvaPut::create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +{ + PvaPutPtr epv(new PvaPut(pva,pvaChannel,channel,pvRequest)); + return epv; +} + + +}} diff --git a/pvaSrc/pvaPutData.cpp b/pvaSrc/pvaPutData.cpp new file mode 100644 index 0000000..8e9d11a --- /dev/null +++ b/pvaSrc/pvaPutData.cpp @@ -0,0 +1,267 @@ +/* easyPutData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include + +#include +#include +#include +#include + + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + +class PvaPostHandlerPvt: public PostHandler +{ + PvaPutData * easyData; + size_t fieldNumber; +public: + PvaPostHandlerPvt(PvaPutData *easyData,size_t fieldNumber) + : easyData(easyData),fieldNumber(fieldNumber){} + void postPut() { easyData->postPut(fieldNumber);} +}; + + +typedef std::tr1::shared_ptr PVArrayPtr; +static ConvertPtr convert = getConvert(); +static string noValue("no value field"); +static string notScalar("value is not a scalar"); +static string notCompatibleScalar("value is not a compatible scalar"); +static string notArray("value is not an array"); +static string notScalarArray("value is not a scalarArray"); +static string notDoubleArray("value is not a doubleArray"); +static string notStringArray("value is not a stringArray"); + +PvaPutDataPtr PvaPutData::create(StructureConstPtr const & structure) +{ + PvaPutDataPtr epv(new PvaPutData(structure)); + return epv; +} + +PvaPutData::PvaPutData(StructureConstPtr const & structure) +: structure(structure), + pvStructure(getPVDataCreate()->createPVStructure(structure)), + bitSet(BitSetPtr(new BitSet(pvStructure->getNumberFields()))) +{ + size_t nfields = pvStructure->getNumberFields(); + postHandler.resize(nfields); + PVFieldPtr pvField; + for(size_t i =0; igetSubField(i); + } + pvField->setPostHandler(postHandler[i]); + } + pvValue = pvStructure->getSubField("value"); +} + +void PvaPutData::checkValue() +{ + if(pvValue) return; + throw std::runtime_error(messagePrefix + noValue); +} + +void PvaPutData::postPut(size_t fieldNumber) +{ + bitSet->set(fieldNumber); +} + +void PvaPutData::setMessagePrefix(std::string const & value) +{ + messagePrefix = value + " "; +} + +StructureConstPtr PvaPutData::getStructure() +{return structure;} + +PVStructurePtr PvaPutData::getPVStructure() +{return pvStructure;} + +BitSetPtr PvaPutData::getBitSet() +{return bitSet;} + +std::ostream & PvaPutData::showChanged(std::ostream & out) +{ + size_t nextSet = bitSet->nextSetBit(0); + PVFieldPtr pvField; + while(nextSet!=string::npos) { + if(nextSet==0) { + pvField = pvStructure; + } else { + pvField = pvStructure->getSubField(nextSet); + } + string name = pvField->getFullName(); + out << name << " = " << pvField << endl; + nextSet = bitSet->nextSetBit(nextSet+1); + } + return out; +} + +bool PvaPutData::hasValue() +{ + if(!pvValue) return false; + return true; +} + +bool PvaPutData::isValueScalar() +{ + if(!pvValue) return false; + if(pvValue->getField()->getType()==scalar) return true; + return false; +} + +bool PvaPutData::isValueScalarArray() +{ + if(!pvValue) return false; + if(pvValue->getField()->getType()==scalarArray) return true; + return false; +} + +PVFieldPtr PvaPutData::getValue() +{ + checkValue(); + return pvValue; +} + +PVScalarPtr PvaPutData::getScalarValue() +{ + checkValue(); + PVScalarPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notScalar); + } + return pv; +} + +PVArrayPtr PvaPutData::getArrayValue() +{ + checkValue(); + PVArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notArray); + } + return pv; +} + +PVScalarArrayPtr PvaPutData::getScalarArrayValue() +{ + checkValue(); + PVScalarArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notScalarArray); + } + return pv; +} + +double PvaPutData::getDouble() +{ + PVScalarPtr pvScalar = getScalarValue(); + ScalarType scalarType = pvScalar->getScalar()->getScalarType(); + if(scalarType==pvDouble) { + PVDoublePtr pvDouble = static_pointer_cast(pvScalar); + return pvDouble->get(); + } + if(!ScalarTypeFunc::isNumeric(scalarType)) { + throw std::runtime_error(notCompatibleScalar); + } + return convert->toDouble(pvScalar); +} + +string PvaPutData::getString() +{ + PVScalarPtr pvScalar = getScalarValue(); + return convert->toString(pvScalar); +} + +shared_vector PvaPutData::getDoubleArray() +{ + checkValue(); + PVDoubleArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notDoubleArray); + } + return pv->view(); +} + +shared_vector PvaPutData::getStringArray() +{ + checkValue(); + PVStringArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notStringArray); + } + return pv->view(); + +} + +void PvaPutData::putDouble(double value) +{ + PVScalarPtr pvScalar = getScalarValue(); + ScalarType scalarType = pvScalar->getScalar()->getScalarType(); + if(scalarType==pvDouble) { + PVDoublePtr pvDouble = static_pointer_cast(pvScalar); + pvDouble->put(value); + } + if(!ScalarTypeFunc::isNumeric(scalarType)) { + throw std::runtime_error(messagePrefix + notCompatibleScalar); + } + convert->fromDouble(pvScalar,value); +} + +void PvaPutData::putString(std::string const & value) +{ + PVScalarPtr pvScalar = getScalarValue(); + convert->fromString(pvScalar,value); +} + + + +void PvaPutData::putDoubleArray(shared_vector const & value) +{ + checkValue(); + PVDoubleArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notDoubleArray); + } + pv->replace(value); +} + +void PvaPutData::putStringArray(shared_vector const & value) +{ + checkValue(); + PVStringArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notStringArray); + } + pv->replace(value); +} + +void PvaPutData::putStringArray(std::vector const & value) +{ + checkValue(); + PVScalarArrayPtr pv = pvStructure->getSubField("value"); + if(!pv) { + throw std::runtime_error(messagePrefix + notScalarArray); + } + convert->fromStringArray(pv,0,value.size(),value,0); +} + +}} diff --git a/pvaSrc/pvaPutGet.cpp b/pvaSrc/pvaPutGet.cpp new file mode 100644 index 0000000..b64a15e --- /dev/null +++ b/pvaSrc/pvaPutGet.cpp @@ -0,0 +1,378 @@ +/* pvaPutGet.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.02 + */ +#define epicsExportSharedSymbols + +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pva { + +class ChannelPutGetRequesterImpl : public ChannelPutGetRequester +{ + PvaPutGet * pvaPutGet; +public: + ChannelPutGetRequesterImpl(PvaPutGet * pvaPutGet) + : pvaPutGet(pvaPutGet) {} + string getRequesterName() + {return pvaPutGet->getRequesterName();} + void message(string const & message,MessageType messageType) + {pvaPutGet->message(message,messageType);} + void channelPutGetConnect( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::StructureConstPtr const & putStructure, + epics::pvData::StructureConstPtr const & getStructure) + { + pvaPutGet->channelPutGetConnect(status,channelPutGet,putStructure,getStructure); + } + void putGetDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructurePtr const & getPVStructure, + epics::pvData::BitSetPtr const & getBitSet) + { + pvaPutGet->putGetDone(status,channelPutGet,getPVStructure,getBitSet); + } + void getPutDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructurePtr const & putPVStructure, + epics::pvData::BitSet::shared_pointer const & putBitSet) + { + pvaPutGet->getPutDone(status,channelPutGet,putPVStructure,putBitSet); + } + void getGetDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, + epics::pvData::PVStructurePtr const & getPVStructure, + epics::pvData::BitSet::shared_pointer const & getBitSet) + { + pvaPutGet->getGetDone(status,channelPutGet,getPVStructure,getBitSet); + } +}; + +PvaPutGet::PvaPutGet( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +: pva(pva), + pvaChannel(pvaChannel), + channel(channel), + pvRequest(pvRequest), + isDestroyed(false), + connectState(connectIdle), + putGetState(putGetIdle) +{ +} + +PvaPutGet::~PvaPutGet() +{ + destroy(); +} + +void PvaPutGet::checkPutGetState() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(connectState==connectIdle){ + connect(); + getPut(); + } +} + +// from ChannelPutGetRequester +string PvaPutGet::getRequesterName() +{ + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + return yyy->getRequesterName(); +} + +void PvaPutGet::message(string const & message,MessageType messageType) +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + PvaPtr yyy = pva.lock(); + if(!yyy) throw std::runtime_error("pva was destroyed"); + yyy->message(message, messageType); +} + +void PvaPutGet::channelPutGetConnect( + const Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + StructureConstPtr const & putStructure, + StructureConstPtr const & getStructure) +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + channelPutGetConnectStatus = status; + this->channelPutGet = channelPutGet; + if(status.isOK()) { + pvaPutData = PvaPutData::create(putStructure); + pvaPutData->setMessagePrefix(pvaChannel.lock()->getChannelName()); + pvaGetData = PvaGetData::create(getStructure); + pvaGetData->setMessagePrefix(pvaChannel.lock()->getChannelName()); + } + waitForConnect.signal(); + +} + +void PvaPutGet::putGetDone( + const Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + PVStructurePtr const & getPVStructure, + BitSetPtr const & getBitSet) +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + channelPutGetStatus = status; + if(status.isOK()) { + pvaGetData->setData(getPVStructure,getBitSet); + } + waitForPutGet.signal(); +} + +void PvaPutGet::getPutDone( + const Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + PVStructurePtr const & putPVStructure, + BitSetPtr const & putBitSet) +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + channelGetPutGetStatus = status; + if(status.isOK()) { + PVStructurePtr pvs = pvaPutData->getPVStructure(); + pvs->copyUnchecked(*putPVStructure,*putBitSet); + BitSetPtr bs = pvaPutData->getBitSet(); + bs->clear(); + *bs |= *putBitSet; + } + waitForPutGet.signal(); +} + +void PvaPutGet::getGetDone( + const Status& status, + ChannelPutGet::shared_pointer const & channelPutGet, + PVStructurePtr const & getPVStructure, + BitSetPtr const & getBitSet) +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + channelPutGetStatus = status; + if(status.isOK()) { + pvaGetData->setData(getPVStructure,getBitSet); + } + waitForPutGet.signal(); +} + + + +// from PvaPutGet +void PvaPutGet::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + if(channelPutGet) channelPutGet->destroy(); + channelPutGet.reset(); +} + +void PvaPutGet::connect() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + issueConnect(); + Status status = waitConnect(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::connect " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaPutGet::issueConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(connectState!=connectIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaPutGet already connected "; + throw std::runtime_error(ss.str()); + } + putGetRequester = ChannelPutGetRequester::shared_pointer(new ChannelPutGetRequesterImpl(this)); + connectState = connectActive; + channelPutGet = channel->createChannelPutGet(putGetRequester,pvRequest); +} + +Status PvaPutGet::waitConnect() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(connectState!=connectActive) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " pvaPutGet illegal connect state "; + throw std::runtime_error(ss.str()); + } + waitForConnect.wait(); + if(channelPutGetConnectStatus.isOK()) { + connectState = connected; + return Status::Ok; + } + connectState = connectIdle; + return Status(Status::STATUSTYPE_ERROR,channelPutGetConnectStatus.getMessage()); +} + + +void PvaPutGet::putGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + issuePutGet(); + Status status = waitPutGet(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::putGet " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaPutGet::issuePutGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(connectState==connectIdle) connect(); + if(putGetState!=putGetIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::issueGet get or put aleady active "; + throw std::runtime_error(ss.str()); + } + putGetState = putGetActive; + channelPutGet->putGet(pvaPutData->getPVStructure(),pvaPutData->getBitSet()); +} + + +Status PvaPutGet::waitPutGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(putGetState!=putGetActive){ + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::waitPutGet llegal put state"; + throw std::runtime_error(ss.str()); + } + waitForPutGet.wait(); + putGetState = putGetIdle; + if(channelGetPutGetStatus.isOK()) { + return Status::Ok; + } + return Status(Status::STATUSTYPE_ERROR,channelGetPutGetStatus.getMessage()); +} + +void PvaPutGet::getGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + issueGetGet(); + Status status = waitGetGet(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::getGet " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaPutGet::issueGetGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(connectState==connectIdle) connect(); + if(putGetState!=putGetIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::issueGetGet aleady active "; + throw std::runtime_error(ss.str()); + } + putGetState = putGetActive; + channelPutGet->getGet(); +} + +Status PvaPutGet::waitGetGet() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(putGetState!=putGetActive){ + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::waitGetGet illegal state"; + throw std::runtime_error(ss.str()); + } + waitForPutGet.wait(); + putGetState = putGetIdle; + if(channelGetPutGetStatus.isOK()) { + return Status::Ok; + } + return Status(Status::STATUSTYPE_ERROR,channelGetPutGetStatus.getMessage()); +} + +void PvaPutGet::getPut() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + issueGetPut(); + Status status = waitGetPut(); + if(status.isOK()) return; + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::getPut " << status.getMessage(); + throw std::runtime_error(ss.str()); +} + +void PvaPutGet::issueGetPut() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(connectState==connectIdle) connect(); + if(putGetState!=putGetIdle) { + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::issueGetPut aleady active "; + throw std::runtime_error(ss.str()); + } + putGetState = putGetActive; + channelPutGet->getPut(); +} + +Status PvaPutGet::waitGetPut() +{ + if(isDestroyed) throw std::runtime_error("pvaPutGet was destroyed"); + if(putGetState!=putGetActive){ + stringstream ss; + ss << "channel " << channel->getChannelName() << " PvaPutGet::waitGetPut illegal state"; + throw std::runtime_error(ss.str()); + } + waitForPutGet.wait(); + putGetState = putGetIdle; + if(channelGetPutGetStatus.isOK()) { + return Status::Ok; + } + return Status(Status::STATUSTYPE_ERROR,channelGetPutGetStatus.getMessage()); +} + +PvaGetDataPtr PvaPutGet::getGetData() +{ + checkPutGetState(); + return pvaGetData; +} + +PvaPutDataPtr PvaPutGet::getPutData() +{ + checkPutGetState(); + return pvaPutData; +} + +PvaPutGetPtr PvaPutGet::create( + PvaPtr const &pva, + PvaChannelPtr const & pvaChannel, + Channel::shared_pointer const & channel, + PVStructurePtr const &pvRequest) +{ + PvaPutGetPtr epv(new PvaPutGet(pva,pvaChannel,channel,pvRequest)); + return epv; +} + + +}} diff --git a/pvaSrc/temp b/pvaSrc/temp new file mode 100644 index 0000000..df77e7f --- /dev/null +++ b/pvaSrc/temp @@ -0,0 +1,120 @@ +make -C O.linux-x86_64 -f ../Makefile TOP=../.. T_A=linux-x86_64 install +make[1]: Entering directory `/home/epicsv4/pvAccessCPP/pvaSrc/O.linux-x86_64' + +/usr/bin/g++ -c -D_POSIX_C_SOURCE=199506L -D_POSIX_THREADS -D_XOPEN_SOURCE=500 -g -ggdb -D_X86_64_ -DUNIX -D_BSD_SOURCE -Dlinux -D_REENTRANT -O3 -g -Wall -m64 -fPIC -MMD -I. -I../O.Common -I. -I.. -I../../include/pv/os/Linux -I../../include/pv -I/home/install/epics/base/include/os/Linux -I/home/install/epics/base/include -I/home/epicsv4/pvCommonCPP/include -I/home/epicsv4/pvDataCPP/include -I/home/epicsv4/pvAccessCPP/include -I/home/epicsv4/pvaSrv/include -I/home/epicsv4/normativeTypesCPP/include -I../../include ../pvaNTMultiChannel.cpp +In file included from ../pvaNTMultiChannel.cpp:13:0: +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:75:5: error: ‘PVAMultiChannelPtr’ does not name a type + PVAMultiChannelPtr getPVAMultiChannel(); + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:78:28: error: expected ‘)’ before ‘const’ + PVAMultiChannelPtr const & channelName, + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:83:5: error: ‘PVAMultiChannelPtr’ does not name a type + PVAMultiChannelPtr pvaMultiChannel; + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:87:17: error: ‘PVAGetPtr’ was not declared in this scope + std::vector pvaGet; + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:87:26: error: template argument 1 is invalid + std::vector pvaGet; + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:87:26: error: template argument 2 is invalid +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:88:17: error: ‘PVAPutPtr’ was not declared in this scope + std::vector pvaPut; + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:88:26: error: template argument 1 is invalid + std::vector pvaPut; + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:88:26: error: template argument 2 is invalid +../pvaNTMultiChannel.cpp: In static member function ‘static epics::pva::PvaNTMultiChannelPtr epics::pva::PvaNTMultiChannel::create(const PvaPtr&, const PVStringArrayPtr&, const StructureConstPtr&, double, const string&)’: +../pvaNTMultiChannel.cpp:41:85: error: no matching function for call to ‘epics::pva::PvaNTMultiChannel::PvaNTMultiChannel(epics::pva::PvaMultiChannelPtr&, epics::nt::NTMultiChannelPtr&)’ + return PvaNTMultiChannelPtr(new PvaNTMultiChannel(pvaMultiChannel,ntMultiChannel)); + ^ +../pvaNTMultiChannel.cpp:41:85: note: candidates are: +In file included from ../pvaNTMultiChannel.cpp:13:0: +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:34:23: note: epics::pva::PvaNTMultiChannel::PvaNTMultiChannel() + class epicsShareClass PvaNTMultiChannel + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:34:23: note: candidate expects 0 arguments, 2 provided +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:34:23: note: epics::pva::PvaNTMultiChannel::PvaNTMultiChannel(const epics::pva::PvaNTMultiChannel&) +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:34:23: note: candidate expects 1 argument, 2 provided +../pvaNTMultiChannel.cpp: At global scope: +../pvaNTMultiChannel.cpp:44:1: error: prototype for ‘epics::pva::PvaNTMultiChannel::PvaNTMultiChannel(const PvaMultiChannelPtr&, const NTMultiChannelPtr&)’ does not match any in class ‘epics::pva::PvaNTMultiChannel’ + PvaNTMultiChannel::PvaNTMultiChannel( + ^ +In file included from ../pvaNTMultiChannel.cpp:13:0: +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:34:23: error: candidates are: epics::pva::PvaNTMultiChannel::PvaNTMultiChannel(const epics::pva::PvaNTMultiChannel&) + class epicsShareClass PvaNTMultiChannel + ^ +/home/epicsv4/pvAccessCPP/include/pv/pvaNTMultiChannel.h:34:23: error: epics::pva::PvaNTMultiChannel::PvaNTMultiChannel() +../pvaNTMultiChannel.cpp: In member function ‘void epics::pva::PvaNTMultiChannel::createGet()’: +../pvaNTMultiChannel.cpp:72:42: error: ‘pvaMultiChannel’ was not declared in this scope + PvaChannelArrayPtr pvaChannelArray = pvaMultiChannel->getPvaChannelArray().lock(); + ^ +../pvaNTMultiChannel.cpp:76:12: error: cannot convert ‘std::vector >’ to ‘int’ in assignment + pvaGet = std::vector(numChannel,PvaGetPtr()); + ^ +../pvaNTMultiChannel.cpp:81:17: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + pvaGet[i] = pvaChannels[i]->createGet(request); + ^ +../pvaNTMultiChannel.cpp:82:17: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + pvaGet[i]->issueConnect(); + ^ +../pvaNTMultiChannel.cpp:86:34: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + Status status = pvaGet[i]->waitConnect(); + ^ +../pvaNTMultiChannel.cpp: In member function ‘void epics::pva::PvaNTMultiChannel::createPut()’: +../pvaNTMultiChannel.cpp:99:42: error: ‘pvaMultiChannel’ was not declared in this scope + PvaChannelArrayPtr pvaChannelArray = pvaMultiChannel->getPvaChannelArray().lock(); + ^ +../pvaNTMultiChannel.cpp:103:12: error: cannot convert ‘std::vector >’ to ‘int’ in assignment + pvaPut = std::vector(numChannel,PvaPutPtr()); + ^ +../pvaNTMultiChannel.cpp:108:17: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + pvaPut[i] = pvaChannels[i]->createPut("value"); + ^ +../pvaNTMultiChannel.cpp:109:17: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + pvaPut[i]->issueConnect(); + ^ +../pvaNTMultiChannel.cpp:113:34: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + Status status = pvaPut[i]->waitConnect(); + ^ +../pvaNTMultiChannel.cpp: In member function ‘epics::nt::NTMultiChannelPtr epics::pva::PvaNTMultiChannel::get()’: +../pvaNTMultiChannel.cpp:125:15: error: request for member ‘empty’ in ‘((epics::pva::PvaNTMultiChannel*)this)->epics::pva::PvaNTMultiChannel::pvaGet’, which is of non-class type ‘int’ + if(pvaGet.empty()) createGet(); + ^ +../pvaNTMultiChannel.cpp:127:48: error: ‘pvaMultiChannel’ was not declared in this scope + shared_vector channelNames = pvaMultiChannel->getChannelNames()->view(); + ^ +../pvaNTMultiChannel.cpp:162:17: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + pvaGet[i]->issueGet(); + ^ +../pvaNTMultiChannel.cpp:166:31: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + Status stat = pvaGet[i]->waitGet(); + ^ +../pvaNTMultiChannel.cpp:171:46: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + PVStructurePtr pvStructure = pvaGet[i]->getData()->getPVStructure(); + ^ +../pvaNTMultiChannel.cpp: In member function ‘void epics::pva::PvaNTMultiChannel::put(const NTMultiChannelPtr&)’: +../pvaNTMultiChannel.cpp:234:15: error: request for member ‘empty’ in ‘((epics::pva::PvaNTMultiChannel*)this)->epics::pva::PvaNTMultiChannel::pvaPut’, which is of non-class type ‘int’ + if(pvaPut.empty()) createPut(); + ^ +../pvaNTMultiChannel.cpp:235:48: error: ‘pvaMultiChannel’ was not declared in this scope + shared_vector channelNames = pvaMultiChannel->getChannelNames()->view(); + ^ +../pvaNTMultiChannel.cpp:244:39: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + PVFieldPtr pvTo = pvaPut[i]->getData()->getValue(); + ^ +../pvaNTMultiChannel.cpp:252:21: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + pvaPut[i]->issuePut(); + ^ +../pvaNTMultiChannel.cpp:260:33: error: invalid types ‘int[size_t {aka long unsigned int}]’ for array subscript + Status status = pvaPut[i]->waitPut(); + ^ +../pvaNTMultiChannel.cpp: In static member function ‘static epics::pva::PvaNTMultiChannelPtr epics::pva::PvaNTMultiChannel::create(const PvaPtr&, const PVStringArrayPtr&, const StructureConstPtr&, double, const string&)’: +../pvaNTMultiChannel.cpp:42:1: warning: control reaches end of non-void function [-Wreturn-type] + } + ^ +make[1]: *** [pvaNTMultiChannel.o] Error 1 +make[1]: Leaving directory `/home/epicsv4/pvAccessCPP/pvaSrc/O.linux-x86_64' +make: *** [install.linux-x86_64] Error 2 diff --git a/pvaTest/Makefile b/pvaTest/Makefile new file mode 100644 index 0000000..0a9fd57 --- /dev/null +++ b/pvaTest/Makefile @@ -0,0 +1,13 @@ +# Makefile at top of application tree + +TOP = . +include $(TOP)/configure/CONFIG + +DIRS += configure + +DIRS += src +src_DEPEND_DIRS = configure + +include $(TOP)/configure/RULES_TOP + + diff --git a/pvaTest/configure/CONFIG b/pvaTest/configure/CONFIG new file mode 100644 index 0000000..c1a4703 --- /dev/null +++ b/pvaTest/configure/CONFIG @@ -0,0 +1,29 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common +ifdef T_A +-include $(TOP)/configure/RELEASE.Common.$(T_A) +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain other build configuration settings +include $(TOP)/configure/CONFIG_SITE +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +ifdef T_A + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/pvaTest/configure/CONFIG_SITE b/pvaTest/configure/CONFIG_SITE new file mode 100644 index 0000000..6648852 --- /dev/null +++ b/pvaTest/configure/CONFIG_SITE @@ -0,0 +1,27 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building anyway if conflicts are found. +CHECK_RELEASE = WARN + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv +USR_INCLUDES += -I $(INSTALL_LOCATION)/include + +-include $(TOP)/../../CONFIG_SITE.local +-include $(TOP)/../configure/CONFIG_SITE.local diff --git a/pvaTest/configure/ExampleRELEASE.local b/pvaTest/configure/ExampleRELEASE.local new file mode 100644 index 0000000..3c70d98 --- /dev/null +++ b/pvaTest/configure/ExampleRELEASE.local @@ -0,0 +1,6 @@ +EPICS_BASE=/home/install/epics/base +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top +EPICSV4HOME=/home/epicsv4 +PVCOMMON=${EPICSV4HOME}/pvCommonCPP +PVDATA=${EPICSV4HOME}/pvDataCPP +PVACCESS=${EPICSV4HOME}/pvAccessCPP diff --git a/pvaTest/configure/Makefile b/pvaTest/configure/Makefile new file mode 100644 index 0000000..9254309 --- /dev/null +++ b/pvaTest/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/pvaTest/configure/RELEASE b/pvaTest/configure/RELEASE new file mode 100644 index 0000000..56e5b8b --- /dev/null +++ b/pvaTest/configure/RELEASE @@ -0,0 +1,41 @@ +# pvDatabaseCPP/example RELEASE - Location of external support modules +# +# IF YOU CHANGE this file or any file it includes you must +# subsequently do a "gnumake rebuild" in the application's +# top level directory. +# +# The build process does not check dependencies against files +# that are outside this application, thus you should also do a +# "gnumake rebuild" in the top level directory after EPICS_BASE +# or any other external module pointed to below is rebuilt. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) + +# EPICS V4 Developers: Do not edit the locations in this file! +# +# Create a file RELEASE.local pointing to your PVASRV, PVACCESS, +# PVDATA, PVCOMMON and EPICS_BASE build directories, e.g. +# PVASRV = /path/to/epics/pvaSrvCPP +# PVACCESS = /path/to/epics/pvAccessCPP +# PVDATA = /path/to/epics/pvDataCPP +# PVCOMMON = /path/to/epics/pvCommonCPP +# EPICS_BASE = /path/to/epics/base + +# If this example is built in a directory under pvDatabaseCPP, +# use the following definitions: + +EASYPVA = $(TOP)/.. + +-include $(TOP)/../configure/RELEASE.local +-include $(TOP)/../../RELEASE.local + +# If you copied this example from pvDatabaseCPP to be built as a +# standalone TOP, adjust and use the following definitions: + +#EASYPVA = /path/to/epics/easyPVACPP + +#-include $(TOP)/../RELEASE.local +#-include $(TOP)/configure/RELEASE.local diff --git a/pvaTest/configure/RULES b/pvaTest/configure/RULES new file mode 100644 index 0000000..6d56e14 --- /dev/null +++ b/pvaTest/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/pvaTest/configure/RULES.ioc b/pvaTest/configure/RULES.ioc new file mode 100644 index 0000000..901987c --- /dev/null +++ b/pvaTest/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/pvaTest/configure/RULES_DIRS b/pvaTest/configure/RULES_DIRS new file mode 100644 index 0000000..3ba269d --- /dev/null +++ b/pvaTest/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/pvaTest/configure/RULES_TOP b/pvaTest/configure/RULES_TOP new file mode 100644 index 0000000..d09d668 --- /dev/null +++ b/pvaTest/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/pvaTest/src/Makefile b/pvaTest/src/Makefile new file mode 100644 index 0000000..ec4c1a6 --- /dev/null +++ b/pvaTest/src/Makefile @@ -0,0 +1,57 @@ +# Makefile for the pvAccess tests + +TOP = .. +include $(TOP)/configure/CONFIG + +TESTPROD_HOST += testPvaPutData +testPvaPutData_SRCS = testPvaPutData +testHarness_SRCS += testPvaPutData.cpp +TESTS += testPvaPutData + +TESTPROD_HOST += testPvaGetData +testPvaGetData_SRCS = testPvaGetData +testHarness_SRCS += testPvaGetData.cpp +TESTS += testPvaGetData + +TESTPROD_HOST += testPvaMonitorData +testPvaMonitorData_SRCS = testPvaMonitorData +testHarness_SRCS += testPvaMonitorData.cpp +TESTS += testPvaMonitorData + +TESTPROD_HOST += testPvaPutGetMonitor +testPvaPutGetMonitor_SRCS = testPvaPutGetMonitor +testHarness_SRCS += testPvaPutGetMonitor.cpp +TESTS += testPvaPutGetMonitor + +TESTPROD_HOST += testPvaPutGet +testPvaPutGet_SRCS = testPvaPutGet +testHarness_SRCS += testPvaPutGet.cpp +TESTS += testPvaPutGet + +TESTPROD_HOST += testPvaMultiDouble +testPvaMultiDouble_SRCS = testPvaMultiDouble +testHarness_SRCS += testPvaMultiDouble.cpp +TESTS += testPvaMultiDouble + +TESTPROD_HOST += testPvaNTMultiChannel +testPvaNTMultiChannel_SRCS = testPvaNTMultiChannel +testHarness_SRCS += testPvaNTMultiChannel.cpp +TESTS += testPvaNTMultiChannel + + +PROD_LIBS += pva pvAccess pvData nt Com + +testHarness_SRCS += easyAllTests.c + +PROD_vxWorks = vxTestHarness +vxTestHarness_SRCS += $(testHarness_SRCS) +TESTSPEC_vxWorks = vxTestHarness.$(MUNCH_SUFFIX); easyAllTests + +PROD_RTEMS += rtemsTestHarness +rtemsTestHarness_SRCS += rtemsTestHarness.c rtemsConfig.c +rtemsTestHarness_SRCS += $(testHarness_SRCS) +TESTSPEC_RTEMS = rtemsTestHarness.$(MUNCH_SUFFIX); easyAllTests + +TESTSCRIPTS_HOST += $(TESTS:%=%.t) + +include $(TOP)/configure/RULES diff --git a/pvaTest/src/pvaAllTests.c b/pvaTest/src/pvaAllTests.c new file mode 100644 index 0000000..84d8fc3 --- /dev/null +++ b/pvaTest/src/pvaAllTests.c @@ -0,0 +1,31 @@ +/* + * Run PvaPVA tests as a batch. + * + * Do *not* include performance measurements here, they don't help to + * prove functionality (which is the point of this convenience routine). + */ + +#include +#include +#include + +int testPvaGetData(void); +int testPvaPutData(void); +int testPvaMonitorData(void); +int testPvaPutGetMonitor(void); +int testPvaPutGet(void); +int testPvaMultiDouble(void); +int testPvaNTMultiChannel(void); + +void easyAllTests(void) +{ + testHarness(); + runTest(testPvaGetData); + runTest(testPvaPutData); + runTest(testPvaMonitorData); + runTest(testPvaPutMonitor); + runTest(testPvaPut); + runTest(testPvaMultiDouble); + runTest(testPvaNTMultiChannel); +} + diff --git a/pvaTest/src/testPvaGetData.cpp b/pvaTest/src/testPvaGetData.cpp new file mode 100644 index 0000000..14c5bb1 --- /dev/null +++ b/pvaTest/src/testPvaGetData.cpp @@ -0,0 +1,155 @@ +/*testPvaGetData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + +static PvaPtr pva = Pva::create(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static StandardFieldPtr standardField = getStandardField(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); + + +void testDouble() +{ + cout << "\nstarting testDouble\n"; + StructureConstPtr structure = + fieldCreate->createFieldBuilder()-> + add("alarm",standardField->alarm()) -> + add("timeStamp",standardField->timeStamp()) -> + add("value",pvDouble) -> + createStructure(); + + PvaGetDataPtr pvaData = PvaGetData::create(structure); + PVStructurePtr pvStructure = pvDataCreate->createPVStructure(pvaData->getStructure()); + BitSetPtr bitSet = BitSetPtr(new BitSet(pvStructure->getNumberFields())); + pvaData->setData(pvStructure,bitSet); + PVDoublePtr pvDouble = pvStructure->getSubField("value"); + size_t valueOffset = pvDouble->getFieldOffset(); + BitSetPtr change = pvaData->getBitSet(); + pvDouble->put(5.0); + change->set(pvDouble->getFieldOffset()); + testOk(change->cardinality()==1,"num set bits 1"); + testOk(change->get(valueOffset)==true,"value changed"); + testOk(pvaData->hasValue()==true,"hasValue"); + testOk(pvaData->isValueScalar()==true,"isValueScalar"); + testOk(pvaData->isValueScalarArray()==false,"isValueScalarArray"); + bool result; + result = false; + if(pvaData->getValue()) result = true; + testOk(result==true,"getValue"); + result = false; + if(pvaData->getScalarValue()) result = true; + testOk(result==true,"getScalarValue"); + try { + pvaData->getArrayValue(); + } catch (std::runtime_error e) { + cout << "getArrayValue " << e.what() << endl; + } + try { + pvaData->getScalarArrayValue(); + } catch (std::runtime_error e) { + cout << " getScalarArrayValue " << e.what() << endl; + } + cout << "as double " << pvaData->getDouble() << endl; + cout << "as string " << pvaData->getString() << endl; + try { + shared_vector value = pvaData->getDoubleArray(); + } catch (std::runtime_error e) { + cout << " getDoubleArray " << e.what() << endl; + } + try { + shared_vector value = pvaData->getStringArray(); + } catch (std::runtime_error e) { + cout << " getStringArray " << e.what() << endl; + } +} + +void testDoubleArray() +{ + cout << "\nstarting testDoubleArray\n"; + StructureConstPtr structure = + fieldCreate->createFieldBuilder()-> + add("alarm",standardField->alarm()) -> + add("timeStamp",standardField->timeStamp()) -> + addArray("value",pvDouble) -> + createStructure(); + + PvaGetDataPtr pvaData = PvaGetData::create(structure); + PVStructurePtr pvStructure = pvDataCreate->createPVStructure(pvaData->getStructure()); + BitSetPtr bitSet = BitSetPtr(new BitSet(pvStructure->getNumberFields())); + pvaData->setData(pvStructure,bitSet); + PVDoubleArrayPtr pvalue = pvaData->getPVStructure()->getSubField("value"); + BitSetPtr change = pvaData->getBitSet(); + size_t valueOffset = pvalue->getFieldOffset(); + size_t len = 5; + shared_vector value(len); + for(size_t i=0; ireplace(freeze(value)); + change->set(valueOffset); + testOk(change->cardinality()==1,"num set bits 1"); + testOk(change->get(valueOffset)==true,"value changed"); + testOk(pvaData->hasValue()==true,"hasValue"); + testOk(pvaData->isValueScalar()==false,"isValueScalar"); + testOk(pvaData->isValueScalarArray()==true,"isValueScalarArray"); + bool result; + result = false; + if(pvaData->getValue()) result = true; + testOk(result==true,"getValue"); + result = false; + if(pvaData->getArrayValue()) result = true; + testOk(result==true,"getArrayValue"); + result = false; + if(pvaData->getScalarArrayValue()) result = true; + testOk(result==true,"getScalarValue"); + try { + pvaData->getScalarValue(); + } catch (std::runtime_error e) { + cout << " getScalarValue " << e.what() << endl; + } + try { + cout << "as double " << pvaData->getDouble() << endl; + } catch (std::runtime_error e) { + cout << " getDouble " << e.what() << endl; + } + try { + string val = pvaData->getString(); + } catch (std::runtime_error e) { + cout << " getString " << e.what() << endl; + } + cout << "as doubleArray " << pvaData->getDoubleArray() << endl; + try { + shared_vector value = pvaData->getStringArray(); + } catch (std::runtime_error e) { + cout << " getStringArray " << e.what() << endl; + } +} + +MAIN(testPvaGetData) +{ + cout << "\nstarting testPvaGetData\n"; + testPlan(15); + testDouble(); + testDoubleArray(); + return 0; +} + diff --git a/pvaTest/src/testPvaMonitorData.cpp b/pvaTest/src/testPvaMonitorData.cpp new file mode 100644 index 0000000..92ce4df --- /dev/null +++ b/pvaTest/src/testPvaMonitorData.cpp @@ -0,0 +1,153 @@ +/*testPvaMonitorData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + +static PvaPtr pva = Pva::create(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static StandardFieldPtr standardField = getStandardField(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); + + +void testDouble() +{ + cout << "\nstarting testDouble\n"; + StructureConstPtr structure = + fieldCreate->createFieldBuilder()-> + add("alarm",standardField->alarm()) -> + add("timeStamp",standardField->timeStamp()) -> + add("value",pvDouble) -> + createStructure(); + + PvaMonitorDataPtr pvaData = PvaMonitorData::create(structure); + MonitorElementPtr monitorElement(new MonitorElement(pvDataCreate->createPVStructure(pvaData->getStructure()))); + pvaData->setData(monitorElement); + PVDoublePtr pvDouble = pvaData->getPVStructure()->getSubField("value"); + size_t valueOffset = pvDouble->getFieldOffset(); + BitSetPtr change = pvaData->getChangedBitSet(); + pvDouble->put(5.0); + change->set(pvDouble->getFieldOffset()); + testOk(change->cardinality()==1,"num set bits 1"); + testOk(change->get(valueOffset)==true,"value changed"); + testOk(pvaData->hasValue()==true,"hasValue"); + testOk(pvaData->isValueScalar()==true,"isValueScalar"); + testOk(pvaData->isValueScalarArray()==false,"isValueScalarArray"); + bool result; + result = false; + if(pvaData->getValue()) result = true; + testOk(result==true,"getValue"); + result = false; + if(pvaData->getScalarValue()) result = true; + testOk(result==true,"getScalarValue"); + try { + pvaData->getArrayValue(); + } catch (std::runtime_error e) { + cout << "getArrayValue " << e.what() << endl; + } + try { + pvaData->getScalarArrayValue(); + } catch (std::runtime_error e) { + cout << " getScalarArrayValue " << e.what() << endl; + } + cout << "as double " << pvaData->getDouble() << endl; + cout << "as string " << pvaData->getString() << endl; + try { + shared_vector value = pvaData->getDoubleArray(); + } catch (std::runtime_error e) { + cout << " getDoubleArray " << e.what() << endl; + } + try { + shared_vector value = pvaData->getStringArray(); + } catch (std::runtime_error e) { + cout << " getStringArray " << e.what() << endl; + } +} + +void testDoubleArray() +{ + cout << "\nstarting testDoubleArray\n"; + StructureConstPtr structure = + fieldCreate->createFieldBuilder()-> + add("alarm",standardField->alarm()) -> + add("timeStamp",standardField->timeStamp()) -> + addArray("value",pvDouble) -> + createStructure(); + + PvaMonitorDataPtr pvaData = PvaMonitorData::create(structure); + MonitorElementPtr monitorElement(new MonitorElement(pvDataCreate->createPVStructure(pvaData->getStructure()))); + pvaData->setData(monitorElement); + PVDoubleArrayPtr pvalue = pvaData->getPVStructure()->getSubField("value"); + BitSetPtr change = pvaData->getChangedBitSet(); + size_t valueOffset = pvalue->getFieldOffset(); + size_t len = 5; + shared_vector value(len); + for(size_t i=0; ireplace(freeze(value)); + change->set(valueOffset); + testOk(change->cardinality()==1,"num set bits 1"); + testOk(change->get(valueOffset)==true,"value changed"); + testOk(pvaData->hasValue()==true,"hasValue"); + testOk(pvaData->isValueScalar()==false,"isValueScalar"); + testOk(pvaData->isValueScalarArray()==true,"isValueScalarArray"); + bool result; + result = false; + if(pvaData->getValue()) result = true; + testOk(result==true,"getValue"); + result = false; + if(pvaData->getArrayValue()) result = true; + testOk(result==true,"getArrayValue"); + result = false; + if(pvaData->getScalarArrayValue()) result = true; + testOk(result==true,"getScalarValue"); + try { + pvaData->getScalarValue(); + } catch (std::runtime_error e) { + cout << " getScalarValue " << e.what() << endl; + } + try { + cout << "as double " << pvaData->getDouble() << endl; + } catch (std::runtime_error e) { + cout << " getDouble " << e.what() << endl; + } + try { + string val = pvaData->getString(); + } catch (std::runtime_error e) { + cout << " getString " << e.what() << endl; + } + cout << "as doubleArray " << pvaData->getDoubleArray() << endl; + try { + shared_vector value = pvaData->getStringArray(); + } catch (std::runtime_error e) { + cout << " getStringArray " << e.what() << endl; + } +} + +MAIN(testPvaMonitorData) +{ + cout << "\nstarting testPvaMonitorData\n"; + testPlan(15); + testDouble(); + testDoubleArray(); + return 0; +} + diff --git a/pvaTest/src/testPvaMultiDouble.cpp b/pvaTest/src/testPvaMultiDouble.cpp new file mode 100644 index 0000000..adb2038 --- /dev/null +++ b/pvaTest/src/testPvaMultiDouble.cpp @@ -0,0 +1,156 @@ +/*testPvaMultiDouble.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void testGood(PvaPtr const &pva) +{ + bool isOk = true; + cout << "\nstarting testGood\n"; + try { + PvaPtr pva(Pva::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "exampleDouble04"; + channelNames[4] = "exampleDouble05"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + PvaMultiDoublePtr multiDouble(PvaMultiDouble::create(pva,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==true,"all channels double"); +} + +static void testGoodMixed(PvaPtr const &pva) +{ + bool isOk = true; + cout << "\nstarting testGoodMixed\n"; + try { + PvaPtr pva(Pva::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleByte"; + channelNames[1] = "exampleShort"; + channelNames[2] = "exampleInt"; + channelNames[3] = "exampleFloat"; + channelNames[4] = "exampleDouble"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + PvaMultiDoublePtr multiDouble(PvaMultiDouble::create(pva,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==true,"channels mixed type"); +} + +static void testChannelNotExist(PvaPtr const &pva) +{ + bool isOk = true; + cout << "\nstarting testChannelNotExist\n"; + try { + PvaPtr pva(Pva::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "NoneExistChannel"; + channelNames[4] = "exampleDouble05"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + PvaMultiDoublePtr multiDouble(PvaMultiDouble::create(pva,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==false,"channel not exist"); +} + +static void testNonNumeric(PvaPtr const &pva) +{ + bool isOk = true; + cout << "\nstarting testNonNumeric\n"; + try { + PvaPtr pva(Pva::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "exampleDouble04"; + channelNames[4] = "exampleDouble05Array"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + PvaMultiDoublePtr multiDouble(PvaMultiDouble::create(pva,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==false,"channel not numeric"); +} + +MAIN(testPvaMultiDouble) +{ + cout << "\nstarting testPvaMultiDouble\n"; + testPlan(4); + PvaPtr pva = Pva::create(); + testGood(pva); + testGoodMixed(pva); + testChannelNotExist(pva); + testNonNumeric(pva); + cout << "done\n"; + return 0; +} diff --git a/pvaTest/src/testPvaNTMultiChannel.cpp b/pvaTest/src/testPvaNTMultiChannel.cpp new file mode 100644 index 0000000..512e503 --- /dev/null +++ b/pvaTest/src/testPvaNTMultiChannel.cpp @@ -0,0 +1,132 @@ +/*testPvaNTMultiChannel.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; +using namespace epics::nt; +using std::tr1::static_pointer_cast; + + +static void testGood(PvaPtr const &pva) +{ + PVDataCreatePtr pvDataCreate(getPVDataCreate()); + bool isOk = true; + cout << "\nstarting testGood\n"; + try { + PvaPtr pva(Pva::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble"; + channelNames[1] = "exampleDoubleArray"; + channelNames[2] = "exampleString"; + channelNames[3] = "exampleBoolean"; + channelNames[4] = "exampleEnum"; + PVStringArrayPtr pvNames = pvDataCreate-> + createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + StructureConstPtr structure = builder-> + addTimeStamp()-> + addSeverity() -> + addStatus() -> + addMessage() -> + addSecondsPastEpoch() -> + addNanoseconds() -> + addUserTag() -> + createStructure(); + PvaNTMultiChannelPtr multi = PvaNTMultiChannel::create( + pva,pvNames,structure); + NTMultiChannelPtr nt = multi->get(); + for(size_t numtimes=0; numtimes<3; ++numtimes) { + PVUnionArrayPtr pvValue = nt->getPVStructure()-> + getSubField("value"); + cout << "initial\n" << nt->getPVStructure() << endl; + shared_vector valueVector = pvValue->reuse(); + for(size_t i=0; iget(); + Type type = pvField->getField()->getType(); + if(type==scalar) { + PVScalarPtr pvScalar = static_pointer_cast(pvField); + ScalarType scalarType = pvScalar->getScalar()->getScalarType(); + if(ScalarTypeFunc::isNumeric(scalarType)) { + double oldValue = pvScalar->getAs(); + oldValue++; + pvScalar->putFrom(oldValue); + } else if(scalarType==pvString) { + PVStringPtr pv = static_pointer_cast(pvField); + string val = pv->get(); + val += " added"; + pv->put(val); + } else if(scalarType==pvBoolean) { + PVBooleanPtr pv = static_pointer_cast(pvField); + bool val = pv->get(); + pv->put(!val); + } + } else if(type==scalarArray) { + PVScalarArrayPtr pv = + static_pointer_cast(pvField); + ScalarType scalarType = pv->getScalarArray()->getElementType(); + if(scalarType==pvDouble) { + PVDoubleArrayPtr pvd = static_pointer_cast(pv); + shared_vector valvec = pvd->reuse(); + if(valvec.capacity()==0) { + valvec.resize(4); + for(size_t i=0; ireplace(freeze(valvec)); + } + } else if(type==epics::pvData::structure) { + PVStructurePtr pvStructure = static_pointer_cast(pvField); + PVIntPtr pv = pvStructure->getSubField("index"); + if(pv) { + PVStringArrayPtr choices = pvStructure->getSubField("choices"); + if(choices) { + int32 nchoices = choices->getLength(); + int32 oldval = pv->get(); + int32 newval = (oldval==nchoices) ? 0 : ++oldval; + pv->put(newval); + } + } + } + } + pvValue->replace(freeze(valueVector)); + multi->put(nt); + nt = multi->get(); + } + cout << "final\n" << nt->getPVStructure() << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==true,"no problems"); +} + + +MAIN(testPvaNTMultiChannel) +{ + cout << "\nstarting testPvaNTMultiChannel\n"; + testPlan(1); + PvaPtr pva = Pva::create(); + testGood(pva); + cout << "done\n"; + return 0; +} diff --git a/pvaTest/src/testPvaPutData.cpp b/pvaTest/src/testPvaPutData.cpp new file mode 100644 index 0000000..ef08e05 --- /dev/null +++ b/pvaTest/src/testPvaPutData.cpp @@ -0,0 +1,229 @@ +/*testPvaPutData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + +static PvaPtr pva = Pva::create(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static StandardFieldPtr standardField = getStandardField(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); + +static void testPostPut() +{ + cout << "\nstarting testPostPut\n"; + StructureConstPtr structure = + fieldCreate->createFieldBuilder()-> + add("alarm",standardField->alarm()) -> + add("timeStamp",standardField->timeStamp()) -> + addNestedStructure("power") -> + add("value",pvDouble) -> + add("alarm",standardField->alarm()) -> + endNested()-> + addNestedStructure("voltage") -> + add("value",pvDouble) -> + add("alarm",standardField->alarm()) -> + endNested()-> + addNestedStructure("current") -> + add("value",pvDouble) -> + add("alarm",standardField->alarm()) -> + endNested()-> + createStructure(); + + PvaPutDataPtr pvaData = PvaPutData::create(structure); + PVStructurePtr pvStructure = pvaData->getPVStructure(); + BitSetPtr change = pvaData->getBitSet(); + PVDoublePtr powerValue = pvStructure->getSubField("power.value"); + PVDoublePtr voltageValue = pvStructure->getSubField("voltage.value"); + PVDoublePtr currentValue = pvStructure->getSubField("current.value"); + size_t powerOffset = powerValue->getFieldOffset(); + size_t voltageOffset = voltageValue->getFieldOffset(); + size_t currentOffset = currentValue->getFieldOffset(); + change->clear(); + powerValue->put(1.0); + voltageValue->put(2.0); + currentValue->put(.5); + cout << "changed\n"; + cout << pvaData->showChanged(cout) << endl; + testOk(change->cardinality()==3,"num set bits 3"); + testOk(change->get(powerOffset)==true,"power changed"); + testOk(change->get(voltageOffset)==true,"voltage changed"); + testOk(change->get(currentOffset)==true,"current changed"); +} + +void testDouble() +{ + cout << "\nstarting testDouble\n"; + StructureConstPtr structure = + fieldCreate->createFieldBuilder()-> + add("alarm",standardField->alarm()) -> + add("timeStamp",standardField->timeStamp()) -> + add("value",pvDouble) -> + createStructure(); + + PvaPutDataPtr pvaData = PvaPutData::create(structure); + PVDoublePtr pvDouble = pvaData->getPVStructure()->getSubField("value"); + pvDouble->put(5.0); + BitSetPtr change = pvaData->getBitSet(); + size_t valueOffset = pvDouble->getFieldOffset(); + testOk(change->cardinality()==1,"num set bits 1"); + testOk(change->get(valueOffset)==true,"value changed"); + testOk(pvaData->hasValue()==true,"hasValue"); + testOk(pvaData->isValueScalar()==true,"isValueScalar"); + testOk(pvaData->isValueScalarArray()==false,"isValueScalarArray"); + bool result; + result = false; + if(pvaData->getValue()) result = true; + testOk(result==true,"getValue"); + result = false; + if(pvaData->getScalarValue()) result = true; + testOk(result==true,"getScalarValue"); + try { + pvaData->getArrayValue(); + } catch (std::runtime_error e) { + cout << "getArrayValue " << e.what() << endl; + } + try { + pvaData->getScalarArrayValue(); + } catch (std::runtime_error e) { + cout << " getScalarArrayValue " << e.what() << endl; + } + cout << "as double " << pvaData->getDouble() << endl; + cout << "as string " << pvaData->getString() << endl; + try { + shared_vector value = pvaData->getDoubleArray(); + } catch (std::runtime_error e) { + cout << " getDoubleArray " << e.what() << endl; + } + try { + shared_vector value = pvaData->getStringArray(); + } catch (std::runtime_error e) { + cout << " getStringArray " << e.what() << endl; + } + pvaData->putDouble(5.0); + pvaData->putString("1e5"); + try { + size_t len = 2; + shared_vector val(len); + for(size_t i=0; iputDoubleArray(freeze(val)); + } catch (std::runtime_error e) { + cout << " putDoubleArray " << e.what() << endl; + } + try { + size_t len = 2; + shared_vector val(len); + val[0] = "one"; val[1] = "two"; + pvaData->putStringArray(freeze(val)); + } catch (std::runtime_error e) { + cout << " putStringArray " << e.what() << endl; + } +} + +void testDoubleArray() +{ + cout << "\nstarting testDoubleArray\n"; + StructureConstPtr structure = + fieldCreate->createFieldBuilder()-> + add("alarm",standardField->alarm()) -> + add("timeStamp",standardField->timeStamp()) -> + addArray("value",pvDouble) -> + createStructure(); + + PvaPutDataPtr pvaData = PvaPutData::create(structure); + PVDoubleArrayPtr pvalue = pvaData->getPVStructure()->getSubField("value"); + size_t len = 5; + shared_vector value(len); + for(size_t i=0; ireplace(freeze(value)); + BitSetPtr change = pvaData->getBitSet(); + size_t valueOffset = pvalue->getFieldOffset(); + testOk(change->cardinality()==1,"num set bits 1"); + testOk(change->get(valueOffset)==true,"value changed"); + testOk(pvaData->hasValue()==true,"hasValue"); + testOk(pvaData->isValueScalar()==false,"isValueScalar"); + testOk(pvaData->isValueScalarArray()==true,"isValueScalarArray"); + bool result; + result = false; + if(pvaData->getValue()) result = true; + testOk(result==true,"getValue"); + result = false; + if(pvaData->getArrayValue()) result = true; + testOk(result==true,"getArrayValue"); + result = false; + if(pvaData->getScalarArrayValue()) result = true; + testOk(result==true,"getScalarValue"); + try { + pvaData->getScalarValue(); + } catch (std::runtime_error e) { + cout << " getScalarValue " << e.what() << endl; + } + try { + cout << "as double " << pvaData->getDouble() << endl; + } catch (std::runtime_error e) { + cout << " getDouble " << e.what() << endl; + } + try { + string val = pvaData->getString(); + } catch (std::runtime_error e) { + cout << " getString " << e.what() << endl; + } + cout << "as doubleArray " << pvaData->getDoubleArray() << endl; + try { + shared_vector value = pvaData->getStringArray(); + } catch (std::runtime_error e) { + cout << " getStringArray " << e.what() << endl; + } + try { + pvaData->putDouble(5.0); + } catch (std::runtime_error e) { + cout << " putDouble " << e.what() << endl; + } + try { + pvaData->putString("1e5"); + } catch (std::runtime_error e) { + cout << " putString " << e.what() << endl; + } + value = shared_vector(len); + for(size_t i=0; iputDoubleArray(freeze(value)); + cout << "as doubleArray " << pvaData->getDoubleArray() << endl; + try { + size_t len = 2; + shared_vector val(len); + val[0] = "one"; val[1] = "two"; + pvaData->putStringArray(freeze(val)); + cout << "as stringArray " << val << endl; + } catch (std::runtime_error e) { + cout << " putStringArray " << e.what() << endl; + } +} + +MAIN(testPvaPutData) +{ + cout << "\nstarting testPvaPutData\n"; + testPlan(19); + testPostPut(); + testDouble(); + testDoubleArray(); + return 0; +} diff --git a/pvaTest/src/testPvaPutGet.cpp b/pvaTest/src/testPvaPutGet.cpp new file mode 100644 index 0000000..3e1f193 --- /dev/null +++ b/pvaTest/src/testPvaPutGet.cpp @@ -0,0 +1,66 @@ +/*examplePvaPutGet.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +static void example(PvaPtr const &pva) +{ + cout << "\nstarting channelPutGet example\n"; + try { + PvaChannelPtr pvaChannel = pva->createChannel("examplePowerSupply"); + pvaChannel->connect(2.0); + testOk(true==true,"connected"); + PvaPutGetPtr putGet = pvaChannel->createPutGet( + "putField(power.value,voltage.value)getField()"); + PvaPutDataPtr putData = putGet->getPutData(); + testOk(true==true,"put connected"); + PVStructurePtr pvStructure = putData->getPVStructure(); + PVDoublePtr power = pvStructure->getSubField("power.value"); + PVDoublePtr voltage = pvStructure->getSubField("voltage.value"); + power->put(5.0); + voltage->put(5.0); + putGet->putGet(); + PvaGetDataPtr getData = putGet->getGetData(); + pvStructure = getData->getPVStructure(); + BitSetPtr bitSet = getData->getBitSet(); + cout << "changed " << getData->showChanged(cout) << endl; + cout << "bitSet " << *bitSet << endl; + power->put(6.0); + putGet->putGet(); + pvStructure = getData->getPVStructure(); + bitSet = getData->getBitSet(); + cout << "changed " << getData->showChanged(cout) << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + + +MAIN(testPvaPutGet) +{ + cout << "\nstarting testPvaPutGet\n"; + testPlan(2); + PvaPtr pva = Pva::create(); + example(pva); + cout << "done\n"; + return 0; +} diff --git a/pvaTest/src/testPvaPutGetMonitor.cpp b/pvaTest/src/testPvaPutGetMonitor.cpp new file mode 100644 index 0000000..a01afec --- /dev/null +++ b/pvaTest/src/testPvaPutGetMonitor.cpp @@ -0,0 +1,89 @@ +/*testPvaPutGetMonitor.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pva; + + +class MyMonitor : public PvaMonitorRequester +{ +public: + MyMonitor() {} + virtual ~MyMonitor() {} + virtual void event(PvaMonitorPtr monitor) + { + while(true) { + if(!monitor->poll()) return; + PvaMonitorDataPtr pvaData = monitor->getData(); + cout << "changed\n"; + pvaData->showChanged(cout); + cout << "overrun\n"; + pvaData->showOverrun(cout); + monitor->releaseEvent(); + + } + } +}; + +static void exampleDouble(PvaPtr const &pva) +{ + cout << "\nstarting exampleDouble\n"; + try { + cout << "long way\n"; + PvaChannelPtr pvaChannel = pva->createChannel("exampleDouble"); + pvaChannel->connect(2.0); + testOk(true==true,"connected"); + PvaPutPtr put = pvaChannel->createPut(); + PvaPutDataPtr putData = put->getData(); + testOk(true==true,"put connected"); + PvaGetPtr get = pvaChannel->createGet(); + PvaGetDataPtr getData = get->getData(); + testOk(true==true,"get connected"); + PvaMonitorRequesterPtr requester(new MyMonitor()); + PvaMonitorPtr monitor = pvaChannel->monitor(requester); + testOk(true==true,"monitor connected"); + double out; + double in; + for(size_t i=0 ; i< 5; ++i) { + out = i; + putData->putDouble(out); + put->put(); + get->get(); + in = getData->getDouble(); + cout << "out " << out << " in " << in << endl; + } + PvaProcessPtr process = pvaChannel->createProcess(); + process->connect(); + process->process(); + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + + +MAIN(testPvaPutGetMonitor) +{ + cout << "\nstarting testPvaPutGetMonitor\n"; + testPlan(4); + PvaPtr pva = Pva::create(); + exampleDouble(pva); + cout << "done\n"; + return 0; +} From bf550ebd4e45faf62a537a91ae911f7d0f6adafe Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Fri, 5 Jun 2015 09:09:34 -0400 Subject: [PATCH 3/3] Update pvAccessCPP.html. pvAccessOverview.html also appears in doxygen. --- Doxyfile | 1 + documentation/pvAccessCPP.html | 77 +- documentation/pvAccessCPP_20150505.html | 136 +++ documentation/pvAccessOverview.html | 1108 +++++++++++++++++++++++ src/client/pvAccess.h | 7 + 5 files changed, 1309 insertions(+), 20 deletions(-) create mode 100644 documentation/pvAccessCPP_20150505.html create mode 100644 documentation/pvAccessOverview.html diff --git a/Doxyfile b/Doxyfile index 4faffdc..c4702f8 100644 --- a/Doxyfile +++ b/Doxyfile @@ -908,6 +908,7 @@ HTML_STYLESHEET = # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. +HTML_EXTRA_FILES = documentation/pvAccessOverview.html HTML_EXTRA_FILES = documentation/pvaOverview.html # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. diff --git a/documentation/pvAccessCPP.html b/documentation/pvAccessCPP.html index 1a66012..78b5a3c 100644 --- a/documentation/pvAccessCPP.html +++ b/documentation/pvAccessCPP.html @@ -38,7 +38,7 @@

EPICS pvAccessCPP

-

EPICS v4 Working Group, Working Draft, 09-July-2011

+

EPICS v4 Working Group, Working Draft, 05-June-2011

Latest version:
This version:
pvAccessCPP_20140709.html + href="pvAccessCPP_20150505.html">pvAccessCPP_20150505.html
Previous version:
pvAccessCPP_20111220.html + href="pvAccessCPP_20140709.html">pvAccessCPP_20140709.html
Editors:
Marty Kraimer, BNL
@@ -59,40 +59,77 @@

Abstract

-

pvAccessCPP is the C++ implementation of pvAccess, which is one of a related -set of products:
+

pvAccessCPP is the C++ implementation of pvAccess, +which is network support for transporting structured data as defined by pvData. +

+

+pvAccess is one of a related +set of products: relatedDocumentsV4.html

+

Status of this Document

-

This is the 09-July-2011 version of the C++ implementation of pvAccess. The -code is a complete implementation of pvAccess as currently defined. This -overview is NOT written.

+

This is the 05-June-2011 version of the C++ implementation of pvAccess. The +code is a complete implementation of pvAccess.

-

Table of Contents

+

Table of Contents

+
- - - -

Introduction


-

This product is available via an open source -license

+

Preface

+

This document describes the pvAccess Application Program Interface (API). +The reader is assumed to have a basic understanding of EPICS V4 as described in:

+ +EPICS V4 Developer's Guide + +

The pvAccess API is callback based and uses Status to report problem to the +client, which means that it can be complex to use. +If your primary interest is client access then, instead of reading this document, +read:

+ +EPICS pva + +

If your primary interest is implementing pvAccess services then, +before reading this documement read:

+ +pvDatabaseCPP + -

This overview for pvAccessCPP. Doxygen documentation is available at doxygenDoc

-

THIS IS NOT WRITTEN For now please consult pvAccessJava.html. -In addition look at the Doxygen documentation for this project.

+ + +

Introduction

+

This product is available via an +open source license + +

+

+A user overview is available via +pvAccessOverview.html + +

+

+Doxygen documentation is available at +doxygenDoc + + +

???

+

Matej decide what else should go in this document

diff --git a/documentation/pvAccessCPP_20150505.html b/documentation/pvAccessCPP_20150505.html new file mode 100644 index 0000000..78b5a3c --- /dev/null +++ b/documentation/pvAccessCPP_20150505.html @@ -0,0 +1,136 @@ + + + + + + EPICS pvAccessCPP + + + + + + + + + +
+

EPICS pvAccessCPP

+ + +

EPICS v4 Working Group, Working Draft, 05-June-2011

+
+
Latest version:
+
pvAccessCPP.html +
+
This version:
+
pvAccessCPP_20150505.html +
+
Previous version:
+
pvAccessCPP_20140709.html +
+
Editors:
+
Marty Kraimer, BNL
+ Matej Sekoranja, CosyLab
+
+
+ +

Abstract

+

pvAccessCPP is the C++ implementation of pvAccess, +which is network support for transporting structured data as defined by pvData. +

+

+pvAccess is one of a related +set of products: +relatedDocumentsV4.html +

+ + + +

Status of this Document

+ +

This is the 05-June-2011 version of the C++ implementation of pvAccess. The +code is a complete implementation of pvAccess.

+ +
+ +
+

Table of Contents

+
+ + +
+
+ +

Preface

+

This document describes the pvAccess Application Program Interface (API). +The reader is assumed to have a basic understanding of EPICS V4 as described in:

+ +EPICS V4 Developer's Guide + +

The pvAccess API is callback based and uses Status to report problem to the +client, which means that it can be complex to use. +If your primary interest is client access then, instead of reading this document, +read:

+ +EPICS pva + +

If your primary interest is implementing pvAccess services then, +before reading this documement read:

+ +pvDatabaseCPP + + + + + +

Introduction

+

This product is available via an +open source license + +

+

+A user overview is available via +pvAccessOverview.html + +

+

+Doxygen documentation is available at +doxygenDoc + + +

???

+

Matej decide what else should go in this document

+ +
+ + diff --git a/documentation/pvAccessOverview.html b/documentation/pvAccessOverview.html new file mode 100644 index 0000000..d7c94e5 --- /dev/null +++ b/documentation/pvAccessOverview.html @@ -0,0 +1,1108 @@ + + + + + + pvAccess C++ Overview + + + + + + + + + +
+

pvAccess C++ Overview

+
+ +
+

Table of Contents

+
+ + +
+
+ +

Preface

+

This document describes the pvAccess Application Program Interface (API). +The reader is assumed to have a basic understanding of EPICS V4 as described in:
+ +EPICS V4 Developer's Guide + +

+

The pvAccess API is callback based and uses Status to report problems to the +client, which means that it can be complex to use. +If your primary interest is client access then, instead of reading this document, +read:
+ +EPICS pva + +

+

If your primary interest is implementing pvAccess services then, +before reading this documement read:
+ +pvDatabaseCPP + +

+ +

Introduction

+

This section briefly describes the most important classes, +class methods, and global methods used by client and/or service code. +Not all classes and methods are described. +When source code from include files is shown it +is often a simplified version. +Ptr is shorthand for ::shared_pointer +For example: +

+
+ChannelFindPtr
+
+instead of +
+ChannelFind::shared_pointer
+
+

pvAccess provides network support for structured data as described by +pvData. +

+

The main concepts of pvAccess are:

+
+
ChannelProvider
+
A channelProvider creates channels, + where a channel instance is a connection between a client and a server. +
+ +
Channel
+
A channel has a number of create methods: createChannelGet, + createChannelPut, etc. Each of ChannelGet, ChannelPut, etc + provides methods to pass data between client and server. +
+
+

An arbitrary number of channelProviders can be implemented +on both the client and server side. +A ChannelProviderRegistry allows clients to connect to +servers and for Providers to register with the registry. +

+

ChannelProviderRegistry Overview

+

Three global methods are available:

+
+
getChannelProviderRegistry
+
Get the single instance of ChannelProviderRegistry.
+
registerChannelProviderFactory
+
Register a ChannelProvider
+
unregisterChannelProviderFactory
+
Remove a ChannelProvider
+
+

ChannelProviderRegistry provides the method:

+
+
getProvider
+
+ +

ChannelProvider Overview

+

Provides the following methods:

+
+
createChannel
+
Create a channel.
+
+

Channel Overview

+

Channel provides methods to create the following:

+
+
ChannelProcess
+
Client can make requests to process the channel.
+
ChannelGet
+
Client can make requests to get data from a channel.
+
ChannelPut
+
Client can make requests to put data to a channel.
+
ChannelPutGet
+
Client can make requests to put data to a channel, + process the channel, and get data from the channel. +
+
Monitor
+
Monitor data changes in the channel.
+
ChannelArray
+
Get or put data to a sub-array.
+
ChannelRPC
+
Similar to ChannelPutGet but data types can change for each request.
+
+

ChannelProviders implemented by pvAccessCPP

+

Client Side

+
+
pva network protocal
+
+ This connects the client to a server via the pva network protocol, + which is a protocol for passing pvData objects. + The protocol is described in:
+ + +pvAccess Protocol Specification + +
+
ca network protocol
+
This connects the client to a server via the ca network protocal, + i. e. it connects to an existing V3 IOC. + This is client side only code. + It transforms data between pvData and ca DBR data, + The ca protocol is described in:
+ +Channel Access Reference Manual + +
+
codec
+
Matej please explain
+
+

The client side of pva also allows an arbitrary number of additional providers to register with it.

+ +

Server Side

+
+
pva network protocal
+
The server side for pva network protocol. + It connects the server side of the network to ChannelProviders. +
+
RPC Server
+
This is the "glue" code for implementing a ChannelRPC service. + An actual service must implement method request.
+
codec
+
Matej please explain
+
+

The server side of the pva network protocal. +allows an arbitrary number of providers to register with it. +Existing examples are:

+
+
local provider
+
pvDatabase implements a PVDatabase, which is a memory resident + database of PVRecords. Each PVRecord has a name, which is the channel name, + and a top level PVStructure. A record is "smart" because each record has + an associated method named process. +
+
pvaSrv
+
This is a ChannelProvider for accessing V3 IOC DBRecords. + It transforms the data in a V3 DBRecord to a top level PVStructure. +
+
+ +

Command Line Utilities

+

pvAccessCPP provides the following command line utilities:
pvlist, pvinfo, pvget, pvput, and eget.

+

In order to use these commands a path to the pvAccessCPP bin directory must exists. +For example, on my linux workstation .bash_profile includes the statements:

+
+export EPICSV4=/home/epicsv4
+export PATH=$PATH:${EPICSV4}/pvAccessCPP/bin/${EPICS_HOST_ARCH}
+
+

+This document gives a VERY brief explaination if each command but each provides a -help option. +For example:

+
+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 10.5.1.205:10000
+	pvlist 0x83DE3C540000000000BF351F
+
+

+A longer explanation of the commands is in:

+ +EPICS V4 Developer's Guide + +

pvlist

+

Shows all servers avaliable via the pva network protocal and also a list +of all channels for a particular server. +

+

pvinfo

+

Shows the connection status and introspection interface for channels.

+

pvget

+

Returns data for a channel via channelGet or monitor. +

+

pvput

+

Puts data to a channel via channelPut.

+

eget

+

pvget on steroids. +Also has support for channelRPC and some of the normative types.

+

Include Files

+

The following are the include files that are of most interest to clients:

+
+
pvAccess.h
+
This document discusses most of the clases described in pvAccess.h. + The following are not discussed in this document: +
+enum AccessRights {none,read,readWrite};
+class Lockable...
+class ScopedLock...
+
+
+
clientFactory.h
+
Static methods to start and stop the pva provider.
+
rpcClient.h
+
Code for implementing the client side of a channelRPC request. +
+
caProvider.h
+
Needed to start the provider for the ca network protocol. +
+
+

The following are of interest to service code:

+
+
serverContext.h
+
Needed to start pvAccess Server Context.
+
rpcServer.h
+
Code for implementing the server side of a channelRPC request. +
+
rpcService.h
+
Matej please explain.
+
+

Matej are any others of interest to client or service code?

+ +

Starting PVAccess Clients

+

To start both the pva and ca client providers issue the commands:

+
+ClientFactory::start();
+CAClientFactory::start();
+
+ +

Starting pvAccess Server Context

+

To see examples of how to start a pvAccess server look at the examples provided +in exampleDatabasePVA.zip. +It shows examples for both a standalone main server and a V4 server that runs as part of +a V3 IOC. +The following is taken from exampleDatabaseMain.cpp that is in the example:

+
+int main(int argc,char *argv[])
+{
+
+...
+    ContextLocal::shared_pointer contextLocal = ContextLocal::create();
+    contextLocal->start();
+
+...
+    contextLocal->waitForExit();
+    return 0;
+}
+
+ + +

ChannelProvider

+

class ChannelProviderRegistry

+
+class ChannelProviderRegistry
+{
+public:
+   virtual ~ChannelProviderRegistry();
+   virtual ChannelProviderPtr getProvider(string const & providerName);
+   virtual ChannelProviderPtr createProvider(string const & providerName);
+   virtual std::auto_ptr<vector<string> > getProviderNames();
+};
+epicsShareExtern ChannelProviderRegistryPtr getChannelProviderRegistry();
+epicsShareExtern void registerChannelProviderFactory(ChannelProviderFactoryPtr const & channelProviderFactory);
+epicsShareExtern void unregisterChannelProviderFactory(ChannelProviderFactoryPtr const & channelProviderFactor
+
+

The global methods are:

+
+
getChannelProviderRegistry
+
Called by both client and services to get the single instance of ChannelProviderRegistry. +
+
registerChannelProviderFactory
+
Called by a service that implements ChannelProvider. + Note that implementing a ChannelProvider is a big task, + which is why pvDatabaseCPP exists. +
+
unregisterChannelProviderFactory
+
Called by a service if it no longer wants the provider to be used.
+
+

The methods for ChannelProviderRegistry are:

+
+
getProvider
+
Called by both client and services to get the channelProvider.
+ The providerName must be the name of a registered provider.
+ Most clients will use either pva or ca.
+ Most services will use pvDatabaseCPP, which implements provider local. + A service that is also a client can also use local or pvaSrv. +
+
createProvider
+
Called by a service to start the provider.
+
getProviderNames
+
Gets the names of all registered providers.
+
+

class ChannelProvider

+
+class ChannelProvider
+{
+public:
+    static const short PRIORITY_MIN = 0;
+    static const short PRIORITY_MAX = 99;
+    static const short PRIORITY_DEFAULT = PRIORITY_MIN;
+    static const short PRIORITY_LINKS_DB = PRIORITY_MAX;
+    static const short PRIORITY_ARCHIVE = (PRIORITY_MAX + PRIORITY_MIN) / 2;
+    static const short PRIORITY_OPI = PRIORITY_MIN;
+
+    virtual destroy() {}
+    virtual std::string getProviderName() = 0;
+    virtual ChannelFindPtr channelFind(
+        std::string const & channelName,
+        ChannelFindRequesterPtr const & channelFindRequester) = 0;
+    virtual ChannelFindPtr channelList(
+        ChannelListRequesterPtr const & channelListRequester) = 0;
+    virtual ChannelPtr createChannel(
+        std::string const & channelName,
+        ChannelRequesterPtr const & channelRequester,
+    virtual ChannelPtr createChannel(
+        std::string const & channelName,
+        ChannelRequesterPtr const & channelRequester,
+        short priority,
+        std::string const & address);
+    virtual void configure(PVStructurePtr /*configuration*/) {};
+    virtual void flush() {};
+    virtual void poll() {};
+
+};
+
+class ChannelFind
+{
+public:
+    virtual ChannelProviderPtr getChannelProvider();
+    virtual void cancel();
+};
+
+class ChannelFindRequester
+{
+public:
+    virtual ~ChannelFindRequester() {}
+    virtual void channelFindResult(
+        const Status& status,
+        ChannelFindPtr const & channelFind,
+        bool wasFound) = 0;
+};
+
+class ChannelListRequester
+{
+public:
+    virtual ~ChannelListRequester() {};
+    virtual void channelListResult(
+        const Status& status,
+        ChannelFindPtr const & channelFind,
+        PVStringArray::const_svector const & channelNames,
+        bool hasDynamic) = 0;
+};
+
+

The methods of ChannelProvider are:

+
+
getProviderName
+
Returns the name of the channel provider.
+
channelFind
+
Determines if the channel exists. + The result is passed by calling the channelFindResult of channelFindRequester. + The caller must implement channelFindRequester, which is described below. + The return value is ChannelFindPtr, which the caller can use to cancel a request. +
+
channelList
+
Gets a list of all the channels served by this provider. + The result is passed by calling the channelListResult of channelListRequester. + The caller must implement channelListRequester, which is described below. + The return value is ChannelFindPtr, which the caller can use to cancel a request. +
+
createChannel
+
Creates a connection to a channel. + The result passed by calling methods of ChannelRequester. + The caller must implememt ChannelRequester, which is described along with Channel below. +
+
configure
+
Not called by client, + Matej please explain +
+
flush
+
Not called by client, + Matej please explain +
+
poll
+
Not called by client, + Matej please explain +
+
+

The methods of ChannelFind are:

+
+
getChannelProvider
+
Returns the provider.
+
cancel
+
Cancel the current channelFind or channelList request.
+
+

The method of ChannelFindRequester are:

+
+
channelFindResult
+
If wasFound is true then status is OK. + If not found then status provides reason for failure. +
+
+

The method of ChannelListRequester are:

+
+
channelListResult
+
If there is a problem with the channelList request status provides the reason. + channelNames provides the list of channels the provider is + currently providing.
+ Matej please explain hasDynamic. +
+
+

Channel

+

class ChannelRequester

+

This must be implemented by a client. +It shows the result of a ChannelProvider::createChannel request +and also the connection state of the channel. +

+
+class ChannelRequester : Requester
+{
+public:
+    virtual void channelCreated(
+        const Status& status, ChannelPtr const & channel) = 0;
+    virtual void channelStateChange(
+        ChannelPtr const & channel,
+        Channel::ConnectionState connectionState) = 0;
+};
+
+

The methods of ChannelRequester are:

+
+
channelCreated
+
This is called as a result of a ChannelProvider::createChannel request. + It shows if the request was successful. + If not successful then channel is null and status shows why the request failed. +
+
channelStateChange
+
When the client successfuly connects to a channel this is called with ConnectionState=CONNECTED. + After successfuly connecting the client can call the channel methods. +
+ This method is also called whenever the channel disconnects or re-connects. + When a reconnect occurs the implementaion automatically reconnects any + channelGet, channelPut, etc that the client has created. +
+
+

class Channel

+
+class Channel : Requester ...
+{
+public:
+    POINTER_DEFINITIONS(Channel);
+
+    enum ConnectionState {
+        NEVER_CONNECTED, CONNECTED, DISCONNECTED, DESTROYED
+    };
+
+    static const char* ConnectionStateNames[];
+
+    virtual destroy() {}
+    virtual ChannelProviderPtr getProvider() = 0;
+    virtual std::string getRemoteAddress() = 0;
+    virtual ConnectionState getConnectionState() = 0;
+    virtual std::string getChannelName() = 0;
+    virtual ChannelRequesterPtr getChannelRequester() = 0;
+    virtual bool isConnected() = 0;
+    virtual void getField(
+        GetFieldRequesterPtr const & requester,
+        std::string const & subField) = 0;
+    virtual AccessRights getAccessRights(PVFieldPtr const & pvField) = 0;
+    virtual ChannelProcessPtr createChannelProcess(
+            ChannelProcessRequesterPtr const & channelProcessRequester,
+            PVStructurePtr const & pvRequest) = 0;
+    virtual ChannelGetPtr createChannelGet(
+            ChannelGetRequesterPtr const & channelGetRequester,
+            PVStructurePtr const & pvRequest) = 0;
+    virtual ChannelPutPtr createChannelPut(
+            ChannelPutRequesterPtr const & channelPutRequester,
+            PVStructurePtr const & pvRequest) = 0;
+    virtual ChannelPutGetPtr createChannelPutGet(
+            ChannelPutGetRequesterPtr const & channelPutGetRequester,
+            PVStructurePtr const & pvRequest) = 0;
+    virtual ChannelRPCPtr createChannelRPC(
+            ChannelRPCRequesterPtr const & channelRPCRequester,
+            PVStructurePtr const & pvRequest) = 0;
+    virtual MonitorPtr createMonitor(
+            MonitorRequesterPtr const & monitorRequester,
+            PVStructurePtr const & pvRequest) = 0;
+    virtual ChannelArrayPtr createChannelArray(
+            ChannelArrayRequesterPtr const & channelArrayRequester,
+            PVStructurePtr const & pvRequest) = 0;
+    virtual void printInfo() = 0;
+    virtual void printInfo(std::ostream& out) = 0;
+};
+
+where: +
+
destroy
+
+ Destroy all resources belonging to the channel. + This includes all channelPuts, channelGets, etc and any remote connections. +
+
getProvider
+
+ Get the name of the provider. +
+
getRemoteAddress
+
+ Get the remote address of the channel. +
+
getConnectionState
+
+ Get the connection state. +
+
getChannelName
+
+ Get the channel name. +
+
getChannelRequester
+
+ Get the interface to the code that created the channel. +
+
isConnected
+
+ Is the channel connected? +
+
getField
+
+ Get the introspection interface for the subfield of the PVStructure attached to the channel. + The result is returned via the GetFieldRequester, which must be implemented by the caller. +
+
getAccessRights
+
+ Get the access rights for the caller. + The access rights are one of none, read , or readWrite. +
+
createChannelProcess
+
+ Create a ChannelProcess, which is described below. +
+
createChannelGet
+
+ Create a ChannelGet, which is described below. +
+
createChannelPut
+
+ Create a ChannelPut, which is described below. +
+
createChannelPutGet
+
+ Create a ChannelPutGet, which is described below. +
+
createChannelRPC
+
+ Create a ChannelRPC, which is described below. +
+
createMonitor
+
+ Create a Monitor, which is described below. +
+
createChannelArray
+
+ Create a ChannelArray, which is described below. +
+
printInfo
+
+ Print information about the channel. +
+
+ +

class GetFieldRequester

+
+class GetFieldRequester : virtual public Requester {
+public:
+    virtual void getDone(
+        const Status& status,
+        FieldConstPtr const & field) = 0;
+};
+
+where: +
+
getDone
+
This is called as a result of a call to Channel::getField. + status shows the result. + if status is OK then field is the introspection interface for the requested field. +
+
+

class ChannelRequest

+

This is a base class for ChannelGet, ChannelPut, etc.

+
+class ChannelRequest
+{
+public:
+    virtual ChannelPtr getChannel() = 0;
+    virtual void cancel() = 0;
+    virtual void lastRequest() = 0;
+};
+
+where: +
+
getChannel
+
Get the Channel interface.
+
cancel
+
Cancel any outstanding request
+
lastRequest
+
The current request is the last request. + Allows the implementation to release resources +
+
+

ChannelGet

+

This is used to get data from a server.

+

class ChannelGet

+
+class ChannelGet : public ChannelRequest {
+public:
+    virtual void get() = 0;
+};
+
+where +
+
get
+
Issue a get request to the server. + The result is returned via a call to ChannelGetRequester::getDone. + Only one get request at a time can be outstanding, i. e. + a new get can not be issued until the callback for the first is called. +
+
+

class ChannelGetRequester

+
+class ChannelGetRequester : virtual public Requester {
+    public:
+    virtual void channelGetConnect(
+            const Status& status,
+            ChannelGetPtr const & channelGet,
+            Structure::const_shared_pointer const & structure) = 0;
+    virtual void getDone(
+            const Status& status,
+            ChannelGetPtr const & channelGet,
+            PVStructurePtr const & pvStructure,
+            BitSetPtr const & bitSet) = 0;
+};
+
+where: +
+
channelGetConnect
+
This is called as a result of calling Channel::createChannelGet. + If status is OK, then channelGet is the interface to ChannelGet and + structure is the introspection interface that will be used for + the data returned by every call to ChannelGet::get. + If status shows a failure then the client should NOT use either channelGet + or structure. +
+
getDone
+
This is called as a result of a call to ChannelGet::get. + status shows the result. + if status is OK then pvStructure has the data and bitSet shows which fields + have changed since the previous call. + The data and bitSet "belong" to the client until the next get is issued. + After that the data may change. +
+
+

ChannelPut

+

This is used to put data to a server.

+

class ChannelPut

+
+class ChannelPut : public ChannelRequest {
+public:
+    virtual void put(
+            PVStructurePtr const & pvPutStructure,
+            BitSetPtr const & putBitSet) = 0;
+    virtual void get() = 0;
+
+};
+
+where: +
+
put
+
Put all changed fields of pvPutStructure to the server. + putBitSet shows which fields are to be sent. + When the put completes (an ack is received from the server) + ChannelPutRequester::putDone is called. + Only one put or get request at a time can be outstanding, i. e. + a new put or get can not be issued until the callback for the first is called. +
+
get
+
Get the current data from the server. + The result is returned via a call to ChannelPutRequester::getDone. +
+
+

class ChannelPutRequester

+
+class ChannelPutRequester : virtual public Requester {
+public:
+    virtual void channelPutConnect(
+            const Status& status,
+            ChannelPutPtr const & channelPut,
+            Structure::const_shared_pointer const & structure) = 0;
+    virtual void putDone(
+            Status & status,
+            ChannelPutPtr const & channelPut) = 0;
+    virtual void getDone(
+            const Status& status,
+            ChannelPutPtr const & channelPut,
+            PVStructurePtr const & pvStructure,
+            BitSetPtr const & bitSet) = 0;
+};
+
+where: +
+
channelPutConnect
+
This is called as a result of calling Channel::createChannelPut. + If status is OK, then channelPut is the interface to ChannelPut and + structure is the introspection interface that + must be used for the pvStructure passed to each ChannelPut::put + and will be used for + the data returned by every call to ChannelPut::get. + If status shows a failure then the client should NOT use either channelPut + or structure. +
+
putDone
+
Called when ChannelPut::put is acknowledged by the server. + status shows the result. +
+ +
getDone
+
This is called as a result of a call to ChannelPut::get. + status shows the result. + if status is OK then pvStructure has the data and bitSet shows which fields + have changed since the previous call. + The data and bitSet "belong" to the client until the next get is issued. + After that the data may change. +
+
+

ChannelPutGet

+

This is used to:

+
+put data to a server
+process
+get data from the server
+
+

class ChannelPutGet

+
+class ChannelPutGet : public ChannelRequest {
+public:
+    virtual void putGet(
+            PVStructurePtr const & pvPutStructure,
+            BitSetPtr const & putBitSet) = 0;
+    virtual void getPut() = 0;
+    virtual void getGet() = 0;
+};
+
+where: +
+
putGet
+
Put all changed fields of pvPutStructure to the server. + putBitSet shows which fields are to be sent. +
+ The server processes and returns data to the client. +
+ When the putGet completes + ChannelPutGetRequester::putDone is called with the result. +
+ Only one putGet or getGet or getPut request at a time can be outstanding, i. e. + a new request can not be issued until the callback for the first is called. +
+
getPut
+
Get the current put data from the server. +
+ The result is returned via a call to ChannelPutGetRequester::getPutDone. +
+
getGet
+
Get the current get data from the server. +
+ The result is returned via a call to ChannelPutGetRequester::getGet. +
+
+

class ChannelPutGetRequester

+
+class ChannelPutGetRequester : virtual public Requester
+{
+    public:
+    virtual void channelPutGetConnect(
+            const Status& status,
+            ChannelPutGetPtr const & channelPutGet,
+            Structure::const_shared_pointer const & putStructure,
+            Structure::const_shared_pointer const & getStructure) = 0;
+
+    virtual void putGetDone(
+            const Status& status,
+            ChannelPutGetPtr const & channelPutGet,
+            PVStructurePtr const & pvGetStructure,
+            BitSetPtr const & getBitSet) = 0;
+
+    virtual void getPutDone(
+            const Status& status,
+            ChannelPutGetPtr const & channelPutGet,
+            PVStructurePtr const & pvPutStructure,
+            BitSetPtr const & putBitSet) = 0;
+
+    virtual void getGetDone(
+            const Status& status,
+            ChannelPutGetPtr const & channelPutGet,
+            PVStructurePtr const & pvGetStructure,
+            BitSetPtr const & getBitSet) = 0;
+};
+
+where: +
+
channelPutGetConnect
+
This is called as a result of calling Channel::createChannelPutGet. +
+ If status is OK, then + putStructure is the introspection interface that 1) + must be used for the pvStructure passed to each ChannelPutGet::putGet + and 2) will be used for + the data returned by every call to ChannelPutGet::getPut. +
+ getStructure is the introspection interface that will be used for + the data returned by every call to ChannelPutGet::getGet and ChannelPut::putGet. +
+ If status shows a failure then the client should NOT use either channelPut + or putStructure or getStructure. +
+
putGetDone
+
Called when ChannelPutGet::putGet is acknowledged by the server. + status shows the result. + If status is OK then pvGetStructure has the data and getBitSet shows which fields + have changed since the previous call. + The data and bitSet "belong" to the client until the next putGet or getGet is issued. + After that the data may change. +
+ +
getPutDone
+
This is called as a result of a call to ChannelPutGet::getPut. + status shows the result. + If status is OK then pvPutStructure has the data and putBitSet shows which fields + have changed since the previous call. + The data and bitSet "belong" to the client until the next get is issued. + After that the data may change. +
+
getGetDone
+
Called when ChannelPutGet::getGet is acknowledged by the server. + status shows the result. + If status is OK then pvGetStructure has the data and getBitSet shows which fields + have changed since the previous call. + The data and bitSet "belong" to the client until the next putGet or getGet is issued. + After that the data may change. +
+ +
getPutDone
+
This is called as a result of a call to ChannelPutGet::getPut. + status shows the result. + If status is OK then pvPutStructure has the data and putBitSet shows which fields + have changed since the previous call. + The data and bitSet "belong" to the client until the next get is issued. + After that the data may change. +
+
+

ChannelArray

+

class ChannelArray

+

Get/Put a subset of an array. +This works for all of scalarArray, unionArray, and structureArray.

+
+class ChannelArray : public ChannelRequest
+{
+public:
+    virtual void putArray(
+            PVArrayPtr const & putArray,
+            size_t offset = 0,
+            size_t count = 0,
+            size_t stride = 1) = 0;
+    virtual void getArray(
+            size_t offset = 0,
+            size_t count = 0,
+            size_t stride = 1) = 0;
+    virtual void getLength() = 0;
+    virtual void setLength(size_t length) = 0;
+};
+
+where: +
+
putArray
+
The putArray is sent to the server, which changes to specified + elements of the server array.
+
getArray
+
The server selects the specified set of elements in the + server array and returns the result to the client, +
getLength
+
Get the current length of the server array.
+
setLength
+
Set the length of the server array.
+
+

class ChannelArrayRequester

+
+class ChannelArrayRequester : virtual public Requester {
+public:
+    virtual void channelArrayConnect(
+            const Status& status,
+            ChannelArrayPtr const & channelArray,
+            Array::const_shared_pointer const & array) = 0;
+    virtual void putArrayDone(
+            const Status& status,
+            ChannelArrayPtr const & channelArray) = 0;
+    virtual void getArrayDone(
+            const Status& status,
+            ChannelArrayPtr const & channelArray,
+            PVArrayPtr const & pvArray) = 0;
+    virtual void getLengthDone(
+            const Status& status,
+            ChannelArrayPtr const & channelArray,
+            size_t length) = 0;
+    virtual void setLengthDone(
+            const Status& status,
+            ChannelArrayPtr const & channelArray) = 0;
+};
+
+where: +
+
channelArrayConnect
+
This is called as a result of calling Channel::createChannelArray. +
+ If status is OK, then array is the introspection interface + that 1) must be used for creating the putArray for ChannelArray::putArray, + and 2) will be the interface for the result passed to getArrayDone. +
+
putArrayDone
+
The result of calling ChannelArray::putArray. + status shows the result. +
+
getArrayDone
+
The result of calling ChannelArray::getArray. + status shows the result. +
+ If status is OK, pvArray has the result. +
+
getLengthDone
+
The result of calling ChannelArray::getLength. + status shows the result. +
+ If status is OK length is the length of the server array. +
+
setLengthDone
+
The result of calling ChannelArray::setLength. + status shows the result. +
+
+ +

Monitor

+

Described in pvDataCPP. +See:
+ +EPICS pvDataCPP + +

+

For convenience the classes are shown here.

+

class MonitorElement

+
+class MonitorElement {
+public:
+    MonitorElement(){}
+    MonitorElement(PVStructurePtr const & pvStructurePtr);
+    PVStructurePtr pvStructurePtr;
+    BitSetPtr changedBitSet;
+    BitSetPtr overrunBitSet;
+};
+
+

class Monitor

+
+class Monitor : public Destroyable{
+public:
+    virtual ~Monitor(){}
+    virtual Status start() = 0;
+    virtual Status stop() = 0;
+    virtual MonitorElementPtr poll() = 0;
+    virtual void release(MonitorElementPtr const & monitorElement) = 0;
+};
+
+

class MonitorRequester

+
+class MonitorRequester : public virtual Requester {
+public:
+    virtual ~MonitorRequester(){}
+    virtual void monitorConnect(Status const & status,
+        MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
+    virtual void monitorEvent(MonitorPtr const & monitor) = 0;
+    virtual void unlisten(MonitorPtr const & monitor) = 0;
+};
+
+

ChannelRPC

+

class ChannelRPC

+
+class ChannelRPC : public ChannelRequest {
+public:
+    virtual void request(PVStructurePtr const & pvArgument) = 0;
+};
+
+where: +
+
request
+
Issue a request to the server. +
+ pvArgument is sent to the server. + The server processes the request and returns the result by calling ChannelRPCRequester::requestDone. +
+
+

class ChannelRPCRequester

+
+class ChannelRPCRequester : virtual public Requester {
+public:
+    virtual void channelRPCConnect(
+            const Status& status,
+            ChannelRPCPtr const & channelRPC) = 0;
+
+    virtual void requestDone(
+            const Status& status,
+            ChannelRPCPtr const & channelRPC,
+            PVStructurePtr const & pvResponse) = 0;
+};
+
+where: +
+
channelRPCConnect
+
Called as a result of Channel::createChannelRPC. +
+ status shows the result. +
+
requestDone
+
Called as a result of ChannelRPC::request. +
+ status shows the result. +
+ If status is OK pvResponse is the result. +
+
+

RPC Server and Service

+

Matej please explain

+ + +
+ + diff --git a/src/client/pvAccess.h b/src/client/pvAccess.h index 4347566..17f4450 100644 --- a/src/client/pvAccess.h +++ b/src/client/pvAccess.h @@ -944,3 +944,10 @@ namespace pvAccess { }} #endif /* PVACCESS_H */ + +/** @page Overview Documentation + * + *pvAccessOverview.html + * + */ +