diff --git a/caProvider.md b/caProvider.md
new file mode 100644
index 0000000..2ceb15a
--- /dev/null
+++ b/caProvider.md
@@ -0,0 +1,636 @@
+#pvAccessCPP: ca provider
+
+2018.06.25
+
+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().
+
+Client code can create an Auxillary Thread by calling:
+
+```
+ca_client_context* current_context = CAClientFactory::get_ca_client_context();
+int result = ca_attach_context(current_context);
+
+```
+
+
+[Deadlock in ca_clear_subscription()](https://bugs.launchpad.net/epics-base/7.0/+bug/1751380)
+
+Shows a problem with monitor callbacks.
+
+
+In order to prevent this problem **ca** creates a monitorEventThread.
+All calls to the requester's **monitorEvent** method are made from the monitorEventThread.
+
+**Note** the monitorEventThread does not call **ca_attach_context**.
+This means that no **ca_xxx** function can be called from
+the requester's **monitorEvent** method.
+
+
+
+