diff --git a/Makefile b/Makefile
index 71c65d9a..249e8b39 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,11 @@ pvtoolsSrc_DEPEND_DIRS = src src/ca
DIRS += testApp
testApp_DEPEND_DIRS = src
+
+DIRS += testCa
+testCa_DEPEND_DIRS = src src/ca
+
+
DIRS += examples
examples_DEPEND_DIRS += src src/ca
diff --git a/caProvider.md b/caProvider.md
new file mode 100644
index 00000000..6a479aac
--- /dev/null
+++ b/caProvider.md
@@ -0,0 +1,636 @@
+# pvAccessCPP: ca provider
+
+2018.07.09
+
+Editors:
+
+* Marty Kraimer
+
+This is a description of channel provider **ca** that is implemented as part of **pvAccessCPP**.
+
+It uses the **channel access** network protocol to communicate with a server,
+i. e. the network protocol that has been used to communicate with **EPICS IOCs** since 1990.
+
+Provider **pva** is another way to connect to a **DBRecord**,
+But this only works if the IOC has **qsrv** installed.
+**qsrv**, which is provided with
+[pva2pva](https://github.com/epics-base/pva2pva),
+has full support for communicating with a **DBRecord**.
+The only advantage of **ca** is that it does require any changes to an existing IOC.
+
+
+The following are discussed.
+
+* [Introduction](#S-introduction)
+* [client API](#S-client)
+* [Mapping DBD data to pvData](#S-dbd_to_pvdata)
+* [Developing plugins for ca provider.](#S-plugin)
+
+
+
+## Introduction
+
+The primary purpose of the **ca** provider is to access **DBRecord**s in an EPICS IOC via the
+**channel access** network protocol but to use pvData objects for the client.
+
+Each **DBRecord** instance has a record name that must be unique in the local area network.
+A client can access any public field of a **DBRecord**;
+Each **DBRecord** instance has a record name that is unique with in the local area network
+A channel name is a **recordname.fieldName**.
+If the fieldname is not specified then **.VAL** is assumed
+
+### example database
+
+The following:
+
+```
+mrk> pwd
+/home/epicsv4/masterCPP/pvAccessCPP/testCa
+mrk> softIoc -d testCaProvider.db
+```
+
+Starts an EPICS IOC that is used for all examples in this document.
+
+### examples
+
+```
+mrk> caget -d DBR_TIME_FLOAT DBRdoubleout
+DBRdoubleout
+ Native data type: DBF_DOUBLE
+ Request type: DBR_TIME_FLOAT
+ Element count: 1
+ Value: 1
+ Timestamp: 2018-06-21 06:23:07.939894
+ Status: NO_ALARM
+ Severity: NO_ALARM
+mrk> pvget -p ca -r "value,alarm,timeStamp" -i DBRdoubleout
+DBRdoubleout
+structure
+ double value 1
+ alarm_t alarm
+ int severity 0
+ int status 0
+ string message
+ time_t timeStamp
+ long secondsPastEpoch 1529576587
+ int nanoseconds 939894210
+ int userTag 0
+mrk> pvget -p ca -r "value,alarm,timeStamp" DBRdoubleout
+DBRdoubleout
+structure
+ double value 1
+ alarm_t alarm NO_ALARM NO_STATUS
+ time_t timeStamp 2018-06-21T06:23:07.940 0
+
+mrk> pvget -p ca -r value -i DBRdoubleout.SCAN
+DBRdoubleout.SCAN
+epics:nt/NTEnum:1.0
+ enum_t value
+ int index 0
+ string[] choices [Passive,Event,I/O Intr,10 second,5 second,2 second,1 second,.5 second,.2 second,.1 second]
+```
+
+### Overview of Channel Access
+
+**channel access**, which is provided with **epics-base**, defines and implements a protocol
+for client/server network communication.
+
+**epics-base** provides both a client and a server implementation
+This document only discusses the client API.
+
+For details see:
+
+[EPICS Channel Access 4.13.1 Reference Manual](https://epics.anl.gov/base/R7-0/1-docs/CAref.html)
+
+**channel access** allows a client to get, put, and monitor monitor data from a server.
+The data is defined by various DBD types.
+
+The following, in **epics-base/include**, are the
+main include files that show the **channel access** API:
+
+```
+cadef.h
+db_access.h
+```
+
+The client requests data via one of the DBR types.
+
+For example:
+
+```
+DBR_STS_DOUBLE returns a double status structure (dbr_sts_double)
+where
+struct dbr_sts_double{
+ dbr_short_t status; /* status of value */
+ dbr_short_t severity; /* severity of alarm */
+ dbr_long_t RISC_pad; /* RISC alignment */
+ dbr_double_t value; /* current value */
+};
+```
+
+The server converts data between the native type of the field being accessed and the DBR type.
+
+
+### Overview of ca provider
+
+**ca** is a pvAccess Channel Provider that uses **channel access** to connect a client to a server.
+
+With **ca**, the client data appears as pvData objects, i. e.
+**ca** converts the data provided by **channel access** to/from pvData
+
+Thus a pvAccess client can communicate with an existing V3 EPICS IOC without making
+any changes to existing IOCs.
+
+For an overview of pvData and pvAccess see:
+
+[EPICS V4 Developer's Guide](https://mrkraimer.github.io/website/developerGuide/developerGuide.html)
+
+**ca** requests data from the server with a DBR type that matches the native type.
+See the next section for more details.
+
+All conversion to/from other types must be done by the client.
+
+## Client API
+
+**ca** implements the following pvAccess methods : **getField**, **channelGet**, **channelPut** and **monitor**.
+
+For channelPut the only field that can be accessed is **value**.
+For channelPut a client can issue puts with and without a callback from the server.
+The default is no callback. If createChannelPut has the option "record[block=true]" then a put callback used.
+
+All of the other pvAccess methods provide access to fields **alarm** and **timeStamp**.
+
+Depending on the type associated with the **value** field the following fields may also be available:
+**display**, **control** , and **valueAlarm**.
+
+Thus a client can make requests like:
+
+```
+pvget -p ca -r "value,alarm,timeStamp,display,control,valueAlarm" names ...
+```
+
+**ca** will create a structure that has the fields requested but only for fields that are supported
+by the server.
+
+* For puts only value is supported.
+* For gets and monitors every channel supports value, alarm, and timeStamp;
+* If any of display,control, or valueAlarm are requested then timeStamp is NOT available.
+
+Lets discuss the various fields.
+
+### value
+
+This can be a scalar, scalarArray, or an enumerated structure.
+
+For a scalar or scalarArray the ScalarType is one of the following:
+**pvString**, **pvByte**, **pvShort**, **pvInt**, **pvFloat**, or **pvDouble**.
+
+Note that **channel access** does not support unsigned integers or 64 bit integers.
+
+A enumerated structure is created if the native type is **DBR_ENUM**.
+
+Some examples are:
+
+```
+pvget -p ca -r value -i DBRlongout
+DBRlongout
+structure
+ int value 0
+mrk> pvget -p ca -r value -i DBRdoubleout
+DBRdoubleout
+structure
+ double value 0
+mrk> pvget -p ca -r value -i DBRshortArray
+DBRshortArray
+structure
+ short[] value []
+mrk> pvget -p ca -r value -i DBRstringArray
+DBRstringArray
+structure
+ string[] value [aa,bb,cc]
+mrk> pvget -p ca -r value -i DBRmbbin
+DBRmbbin
+epics:nt/NTEnum:1.0
+ enum_t value
+ int index 1
+ string[] choices [zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen]
+mrk>
+
+```
+
+
+### alarm,timeStamp,display,control, and valueAlarm
+
+Each of these is one of the property structures defined in pvData.
+
+#### Examples
+
+```
+mrk> pvget -p ca -r alarm -i DBRdoubleout
+DBRdoubleout
+structure
+ alarm_t alarm
+ int severity 2
+ int status 3
+ string message HIHI
+
+mrk> pvget -p ca -r timeStamp -i DBRdoubleout
+DBRdoubleout
+structure
+ time_t timeStamp
+ long secondsPastEpoch 1529923341
+ int nanoseconds 314916189
+ int userTag 0
+mrk> pvget -p ca -r display -i DBRdoubleout
+DBRdoubleout
+structure
+ display_t display
+ double limitLow -10
+ double limitHigh 10
+ string description
+ string format F8.2
+ string units volts
+mrk> pvget -p ca -r control -i DBRdoubleout
+DBRdoubleout
+structure
+ control_t control
+ double limitLow -1e+29
+ double limitHigh 1e+29
+ double minStep 0
+mrk> pvget -p ca -r valueAlarm -i DBRdoubleout
+DBRdoubleout
+structure
+ valueAlarm_t valueAlarm
+ boolean active false
+ double lowAlarmLimit -8
+ double lowWarningLimit -6
+ double highWarningLimit 6
+ double highAlarmLimit 8
+ int lowAlarmSeverity 0
+ int lowWarningSeverity 0
+ int highWarningSeverity 0
+ int highAlarmSeverity 0
+```
+
+
+
+## DBD to pvData
+
+### Type Conversion
+
+Three type systems are involved in accessing data in a **DBRecord** and converting it to/from pvData:
+
+* DBF The type system used for **DBRecord**s.
+* DBR The type system used by **channel access**.
+* pvData
+
+The following gives a summary of the conversions between the type systems:
+
+```
+rawtype DBF DBR pvData ScalarType
+
+char[MAX_STRING_SIZE] DBF_STRING DBR_STRING pvString
+epicsInt8 DBF_CHAR DBR_CHAR pvByte
+epicsUint8 DBF_UCHAR DBR_CHAR pvByte
+epicsInt16 DBF_SHORT DBR_SHORT pvShort
+epicsUInt16 DBF_USHORT DBR_LONG pvInt
+epicsInt32 DBF_LONG DBR_LONG pvInt
+epicsUInt32 DBF_ULONG DBR_DOUBLE pvDouble
+epicsInt64 DBF_INT64 no support
+epicsUInt64 DBF_UINT64 no support
+float DBF_FLOAT DBR_FLOAT pvFloat
+double DBF_DOUBLE DBR_DOUBLE pvDouble
+epicsUInt16 DBF_ENUM DBR_ENUM enum structure
+epicsUInt16 DBF_MENU DBR_ENUM enum structure
+```
+
+Notes:
+
+* Both DBF_CHAR and DBF_UCHAR go to DBR_CHAR. This is ambigous.
+* DBF_USHORT promoted to DBR_LONG
+* DBF_ULONG promoted to DBR_DOUBLE
+* qsrv provides full access to all DBF types, but the IOC must have qsrv installed.
+
+### Accessing data in a DBRecord
+
+An IOC database is a memory resident database of **DBRecord** instances.
+
+Each **DBRecord** is an instance of one of an extensible set of record types.
+Each record type has an associated dbd definition which defines a set of fields for
+each record instance.
+
+For example an aoRecord.dbd has the definition:
+
+```
+recordtype(ao) {
+ include "dbCommon.dbd"
+ field(VAL,DBF_DOUBLE) {
+ ...
+ }
+ field(OVAL,DBF_DOUBLE) {
+ ...
+ }
+ ... many more fields
+```
+
+In addition each record type has a associated set of support code defined in recSup.h
+
+```
+/* record support entry table */
+struct typed_rset {
+ long number; /* number of support routines */
+ long (*report)(void *precord);
+ long (*init)();
+ long (*init_record)(struct dbCommon *precord, int pass);
+ long (*process)(struct dbCommon *precord);
+ long (*special)(struct dbAddr *paddr, int after);
+ long (*get_value)(void); /* DEPRECATED set to NULL */
+ long (*cvt_dbaddr)(struct dbAddr *paddr);
+ long (*get_array_info)(struct dbAddr *paddr, long *no_elements, long *offset);
+ long (*put_array_info)(struct dbAddr *paddr, long nNew);
+ long (*get_units)(struct dbAddr *paddr, char *units);
+ long (*get_precision)(const struct dbAddr *paddr, long *precision);
+ long (*get_enum_str)(const struct dbAddr *paddr, char *pbuffer);
+ long (*get_enum_strs)(const struct dbAddr *paddr, struct dbr_enumStrs *p);
+ long (*put_enum_str)(const struct dbAddr *paddr, const char *pbuffer);
+ long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p);
+ long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p);
+ long (*get_alarm_double)(struct dbAddr *paddr, struct dbr_alDouble *p);
+};
+```
+
+The methods that support accessing data from the record include:
+
+```
+cvt_dbaddr Implemented by record types that determine VAL type at record initialization
+*array_info Implemented by array record types
+get_units Implemented by numeric record types
+get_precision Implemented by float and double record types
+*_enum_* Implemented by enumerated record types
+get_graphic_double NOTE Always returns limits as double
+get_control_double NOTE Always returns limits as double
+get_alarm_double NOTE Always returns limits as double
+```
+
+Each of these methods is optional, i. e. record support for a particular record type
+only implements methods that make sense for the record type.
+
+For example the enum methods are only implemented by records that have the definition:
+
+```
+...
+ field(VAL,DBF_ENUM) {
+...
+}
+...
+```
+
+
+### Channel Access Data
+
+A client can access any public field of a **DBRecord**;
+Each **DBRecord** instance has a record name that is unique within the local area network.
+
+A channel name is a **recordname.fieldName**.
+
+If the fieldname is not specified then **.VAL** is assumed and the record support methods shown
+above can also be used to get additional data from the record.
+
+Any field that is accessable by client code must have a vald DBF_ type.
+
+A client gets/puts data via a **DBR_*** request.
+
+The basic DBR types are:
+```
+rawtype DBR
+
+char[MAX_STRING_SIZE] DBR_STRING
+epicsInt8 DBR_CHAR
+epicsInt16 DBR_SHORT
+epicsInt32 DBR_LONG
+float DBF_FLOAT
+double DBF_DOUBLE
+epicsUInt16 DBR_ENUM
+```
+
+In addition to the DBR basic types the following DBR types provide additional data:
+
+```
+DBR one of the types above.
+DBR_STATUS_* adds status and severity to DBR.
+DBR_TIME_* adds epicsTimeStamp to DBR_STATUS.
+DBR_GR_* adds display limits to DBR_STATUS. NOTE: no epicsTimeStamp
+DBR_CTRL_ adds control limits to DBR_GR. NOTE: no epicsTimeStamp
+DBR_CTRL_ENUM This is a special case.
+```
+
+NOTES:
+
+* status, severity, and epicsTimeStamp are the same for each DBR type.
+* limits have the same types as the correspondng DBR type.
+* server converts limits from double to the DBR type.
+* GR and CTRL have precision only for DBR_FLOAT and DBR_DOUBLE
+
+
+Some examples:
+
+```
+DBR_STS_DOUBLE returns a double status structure (dbr_sts_double)
+where
+struct dbr_sts_double{
+ dbr_short_t status; /* status of value */
+ dbr_short_t severity; /* severity of alarm */
+ dbr_long_t RISC_pad; /* RISC alignment */
+ dbr_double_t value; /* current value */
+};
+
+DBR_TIME_DOUBLE returns a double time structure (dbr_time_double)
+where
+struct dbr_time_double{
+ dbr_short_t status; /* status of value */
+ dbr_short_t severity; /* severity of alarm */
+ epicsTimeStamp stamp; /* time stamp */
+ dbr_long_t RISC_pad; /* RISC alignment */
+ dbr_double_t value; /* current value */
+};
+
+DBR_GR_SHORT returns a graphic short structure (dbr_gr_short)
+where
+struct dbr_gr_short{
+ dbr_short_t status; /* status of value */
+ dbr_short_t severity; /* severity of alarm */
+ char units[MAX_UNITS_SIZE]; /* units of value */
+ dbr_short_t upper_disp_limit; /* upper limit of graph */
+ dbr_short_t lower_disp_limit; /* lower limit of graph */
+ dbr_short_t upper_alarm_limit;
+ dbr_short_t upper_warning_limit;
+ dbr_short_t lower_warning_limit;
+ dbr_short_t lower_alarm_limit;
+ dbr_short_t value; /* current value */
+};
+
+DBR_GR_DOUBLE returns a graphic double structure (dbr_gr_double)
+where
+struct dbr_gr_double{
+ dbr_short_t status; /* status of value */
+ dbr_short_t severity; /* severity of alarm */
+ dbr_short_t precision; /* number of decimal places */
+ dbr_short_t RISC_pad0; /* RISC alignment */
+ char units[MAX_UNITS_SIZE]; /* units of value */
+ dbr_double_t upper_disp_limit; /* upper limit of graph */
+ dbr_double_t lower_disp_limit; /* lower limit of graph */
+ dbr_double_t upper_alarm_limit;
+ dbr_double_t upper_warning_limit;
+ dbr_double_t lower_warning_limit;
+ dbr_double_t lower_alarm_limit;
+ dbr_double_t value; /* current value */
+};
+
+DBR_CTRL_DOUBLE returns a control double structure (dbr_ctrl_double)
+where
+struct dbr_ctrl_double{
+ dbr_short_t status; /* status of value */
+ dbr_short_t severity; /* severity of alarm */
+ dbr_short_t precision; /* number of decimal places */
+ dbr_short_t RISC_pad0; /* RISC alignment */
+ char units[MAX_UNITS_SIZE]; /* units of value */
+ dbr_double_t upper_disp_limit; /* upper limit of graph */
+ dbr_double_t lower_disp_limit; /* lower limit of graph */
+ dbr_double_t upper_alarm_limit;
+ dbr_double_t upper_warning_limit;
+ dbr_double_t lower_warning_limit;
+ dbr_double_t lower_alarm_limit;
+ dbr_double_t upper_ctrl_limit; /* upper control limit */
+ dbr_double_t lower_ctrl_limit; /* lower control limit */
+ dbr_double_t value; /* current value */
+};
+
+
+DBR_CTRL_ENUM returns a control enum structure (dbr_ctrl_enum)
+where
+struct dbr_ctrl_enum{
+ dbr_short_t status; /* status of value */
+ dbr_short_t severity; /* severity of alarm */
+ dbr_short_t no_str; /* number of strings */
+ char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
+ /* state strings */
+ dbr_enum_t value; /* current value */
+};
+```
+
+### PVData for a DBRrecord via ca provider
+
+**pvAccessCPP/src/ca** has files **dbdToPv.h** and **dbdToPv.cpp**.
+This is the code that converts between DBD data and pvData.
+
+This code must decide which of the many **DBR_*** types to use.
+
+
+There is a static method:
+
+```
+static DbdToPvPtr create(
+ CAChannelPtr const & caChannel,
+ epics::pvData::PVStructurePtr const & pvRequest,
+ IOType ioType); // one of getIO, putIO, and monitorIO
+```
+
+
+When this is called the first thing is to determine which fields are requested by the client.
+This is from the set **value**, **alarm**, **timeStamp**. **display**, **control** , and **valueAlarm**.
+
+
+* If the ioType is putIO only **value** is valid.
+* If the channel type is **DBR_ENUM** then **display**, **control** , and **valueAlarm** are ignored.
+* If the channel is an array then **control** , and **valueAlarm** are ignored.
+* If the channel type is **DBR_STRING** then **display**, **control** , and **valueAlarm** are ignored.
+* If any of **display**, **control** , and **valueAlarm** are still allowed then **timeStamp** is ignored,
+because the DBR type selected will not return the timeStamp.
+
+If ths channel type is **DBR_ENUM** a one time **ca_array_get_callback(DBR_GR_ENUM...** request is issued
+to get the choices for the enumerated value.
+
+Depending or which fields are still valid, the DBR type is obtained via
+
+* If any of **display**, **control** ,or **valueAlarm** is valid then **dbf_type_to_DBR_CTRL(caValueType)** .
+* else If **alarm** or **timeStamp** is valid then **dbf_type_to_DBR_TIME(caValueType)** .
+* else **dbf_type_to_DBR(caValueType)**
+
+Where **caValueType** is one of DBR_STRING, DBR_SHORT, DBR_FLOAT, DBR_ENUM, DBR_CHAR, DBR_LONG, DBR_DOUBLE.
+
+If **display** is still valid then the following call is made:
+
+```
+string name(caChannel->getChannelName() + ".DESC");
+int result = ca_create_channel(name.c_str(),
+...
+```
+When the channel connects a get is issued to get the value for **display.description**.
+
+## Developing plugins for ca provider
+
+This section provides guidelines for code developers that use **ca** to connect a client to a server.
+This includes plugins for things like MEDM, EDM, caqtDM, etc.
+But also means any code that use **ca**: pvget, pvput, pvaClientCPP, exampleCPP/exampleClient, etc.
+
+The **channel access** reference manual describes channel context:
+
+[CA Client Contexts and Application Specific Auxiliary Threads](https://epics.anl.gov/base/R7-0/1-docs/CAref.html#Client2)
+
+A brief summary of channel context is:
+
+
+* Only the thread that calls CAClientFactory::start() and associated auxillary threads
+can call **ca_xxx** functions.
+
+The public access to **ca** is:
+
+```
+class epicsShareClass CAClientFactory
+{
+public:
+ /** @brief start provider ca
+ *
+ */
+ static void start();
+ /** @brief get the ca_client_context
+ *
+ * This can be called by an application specific auxiliary thread.
+ * See ca documentation. Not for casual use.
+ */
+ static ca_client_context * get_ca_client_context();
+ /** @brief stop provider ca
+ *
+ * This does nothing since epicsAtExit is used to destroy the instance.
+ */
+ static void stop();
+};
+```
+Any code that uses **ca** must call **CAClientFactory::start()** before making any pvAccess client requests.
+
+ca_context_create is called for the thread that calls CAClientFactory::start().
+
+If the client creates auxillary threads the make pvAccess client requests then the auxillary threads will automatically become
+a **ca** auxilary thread.
+
+
+[Deadlock in ca_clear_subscription()](https://bugs.launchpad.net/epics-base/7.0/+bug/1751380)
+
+Shows a problem with monitor callbacks.
+A test was created that shows that the same problem can occur with a combination of rapid get, put and monitor events.
+
+
+In order to prevent this problem **ca** creates the following threads:
+**getEventThread**, **putEventThread**, and **monitorEventThread**.
+
+All client callbacks are made via one of these threads.
+For example a call to the requester's **monitorEvent** method is made from the monitorEventThread.
+
+**Notes**
+
+* These threads do not call **ca_attach_context**.
+* No **ca_xxx** function should be called from the requester's callback method.
+
+
+
+
diff --git a/src/ca/Makefile b/src/ca/Makefile
index bc376f0c..93e6b27d 100644
--- a/src/ca/Makefile
+++ b/src/ca/Makefile
@@ -2,8 +2,7 @@ TOP = ../..
include $(TOP)/configure/CONFIG
LIBRARY += pvAccessCA
-pvAccessCA_LIBS += ca pvAccess pvData
-LIB_LIBS += Com
+pvAccessCA_LIBS += pvAccess pvData ca Com
SHRLIB_VERSION ?= $(EPICS_PVA_MAJOR_VERSION).$(EPICS_PVA_MINOR_VERSION).$(EPICS_PVA_MAINTENANCE_VERSION)
@@ -11,10 +10,12 @@ SHRLIB_VERSION ?= $(EPICS_PVA_MAJOR_VERSION).$(EPICS_PVA_MINOR_VERSION).$(EPICS_
LIB_SYS_LIBS_WIN32 += ws2_32
INC += pv/caProvider.h
-INC += pv/caStatus.h
+pvAccessCA_SRCS += monitorEventThread.cpp
+pvAccessCA_SRCS += getDoneThread.cpp
+pvAccessCA_SRCS += putDoneThread.cpp
pvAccessCA_SRCS += caProvider.cpp
pvAccessCA_SRCS += caChannel.cpp
-pvAccessCA_SRCS += caStatus.cpp
+pvAccessCA_SRCS += dbdToPv.cpp
include $(TOP)/configure/RULES
diff --git a/src/ca/caChannel.cpp b/src/ca/caChannel.cpp
index a6c25411..b19349b1 100644
--- a/src/ca/caChannel.cpp
+++ b/src/ca/caChannel.cpp
@@ -10,11 +10,12 @@
#include
#include
#include
-#include
+#include "monitorEventThread.h"
+#include "getDoneThread.h"
+#include "putDoneThread.h"
#define epicsExportSharedSymbols
#include "caChannel.h"
-#include
using namespace epics::pvData;
using std::string;
@@ -39,10 +40,10 @@ CAChannel::shared_pointer CAChannel::create(CAChannelProvider::shared_pointer co
if(DEBUG_LEVEL>0) {
cout<< "CAChannel::create " << channelName << endl;
}
- CAChannelPtr thisPtr(
+ CAChannelPtr caChannel(
new CAChannel(channelName, channelProvider, channelRequester));
- thisPtr->activate(priority);
- return thisPtr;
+ caChannel->activate(priority);
+ return caChannel;
}
static void ca_connection_handler(struct connection_handler_args args)
@@ -56,248 +57,11 @@ static void ca_connection_handler(struct connection_handler_args args)
}
}
-
-static ScalarType dbr2ST[] =
-{
- pvString, // DBR_STRING = 0
- pvShort, // DBR_SHORT. DBR_INT = 1
- pvFloat, // DBR_FLOAT = 2
- static_cast(-1), // DBR_ENUM = 3
- pvByte, // DBR_CHAR = 4
- pvInt, // DBR_LONG = 5
- pvDouble // DBR_DOUBLE = 6
-};
-
-static Structure::const_shared_pointer createStructure(CAChannel::shared_pointer const & channel, string const & properties)
-{
- StandardFieldPtr standardField = getStandardField();
- Structure::const_shared_pointer structure;
-
- chtype channelType = channel->getNativeType();
- if (channelType != DBR_ENUM)
- {
- ScalarType st = dbr2ST[channelType];
- structure = (channel->getElementCount() > 1) ?
- standardField->scalarArray(st, properties) :
- standardField->scalar(st, properties);
- }
- else
- {
- // NOTE: enum arrays not supported
- structure = standardField->enumerated(properties);
- }
-
- return structure;
-}
-
-static void ca_get_labels_handler(struct event_handler_args args)
-{
-
- if (args.status == ECA_NORMAL)
- {
- const dbr_gr_enum* dbr_enum_p = static_cast(args.dbr);
-
- PVStringArray* labelsArray = static_cast(args.usr);
- if (labelsArray)
- {
- PVStringArray::svector labels(labelsArray->reuse());
- labels.resize(dbr_enum_p->no_str);
- std::copy(dbr_enum_p->strs, dbr_enum_p->strs + dbr_enum_p->no_str, labels.begin());
- labelsArray->replace(freeze(labels));
- }
- }
- else
- {
- string mess("ca_get_labels_handler ");
- mess += ca_message(args.status);
- throw std::runtime_error(mess);
- }
-}
-
-// Filter out unrequested fields from a source structure according to a
-// structure conforming to the format of the "field" field of a pvRequest,
-// preserving type ids of unchanged structures. If ntTop is true also preserve
-// type id if none of the deleted top-level subfields are the value field.
-static StructureConstPtr refineStructure(StructureConstPtr const & source,
- StructureConstPtr const & requestedFields, bool ntTop)
-{
- if (requestedFields.get() == NULL || requestedFields->getNumberFields() == 0)
- return source;
-
- FieldBuilderPtr builder = getFieldCreate()->createFieldBuilder();
- bool addId = true;
-
- FieldConstPtrArray fields = source->getFields();
- StringArray names = source->getFieldNames();
- size_t i = 0;
- for (FieldConstPtrArray::const_iterator it = fields.begin(); it != fields.end(); ++it)
- {
- FieldConstPtr field = *it;
- const std::string & name = names[i++];
- FieldConstPtr reqField = requestedFields->getField(name);
- if (reqField.get())
- {
- if (field->getType() != structure || (reqField->getType() != structure))
- builder->add(name,field);
- else
- {
- StructureConstPtr substruct =
- std::tr1::dynamic_pointer_cast(field);
-
- StructureConstPtr reqSubstruct =
- std::tr1::dynamic_pointer_cast(reqField);
-
- StructureConstPtr nested = refineStructure(substruct, reqSubstruct, false);
- builder->add(name,nested);
- if (nested->getID() != substruct->getID())
- addId = false;
- }
- }
- else if (!ntTop || name == "value")
- addId = false;
- }
- if (addId)
- builder->setId(source->getID());
- return builder->createStructure();
-}
-
-static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer const & channel, string const & properties, PVStructurePtr pvRequest)
-{
- StructureConstPtr unrefinedStructure = createStructure(channel, properties);
-
- PVStructurePtr fieldPVStructure = pvRequest->getSubField("field");
- StructureConstPtr finalStructure = fieldPVStructure.get() ?
- refineStructure(unrefinedStructure, fieldPVStructure->getStructure(),true) :
- unrefinedStructure;
-
- PVStructure::shared_pointer pvStructure = getPVDataCreate()->createPVStructure(finalStructure);
- if (channel->getNativeType() == DBR_ENUM)
- {
- PVScalarArrayPtr pvScalarArray = pvStructure->getSubField("value.choices");
-
- // TODO avoid getting labels if DBR_GR_ENUM or DBR_CTRL_ENUM is used in subsequent get
- int result = ca_array_get_callback(
- DBR_GR_ENUM, 1, channel->getChannelID(), ca_get_labels_handler, pvScalarArray.get());
- if (result == ECA_NORMAL)
- {
- result = ca_flush_io();
- // NOTE: we do not wait here, since all subsequent request (over TCP) is serialized
- // and will guarantee that ca_get_labels_handler is called first
- }
- if (result != ECA_NORMAL){
- string mess(channel->getChannelName() + "PVStructure::shared_pointer createPVStructure ");
- mess += "failed to get labels for enum ";
- throw std::runtime_error(mess);
- }
- }
- return pvStructure;
-}
-
-static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer const & channel, chtype dbrType, PVStructurePtr pvRequest)
-{
- // Match to closest DBR type
- // NOTE: value is always there
- string properties;
- bool isArray = channel->getElementCount() > 1;
- if (dbrType >= DBR_CTRL_STRING) // 28
- {
- if (dbrType != DBR_CTRL_STRING && dbrType != DBR_CTRL_ENUM)
- {
- if (isArray)
- properties = "value,alarm,display";
- else
- properties = "value,alarm,display,valueAlarm,control";
- }
- else
- properties = "value,alarm";
- }
- else if (dbrType >= DBR_GR_STRING) // 21
- {
- if (dbrType != DBR_GR_STRING && dbrType != DBR_GR_ENUM)
- {
- if (isArray)
- properties = "value,alarm,display";
- else
- properties = "value,alarm,display,valueAlarm";
- }
- else
- properties = "value,alarm";
- }
- else if (dbrType >= DBR_TIME_STRING) // 14
- properties = "value,alarm,timeStamp";
- else if (dbrType >= DBR_STS_STRING) // 7
- properties = "value,alarm";
- else
- properties = "value";
-
- return createPVStructure(channel, properties, pvRequest);
-}
-
-
void CAChannel::connected()
{
if(DEBUG_LEVEL>0) {
cout<< "CAChannel::connected " << channelName << endl;
}
- std::queue putQ;
- std::queue getQ;
- std::queue monitorQ;
- {
- Lock lock(requestsMutex);
- // we assume array if element count > 1
- elementCount = ca_element_count(channelID);
- channelType = ca_field_type(channelID);
- bool isArray = elementCount > 1;
-
- // no valueAlarm and control,display for non-numeric type
- // no control,display for numeric arrays
- string allProperties =
- (channelType != DBR_STRING && channelType != DBR_ENUM) ?
- isArray ?
- "value,timeStamp,alarm,display" :
- "value,timeStamp,alarm,display,valueAlarm,control" :
- "value,timeStamp,alarm";
- Structure::const_shared_pointer structure = createStructure(
- shared_from_this(), allProperties);
-
- // TODO we need only Structure here
- this->structure = structure;
-
- std::vector::const_iterator getiter;
- for (getiter = getList.begin(); getiter != getList.end(); ++getiter) {
- CAChannelGetPtr temp = (*getiter).lock();
- if(!temp) continue;
- getQ.push(temp);
- }
- std::vector::const_iterator putiter;
- for (putiter = putList.begin(); putiter != putList.end(); ++putiter) {
- CAChannelPutPtr temp = (*putiter).lock();
- if(!temp) continue;
- putQ.push(temp);
- }
- std::vector::const_iterator monitoriter;
- for (monitoriter = monitorList.begin(); monitoriter != monitorList.end(); ++monitoriter) {
- CAChannelMonitorPtr temp = (*monitoriter).lock();
- if(!temp) continue;
- monitorQ.push(temp);
- }
- }
- while(!putQ.empty()) {
- putQ.front()->channelCreated(Status::Ok,shared_from_this());
- putQ.pop();
- }
- while(!getQ.empty()) {
- getQ.front()->channelCreated(Status::Ok,shared_from_this());
- getQ.pop();
- }
- while(!monitorQ.empty()) {
- monitorQ.front()->channelCreated(Status::Ok,shared_from_this());
- monitorQ.pop();
- }
- while(!getFieldQueue.empty()) {
- getFieldQueue.front()->callRequester(shared_from_this());
- getFieldQueue.pop();
- }
while(!putQueue.empty()) {
putQueue.front()->activate();
putQueue.pop();
@@ -307,7 +71,9 @@ void CAChannel::connected()
getQueue.pop();
}
while(!monitorQueue.empty()) {
- monitorQueue.front()->activate();
+ CAChannelMonitorPtr monitor(monitorQueue.front());
+ monitor->activate();
+ addMonitor(monitor);
monitorQueue.pop();
}
ChannelRequester::shared_pointer req(channelRequester.lock());
@@ -322,42 +88,7 @@ void CAChannel::disconnected()
if(DEBUG_LEVEL>0) {
cout<< "CAChannel::disconnected " << channelName << endl;
}
- std::queue putQ;
- std::queue getQ;
- std::queue monitorQ;
- {
- Lock lock(requestsMutex);
- std::vector::const_iterator getiter;
- for (getiter = getList.begin(); getiter != getList.end(); ++getiter) {
- CAChannelGetPtr temp = (*getiter).lock();
- if(!temp) continue;
- getQ.push(temp);
- }
- std::vector::const_iterator putiter;
- for (putiter = putList.begin(); putiter != putList.end(); ++putiter) {
- CAChannelPutPtr temp = (*putiter).lock();
- if(!temp) continue;
- putQ.push(temp);
- }
- std::vector::const_iterator monitoriter;
- for (monitoriter = monitorList.begin(); monitoriter != monitorList.end(); ++monitoriter) {
- CAChannelMonitorPtr temp = (*monitoriter).lock();
- if(!temp) continue;
- monitorQ.push(temp);
- }
- }
- while(!putQ.empty()) {
- putQ.front()->channelDisconnect(false);
- putQ.pop();
- }
- while(!getQ.empty()) {
- getQ.front()->channelDisconnect(false);
- getQ.pop();
- }
- while(!monitorQ.empty()) {
- monitorQ.front()->channelDisconnect(false);
- monitorQ.pop();
- }
+
ChannelRequester::shared_pointer req(channelRequester.lock());
if(req) {
EXCEPTION_GUARD(req->channelStateChange(
@@ -365,17 +96,13 @@ void CAChannel::disconnected()
}
}
-size_t CAChannel::num_instances;
-
-CAChannel::CAChannel(std::string const & _channelName,
- CAChannelProvider::shared_pointer const & _channelProvider,
- ChannelRequester::shared_pointer const & _channelRequester) :
- channelName(_channelName),
- channelProvider(_channelProvider),
- channelRequester(_channelRequester),
+CAChannel::CAChannel(std::string const & channelName,
+ CAChannelProvider::shared_pointer const & channelProvider,
+ ChannelRequester::shared_pointer const & channelRequester) :
+ channelName(channelName),
+ channelProvider(channelProvider),
+ channelRequester(channelRequester),
channelID(0),
- channelType(0),
- elementCount(0),
channelCreated(false)
{
if(DEBUG_LEVEL>0) {
@@ -411,7 +138,13 @@ void CAChannel::activate(short priority)
CAChannel::~CAChannel()
{
if(DEBUG_LEVEL>0) {
- cout << "CAChannel::~CAChannel() " << channelName << endl;
+ cout << "CAChannel::~CAChannel() " << channelName
+ << " channelCreated " << (channelCreated ? "true" : "false")
+ << endl;
+ }
+ {
+ Lock lock(requestsMutex);
+ if(!channelCreated) return;
}
disconnectChannel();
}
@@ -429,8 +162,19 @@ void CAChannel::disconnectChannel()
if(!channelCreated) return;
channelCreated = false;
}
+ std::vector::iterator it;
+ for(it = monitorlist.begin(); it!=monitorlist.end(); ++it)
+ {
+ CAChannelMonitorPtr mon = (*it).lock();
+ if(!mon) continue;
+ mon->stop();
+ }
+ monitorlist.resize(0);
/* Clear CA Channel */
- attachContext();
+ CAChannelProviderPtr provider(channelProvider.lock());
+ if(provider) {
+ std::tr1::static_pointer_cast(provider)->attachContext();
+ }
int result = ca_clear_channel(channelID);
if (result == ECA_NORMAL) return;
string mess("CAChannel::disconnectChannel() ");
@@ -438,77 +182,11 @@ void CAChannel::disconnectChannel()
cerr << mess << endl;
}
-
-
-void CAChannel::addChannelGet(const CAChannelGetPtr & get)
-{
- if(DEBUG_LEVEL>0) {
- cout<< "CAChannel::addChannelGet " << channelName << endl;
- }
- Lock lock(requestsMutex);
- for(size_t i=0; i< getList.size(); ++i) {
- if(!(getList[i].lock())) {
- getList[i] = get;
- return;
- }
- }
- getList.push_back(get);
-}
-
-void CAChannel::addChannelPut(const CAChannelPutPtr & put)
-{
- if(DEBUG_LEVEL>0) {
- cout<< "CAChannel::addChannelPut " << channelName << endl;
- }
- Lock lock(requestsMutex);
- for(size_t i=0; i< putList.size(); ++i) {
- if(!(putList[i].lock())) {
- putList[i] = put;
- return;
- }
- }
- putList.push_back(put);
-}
-
-
-void CAChannel::addChannelMonitor(const CAChannelMonitorPtr & monitor)
-{
- if(DEBUG_LEVEL>0) {
- cout<< "CAChannel::addChannelMonitor " << channelName << endl;
- }
- Lock lock(requestsMutex);
- for(size_t i=0; i< monitorList.size(); ++i) {
- if(!(monitorList[i].lock())) {
- monitorList[i] = monitor;
- return;
- }
- }
- monitorList.push_back(monitor);
-}
-
chid CAChannel::getChannelID()
{
return channelID;
}
-
-chtype CAChannel::getNativeType()
-{
- return channelType;
-}
-
-
-unsigned CAChannel::getElementCount()
-{
- return elementCount;
-}
-
-Structure::const_shared_pointer CAChannel::getStructure()
-{
- return structure;
-}
-
-
std::tr1::shared_ptr CAChannel::getProvider()
{
return channelProvider.lock();
@@ -564,7 +242,7 @@ void CAChannel::getField(GetFieldRequester::shared_pointer const & requester,
}
-AccessRights CAChannel::getAccessRights(epics::pvData::PVField::shared_pointer const & /*pvField*/)
+AccessRights CAChannel::getAccessRights(PVField::shared_pointer const & /*pvField*/)
{
if (ca_write_access(channelID))
return readWrite;
@@ -577,7 +255,7 @@ AccessRights CAChannel::getAccessRights(epics::pvData::PVField::shared_pointer c
ChannelGet::shared_pointer CAChannel::createChannelGet(
ChannelGetRequester::shared_pointer const & channelGetRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
+ PVStructure::shared_pointer const & pvRequest)
{
if(DEBUG_LEVEL>0) {
cout << "CAChannel::createChannelGet " << channelName << endl;
@@ -598,7 +276,7 @@ ChannelGet::shared_pointer CAChannel::createChannelGet(
ChannelPut::shared_pointer CAChannel::createChannelPut(
ChannelPutRequester::shared_pointer const & channelPutRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
+ PVStructure::shared_pointer const & pvRequest)
{
if(DEBUG_LEVEL>0) {
cout << "CAChannel::createChannelPut " << channelName << endl;
@@ -619,7 +297,7 @@ ChannelPut::shared_pointer CAChannel::createChannelPut(
Monitor::shared_pointer CAChannel::createMonitor(
MonitorRequester::shared_pointer const & monitorRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
+ PVStructure::shared_pointer const & pvRequest)
{
if(DEBUG_LEVEL>0) {
cout << "CAChannel::createMonitor " << channelName << endl;
@@ -634,9 +312,22 @@ Monitor::shared_pointer CAChannel::createMonitor(
}
}
channelMonitor->activate();
+ addMonitor(channelMonitor);
return channelMonitor;
}
+void CAChannel::addMonitor(CAChannelMonitorPtr const & monitor)
+{
+ std::vector::iterator it;
+ for(it = monitorlist.begin(); it!=monitorlist.end(); ++it)
+ {
+ CAChannelMonitorWPtr mon = *it;
+ if(mon.lock()) continue;
+ mon = monitor;
+ return;
+ }
+ monitorlist.push_back(monitor);
+}
void CAChannel::printInfo(std::ostream& out)
{
@@ -676,7 +367,10 @@ void CAChannelGetField::callRequester(CAChannelPtr const & caChannel)
}
GetFieldRequester::shared_pointer requester(getFieldRequester.lock());
if(!requester) return;
- epics::pvData::Structure::const_shared_pointer structure(caChannel->getStructure());
+ PVStructurePtr pvRequest(createRequest(""));
+ DbdToPvPtr dbdToPv = DbdToPv::create(caChannel,pvRequest,getIO);
+ PVStructurePtr pvStructure = dbdToPv->createPVStructure();
+ Structure::const_shared_pointer structure(pvStructure->getStructure());
Field::const_shared_pointer field =
subField.empty() ?
std::tr1::static_pointer_cast(structure) :
@@ -700,67 +394,34 @@ void CAChannel::attachContext()
CAChannelProviderPtr provider(channelProvider.lock());
if(provider) {
std::tr1::static_pointer_cast(provider)->attachContext();
+ return;
}
+ string mess("CAChannel::attachContext provider does not exist ");
+ mess += getChannelName();
+ throw std::runtime_error(mess);
}
-static chtype getDBRType(PVStructure::shared_pointer const & pvRequest, chtype nativeType)
-{
- // get "field" sub-structure
- PVStructure::shared_pointer fieldSubField =
- std::tr1::dynamic_pointer_cast(pvRequest->getSubField("field"));
- if (!fieldSubField)
- fieldSubField = pvRequest;
- Structure::const_shared_pointer fieldStructure = fieldSubField->getStructure();
-
- // no fields
- if (fieldStructure->getNumberFields() == 0)
- {
- return static_cast(static_cast(nativeType) + DBR_TIME_STRING);
- }
- // control -> DBR_CTRL_
- if (fieldStructure->getField("control"))
- return static_cast(static_cast(nativeType) + DBR_CTRL_STRING);
-
- // display/valueAlarm -> DBR_GR_
- if (fieldStructure->getField("display") || fieldStructure->getField("valueAlarm"))
- return static_cast(static_cast(nativeType) + DBR_GR_STRING);
-
- // timeStamp -> DBR_TIME_
- // NOTE: that only DBR_TIME_ type holds timestamp, therefore if you request for
- // the fields above, you will never get timestamp
- if (fieldStructure->getField("timeStamp"))
- return static_cast(static_cast(nativeType) + DBR_TIME_STRING);
-
- // alarm -> DBR_STS_
- if (fieldStructure->getField("alarm"))
- return static_cast(static_cast(nativeType) + DBR_STS_STRING);
-
- return nativeType;
-}
-
-size_t CAChannelGet::num_instances;
-
CAChannelGetPtr CAChannelGet::create(
CAChannel::shared_pointer const & channel,
ChannelGetRequester::shared_pointer const & channelGetRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
+ PVStructure::shared_pointer const & pvRequest)
{
+ if(DEBUG_LEVEL>0) {
+ cout << "CAChannelGet::create " << channel->getChannelName() << endl;
+ }
return CAChannelGetPtr(new CAChannelGet(channel, channelGetRequester, pvRequest));
}
-
CAChannelGet::CAChannelGet(CAChannel::shared_pointer const & channel,
ChannelGetRequester::shared_pointer const & channelGetRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
+ PVStructure::shared_pointer const & pvRequest)
:
channel(channel),
channelGetRequester(channelGetRequester),
- pvRequest(pvRequest)
-{
- if(DEBUG_LEVEL>0) {
- cout << "CAChannelGet::CAChannelGet() " << channel->getChannelName() << endl;
- }
-}
+ pvRequest(pvRequest),
+ getStatus(Status::Ok),
+ getDoneThread(GetDoneThread::get())
+{}
CAChannelGet::~CAChannelGet()
{
@@ -772,65 +433,22 @@ CAChannelGet::~CAChannelGet()
void CAChannelGet::activate()
{
ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
- if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelGet::activate " << channel->getChannelName() << " requester "<getNativeType());
- pvStructure = createPVStructure(channel, getType, pvRequest);
- bitSet = BitSetPtr(new BitSet(pvStructure->getStructure()->getNumberFields()));
- bitSet->set(0);
- channel->addChannelGet(shared_from_this());
- if(channel->getConnectionState()==Channel::CONNECTED) {
- EXCEPTION_GUARD(getRequester->channelGetConnect(Status::Ok, shared_from_this(),
- pvStructure->getStructure()));
- }
-}
-
-void CAChannelGet::channelCreated(const Status& status,Channel::shared_pointer const & cl)
-{
if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelGet::channelCreated " << channel->getChannelName() << endl;
- }
- ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
- if(!getRequester) return;
- chtype newType = getDBRType(pvRequest, channel->getNativeType());
- if(newType!=getType) {
- getType = getDBRType(pvRequest, channel->getNativeType());
- pvStructure = createPVStructure(channel, getType, pvRequest);
- bitSet = BitSetPtr(new BitSet(pvStructure->getStructure()->getNumberFields()));
- bitSet->set(0);
+ std::cout << "CAChannelGet::activate " << channel->getChannelName() << endl;
}
+ dbdToPv = DbdToPv::create(channel,pvRequest,getIO);
+ pvStructure = dbdToPv->createPVStructure();
+ bitSet = BitSetPtr(new BitSet(pvStructure->getStructure()->getNumberFields()));
+ notifyGetRequester = NotifyGetRequesterPtr(new NotifyGetRequester());
+ notifyGetRequester->setChannelGet(shared_from_this());
EXCEPTION_GUARD(getRequester->channelGetConnect(Status::Ok, shared_from_this(),
pvStructure->getStructure()));
}
-void CAChannelGet::channelStateChange(
- Channel::shared_pointer const & channel,
- Channel::ConnectionState connectionState)
-{
- if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelGet::channelStateChange " << channel->getChannelName() << endl;
- }
- ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
- if(!getRequester) return;
- if(connectionState==Channel::DISCONNECTED || connectionState==Channel::DESTROYED) {
- EXCEPTION_GUARD(getRequester->channelDisconnect(connectionState==Channel::DESTROYED);)
- }
-}
-void CAChannelGet::channelDisconnect(bool destroy)
-{
- if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelGet::channelDisconnect " << channel->getChannelName() << endl;
- }
- ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
- if(!getRequester) return;
- EXCEPTION_GUARD(getRequester->channelDisconnect(destroy);)
-}
-/* --------------- epics::pvAccess::ChannelGet --------------- */
+std::string CAChannelGet::getRequesterName() { return "CAChannelGet";}
namespace {
@@ -840,536 +458,122 @@ static void ca_get_handler(struct event_handler_args args)
channelGet->getDone(args);
}
-typedef void (*copyDBRtoPVStructure)(const void * from, unsigned count, PVStructure::shared_pointer const & to);
-
+} // namespace
-// template
-template
-void copy_DBR(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
+void CAChannelGet::getDone(struct event_handler_args &args)
{
- if (count == 1)
- {
- std::tr1::shared_ptr value = pvStructure->getSubField("value");
- if (value.get()) value->put(static_cast(dbr)[0]);
- }
- else
- {
- std::tr1::shared_ptr value = pvStructure->getSubField("value");
- if (value.get())
- {
- std::tr1::shared_ptr value = pvStructure->getSubField("value");
- typename aF::svector temp(value->reuse());
- temp.resize(count);
- std::copy(static_cast(dbr), static_cast(dbr) + count, temp.begin());
- value->replace(freeze(temp));
- }
+ if(DEBUG_LEVEL>1) {
+ std::cout << "CAChannelGet::getDone "
+ << channel->getChannelName() << endl;
}
+
+ ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
+ if(!getRequester) return;
+ getStatus = dbdToPv->getFromDBD(pvStructure,bitSet,args);
+ getDoneThread->getDone(notifyGetRequester);
}
-#if defined(__vxworks) || defined(__rtems__)
-// dbr_long_t is defined as "int", pvData uses int32 which can be defined as "long int" (32-bit)
-// template
-template<>
-void copy_DBR(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
+void CAChannelGet::notifyClient()
{
- if (count == 1)
- {
- std::tr1::shared_ptr value = pvStructure->getSubField("value");
- if (value.get()) value->put(static_cast(dbr)[0]);
- }
- else
- {
- std::tr1::shared_ptr value = pvStructure->getSubField("value");
- if (value.get())
- {
- PVIntArray::svector temp(value->reuse());
- temp.resize(count);
- std::copy(static_cast(dbr), static_cast(dbr) + count, temp.begin());
- value->replace(freeze(temp));
- }
- }
+ ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
+ if(!getRequester) return;
+ EXCEPTION_GUARD(getRequester->getDone(getStatus, shared_from_this(), pvStructure, bitSet));
}
-#endif
-// string specialization
-template<>
-void copy_DBR(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
+void CAChannelGet::get()
{
- if (count == 1)
+ if(DEBUG_LEVEL>1) {
+ std::cout << "CAChannelGet::get " << channel->getChannelName() << endl;
+ }
+ ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
+ if(!getRequester) return;
+ channel->attachContext();
+ bitSet->clear();
+ int result = ca_array_get_callback(dbdToPv->getRequestType(),
+ 0,
+ channel->getChannelID(), ca_get_handler, this);
+ if (result == ECA_NORMAL)
{
- std::tr1::shared_ptr value = pvStructure->getSubField("value");
- if (value.get()) value->put(std::string(static_cast(dbr)));
+ result = ca_flush_io();
}
- else
+ if (result != ECA_NORMAL)
{
- std::tr1::shared_ptr value = pvStructure->getSubField("value");
- if (value.get())
- {
- const dbr_string_t* dbrStrings = static_cast(dbr);
- PVStringArray::svector sA(value->reuse());
- sA.resize(count);
- std::copy(dbrStrings, dbrStrings + count, sA.begin());
- value->replace(freeze(sA));
- }
+ string mess("CAChannelGet::get ");
+ mess += channel->getChannelName() + " message " + ca_message(result);
+ getStatus = Status(Status::STATUSTYPE_ERROR,mess);
+ notifyClient();
}
}
-// enum specialization
-template<>
-void copy_DBR(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
+Channel::shared_pointer CAChannelGet::getChannel()
{
- if (count == 1)
- {
- PVIntPtr value = pvStructure->getSubField("value.index");
- if (value.get()) value->put(static_cast(dbr)[0]);
- }
- else
- {
- // not supported
- std::cerr << "caChannel: array of enums not supported" << std::endl;
- }
+ return channel;
}
-// template
-template
-void copy_DBR_STS(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
+void CAChannelGet::cancel()
{
- const T* data = static_cast(dbr);
-
- PVStructure::shared_pointer alarm = pvStructure->getSubField("alarm");
- if (alarm.get())
- {
- PVIntPtr status = alarm->getSubField("status");
- if (status.get()) status->put(dbrStatus2alarmStatus[data->status]);
-
- PVIntPtr severity = alarm->getSubField("severity");
- if (severity.get()) severity->put(data->severity);
-
- PVStringPtr message = alarm->getSubField("message");
- if (message.get()) message->put(dbrStatus2alarmMessage[data->status]);
- }
-
- copy_DBR(&data->value, count, pvStructure);
}
-// template
-template
-void copy_DBR_TIME(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
+void CAChannelGet::lastRequest()
{
- const T* data = static_cast(dbr);
-
- PVStructure::shared_pointer ts = pvStructure->getSubField("timeStamp");
- if (ts.get())
- {
- epics::pvData::int64 spe = data->stamp.secPastEpoch;
- spe += 7305*86400;
-
- PVLongPtr secondsPastEpoch = ts->getSubField("secondsPastEpoch");
- if (secondsPastEpoch.get()) secondsPastEpoch->put(spe);
+}
- PVIntPtr nanoseconds = ts->getSubField("nanoseconds");
- if (nanoseconds.get()) nanoseconds->put(data->stamp.nsec);
+CAChannelPutPtr CAChannelPut::create(
+ CAChannel::shared_pointer const & channel,
+ ChannelPutRequester::shared_pointer const & channelPutRequester,
+ PVStructure::shared_pointer const & pvRequest)
+{
+ if(DEBUG_LEVEL>0) {
+ cout << "CAChannelPut::create " << channel->getChannelName() << endl;
}
-
- copy_DBR_STS(dbr, count, pvStructure);
+ return CAChannelPutPtr(new CAChannelPut(channel, channelPutRequester, pvRequest));
}
+CAChannelPut::CAChannelPut(CAChannel::shared_pointer const & channel,
+ ChannelPutRequester::shared_pointer const & channelPutRequester,
+ PVStructure::shared_pointer const & pvRequest)
+:
+ channel(channel),
+ channelPutRequester(channelPutRequester),
+ pvRequest(pvRequest),
+ block(false),
+ isPut(false),
+ getStatus(Status::Ok),
+ putStatus(Status::Ok),
+ putDoneThread(PutDoneThread::get())
+{}
-template
-void copy_format(const void * /*dbr*/, PVStructure::shared_pointer const & pvDisplayStructure)
+CAChannelPut::~CAChannelPut()
{
- PVStringPtr format = pvDisplayStructure->getSubField("format");
- if (format.get()) format->put("%d");
-}
-
-#define COPY_FORMAT_FOR(T) \
-template <> \
-void copy_format(const void * dbr, PVStructure::shared_pointer const & pvDisplayStructure) \
-{ \
- const T* data = static_cast(dbr); \
-\
- if (data->precision) \
- { \
- char fmt[16]; \
- sprintf(fmt, "%%.%df", data->precision); \
- PVStringPtr format = pvDisplayStructure->getSubField("format");\
- if (format.get()) format->put(std::string(fmt));\
- } \
- else \
- { \
- PVStringPtr format = pvDisplayStructure->getSubField("format");\
- if (format.get()) format->put("%f");\
- } \
+ if(DEBUG_LEVEL>0) {
+ std::cout << "CAChannelPut::~CAChannelPut() " << channel->getChannelName() << endl;
+ }
}
-COPY_FORMAT_FOR(dbr_gr_float)
-COPY_FORMAT_FOR(dbr_ctrl_float)
-COPY_FORMAT_FOR(dbr_gr_double)
-COPY_FORMAT_FOR(dbr_ctrl_double)
-#undef COPY_FORMAT_FOR
-
-// template
-template
-void copy_DBR_GR(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
+void CAChannelPut::activate()
{
- const T* data = static_cast(dbr);
-
- PVStructurePtr alarm = pvStructure->getSubField("alarm");
- if (alarm.get())
- {
- PVIntPtr status = alarm->getSubField("status");
- if (status.get()) status->put(dbrStatus2alarmStatus[data->status]);
-
- PVIntPtr severity = alarm->getSubField("severity");
- if (severity.get()) severity->put(data->severity);
-
- PVStringPtr message = alarm->getSubField("message");
- if (message.get()) message->put(dbrStatus2alarmMessage[data->status]);
+ ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
+ if(!putRequester) return;
+ if(DEBUG_LEVEL>0) {
+ cout << "CAChannelPut::activate " << channel->getChannelName() << endl;
}
-
- PVStructurePtr disp = pvStructure->getSubField("display");
- if (disp.get())
- {
- PVStringPtr units = disp->getSubField("units");
- if (units.get()) units->put(std::string(data->units));
-
- PVDoublePtr limitHigh = disp->getSubField("limitHigh");
- if (limitHigh.get()) limitHigh->put(data->upper_disp_limit);
-
- PVDoublePtr limitLow = disp->getSubField("limitLow");
- if (limitLow.get()) limitLow->put(data->lower_disp_limit);
-
- copy_format(dbr, disp);
- }
-
- PVStructurePtr va = pvStructure->getSubField("valueAlarm");
- if (va.get())
- {
- std::tr1::shared_ptr highAlarmLimit = va->getSubField("highAlarmLimit");
- if (highAlarmLimit.get()) highAlarmLimit->put(data->upper_alarm_limit);
-
- std::tr1::shared_ptr highWarningLimit = va->getSubField("highWarningLimit");
- if (highWarningLimit.get()) highWarningLimit->put(data->upper_warning_limit);
-
- std::tr1::shared_ptr lowWarningLimit = va->getSubField("lowWarningLimit");
- if (lowWarningLimit.get()) lowWarningLimit->put(data->lower_warning_limit);
-
- std::tr1::shared_ptr lowAlarmLimit = va->getSubField("lowAlarmLimit");
- if (lowAlarmLimit.get()) lowAlarmLimit->put(data->lower_alarm_limit);
- }
-
- copy_DBR(&data->value, count, pvStructure);
-}
-
-// enum specialization
-template<>
-void copy_DBR_GR
-(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
-{
- const dbr_gr_enum* data = static_cast(dbr);
-
- copy_DBR_STS(data, count, pvStructure);
-}
-
-
-// template
-template
-void copy_DBR_CTRL(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
-{
- const T* data = static_cast(dbr);
-
- PVStructure::shared_pointer alarm = pvStructure->getSubField("alarm");
- if (alarm.get())
- {
- PVIntPtr status = alarm->getSubField("status");
- if (status.get()) status->put(dbrStatus2alarmStatus[data->status]);
-
- PVIntPtr severity = alarm->getSubField("severity");
- if (severity.get()) severity->put(data->severity);
-
- PVStringPtr message = alarm->getSubField("message");
- if (message.get()) message->put(dbrStatus2alarmMessage[data->status]);
- }
-
- PVStructurePtr disp = pvStructure->getSubField("display");
- if (disp.get())
- {
- PVStringPtr units = disp->getSubField("units");
- if (units.get()) units->put(std::string(data->units));
-
- PVDoublePtr limitHigh = disp->getSubField("limitHigh");
- if (limitHigh.get()) limitHigh->put(data->upper_disp_limit);
-
- PVDoublePtr limitLow = disp->getSubField("limitLow");
- if (limitLow.get()) limitLow->put(data->lower_disp_limit);
-
- copy_format(dbr, disp);
- }
-
- PVStructurePtr va = pvStructure->getSubField("valueAlarm");
- if (va.get())
- {
- std::tr1::shared_ptr highAlarmLimit = va->getSubField("highAlarmLimit");
- if (highAlarmLimit.get()) highAlarmLimit->put(data->upper_alarm_limit);
-
- std::tr1::shared_ptr highWarningLimit = va->getSubField("highWarningLimit");
- if (highWarningLimit.get()) highWarningLimit->put(data->upper_warning_limit);
-
- std::tr1::shared_ptr lowWarningLimit = va->getSubField("lowWarningLimit");
- if (lowWarningLimit.get()) lowWarningLimit->put(data->lower_warning_limit);
-
- std::tr1::shared_ptr lowAlarmLimit = va->getSubField("lowAlarmLimit");
- if (lowAlarmLimit.get()) lowAlarmLimit->put(data->lower_alarm_limit);
- }
-
- PVStructurePtr ctrl = pvStructure->getSubField("control");
- if (ctrl.get())
- {
- PVDoublePtr limitHigh = ctrl->getSubField("limitHigh");
- if (limitHigh.get()) limitHigh->put(data->upper_ctrl_limit);
-
- PVDoublePtr limitLow = ctrl->getSubField("limitLow");
- if (limitLow.get()) limitLow->put(data->lower_ctrl_limit);
- }
-
- copy_DBR(&data->value, count, pvStructure);
-}
-
-// enum specialization
-template<>
-void copy_DBR_CTRL
-(const void * dbr, unsigned count, PVStructure::shared_pointer const & pvStructure)
-{
- const dbr_ctrl_enum* data = static_cast(dbr);
-
- copy_DBR_STS(data, count, pvStructure);
-}
-
-
-static copyDBRtoPVStructure copyFuncTable[] =
-{
- copy_DBR, // DBR_STRING
- copy_DBR, // DBR_INT, DBR_SHORT
- copy_DBR, // DBR_FLOAT
- copy_DBR, // DBR_ENUM
- copy_DBR, // DBR_CHAR
- copy_DBR, // DBR_LONG
- copy_DBR, // DBR_DOUBLE
-
- copy_DBR_STS, // DBR_STS_STRING
- copy_DBR_STS, // DBR_STS_INT, DBR_STS_SHORT
- copy_DBR_STS, // DBR_STS_FLOAT
- copy_DBR_STS, // DBR_STS_ENUM
- copy_DBR_STS, // DBR_STS_CHAR
- copy_DBR_STS, // DBR_STS_LONG
- copy_DBR_STS, // DBR_STS_DOUBLE
-
- copy_DBR_TIME, // DBR_TIME_STRING
- copy_DBR_TIME, // DBR_TIME_INT, DBR_TIME_SHORT
- copy_DBR_TIME, // DBR_TIME_FLOAT
- copy_DBR_TIME, // DBR_TIME_ENUM
- copy_DBR_TIME, // DBR_TIME_CHAR
- copy_DBR_TIME, // DBR_TIME_LONG
- copy_DBR_TIME, // DBR_TIME_DOUBLE
-
- copy_DBR_STS, // DBR_GR_STRING -> DBR_STS_STRING
- copy_DBR_GR, // DBR_GR_INT, DBR_GR_SHORT
- copy_DBR_GR, // DBR_GR_FLOAT
- copy_DBR_GR, // DBR_GR_ENUM
- copy_DBR_GR, // DBR_GR_CHAR
- copy_DBR_GR, // DBR_GR_LONG
- copy_DBR_GR, // DBR_GR_DOUBLE
-
- copy_DBR_STS, // DBR_CTRL_STRING -> DBR_STS_STRING
- copy_DBR_CTRL, // DBR_CTRL_INT, DBR_CTRL_SHORT
- copy_DBR_CTRL, // DBR_CTRL_FLOAT
- copy_DBR_CTRL, // DBR_CTRL_ENUM
- copy_DBR_CTRL, // DBR_CTRL_CHAR
- copy_DBR_CTRL, // DBR_CTRL_LONG
- copy_DBR_CTRL // DBR_CTRL_DOUBLE
-};
-
-} // namespace
-
-void CAChannelGet::getDone(struct event_handler_args &args)
-{
- if(DEBUG_LEVEL>1) {
- std::cout << "CAChannelGet::getDone " << channel->getChannelName() << endl;
- }
- ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
- if(!getRequester) return;
- if (args.status == ECA_NORMAL)
- {
- copyDBRtoPVStructure copyFunc = copyFuncTable[getType];
- if (copyFunc)
- copyFunc(args.dbr, args.count, pvStructure);
- else
- {
- throw std::runtime_error("CAChannelGet::getDone no copy func implemented");
- }
- EXCEPTION_GUARD(getRequester->getDone(Status::Ok, shared_from_this(), pvStructure, bitSet));
- }
- else
- {
- Status errorStatus(Status::STATUSTYPE_ERROR, string(ca_message(args.status)));
- EXCEPTION_GUARD(getRequester->getDone(errorStatus, shared_from_this(),
- PVStructure::shared_pointer(), BitSet::shared_pointer()));
- }
-}
-
-
-void CAChannelGet::get()
-{
- if(DEBUG_LEVEL>1) {
- std::cout << "CAChannelGet::get " << channel->getChannelName() << endl;
- }
- ChannelGetRequester::shared_pointer getRequester(channelGetRequester.lock());
- if(!getRequester) return;
- channel->attachContext();
-
- /*
- From R3.14.12 onwards ca_array_get_callback() replies will give a CA client application the current number
- of elements in an array field, provided they specified an element count of zero in their original request.
- The element count is passed in the callback argument structure.
- Prior to R3.14.12 requesting zero elements in a ca_array_get_callback() call was illegal and would fail
- immediately.
- */
-
- int result = ca_array_get_callback(getType,
- 0,
- channel->getChannelID(), ca_get_handler, this);
- if (result == ECA_NORMAL)
- {
- result = ca_flush_io();
- }
- if (result == ECA_NORMAL) return;
- string mess("CAChannelGet::get ");
- mess += ca_message(result);
- throw std::runtime_error(mess);
-}
-
-
-/* --------------- epics::pvData::ChannelRequest --------------- */
-
-Channel::shared_pointer CAChannelGet::getChannel()
-{
- return channel;
-}
-
-void CAChannelGet::cancel()
-{
-}
-
-void CAChannelGet::lastRequest()
-{
-}
-
-
-
-CAChannelPutPtr CAChannelPut::create(
- CAChannel::shared_pointer const & channel,
- ChannelPutRequester::shared_pointer const & channelPutRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
-{
- return CAChannelPutPtr(new CAChannelPut(channel, channelPutRequester, pvRequest));
-}
-
-
-CAChannelPut::~CAChannelPut()
-{
- if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelPut::~CAChannelPut() " << channel->getChannelName() << endl;
- }
-}
-
-size_t CAChannelPut::num_instances;
-
-CAChannelPut::CAChannelPut(CAChannel::shared_pointer const & channel,
- ChannelPutRequester::shared_pointer const & channelPutRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
-:
- channel(channel),
- channelPutRequester(channelPutRequester),
- pvRequest(pvRequest),
- block(false)
-{
- if(DEBUG_LEVEL>0) {
- cout << "CAChannelPut::CAChannePut() " << channel->getChannelName() << endl;
- }
-}
-
-void CAChannelPut::activate()
-{
- if(DEBUG_LEVEL>0) {
- cout << "CAChannelPut::activate " << channel->getChannelName() << endl;
- }
- ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
- if(!putRequester) return;
- if(pvStructure) throw std::runtime_error("CAChannelPut::activate() was called twice");
- getType = getDBRType(pvRequest,channel->getNativeType());
- pvStructure = createPVStructure(channel, getType, pvRequest);
+ dbdToPv = DbdToPv::create(channel,pvRequest,putIO);
+ pvStructure = dbdToPv->createPVStructure();
bitSet = BitSetPtr(new BitSet(pvStructure->getStructure()->getNumberFields()));
PVStringPtr pvString = pvRequest->getSubField("record._options.block");
if(pvString) {
std::string val = pvString->get();
if(val.compare("true")==0) block = true;
}
- bitSet->set(pvStructure->getSubFieldT("value")->getFieldOffset());
- channel->addChannelPut(shared_from_this());
- if(channel->getConnectionState()==Channel::CONNECTED) {
- EXCEPTION_GUARD(putRequester->channelPutConnect(Status::Ok, shared_from_this(),
- pvStructure->getStructure()));
- }
-}
-
-
-void CAChannelPut::channelCreated(const Status& status,Channel::shared_pointer const & c)
-{
- if(DEBUG_LEVEL>0) {
- cout << "CAChannelPut::channelCreated " << channel->getChannelName() << endl;
- }
- ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
- if(!putRequester) return;
- chtype newType = getDBRType(pvRequest, channel->getNativeType());
- if(newType!=getType) {
- getType = getDBRType(pvRequest, channel->getNativeType());
- pvStructure = createPVStructure(channel, getType, pvRequest);
- bitSet = BitSetPtr(new BitSet(pvStructure->getStructure()->getNumberFields()));
- PVStringPtr pvString = pvRequest->getSubField("record._options.block");
- if(pvString) {
- std::string val = pvString->get();
- if(val.compare("true")==0) block = true;
- }
- bitSet->set(0);
- }
+ notifyPutRequester = NotifyPutRequesterPtr(new NotifyPutRequester());
+ notifyPutRequester->setChannelPut(shared_from_this());
EXCEPTION_GUARD(putRequester->channelPutConnect(Status::Ok, shared_from_this(),
pvStructure->getStructure()));
}
-void CAChannelPut::channelStateChange(
- Channel::shared_pointer const & channel,
- Channel::ConnectionState connectionState)
-{
- if(DEBUG_LEVEL>0) {
- cout << "CAChannelPut::channelStateChange " << channel->getChannelName() << endl;
- }
- ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
- if(!putRequester) return;
- if(connectionState==Channel::DISCONNECTED || connectionState==Channel::DESTROYED) {
- EXCEPTION_GUARD(putRequester->channelDisconnect(connectionState==Channel::DESTROYED);)
- }
-}
+std::string CAChannelPut::getRequesterName() { return "CAChannelPut";}
-void CAChannelPut::channelDisconnect(bool destroy)
-{
- if(DEBUG_LEVEL>0) {
- cout << "CAChannelPut::channelDisconnect " << channel->getChannelName() << endl;
- }
- ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
- if(!putRequester) return;
- EXCEPTION_GUARD(putRequester->channelDisconnect(destroy);)
-}
/* --------------- epics::pvAccess::ChannelPut --------------- */
@@ -1381,315 +585,105 @@ static void ca_put_handler(struct event_handler_args args)
channelPut->putDone(args);
}
-
static void ca_put_get_handler(struct event_handler_args args)
{
CAChannelPut *channelPut = static_cast(args.usr);
channelPut->getDone(args);
}
-typedef int (*doPut)(CAChannel::shared_pointer const & channel, void *usrArg, PVStructure::shared_pointer const & from);
-
-
-// template
-template
-int doPut_pvStructure(CAChannel::shared_pointer const & channel, void *usrArg, PVStructure::shared_pointer const & pvStructure)
-{
- bool isScalarValue = pvStructure->getStructure()->getField("value")->getType() == scalar;
-
- if (isScalarValue)
- {
- std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvStructure->getSubFieldT("value"));
-
- pT val = value->get();
- int result = 0;
- if(usrArg!=NULL) {
- result = ca_array_put_callback(channel->getNativeType(), 1,
- channel->getChannelID(), &val,
- ca_put_handler, usrArg);
- } else {
- result = ca_array_put(channel->getNativeType(), 1,
- channel->getChannelID(), &val);
- }
-
- if (result == ECA_NORMAL)
- {
- ca_flush_io();
- }
-
- return result;
- }
- else
- {
- std::tr1::shared_ptr value = pvStructure->getSubFieldT("value");
-
- const pT* val = value->view().data();
- int result = 0;
- if(usrArg!=NULL) {
- result = ca_array_put_callback(channel->getNativeType(),
- static_cast(value->getLength()),
- channel->getChannelID(), val,
- ca_put_handler, usrArg);
- } else {
- result = ca_array_put(channel->getNativeType(),
- static_cast(value->getLength()),
- channel->getChannelID(), val);
- }
- if (result == ECA_NORMAL)
- {
- ca_flush_io();
- }
+} // namespace
- return result;
- }
-}
-// string specialization
-template<>
-int doPut_pvStructure(CAChannel::shared_pointer const & channel, void *usrArg, PVStructure::shared_pointer const & pvStructure)
+void CAChannelPut::put(PVStructure::shared_pointer const & pvPutStructure,
+ BitSet::shared_pointer const & /*putBitSet*/)
{
- bool isScalarValue = pvStructure->getStructure()->getField("value")->getType() == scalar;
-
- if (isScalarValue)
- {
- std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvStructure->getSubFieldT("value"));
-
- string val = value->get();
- int result = 0;
- if(usrArg!=NULL) {
- result = ca_array_put_callback(
- channel->getNativeType(), 1,
- channel->getChannelID(), val.c_str(),
- ca_put_handler, usrArg);
- } else {
- result = ca_array_put(
- channel->getNativeType(), 1,
- channel->getChannelID(), val.c_str());
- }
- if (result == ECA_NORMAL)
- {
- ca_flush_io();
- }
-
- return result;
- }
- else
- {
- std::tr1::shared_ptr value = pvStructure->getSubFieldT("value");
-
- PVStringArray::const_svector stringArray(value->view());
-
- size_t arraySize = stringArray.size();
- size_t ca_stringBufferSize = arraySize * MAX_STRING_SIZE;
- char* ca_stringBuffer = new char[ca_stringBufferSize];
- memset(ca_stringBuffer, 0, ca_stringBufferSize);
-
- char *p = ca_stringBuffer;
- for(size_t i = 0; i < arraySize; i++)
- {
- string value = stringArray[i];
- size_t len = value.length();
- if (len >= MAX_STRING_SIZE)
- len = MAX_STRING_SIZE - 1;
- memcpy(p, value.c_str(), len);
- p += MAX_STRING_SIZE;
- }
-
- int result = 0;
- if(usrArg!=NULL) {
- result = ca_array_put_callback(
- channel->getNativeType(), arraySize,
- channel->getChannelID(), ca_stringBuffer,
- ca_put_handler, usrArg);
- } else {
- result = ca_array_put(
- channel->getNativeType(), arraySize,
- channel->getChannelID(), ca_stringBuffer);
- }
- delete[] ca_stringBuffer;
-
- if (result == ECA_NORMAL)
- {
- ca_flush_io();
- }
-
- return result;
+ if(DEBUG_LEVEL>1) {
+ cout << "CAChannelPut::put " << channel->getChannelName() << endl;
}
-}
-
-// enum specialization
-template<>
-int doPut_pvStructure(CAChannel::shared_pointer const & channel, void *usrArg, PVStructure::shared_pointer const & pvStructure)
-{
- bool isScalarValue = pvStructure->getStructure()->getField("value")->getType() == structure;
-
- if (isScalarValue)
+ ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
+ if(!putRequester) return;
{
- std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvStructure->getSubFieldT("value.index"));
-
- dbr_enum_t val = value->get();
- int result = 0;
- if(usrArg!=NULL) {
- result = ca_array_put_callback(
- channel->getNativeType(), 1,
- channel->getChannelID(), &val,
- ca_put_handler, usrArg);
- } else {
- result = ca_array_put(
- channel->getNativeType(), 1,
- channel->getChannelID(), &val);
- }
- if (result == ECA_NORMAL)
- {
- ca_flush_io();
- }
-
- return result;
+ Lock lock(mutex);
+ isPut = true;
}
- else
- {
- // no enum arrays in V3
- return ECA_NOSUPPORT;
+ putStatus = dbdToPv->putToDBD(channel,pvPutStructure,block,&ca_put_handler,this);
+ if(!block || !putStatus.isOK()) {
+ EXCEPTION_GUARD(putRequester->putDone(putStatus, shared_from_this()));
}
}
-static doPut doPutFuncTable[] =
-{
- doPut_pvStructure, // DBR_STRING
- doPut_pvStructure, // DBR_INT, DBR_SHORT
- doPut_pvStructure, // DBR_FLOAT
- doPut_pvStructure, // DBR_ENUM
- doPut_pvStructure, // DBR_CHAR
-#if defined(__vxworks) || defined(__rtems__)
- doPut_pvStructure, // DBR_LONG
-#else
- doPut_pvStructure, // DBR_LONG
-#endif
- doPut_pvStructure, // DBR_DOUBLE
-};
-
-} // namespace
void CAChannelPut::putDone(struct event_handler_args &args)
{
- if(DEBUG_LEVEL>1) {
+ if(DEBUG_LEVEL>1) {
cout << "CAChannelPut::putDone " << channel->getChannelName() << endl;
}
ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
if(!putRequester) return;
- if (args.status == ECA_NORMAL)
+ if(args.status!=ECA_NORMAL)
{
- EXCEPTION_GUARD(putRequester->putDone(Status::Ok, shared_from_this()));
- }
- else
- {
- Status errorStatus(Status::STATUSTYPE_ERROR, string(ca_message(args.status)));
- EXCEPTION_GUARD(putRequester->putDone(errorStatus, shared_from_this()));
+ putStatus = Status(Status::STATUSTYPE_ERROR, string(ca_message(args.status)));
+ } else {
+ putStatus = Status::Ok;
}
+ putDoneThread->putDone(notifyPutRequester);
}
-void CAChannelPut::put(PVStructure::shared_pointer const & pvPutStructure,
- BitSet::shared_pointer const & /*putBitSet*/)
+void CAChannelPut::getDone(struct event_handler_args &args)
{
- if(DEBUG_LEVEL>1) {
- cout << "CAChannelPut::put " << channel->getChannelName() << endl;
+ if(DEBUG_LEVEL>1) {
+ cout << "CAChannelPut::getDone " << channel->getChannelName() << endl;
}
+
ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
if(!putRequester) return;
- doPut putFunc = doPutFuncTable[channel->getNativeType()];
- if (putFunc)
- {
- // TODO now we always put all
- if(block) {
- channel->attachContext();
- int result = putFunc(channel, this, pvPutStructure);
- if (result != ECA_NORMAL)
- {
- string message(ca_message(result));
- Status errorStatus(Status::STATUSTYPE_ERROR, message);
- EXCEPTION_GUARD(putRequester->putDone(errorStatus, shared_from_this()));
- }
- } else {
- channel->attachContext();
- int result = putFunc(channel,NULL, pvPutStructure);
- if (result == ECA_NORMAL)
- {
- EXCEPTION_GUARD(putRequester->putDone(Status::Ok, shared_from_this()));
- }
- else
- {
- string message(ca_message(result));
- Status errorStatus(Status::STATUSTYPE_ERROR,message);
- EXCEPTION_GUARD(putRequester->putDone(errorStatus, shared_from_this()));
- }
- }
- }
- else
- {
- // TODO remove
- std::cout << "no put func implemented" << std::endl;
- }
-
+ getStatus = dbdToPv->getFromDBD(pvStructure,bitSet,args);
+ putDoneThread->putDone(notifyPutRequester);
}
-
-void CAChannelPut::getDone(struct event_handler_args &args)
+void CAChannelPut::notifyClient()
{
- if(DEBUG_LEVEL>1) {
- cout << "CAChannelPut::getDone " << channel->getChannelName() << endl;
- }
ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
if(!putRequester) return;
- if (args.status == ECA_NORMAL)
- {
- copyDBRtoPVStructure copyFunc = copyFuncTable[getType];
- if (copyFunc)
- copyFunc(args.dbr, args.count, pvStructure);
- else
- {
- // TODO remove
- std::cout << "no copy func implemented" << std::endl;
- }
-
- EXCEPTION_GUARD(putRequester->getDone(Status::Ok, shared_from_this(), pvStructure, bitSet));
- }
- else
- {
- Status errorStatus(Status::STATUSTYPE_ERROR, string(ca_message(args.status)));
- EXCEPTION_GUARD(putRequester->getDone(errorStatus, shared_from_this(),
- PVStructure::shared_pointer(), BitSet::shared_pointer()));
+ if(isPut) {
+ EXCEPTION_GUARD(putRequester->putDone(putStatus, shared_from_this()));
+ } else {
+ EXCEPTION_GUARD(putRequester->getDone(getStatus, shared_from_this(), pvStructure, bitSet));
}
-
}
void CAChannelPut::get()
{
if(DEBUG_LEVEL>1) {
- cout << "CAChannelPut::get " << channel->getChannelName() << endl;
+ std::cout << "CAChannelPut::get " << channel->getChannelName() << endl;
}
ChannelPutRequester::shared_pointer putRequester(channelPutRequester.lock());
if(!putRequester) return;
- channel->attachContext();
+ {
+ Lock lock(mutex);
+ isPut = false;
+ }
- int result = ca_array_get_callback(getType, channel->getElementCount(),
+ channel->attachContext();
+ bitSet->clear();
+ int result = ca_array_get_callback(dbdToPv->getRequestType(),
+ 0,
channel->getChannelID(), ca_put_get_handler, this);
-
if (result == ECA_NORMAL)
{
result = ca_flush_io();
}
- if (result == ECA_NORMAL) return;
- string message(ca_message(result));
- Status errorStatus(Status::STATUSTYPE_ERROR, message);
- EXCEPTION_GUARD(putRequester->getDone(errorStatus, shared_from_this(),
- PVStructure::shared_pointer(), BitSet::shared_pointer()));
+ if (result != ECA_NORMAL)
+ {
+ string mess("CAChannelPut::get ");
+ mess += channel->getChannelName() + " message " +ca_message(result);
+ Status status(Status::STATUSTYPE_ERROR,mess);
+ EXCEPTION_GUARD(putRequester->getDone(status, shared_from_this(), pvStructure, bitSet));
+ }
}
-
-/* --------------- epics::pvData::ChannelRequest --------------- */
-
Channel::shared_pointer CAChannelPut::getChannel()
{
return channel;
@@ -1720,7 +714,6 @@ class CACMonitorQueue :
POINTER_DEFINITIONS(CACMonitorQueue);
private:
size_t queueSize;
- bool overrunInProgress;
bool isStarted;
Mutex mutex;
@@ -1729,7 +722,6 @@ class CACMonitorQueue :
CACMonitorQueue(
int32 queueSize)
: queueSize(queueSize),
- overrunInProgress(false),
isStarted(false)
{}
~CACMonitorQueue()
@@ -1739,39 +731,29 @@ class CACMonitorQueue :
{
Lock guard(mutex);
while(!monitorElementQueue.empty()) monitorElementQueue.pop();
- overrunInProgress = false;
isStarted = true;
}
void stop()
{
Lock guard(mutex);
while(!monitorElementQueue.empty()) monitorElementQueue.pop();
- overrunInProgress = false;
isStarted = false;
}
- // return true if added to queue
- bool event(const PVStructurePtr &pvStructure)
+
+ bool event(
+ const PVStructurePtr &pvStructure,
+ const MonitorElementPtr & activeElement)
{
Lock guard(mutex);
if(!isStarted) return false;
- if(monitorElementQueue.size()==queueSize)
- {
- overrunInProgress = true;
- return false;
- } else {
- PVStructure::shared_pointer pvs =
- getPVDataCreate()->createPVStructure(pvStructure->getStructure());
- pvs->copy(*pvStructure);
- MonitorElementPtr monitorElement(new MonitorElement(pvs));
- monitorElement->changedBitSet->set(0);
- if(overrunInProgress) {
- overrunInProgress = false;
- monitorElement->overrunBitSet->set(0);
- }
- monitorElementQueue.push(monitorElement);
- return true;
- }
-
+ if(monitorElementQueue.size()==queueSize) return false;
+ PVStructure::shared_pointer pvs =
+ getPVDataCreate()->createPVStructure(pvStructure);
+ MonitorElementPtr monitorElement(new MonitorElement(pvs));
+ *(monitorElement->changedBitSet) = *(activeElement->changedBitSet);
+ *(monitorElement->overrunBitSet) = *(activeElement->overrunBitSet);
+ monitorElementQueue.push(monitorElement);
+ return true;
}
MonitorElementPtr poll()
{
@@ -1784,8 +766,10 @@ class CACMonitorQueue :
void release(MonitorElementPtr const & monitorElement)
{
Lock guard(mutex);
+ if(!isStarted) return;
if(monitorElementQueue.empty()) {
- throw std::runtime_error("client error calling release");
+ string mess("CAChannelMonitor::release client error calling release ");
+ throw std::runtime_error(mess);
}
monitorElementQueue.pop();
}
@@ -1794,27 +778,14 @@ class CACMonitorQueue :
CAChannelMonitorPtr CAChannelMonitor::create(
CAChannel::shared_pointer const & channel,
MonitorRequester::shared_pointer const & monitorRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest)
-{
- return CAChannelMonitorPtr(new CAChannelMonitor(channel, monitorRequester, pvRequest));
-}
-
-CAChannelMonitor::~CAChannelMonitor()
+ PVStructure::shared_pointer const & pvRequest)
{
if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelMonitor::~CAChannelMonitor() " << channel->getChannelName() << endl;
+ cout << "CAChannelMonitor::create " << channel->getChannelName() << endl;
}
- if(!isStarted) return;
- channel->attachContext();
- int result = ca_clear_subscription(eventID);
- if (result == ECA_NORMAL) return;
- string mess("CAChannelMonitor::~CAChannelMonitor() ");
- mess += ca_message(result);
- cerr << mess << endl;
+ return CAChannelMonitorPtr(new CAChannelMonitor(channel, monitorRequester, pvRequest));
}
-size_t CAChannelMonitor::num_instances;
-
CAChannelMonitor::CAChannelMonitor(
CAChannel::shared_pointer const & channel,
MonitorRequester::shared_pointer const & monitorRequester,
@@ -1823,23 +794,32 @@ CAChannelMonitor::CAChannelMonitor(
channel(channel),
monitorRequester(monitorRequester),
pvRequest(pvRequest),
- isStarted(false)
+ isStarted(false),
+ monitorEventThread(MonitorEventThread::get()),
+ pevid(NULL)
+{}
+
+CAChannelMonitor::~CAChannelMonitor()
{
if(DEBUG_LEVEL>0) {
- cout << "CAChannelMonitor::CAChannelMonitor() " << channel->getChannelName() << endl;
+ std::cout << "CAChannelMonitor::~CAChannelMonitor() "
+ << channel->getChannelName()
+ << " isStarted " << (isStarted ? "true" : "false")
+ << endl;
}
+ stop();
}
void CAChannelMonitor::activate()
{
+ MonitorRequester::shared_pointer requester(monitorRequester.lock());
+ if(!requester) return;
if(DEBUG_LEVEL>0) {
std::cout << "CAChannelMonitor::activate " << channel->getChannelName() << endl;
}
- MonitorRequester::shared_pointer requester(monitorRequester.lock());
- if(!requester) return;
- if(pvStructure) throw std::runtime_error("CAChannelMonitor::activate() was called twice");
- getType = getDBRType(pvRequest, channel->getNativeType());
- pvStructure = createPVStructure(channel, getType, pvRequest);
+ dbdToPv = DbdToPv::create(channel,pvRequest,monitorIO);
+ pvStructure = dbdToPv->createPVStructure();
+ activeElement = MonitorElementPtr(new MonitorElement(pvStructure));
int32 queueSize = 2;
PVStructurePtr pvOptions = pvRequest->getSubField("record._options");
if (pvOptions) {
@@ -1852,129 +832,82 @@ void CAChannelMonitor::activate()
if (size > 1) queueSize = size;
}
}
+ notifyMonitorRequester = NotifyMonitorRequesterPtr(new NotifyMonitorRequester());
+ notifyMonitorRequester->setChannelMonitor(shared_from_this());
monitorQueue = CACMonitorQueuePtr(new CACMonitorQueue(queueSize));
- channel->addChannelMonitor(shared_from_this());
- if(channel->getConnectionState()==Channel::CONNECTED) {
- EXCEPTION_GUARD(requester->monitorConnect(Status::Ok, shared_from_this(),
- pvStructure->getStructure()));
- }
-}
-
-void CAChannelMonitor::channelCreated(const Status& status,Channel::shared_pointer const & c)
-{
- if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelMonitor::channelCreated " << channel->getChannelName() << endl;
- }
- MonitorRequester::shared_pointer requester(monitorRequester.lock());
- if(!requester) return;
- chtype newType = getDBRType(pvRequest, channel->getNativeType());
- if(newType!=getType) {
- getType = getDBRType(pvRequest, channel->getNativeType());
- pvStructure = createPVStructure(channel, getType, pvRequest);
- int32 queueSize = 2;
- PVStructurePtr pvOptions = pvRequest->getSubField("record._options");
- if (pvOptions) {
- PVStringPtr pvString = pvOptions->getSubField("queueSize");
- if (pvString) {
- int size;
- std::stringstream ss;
- ss << pvString->get();
- ss >> size;
- if (size > 1) queueSize = size;
- }
- }
- monitorQueue = CACMonitorQueuePtr(new CACMonitorQueue(queueSize));
- }
EXCEPTION_GUARD(requester->monitorConnect(Status::Ok, shared_from_this(),
pvStructure->getStructure()));
}
-void CAChannelMonitor::channelStateChange(
- Channel::shared_pointer const & channel,
- Channel::ConnectionState connectionState)
-{
- if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelMonitor::channelStateChange " << channel->getChannelName() << endl;
- }
- MonitorRequester::shared_pointer requester(monitorRequester.lock());
- if(!requester) return;
- if(connectionState==Channel::DISCONNECTED || connectionState==Channel::DESTROYED) {
- EXCEPTION_GUARD(requester->channelDisconnect(connectionState==Channel::DESTROYED);)
- }
-}
-
-
-void CAChannelMonitor::channelDisconnect(bool destroy)
-{
- if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelMonitor::channelDisconnect " << channel->getChannelName() << endl;
- }
- MonitorRequester::shared_pointer requester(monitorRequester.lock());
- if(!requester) return;
- EXCEPTION_GUARD(requester->channelDisconnect(destroy);)
-}
+std::string CAChannelMonitor::getRequesterName() { return "CAChannelMonitor";}
void CAChannelMonitor::subscriptionEvent(struct event_handler_args &args)
{
if(DEBUG_LEVEL>1) {
- std::cout << "CAChannelMonitor::subscriptionEvent " << channel->getChannelName() << endl;
+ std::cout << "CAChannelMonitor::subscriptionEvent "
+ << channel->getChannelName() << endl;
+ }
+ {
+ Lock lock(mutex);
+ if(!isStarted) return;
}
MonitorRequester::shared_pointer requester(monitorRequester.lock());
if(!requester) return;
- if (args.status == ECA_NORMAL)
+ Status status = dbdToPv->getFromDBD(pvStructure,activeElement->changedBitSet,args);
+ if(status.isOK())
{
- copyDBRtoPVStructure copyFunc = copyFuncTable[getType];
- if (copyFunc) {
- copyFunc(args.dbr, args.count, pvStructure);
- monitorQueue->event(pvStructure);
- // call monitorRequester even if queue is full
- requester->monitorEvent(shared_from_this());
+ if(monitorQueue->event(pvStructure,activeElement)) {
+ activeElement->changedBitSet->clear();
+ activeElement->overrunBitSet->clear();
} else {
- std::cout << "no copy func implemented" << std::endl;
-
+ *(activeElement->overrunBitSet) |= *(activeElement->changedBitSet);
}
+ monitorEventThread->event(notifyMonitorRequester);
}
else
{
string mess("CAChannelMonitor::subscriptionEvent ");
+ mess += channel->getChannelName();
mess += ca_message(args.status);
throw std::runtime_error(mess);
}
}
-epics::pvData::Status CAChannelMonitor::start()
+
+void CAChannelMonitor::notifyClient()
+{
+ {
+ Lock lock(mutex);
+ if(!isStarted) return;
+ }
+ MonitorRequester::shared_pointer requester(monitorRequester.lock());
+ if(!requester) return;
+ requester->monitorEvent(shared_from_this());
+}
+
+Status CAChannelMonitor::start()
{
if(DEBUG_LEVEL>0) {
std::cout << "CAChannelMonitor::start " << channel->getChannelName() << endl;
}
Status status = Status::Ok;
- if(isStarted) {
- status = Status(Status::STATUSTYPE_WARNING,"already started");
- return status;
+ {
+ Lock lock(mutex);
+ if(isStarted) {
+ status = Status(Status::STATUSTYPE_WARNING,"already started");
+ return status;
+ }
+ isStarted = true;
+ monitorQueue->start();
}
channel->attachContext();
-
- /*
- From R3.14.12 onwards when using the IOC server and the C++ client libraries monitor callbacks
- replies will give a CA client application the current number of elements in an array field,
- provided they specified an element count of zero in their original request.
- The element count is passed in the callback argument structure.
- Prior to R3.14.12 you could request a zero-length subscription and the zero would mean
- “use the value of chid->element_count() for this particular channel”,
- but the length of the data you got in your callbacks would never change
- (the server would zero-fill everything after the current length of the field).
- */
-
- // TODO DBE_PROPERTY support
- int result = ca_create_subscription(getType,
+ int result = ca_create_subscription(dbdToPv->getRequestType(),
0,
channel->getChannelID(), DBE_VALUE,
ca_subscription_handler, this,
- &eventID);
+ &pevid);
if (result == ECA_NORMAL)
{
- isStarted = true;
- monitorQueue->start();
result = ca_flush_io();
}
if (result == ECA_NORMAL) return status;
@@ -1983,25 +916,23 @@ epics::pvData::Status CAChannelMonitor::start()
return Status(Status::STATUSTYPE_ERROR,message);
}
-epics::pvData::Status CAChannelMonitor::stop()
+Status CAChannelMonitor::stop()
{
if(DEBUG_LEVEL>0) {
- std::cout << "CAChannelMonitor::stop " << channel->getChannelName() << endl;
+ std::cout << "CAChannelMonitor::stop "
+ << channel->getChannelName()
+ << " isStarted " << (isStarted ? "true" : "false")
+ << endl;
}
- Status status = Status::Ok;
- if(!isStarted) return Status(Status::STATUSTYPE_WARNING,"already stopped");
- channel->attachContext();
- int result = ca_clear_subscription(eventID);
- if (result == ECA_NORMAL)
{
- isStarted = false;
- monitorQueue->stop();
- result = ca_flush_io();
+ Lock lock(mutex);
+ if(!isStarted) return Status(Status::STATUSTYPE_WARNING,"already stopped");
+ isStarted = false;
}
- if (result == ECA_NORMAL) return status;
- string mess("CAChannelMonitor::stop() ");
- mess += ca_message(result);
- return Status(Status::STATUSTYPE_ERROR,mess);
+ monitorQueue->stop();
+ int result = ca_clear_subscription(pevid);
+ if(result==ECA_NORMAL) return Status::Ok;
+ return Status(Status::STATUSTYPE_ERROR,string(ca_message(result)));
}
@@ -2010,6 +941,10 @@ MonitorElementPtr CAChannelMonitor::poll()
if(DEBUG_LEVEL>1) {
std::cout << "CAChannelMonitor::poll " << channel->getChannelName() << endl;
}
+ {
+ Lock lock(mutex);
+ if(!isStarted) return MonitorElementPtr();
+ }
return monitorQueue->poll();
}
@@ -2022,7 +957,7 @@ void CAChannelMonitor::release(MonitorElementPtr const & monitorElement)
monitorQueue->release(monitorElement);
}
-/* --------------- epics::pvData::ChannelRequest --------------- */
+/* --------------- ChannelRequest --------------- */
void CAChannelMonitor::cancel()
{
diff --git a/src/ca/caChannel.h b/src/ca/caChannel.h
index 4a2c40cb..82286278 100644
--- a/src/ca/caChannel.h
+++ b/src/ca/caChannel.h
@@ -4,6 +4,11 @@
* in file LICENSE that is included with this distribution.
*/
+/**
+ * @author msekoranja, mrk
+ * @date 2018.07
+ */
+
#ifndef CACHANNEL_H
#define CACHANNEL_H
@@ -11,17 +16,34 @@
#include
#include
-
+#include
/* for CA */
#include
#include "caProviderPvt.h"
+#include "dbdToPv.h"
namespace epics {
namespace pvAccess {
namespace ca {
+class NotifyMonitorRequester;
+typedef std::tr1::shared_ptr NotifyMonitorRequesterPtr;
+class MonitorEventThread;
+typedef std::tr1::shared_ptr MonitorEventThreadPtr;
+
+class NotifyGetRequester;
+typedef std::tr1::shared_ptr NotifyGetRequesterPtr;
+typedef std::tr1::weak_ptr NotifyGetRequesterWPtr;
+class GetDoneThread;
+typedef std::tr1::shared_ptr GetDoneThreadPtr;
+
+class NotifyPutRequester;
+typedef std::tr1::shared_ptr NotifyPutRequesterPtr;
+typedef std::tr1::weak_ptr NotifyPutRequesterWPtr;
+class PutDoneThread;
+typedef std::tr1::shared_ptr PutDoneThreadPtr;
class CAChannelGetField;
typedef std::tr1::shared_ptr CAChannelGetFieldPtr;
@@ -53,220 +75,140 @@ class CAChannel :
public Channel,
public std::tr1::enable_shared_from_this
{
-
public:
POINTER_DEFINITIONS(CAChannel);
-
- static size_t num_instances;
-
- static CAChannelPtr create(CAChannelProvider::shared_pointer const & channelProvider,
- std::string const & channelName,
- short priority,
- ChannelRequester::shared_pointer const & channelRequester);
-
+ static CAChannelPtr create(
+ CAChannelProvider::shared_pointer const & channelProvider,
+ std::string const & channelName,
+ short priority,
+ ChannelRequester::shared_pointer const & channelRequester);
virtual ~CAChannel();
void connected();
void disconnected();
-
chid getChannelID();
- chtype getNativeType();
- unsigned getElementCount();
- epics::pvData::Structure::const_shared_pointer getStructure();
-
- /* --------------- epics::pvAccess::Channel --------------- */
virtual std::tr1::shared_ptr getProvider();
virtual std::string getRemoteAddress();
virtual ConnectionState getConnectionState();
virtual std::string getChannelName();
virtual std::tr1::shared_ptr getChannelRequester();
-
virtual void getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField);
-
virtual AccessRights getAccessRights(epics::pvData::PVField::shared_pointer const & pvField);
-
virtual ChannelGet::shared_pointer createChannelGet(
ChannelGetRequester::shared_pointer const & channelGetRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
+ epics::pvData::PVStructurePtr const & pvRequest);
virtual ChannelPut::shared_pointer createChannelPut(
ChannelPutRequester::shared_pointer const & channelPutRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
+ epics::pvData::PVStructurePtr const & pvRequest);
virtual Monitor::shared_pointer createMonitor(
MonitorRequester::shared_pointer const & monitorRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
+ epics::pvData::PVStructurePtr const & pvRequest);
virtual void printInfo(std::ostream& out);
- /* ---------------------------------------------------------------- */
-
void attachContext();
-
- void addChannelGet(const CAChannelGetPtr & get);
- void addChannelPut(const CAChannelPutPtr & get);
- void addChannelMonitor(const CAChannelMonitorPtr & get);
void disconnectChannel();
-
-
private:
-
- /* --------------- Destroyable --------------- */
-
virtual void destroy() {}
-
CAChannel(std::string const & channelName,
CAChannelProvider::shared_pointer const & channelProvider,
ChannelRequester::shared_pointer const & channelRequester);
void activate(short priority);
+ void addMonitor(CAChannelMonitorPtr const & monitor);
std::string channelName;
-
CAChannelProviderWPtr channelProvider;
ChannelRequester::weak_pointer channelRequester;
-
chid channelID;
- chtype channelType;
- unsigned elementCount;
bool channelCreated;
- epics::pvData::Structure::const_shared_pointer structure;
epics::pvData::Mutex requestsMutex;
-
std::queue getFieldQueue;
std::queue putQueue;
std::queue getQueue;
std::queue monitorQueue;
- std::vector getList;
- std::vector putList;
- std::vector monitorList;
+ std::vector monitorlist;
};
class CAChannelGet :
public ChannelGet,
- public ChannelRequester,
- public ChannelBaseRequester,
public std::tr1::enable_shared_from_this
{
-
public:
POINTER_DEFINITIONS(CAChannelGet);
-
- static size_t num_instances;
-
static CAChannelGet::shared_pointer create(CAChannel::shared_pointer const & channel,
ChannelGetRequester::shared_pointer const & channelGetRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
+ epics::pvData::PVStructurePtr const & pvRequest);
virtual ~CAChannelGet();
-
void getDone(struct event_handler_args &args);
-
- /* --------------- epics::pvAccess::ChannelGet --------------- */
virtual void get();
-
- /* --------------- epics::pvData::ChannelRequest --------------- */
virtual Channel::shared_pointer getChannel();
virtual void cancel();
virtual void lastRequest();
-
- /* --------------- ChannelRequester --------------- */
- virtual void channelCreated(
- const epics::pvData::Status& status,
- Channel::shared_pointer const & channel);
- virtual void channelStateChange(
- Channel::shared_pointer const & channel,
- Channel::ConnectionState connectionState);
- virtual std::string getRequesterName() { return "CAChannelGet";}
- /* --------------- ChannelBaseRequester --------------- */
- virtual void channelDisconnect(bool destroy);
+ virtual std::string getRequesterName();
void activate();
-
+ void notifyClient();
private:
- /* --------------- Destroyable --------------- */
- virtual void destroy() {}
-
+ virtual void destroy() {}
CAChannelGet(CAChannel::shared_pointer const & _channel,
ChannelGetRequester::shared_pointer const & _channelGetRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
+ epics::pvData::PVStructurePtr const & pvRequest);
CAChannelPtr channel;
ChannelGetRequester::weak_pointer channelGetRequester;
- const epics::pvData::PVStructure::shared_pointer pvRequest;
-
- chtype getType;
+ epics::pvData::PVStructurePtr const & pvRequest;
+ epics::pvData::Status getStatus;
+ GetDoneThreadPtr getDoneThread;
+ NotifyGetRequesterPtr notifyGetRequester;
+ DbdToPvPtr dbdToPv;
+ epics::pvData::Mutex mutex;
epics::pvData::PVStructure::shared_pointer pvStructure;
epics::pvData::BitSet::shared_pointer bitSet;
};
-
-
class CAChannelPut :
public ChannelPut,
- public ChannelRequester,
- public ChannelBaseRequester,
public std::tr1::enable_shared_from_this
{
public:
POINTER_DEFINITIONS(CAChannelPut);
-
- static size_t num_instances;
-
static CAChannelPut::shared_pointer create(CAChannel::shared_pointer const & channel,
ChannelPutRequester::shared_pointer const & channelPutRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
+ epics::pvData::PVStructurePtr const & pvRequest);
virtual ~CAChannelPut();
-
void putDone(struct event_handler_args &args);
void getDone(struct event_handler_args &args);
-
- /* --------------- epics::pvAccess::ChannelPut --------------- */
-
virtual void put(
epics::pvData::PVStructure::shared_pointer const & pvPutStructure,
epics::pvData::BitSet::shared_pointer const & putBitSet
);
virtual void get();
-
- /* --------------- epics::pvData::ChannelRequest --------------- */
-
virtual Channel::shared_pointer getChannel();
virtual void cancel();
virtual void lastRequest();
- /* --------------- ChannelRequester --------------- */
- virtual void channelCreated(
- const epics::pvData::Status& status,
- Channel::shared_pointer const & channel);
- virtual void channelStateChange(
- Channel::shared_pointer const & channel,
- Channel::ConnectionState connectionState);
- virtual std::string getRequesterName() { return "CAChannelPut";}
- /* --------------- ChannelBaseRequester --------------- */
- virtual void channelDisconnect(bool destroy);
-
- void activate();
-
+ virtual std::string getRequesterName();
+ void activate();
+ void notifyClient();
private:
- /* --------------- Destroyable --------------- */
-
- virtual void destroy() {}
-
+ virtual void destroy() {}
CAChannelPut(CAChannel::shared_pointer const & _channel,
ChannelPutRequester::shared_pointer const & _channelPutRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
+ epics::pvData::PVStructurePtr const & pvRequest);
CAChannelPtr channel;
ChannelPutRequester::weak_pointer channelPutRequester;
const epics::pvData::PVStructure::shared_pointer pvRequest;
bool block;
-
- chtype getType;
+ bool isPut;
+ epics::pvData::Status getStatus;
+ epics::pvData::Status putStatus;
+ PutDoneThreadPtr putDoneThread;
+ NotifyPutRequesterPtr notifyPutRequester;
+ DbdToPvPtr dbdToPv;
+ epics::pvData::Mutex mutex;
epics::pvData::PVStructure::shared_pointer pvStructure;
epics::pvData::BitSet::shared_pointer bitSet;
};
@@ -276,66 +218,46 @@ typedef std::tr1::shared_ptr CACMonitorQueuePtr;
class CAChannelMonitor :
public Monitor,
- public ChannelRequester,
- public ChannelBaseRequester,
public std::tr1::enable_shared_from_this
{
public:
POINTER_DEFINITIONS(CAChannelMonitor);
-
- static size_t num_instances;
-
static CAChannelMonitor::shared_pointer create(CAChannel::shared_pointer const & channel,
MonitorRequester::shared_pointer const & monitorRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
+ epics::pvData::PVStructurePtr const & pvRequest);
virtual ~CAChannelMonitor();
-
void subscriptionEvent(struct event_handler_args &args);
- /* --------------- Monitor --------------- */
-
virtual epics::pvData::Status start();
virtual epics::pvData::Status stop();
virtual MonitorElementPtr poll();
virtual void release(MonitorElementPtr const & monitorElement);
-
- /* --------------- epics::pvData::ChannelRequest --------------- */
virtual void cancel();
- /* --------------- ChannelRequester --------------- */
- virtual void channelCreated(
- const epics::pvData::Status& status,
- Channel::shared_pointer const & channel);
- virtual void channelStateChange(
- Channel::shared_pointer const & channel,
- Channel::ConnectionState connectionState);
- virtual std::string getRequesterName() { return "CAChannelMonitor";}
- /* --------------- ChannelBaseRequester --------------- */
- virtual void channelDisconnect(bool destroy);
+ virtual std::string getRequesterName();
void activate();
+ void notifyClient();
private:
- /* --------------- Destroyable --------------- */
virtual void destroy() {}
-
CAChannelMonitor(CAChannel::shared_pointer const & _channel,
MonitorRequester::shared_pointer const & _monitorRequester,
- epics::pvData::PVStructure::shared_pointer const & pvRequest);
-
-
+ epics::pvData::PVStructurePtr const & pvRequest);
CAChannelPtr channel;
MonitorRequester::weak_pointer monitorRequester;
const epics::pvData::PVStructure::shared_pointer pvRequest;
bool isStarted;
- chtype getType;
+ MonitorEventThreadPtr monitorEventThread;
+ evid pevid;
+ NotifyMonitorRequesterPtr notifyMonitorRequester;
+ DbdToPvPtr dbdToPv;
+ epics::pvData::Mutex mutex;
epics::pvData::PVStructure::shared_pointer pvStructure;
- evid eventID;
+ epics::pvData::MonitorElementPtr activeElement;
+
CACMonitorQueuePtr monitorQueue;
};
-}
-}
-}
+}}}
#endif /* CACHANNEL_H */
diff --git a/src/ca/caProvider.cpp b/src/ca/caProvider.cpp
index 2c459f94..5c5b22ca 100644
--- a/src/ca/caProvider.cpp
+++ b/src/ca/caProvider.cpp
@@ -4,16 +4,16 @@
* in file LICENSE that is included with this distribution.
*/
-#include
-
#include
#include
#include
#include
#include
-#include
#include
-#include
+
+#include "monitorEventThread.h"
+#include "getDoneThread.h"
+#include "putDoneThread.h"
#define epicsExportSharedSymbols
#include