diff --git a/README.md b/README.md index ee6a6c5..db87fc9 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,6 @@ Examples are available in exampleCPP. Status ------ -* The API is for EPICS Version 4 release 4.5.0 +* The API is for EPICS Version 4 release 4.6.0 diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 1efca70..8b3effc 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -2,7 +2,9 @@ EPICS V4 release 4.6 ==================== -The examples are moved to exampleCPP +* The examples are moved to exampleCPP +* Support for channelRPC is now available. +* removeRecord and traceRecord are now available. The test is now a regression test the can be ran via diff --git a/documentation/pvDatabaseCPP.html b/documentation/pvDatabaseCPP.html index 8debfff..89533f4 100644 --- a/documentation/pvDatabaseCPP.html +++ b/documentation/pvDatabaseCPP.html @@ -36,7 +36,7 @@
The main purpose of this project to make it easier to implement services that are accessed via pvAccess. +
+pvDatabaseCPP is one of the components of + +EPICS Version 4 + +
+This document is only a guide to help locate code and documentation related to pvDatabaseCPP
-This project supplies a complete implementation of the server side of pvAccess, -which has the provider name local. +It is intended for developers that want to use pvDatabaseCPP.
--A service must provide a top level PVStructure and a process method. -A service can be run as a main process or can be part of a V3 IOC. -Thus services can be developed that interact with V3 records, asynDriver, -areaDetector, etc. +
A guide for developers is available at + +developerGuide + +
+This guide discusses all the components that are part of an EPICS V4 release. +Some understanding of the components and how they are related is necessary in order to +develop code that uses pvDatabaseCPP. +In particular read everything related to pvDatabase. +
+The developerGuide discusses code in a way that applies to both CPP and C++. +For the descriptions of the CPP specific code consult the next section.
-A brief description of a pvDatabase is that it is a set of network accessible, smart, -memory resident records. -Each record has data composed of a top level PVStructure. -Each record has a name which is the channelName for pvAccess. -A local Channel Provider implements the complete ChannelProvider and -Channel interfaces as defined by pvAccess. -The local provider provides access to the records in the pvDatabase. -This local provider is accessed by the remote pvAccess server. -A record is smart because code can be attached to a record, which is accessed via a method named process.
+doxygen documentation is available at +doxgen +
-This document describes components that provide the following features:
+pvDatabaseCPP itself has the following implementations of a PVRecord
Base classes make it easy to create record instances. -The code attached to each record must create the top -level PVStructure and the following three methods:
-Doxygen documentation is available at doxygenDoc
-The first step is to build pvDatabaseCPP as described in the next section.
-A separate project exampleCPP has examples for pvDatabaseCPP -and for pvaClientCPP. -See it for examples. +
Example code is available as part of this release. + +exampleCPP + +
+In particular look at the example code mentioned in the following sub-sections.
-This has many examples of how to create both soft records and records that implement +other functionality.
+The process method is called when a pvAccess client requests that a record be processed. - If a top level timeStamp field exists, - the default process method just sets the timeStamp to the currect time. - A service is created by implementing process and providing a top level PVStructure. -
-This shows how to implement a record that has a link to another record
+-If a proper RELEASE.local is present one directory level above pvDatabaseCPP. -
--Just type: -
--make --
-An example of a proper RELEASE.local is: -
-
-EPICS4_DIR=/home/epicsv4/master
-EXAMPLE=${EPICS4_DIR}/exampleCPP
-PVDATABASE=${EPICS4_DIR}/pvDatabaseCPP
-PVACLIENT=${EPICS4_DIR}/pvaClientCPP
-PVASRV=${EPICS4_DIR}/pvaSrv
-PVACCESS=${EPICS4_DIR}/pvAccessCPP
-NORMATIVETYPES=${EPICS4_DIR}/normativeTypesCPP
-PVDATA=${EPICS4_DIR}/pvDataCPP
-PVCOMMON=${EPICS4_DIR}/pvCommonCPP
-
-EPICS_BASE=/home/install/epics/base
-
-
-pvDatabaseCPP can also be built if a file RELEASE.local exists in directory configure. -To create one do the following:
--mrk> pwd -/home/hg/pvDatabaseCPP/configure -mrk> cp ExampleRELEASE.local RELEASE.local --
Then edit RELEASE.local so that it has the correct location of each -product pvDatabaseCPP requires. -Than at the top level just execute make:
--mrk> cd .. -mrk> pwd -/home/epicsv4/master/pvDatabaseCPP -mrk> make -
Shell commands are made available via the standard DBD include mechanism provided by iocCore. @@ -252,694 +186,6 @@ pvDatabaseCPP
In addition any code that implements a PVRecord must implement an ioc command. Look at any of the examples in exampleCPP to see how to implement shell commands.
-This Directory has the following files:
-This directory has the following files:
-The classes in pvDatabase.h describe a database of memory resident -smart records. -It describes the following classes:
-Each class is described in a separate subsection.
-
-namespace epics { namespace pvDatabase {
-
-class PVRecord;
-typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
-typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap;
-
-class PVRecordField;
-typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
-typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray;
-typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr;
-
-class PVRecordStructure;
-typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr;
-
-class PVRecordClient;
-typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
-
-class PVListener;
-typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
-
-class PVDatabase;
-typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
-
-
-NOTES:
-
-class PVRecord
- public std::tr1::enable_shared_from_this<PVRecord>
-{
-public:
- POINTER_DEFINITIONS(PVRecord);
-
- virtual bool init() ;
- virtual void start() {}
- virtual void process() {}
- virtual void destroy();
-
- static PVRecordPtr create(
- std::string const & recordName,
- epics::pvData::PVStructurePtr const & pvStructure);
- virtual ~PVRecord();
- std::string getRecordName();
- PVRecordStructurePtr getPVRecordStructure();
- PVRecordFieldPtr findPVRecordField(
- epics::pvData::PVFieldPtr const & pvField);
- void lock();
- void unlock();
- bool tryLock();
- void lockOtherRecord(PVRecordPtr const & otherRecord);
- bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
- bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
- void detachClients();
- bool addListener(PVListenerPtr const & pvListener);
- bool removeListener(PVListenerPtr const & pvListener);
- ServicePtr getService(PVStructurePtr const & pvRequest)
- void beginGroupPut();
- void endGroupPut();
- int getTraceLevel();
- void setTraceLevel(int level);
-protected:
- PVRecord(
- std::string const & recordName,
- epics::pvData::PVStructurePtr const & pvStructure);
- void initPVRecord();
- epics::pvData::PVStructurePtr getPVStructure();
- PVRecordPtr getPtrSelf()
- {
- return shared_from_this();
- }
-private:
-...
-}
-
-The methods are:
-The protected methods are:
-
-class PVRecordField {
- public virtual epics::pvData::PostHandler,
- public std::tr1::enable_shared_from_this<PVRecordField>
-public:
- POINTER_DEFINITIONS(PVRecordField);
- PVRecordField(
- epics::pvData::PVFieldPtr const & pvField,
- PVRecordStructurePtr const & parent,
- PVRecordPtr const & pvRecord);
- virtual ~PVRecordField();
- virtual void destroy();
- PVRecordStructurePtr getParent();
- epics::pvData::PVFieldPtr getPVField();
- std::string getFullFieldName();
- std::string getFullName();
- PVRecordPtr getPVRecord();
- bool addListener(PVListenerPtr const & pvListener);
- virtual void removeListener(PVListenerPtr const & pvListener);
- virtual void postPut();
-protected:
- PVRecordFieldPtr getPtrSelf()
- {
- return shared_from_this();
- }
- virtual void init();
- virtual void postParent(PVRecordFieldPtr const & subField);
- virtual void postSubField();
-private:
-...
-};
-
-When PVRecord is created it creates a PVRecordField for every field in the PVStructure -that holds the data. It has the following methods: -
- -
-class PVRecordStructure : public PVRecordField {
-public:
- POINTER_DEFINITIONS(PVRecordStructure);
- PVRecordStructure(
- epics::pvData::PVStructurePtr const & pvStructure,
- PVRecordStructurePtr const & parent,
- PVRecordPtr const & pvRecord);
- virtual ~PVRecordStructure();
- virtual void destroy();
- PVRecordFieldPtrArrayPtr getPVRecordFields();
- epics::pvData::PVStructurePtr getPVStructure();
- virtual void removeListener(PVListenerPtr const & pvListener);
- virtual void postPut();
-protected:
- virtual void init();
-private:
-...
-};
-
-When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure -that holds the data. It has the following methods: -
-
-class PVRecordClient {
- POINTER_DEFINITIONS(PVRecordClient);
- virtual ~PVRecordClient();
- virtual void detach(PVRecordPtr const & pvRecord);
-};
-
-where
-
-class PVListener {
- virtual public PVRecordClient
-public:
- POINTER_DEFINITIONS(PVListener);
- virtual ~PVListener();
- virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
- virtual void dataPut(
- PVRecordStructurePtr const & requested,
- PVRecordFieldPtr const & pvRecordField) = 0;
- virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
- virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
- virtual void unlisten(PVRecordPtr const & pvRecord);
-};
-
-where
-
-class PVDatabase : virtual public epics::pvData::Requester {
-public:
- POINTER_DEFINITIONS(PVDatabase);
- static PVDatabasePtr getMaster();
- virtual ~PVDatabase();
- virtual void destroy();
- PVRecordPtr findRecord(std::string const & recordName);
- bool addRecord(PVRecordPtr const & record);
- epics::pvData::PVStringArrayPtr getRecordNames();
- bool removeRecord(PVRecordPtr const & record);
-private:
- PVDatabase();
-};
-
-where
-This is code that provides an implementation of channelProvider as -defined by pvAccess. -It provides access to PVRecords and is accessed by the server side of remote pvAccess. -It uses the copy and monitor facilities from pvDataCPP and connects -them to a PVRecord. -
-The implementation is a complete implementation of channelProvider -and channel.
-The following provides a brief description of each channel method that -is implemented.
-Implements channelProcess.
-Implements channelGet.
-Implements channelPut.
-Implements channelPutGet.
-Implements channelArray.
-Implements channelRPC.
-This is the code that implements monitors on changes to fields of a PVRecord. -Because it is called by pvAccess client (monitor methods) and by -PVRecord (when postPut is called), it must be careful to prevent deadlocks. -The implementation is via class MonitorLocal (implemented in monitorFactory.cpp) -and PVCopyMonitor. -MonitorLocal is the interface between pvAccess and PVCopyMonitor. -PVCopyMonitor is the interface between MonitorLocal and PVRecord. -MonitorLocal manages a MonitorElement queue. -While monitoring is active (between start and stop) it keeps an active element -for use by PVCopyMonitor. -While monitoring is active PVCopyMonitor updates the active monitor element whenever -a postPut is issued to any field being monitored. -
-The following two sections provide a few more details about MonitorLocal -and PVCopyMonitor.
-MonitorLocal implements the following abstract base classes:
-A brief description on each method in MonitorLocal is:
--pvCopyMonitor is the code that manages changes to -fields in the record. -It is called by PVRecord whenever a postPut is issued to a field. -pvCopyMonitor uses the active monitor element provided by monitorFactory. -Note that this method is called with the record locked. -It only modifies the changedBitSet and overrunBitSet of the -active element but never modifies the pvStructure. -
-A brief description of the pvCopyMonitor methods is:
-This section provides traceRecord which implements a PVRecord that allows a client to set -the trace level of another PVRecord. It follows the pattern of a channelPutGet -record:
--traceRecord - structure argument - string recordName - int level 0 - structure result - string status --where: -
testExampleServerMain.cpp has an example of how to create a traceRecord:
--PVDatabasePtr master = PVDatabase::getMaster(); -PVRecordPtr pvRecord; -String recordName; -bool result(false); -recordName = "traceRecordPGRPC"; -pvRecord = TraceRecord::create(recordName); -result = master->addRecord(pvRecord); -if(!result) cout<< "record " << recordName << " not added" << endl; -- -