Merge pull request #46 from mrkraimer/master

add record support and processRecord
This commit is contained in:
Marty Kraimer
2019-06-25 09:17:35 -04:00
committed by GitHub
44 changed files with 1363 additions and 153 deletions

View File

@ -3,8 +3,12 @@ TOP = .
include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG
DIRS += configure DIRS += configure
DIRS += src/copy
src/copy_DEPEND_DIRS = configure
DIRS += src DIRS += src
src_DEPEND_DIRS = configure src_DEPEND_DIRS = configure src/copy
DIRS += test DIRS += test
test_DEPEND_DIRS = src test_DEPEND_DIRS = src

View File

@ -2,6 +2,11 @@
This document summarizes the changes to the module between releases. This document summarizes the changes to the module between releases.
## Master (June 2019)
1) support is a new feature.
2) processRecord is new
## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019) ## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019)
Formerly if a client makes a request for a subfield of a non structure field Formerly if a client makes a request for a subfield of a non structure field

View File

@ -1,17 +1,6 @@
TODO TODO
=========== ===========
monitorPlugin
-------------
A debate is on-going about what semantics should be.
Must test record delete.
-------------------
Must test removing a record from the PVDatabase while a pvAccess client
is attached. Also why do both unlisten and detach exists?
create more regression tests create more regression tests
---------------- ----------------

View File

@ -36,7 +36,8 @@
<div class="head"> <div class="head">
<h1>pvDatabaseCPP</h1> <h1>pvDatabaseCPP</h1>
<h2 class="nocount">Release 4.4 - December 2018</h2> <h2 class="nocount">Release ? - TBD</h2>
Latest update 2019.06.19.
<h2 class="nocount">Abstract</h2> <h2 class="nocount">Abstract</h2>
@ -69,8 +70,6 @@ pvDatabaseCPP is one of the components of
EPICS Version 7 EPICS Version 7
</p> </p>
<p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP <p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP
</p>
<p>
It is intended for developers that want to use pvDatabaseCPP. It is intended for developers that want to use pvDatabaseCPP.
</p> </p>
<h2>Developer Guide</h2> <h2>Developer Guide</h2>
@ -87,7 +86,7 @@ In particular read everything related to pvDatabase.
</p> </p>
<p>pvDatabase has plugin support, which is implemented in <b>pvCopy</b>. <p>pvDatabase has plugin support, which is implemented in <b>pvCopy</b>.
<b>pvCopy</b> was originally implemented in <b>pvDataCPP</b>, <b>pvCopy</b> was originally implemented in <b>pvDataCPP</b>,
but pvDatabaseCPP now implemnents its own version and adds plugin support. but pvDatabaseCPP now implements its own version and adds plugin support.
</p> </p>
<p> <p>
See See
@ -98,7 +97,7 @@ pvRequest
for details. for details.
</p> </p>
<p>The developerGuide discusses code in a way that applies to both CPP and C++. <p>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. For the descriptions of the CPP specific code consult the following sections.
</p> </p>
<h2>doxygen</h2> <h2>doxygen</h2>
@ -108,22 +107,82 @@ href="./html/index.html">doxgen</a>
</p> </p>
<h2>pvDatabaseCPP</h2> <h2>pvDatabaseCPP</h2>
<p>pvDatabaseCPP itself has the following implementations of a <b>PVRecord</b></p> <h3>include/pv</h3>
<p>The header files that describe the various components implemented by pvDatabase.
</p>
<dl> <dl>
<dt>RemoveRecord.cpp</dt> <dt>pvDatabase.h</dt>
<dd> <dd>
This is the code that is used to delete another record in the same <b>IOC</b>. This describes PVRecord and PVDatabase.
</dd> </dd>
<dt>TraceRecord.cpp</dt> <dt>channelProviderLocal.h </dt>
<dd> <dd>
This is the code that is used to set the trace level This describes a channel provider for PVDatabase
in another record in the same <b>IOC</b>. </dd>
</dd> <dt>pvSupport.h</dt>
<dd>
This is the base class for support attached to a field of a record.
</dd>
<dt>controlSupport.h</dt>
<dd>
This is support that implements control limits.
</dd>
<dt>scalarAlarmSupport.h</dt>
<dd>
This is support for a alarm limits for a scalar numeric field.
</dd>
<dt>processRecord.h</dt>
<dd>
This is a PVRecord that periodical processes a set of PVRecords in the local PVDatabase.
</dd>
<dt>removeRecord.h</dt>
<dd>
This is a PVRecord that removes a PVRecord in the local PVDatabase.
</dd>
<dt>traceRecord.h</dt>
<dd>
This is a PVRecord that sets the trace value for another PVRecord in the local PVDatabase.
</dd>
<dt>pvStructureCopy.h</dt>
<dd>
This is a facility that allows a client to access a subfield of the fields in a PVRecord.
It also provides record and field options an plugin support.
</dd>
<dt>pvPlugin.h</dt>
<dd>
This is the base class for a plugin attached to a record or field of PVRecord.
</dd>
<dt>pvArrayPlugin.h</dt>
<dd>
A plugin for accessing a subset of the elements in an array field.
</dd>
<dt>pvDeadbandPlugin.h</dt>
<dd>
A deadband plugin for monitors.
</dd>
<dt>pvTimestampPlugin.h</dt>
<dd>
A plugin for timeStamp.
</dd>
</dl> </dl>
<h3>src/database</h3>
<p>This has the code that implements pvDatabase and pvRecord.</p>
<h3>src/pvAccess</h3>
<p>This has the code for the channel provider for pvDatabase.
</p>
<h3>src/support</h3>
<p>This has the pvSupport code.</p>
<h3>src/special</h3>
<p>
This has the code for processRecord, removeRecord, and traceRecord.
</p>
<h3>src/copy</h3>
<p>This has the code for pvStructureCopy and all the plugin support.
</p>
<h2>exampleCPP</h2> <h2>exampleCPP</h2>
<p>Example code is available as part of this release. <p>Example code is available as part of this release.
<a <a
href="http://epics-pvdata.sourceforge.net/docbuild/exampleCPP/tip/documentation/exampleCPP.html"> href="https://github.com/epics-base/exampleCPP">
exampleCPP exampleCPP
</a> </a>
</p> </p>
@ -173,6 +232,24 @@ other functionality.</p>
</dd> </dd>
</dl> </dl>
<h3>support</h3>
<p>This creates records that have the following features:</p>
<dl>
<dt>value</dt>
<dd>
Each record has a value field the is a numeric scalar field.
In addition each has the following fields:
alarm,timeStamp,control,scalarAlarm, and display.
</dd>
<dt>support</dt>
<dd>
Each record uses the control and scalarAlarm support provided by pvDatabaseCPP.
</dd>
</dl>
<p>
It also creates records that can be used by clients to show example of the plugin support.
</p>
<h2>iocshell commands</h2> <h2>iocshell commands</h2>
<p>Shell commands are made available via the standard DBD include mechanism <p>Shell commands are made available via the standard DBD include mechanism
provided by iocCore. provided by iocCore.
@ -194,7 +271,7 @@ pvDatabaseCPP
</dd> </dd>
</dl> </dl>
<p>In addition any code that implements a PVRecord must implement an ioc command. <p>In addition any code that implements a PVRecord must implement an ioc command.
Look at any of the examples in <b>exampleCPP</b> to see how to implement shell commands.</p> Look at the examples in <b>exampleCPP/support</b> to see how to implement shell commands.</p>
</div> </div>
</body> </body>

View File

@ -3,23 +3,31 @@
TOP = .. TOP = ..
include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG
# needed for Windows
LIB_SYS_LIBS_WIN32 += netapi32 ws2_32
PVDATABASE_SRC = $(TOP)/src PVDATABASE_SRC = $(TOP)/src
LIBRARY += pvDatabase LIBRARY += pvDatabase
# shared library ABI version. # shared library ABI version.
SHRLIB_VERSION ?= 4.4.2 SHRLIB_VERSION ?= $(EPICS_PVA_MAJOR_VERSION).$(EPICS_PVA_MINOR_VERSION).$(EPICS_PVA_MAINTENANCE_VERSION)
INC += pv/channelProviderLocal.h INC += pv/channelProviderLocal.h
INC += pv/pvDatabase.h INC += pv/pvDatabase.h
INC += pv/traceRecord.h INC += pv/traceRecord.h
INC += pv/removeRecord.h INC += pv/removeRecord.h
INC += pv/processRecord.h
INC += pv/pvSupport.h
INC += pv/controlSupport.h
INC += pv/scalarAlarmSupport.h
include $(PVDATABASE_SRC)/copy/Makefile
include $(PVDATABASE_SRC)/database/Makefile include $(PVDATABASE_SRC)/database/Makefile
include $(PVDATABASE_SRC)/pvAccess/Makefile include $(PVDATABASE_SRC)/pvAccess/Makefile
include $(PVDATABASE_SRC)/special/Makefile include $(PVDATABASE_SRC)/special/Makefile
include $(PVDATABASE_SRC)/support/Makefile
pvDatabase_LIBS += pvCopy
pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS) pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS) pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)

View File

@ -1,15 +1,27 @@
# This is a Makefile fragment, see ../Makefile TOP = ../..
include $(TOP)/configure/CONFIG
SRC_DIRS += $(PVDATABASE_SRC)/copy LIBRARY += pvCopy
SHRLIB_VERSION ?= $(EPICS_PVA_MAJOR_VERSION).$(EPICS_PVA_MINOR_VERSION).$(EPICS_PVA_MAINTENANCE_VERSION)
# needed for Windows
LIB_SYS_LIBS_WIN32 += netapi32 ws2_32
INC += pv/pvStructureCopy.h
INC += pv/pvPlugin.h INC += pv/pvPlugin.h
INC += pv/pvStructureCopy.h
INC += pv/pvArrayPlugin.h INC += pv/pvArrayPlugin.h
INC += pv/pvDeadbandPlugin.h INC += pv/pvDeadbandPlugin.h
INC += pv/pvTimestampPlugin.h INC += pv/pvTimestampPlugin.h
LIBSRCS += pvCopy.cpp
LIBSRCS += pvPlugin.cpp LIBSRCS += pvPlugin.cpp
LIBSRCS += pvCopy.cpp
LIBSRCS += pvArrayPlugin.cpp LIBSRCS += pvArrayPlugin.cpp
LIBSRCS += pvDeadbandPlugin.cpp LIBSRCS += pvDeadbandPlugin.cpp
LIBSRCS += pvTimestampPlugin.cpp LIBSRCS += pvTimestampPlugin.cpp
pvCopy_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
pvCopy_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES

View File

@ -6,10 +6,6 @@
#ifndef PVARRAYPLUGIN_H #ifndef PVARRAYPLUGIN_H
#define PVARRAYPLUGIN_H #define PVARRAYPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>
#include <pv/lock.h> #include <pv/lock.h>

View File

@ -6,9 +6,6 @@
#ifndef PVDEADBANDPLUGIN_H #ifndef PVDEADBANDPLUGIN_H
#define PVDEADBANDPLUGIN_H #define PVDEADBANDPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>

View File

@ -9,14 +9,10 @@
#ifndef PVPLUGIN_H #ifndef PVPLUGIN_H
#define PVPLUGIN_H #define PVPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>
#include <pv/lock.h> #include <pv/lock.h>
#include <pv/pvStructureCopy.h> #include <pv/bitSet.h>
#include <shareLib.h> #include <shareLib.h>
@ -26,6 +22,9 @@ class PVPlugin;
class PVFilter; class PVFilter;
class PVPluginRegistry; class PVPluginRegistry;
class PVCopy;
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr; typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr;
typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr; typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr;
typedef std::map<std::string,PVPluginPtr> PVPluginMap; typedef std::map<std::string,PVPluginPtr> PVPluginMap;

View File

@ -10,10 +10,6 @@
#ifndef PVSTRUCTURECOPY_H #ifndef PVSTRUCTURECOPY_H
#define PVSTRUCTURECOPY_H #define PVSTRUCTURECOPY_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
@ -245,7 +241,6 @@ private:
std::string *builder, std::string *builder,
CopyNodePtr const &node, CopyNodePtr const &node,
int indentLevel); int indentLevel);
friend class PVCopyMonitor;
}; };
}} }}

View File

@ -6,10 +6,6 @@
#ifndef PVTIMESTAMPPLUGIN_H #ifndef PVTIMESTAMPPLUGIN_H
#define PVTIMESTAMPPLUGIN_H #define PVTIMESTAMPPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>
#include <pv/lock.h> #include <pv/lock.h>
@ -60,7 +56,7 @@ public:
}; };
/** /**
* @brief A filter that sets a timeStamp to the current time. * @brief A filter that sets a timeStamp to/from the current field or pvCopy.
*/ */
class epicsShareClass PVTimestampFilter : public PVFilter class epicsShareClass PVTimestampFilter : public PVFilter
{ {

View File

@ -9,7 +9,7 @@
#include <pv/convert.h> #include <pv/convert.h>
#include <pv/pvSubArrayCopy.h> #include <pv/pvSubArrayCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvArrayPlugin.h> #include "pv/pvArrayPlugin.h"
using std::string; using std::string;
using std::size_t; using std::size_t;
@ -177,8 +177,8 @@ bool PVArrayFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bo
} else { } else {
for(long i=0; i<len; ++i) { for(long i=0; i<len; ++i) {
copy(*copyArray,indfrom,1,*masterArray,indto,1,1); copy(*copyArray,indfrom,1,*masterArray,indto,1,1);
indfrom += increment; indfrom += 1;
indto += 1; indto += increment;
} }
} }
return true; return true;

View File

@ -17,8 +17,8 @@
#include <pv/thread.h> #include <pv/thread.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvPlugin.h> #include "pv/pvPlugin.h"
#include <pv/pvStructureCopy.h> #include "pv/pvStructureCopy.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast; using std::tr1::dynamic_pointer_cast;

View File

@ -4,12 +4,15 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h> #include <pv/pvData.h>
#include <pv/bitSet.h> #include <pv/bitSet.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <pv/pvSubArrayCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvDeadbandPlugin.h> #include "pv/pvDeadbandPlugin.h"
using std::string; using std::string;
using std::size_t; using std::size_t;
@ -64,9 +67,9 @@ PVDeadbandFilterPtr PVDeadbandFilter::create(
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field); ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr(); if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr();
bool absolute = false; bool absolute = false;
if(requestValue.find("abs")>=0) { if(requestValue.find("abs")==0) {
absolute = true; absolute = true;
} else if(requestValue.find("rel")>=0) { } else if(requestValue.find("rel")==0) {
absolute = false; absolute = false;
} else { } else {
return PVDeadbandFilterPtr(); return PVDeadbandFilterPtr();

View File

@ -4,9 +4,13 @@
*/ */
#include <pv/pvData.h> #include <pv/pvData.h>
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/bitSet.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvStructureCopy.h> #include "pv/pvPlugin.h"
#include <pv/pvPlugin.h>
using namespace epics::pvData; using namespace epics::pvData;

View File

@ -3,14 +3,17 @@
* The License for this software can be found in the file LICENSE that is included with the distribution. * The License for this software can be found in the file LICENSE that is included with the distribution.
*/ */
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h> #include <pv/pvData.h>
#include <pv/bitSet.h> #include <pv/bitSet.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <pv/pvTimeStamp.h> #include <pv/pvTimeStamp.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvTimestampPlugin.h> #include "pv/pvPlugin.h"
#include <pv/pvStructureCopy.h> #include "pv/pvTimestampPlugin.h"
using std::string; using std::string;
using std::size_t; using std::size_t;

View File

@ -10,13 +10,19 @@
*/ */
#include <epicsGuard.h> #include <epicsGuard.h>
#define epicsExportSharedSymbols #include <list>
#include <pv/pvDatabase.h> #include <map>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvStructureCopy.h> #include <pv/pvStructureCopy.h>
#include <pv/pvPlugin.h>
#include <pv/pvArrayPlugin.h> #define epicsExportSharedSymbols
#include <pv/pvTimestampPlugin.h> #include "pv/pvDatabase.h"
#include <pv/pvDeadbandPlugin.h> #include "pv/pvPlugin.h"
#include "pv/pvArrayPlugin.h"
#include "pv/pvTimestampPlugin.h"
#include "pv/pvDeadbandPlugin.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;

View File

@ -8,13 +8,25 @@
* @author mrk * @author mrk
* @date 2012.11.21 * @date 2012.11.21
*/ */
#include <list>
#include <epicsGuard.h> #include <epicsGuard.h>
#include <epicsThread.h> #include <epicsThread.h>
#include <pv/status.h>
#define epicsExportSharedSymbols #include <pv/pvAccess.h>
#include <pv/pvDatabase.h> #include <pv/createRequest.h>
#include <pv/pvaVersion.h>
#include <pv/pvaVersionNum.h>
#include <pv/monitor.h>
#include <pv/convert.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
#include <pv/pvData.h>
#include <pv/rpcService.h>
#include <pv/pvTimeStamp.h>
#include <pv/pvStructureCopy.h> #include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
@ -101,20 +113,6 @@ PVRecord::~PVRecord()
void PVRecord::remove() void PVRecord::remove()
{ {
#ifdef XXX
{
epicsGuard<epics::pvData::Mutex> guard(mutex);
if(traceLevel>0) {
cout << "PVRecord::remove() " << recordName
<< " isDestroyed " << (isDestroyed ? "true" : "false")
<< endl;
}
if(isDestroyed) {
return;
}
isDestroyed = true;
}
#endif
PVDatabasePtr pvDatabase(PVDatabase::getMaster()); PVDatabasePtr pvDatabase(PVDatabase::getMaster());
if(pvDatabase) pvDatabase->removeRecord(shared_from_this()); if(pvDatabase) pvDatabase->removeRecord(shared_from_this());
pvTimeStamp.detach(); pvTimeStamp.detach();

View File

@ -11,11 +11,6 @@
#ifndef CHANNELPROVIDERLOCAL_H #ifndef CHANNELPROVIDERLOCAL_H
#define CHANNELPROVIDERLOCAL_H #define CHANNELPROVIDERLOCAL_H
#ifdef epicsExportSharedSymbols
# define channelProviderLocalEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
@ -28,16 +23,10 @@
#include <pv/pvAccess.h> #include <pv/pvAccess.h>
#include <pv/status.h> #include <pv/status.h>
#include <pv/serverContext.h> #include <pv/serverContext.h>
#include <pv/pvStructureCopy.h>
#include <pv/pvDatabase.h>
#ifdef channelProviderLocalEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef channelProviderLocalEpicsExportSharedSymbols
#endif
#include <shareLib.h> #include <shareLib.h>
#include <pv/pvDatabase.h>
#include <pv/pvStructureCopy.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {

90
src/pv/controlSupport.h Normal file
View File

@ -0,0 +1,90 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#ifndef CONTROLSUPPORT_H
#define CONTROLSUPPORT_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class ControlSupport;
typedef std::tr1::shared_ptr<ControlSupport> ControlSupportPtr;
/**
* @brief Base interface for a ControlSupport.
*
*/
class epicsShareClass ControlSupport :
PVSupport
{
public:
POINTER_DEFINITIONS(ControlSupport);
/**
* The Destructor.
*/
virtual ~ControlSupport();
/**
* @brief Connects to contol fields.
*
* @param pvValue The field to support.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVFieldPtr const & pvSupport);
/**
* @brief Honors control fields.
*
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual bool process();
/**
* @brief If implementing minSteps it sets isMinStep to false.
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual void reset();
/**
* @brief create a ControlSupport
*
* @param pvRecord - The pvRecord to which the support is attached.
* @return The new ControlSupport
*/
static ControlSupportPtr create(PVRecordPtr const & pvRecord);
/**
* @brief create a controlSupport required by ControlSupport
*
* @param scalarType The type for outputValue.
* @return The controlField introspection structure.
*/
static epics::pvData::StructureConstPtr controlField(epics::pvData::ScalarType scalarType);
private:
ControlSupport(PVRecordPtr const & pvRecord);
PVRecordPtr pvRecord;
epics::pvData::PVScalarPtr pvValue;
epics::pvData::PVStructurePtr pvControl;
epics::pvData::PVDoublePtr pvLimitLow;
epics::pvData::PVDoublePtr pvLimitHigh;
epics::pvData::PVDoublePtr pvMinStep;
epics::pvData::PVScalarPtr pvOutputValue;
double currentValue;
bool isMinStep;
};
}}
#endif /* CONTROLSUPPORT_H */

89
src/pv/processRecord.h Normal file
View File

@ -0,0 +1,89 @@
/* processRecord.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.07
*/
#ifndef PROCESSRECORD_H
#define PROCESSRECORD_H
#include <map>
#include <epicsThread.h>
#include <pv/event.h>
#include <pv/channelProviderLocal.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
class ProcessRecord;
typedef std::tr1::shared_ptr<ProcessRecord> ProcessRecordPtr;
/**
* @brief Process another record in the same database.
*
* A record to process another record
* It is meant to be used via a channelPutGet request.
* The argument has one field: recordName.
* The result has a field named status.
*/
class epicsShareClass ProcessRecord :
public PVRecord,
public epicsThreadRunable
{
public:
POINTER_DEFINITIONS(ProcessRecord);
/**
* Factory methods to create ProcessRecord.
* @param recordName The name for the ProcessRecord.
* @param delay Delay time to wait between process requests.
* @return A shared pointer to ProcessRecord.
*/
static ProcessRecordPtr create(
std::string const & recordName,double delay);
/**
* standard init method required by PVRecord
* @return true unless record name already exists.
*/
virtual bool init();
/**
* @brief Process the record specified by recordName.
*/
virtual void process();
/**
* @brief The run method for the thread.
*/
virtual void run();
/**
* @brief Start the thread
*/
void startThread();
/**
* @brief Stop the thread
*/
void stop();
private:
ProcessRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,double delay);
double delay;
EpicsThreadPtr thread;
epics::pvData::Event runStop;
epics::pvData::Event runReturn;
PVDatabasePtr pvDatabase;
PVRecordMap pvRecordMap;
epics::pvData::PVStringPtr pvCommand;
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVStringPtr pvResult;
epics::pvData::Mutex mutex;
};
}}
#endif /* PROCESSRECORD_H */

View File

@ -6,26 +6,15 @@
#ifndef PVDATABASE_H #ifndef PVDATABASE_H
#define PVDATABASE_H #define PVDATABASE_H
#ifdef epicsExportSharedSymbols
# define pvdatabaseEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <list> #include <list>
#include <map> #include <map>
#include <pv/pvData.h> #include <pv/pvData.h>
#include <pv/pvTimeStamp.h> #include <pv/pvTimeStamp.h>
#include <pv/rpcService.h> #include <pv/rpcService.h>
#include <pv/pvStructureCopy.h>
#ifdef pvdatabaseEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef pvdatabaseEpicsExportSharedSymbols
#endif
#include <shareLib.h> #include <shareLib.h>
#include <pv/pvStructureCopy.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {

78
src/pv/pvSupport.h Normal file
View File

@ -0,0 +1,78 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#ifndef PVSUPPORT_H
#define PVSUPPORT_H
#include <list>
#include <map>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class PVSupport;
typedef std::tr1::shared_ptr<PVSupport> PVSupportPtr;
/**
* @brief Base interface for a PVSupport.
*
*/
class epicsShareClass PVSupport
{
public:
POINTER_DEFINITIONS(PVSupport);
/**
* The Destructor.
*/
virtual ~PVSupport(){}
/**
* @brief Optional initialization method.
*
* Called after PVRecord is created but before record is installed into PVDatabase.
*
* @param pvValue The field to support.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVFieldPtr const & pvSupport) {return true;}
/**
* @brief Optional method for derived class.
*
* It is called before record is added to database.
*/
virtual void start() {}
/**
* @brief Virtual method for derived class.
*
* Called when record is processed.
* It is the method that implements support.
* It is called each time the record is processed.
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual bool process() = 0;
/**
* @brief Optional method for derived class.
*
*/
virtual void reset() {};
};
}}
#endif /* PVSUPPORT_H */

View File

@ -11,10 +11,10 @@
#ifndef REMOVERECORD_H #ifndef REMOVERECORD_H
#define REMOVERECORD_H #define REMOVERECORD_H
#include <shareLib.h>
#include <pv/channelProviderLocal.h> #include <pv/channelProviderLocal.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {

111
src/pv/scalarAlarmSupport.h Normal file
View File

@ -0,0 +1,111 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#ifndef SCALARALARMSUPPORT_H
#define SCALARALARMSUPPORT_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class ScalarAlarmSupport;
typedef std::tr1::shared_ptr<ScalarAlarmSupport> ScalarAlarmSupportPtr;
/**
* @brief Base interface for a ScalarAlarmSupport.
*
*/
class epicsShareClass ScalarAlarmSupport :
PVSupport
{
public:
POINTER_DEFINITIONS(ScalarAlarmSupport);
/**
* The Destructor.
*/
virtual ~ScalarAlarmSupport();
/**
* @brief Connects to contol fields.
*
* @param pvValue The field to support.
* @param pvAlarm The alarm field.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVStructurePtr const & pvAlarm,
epics::pvData::PVFieldPtr const & pvSupport);
/**
* @brief Honors scalarAlarm fields.
*
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual bool process();
/**
* @brief If implementing minSteps it sets isMinStep to false.
*
*/
virtual void reset();
/**
* @brief create a ScalarAlarm
*
* @param pvRecord - The pvRecord to which the support is attached.
* @return The new ScalarAlarm
*/
static ScalarAlarmSupportPtr create(PVRecordPtr const & pvRecord);
/**
* @brief create a scalarAlarm required by ScalarAlarm
*
* @return The scalarAlarmField introspection structure.
*/
static epics::pvData::StructureConstPtr scalarAlarmField();
private:
ScalarAlarmSupport(PVRecordPtr const & pvRecord);
enum {
range_Lolo = 0,
range_Low,
range_Normal,
range_High,
range_Hihi,
range_Invalid,
range_Undefined
} AlarmRange;
void setAlarm(
epics::pvData::PVStructurePtr const & pvAlarm,
int alarmRange);
PVRecordPtr pvRecord;
int prevAlarmRange;
epics::pvData::PVScalarPtr pvValue;
epics::pvData::PVStructurePtr pvAlarm;
epics::pvData::PVStructurePtr pvScalarAlarm;
epics::pvData::PVBooleanPtr pvActive;
epics::pvData::PVDoublePtr pvLowAlarmLimit;
epics::pvData::PVDoublePtr pvLowWarningLimit;
epics::pvData::PVDoublePtr pvHighWarningLimit;
epics::pvData::PVDoublePtr pvHighAlarmLimit;
epics::pvData::PVDoublePtr pvHysteresis;
double requestedValue;
double currentValue;
bool isHystersis;
};
}}
#endif /* SCALARALARMSUPPORT_H */

View File

@ -11,9 +11,10 @@
#ifndef TRACERECORD_H #ifndef TRACERECORD_H
#define TRACERECORD_H #define TRACERECORD_H
#include <pv/channelProviderLocal.h>
#include <shareLib.h> #include <shareLib.h>
#include <pv/channelProviderLocal.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {

View File

@ -13,12 +13,21 @@
#include <epicsGuard.h> #include <epicsGuard.h>
#include <epicsThread.h> #include <epicsThread.h>
#include <pv/pvData.h>
#include <pv/pvAccess.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h> #include <pv/timeStamp.h>
#include <pv/createRequest.h>
#include <pv/pvaVersion.h>
#include <pv/pvaVersionNum.h>
#include <pv/serverContext.h>
#include <pv/pvSubArrayCopy.h> #include <pv/pvSubArrayCopy.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include <pv/channelProviderLocal.h> #include "pv/channelProviderLocal.h"
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;

View File

@ -1,4 +1,4 @@
/* channelChannelProviderLocal.cpp */ /* channelProviderLocal.cpp */
/** /**
* Copyright - See the COPYRIGHT that is included with this distribution. * Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found * EPICS pvData is distributed subject to a Software License Agreement found
@ -10,13 +10,17 @@
*/ */
#include <epicsThread.h> #include <epicsThread.h>
#include <epicsExport.h>
#include <pv/serverContext.h> #include <pv/serverContext.h>
#include <pv/syncChannelFind.h> #include <pv/syncChannelFind.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include <pv/channelProviderLocal.h> #include "pv/channelProviderLocal.h"
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;

View File

@ -14,11 +14,17 @@
#include <epicsGuard.h> #include <epicsGuard.h>
#include <pv/thread.h> #include <pv/thread.h>
#include <pv/bitSetUtil.h> #include <pv/bitSetUtil.h>
#include <pv/pvData.h>
#include <pv/pvAccess.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/serverContext.h>
#include <pv/timeStamp.h> #include <pv/timeStamp.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include <pv/channelProviderLocal.h> #include "pv/channelProviderLocal.h"
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;

View File

@ -11,30 +11,15 @@
/* Author: Marty Kraimer */ /* Author: Marty Kraimer */
#include <cstddef> #include <epicsExport.h>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <cantProceed.h>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <iocsh.h> #include <iocsh.h>
#include <shareLib.h>
#include <epicsExit.h>
#include <pv/pvAccess.h> #include <pv/pvAccess.h>
#include <pv/serverContext.h> #include <pv/serverContext.h>
// this declared epicsExportSharedSymbols
#include <epicsExport.h>
#include <pv/channelProviderLocal.h> #define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using std::cout; using std::cout;
using std::endl; using std::endl;

View File

@ -4,3 +4,12 @@ SRC_DIRS += $(PVDATABASE_SRC)/special
LIBSRCS += traceRecord.cpp LIBSRCS += traceRecord.cpp
LIBSRCS += removeRecord.cpp LIBSRCS += removeRecord.cpp
LIBSRCS += processRecord.cpp
DBD += traceRecordRegister.dbd
DBD += removeRecordRegister.dbd
DBD += processRecordRegister.dbd
LIBSRCS += traceRecordRegister.cpp
LIBSRCS += removeRecordRegister.cpp
LIBSRCS += processRecordRegister.cpp

View File

@ -0,0 +1,167 @@
/* processRecord.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#include <map>
#include <epicsThread.h>
#include <pv/event.h>
#include <shareLib.h>
#include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <set>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/timeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/processRecord.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
ProcessRecordPtr ProcessRecord::create(
std::string const & recordName,double delay)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("command",pvString)->
add("recordName",pvString)->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
ProcessRecordPtr pvRecord(
new ProcessRecord(recordName,pvStructure,delay));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
void ProcessRecord::startThread()
{
thread = EpicsThreadPtr(new epicsThread(
*this,
"processRecord",
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityLow));
thread->start();
}
void ProcessRecord::stop()
{
runStop.signal();
runReturn.wait();
}
ProcessRecord::ProcessRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,double delay)
: PVRecord(recordName,pvStructure),
delay(delay),
pvDatabase(PVDatabase::getMaster())
{
}
bool ProcessRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvCommand = pvStructure->getSubField<PVString>("argument.command");
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
startThread();
return true;
}
void ProcessRecord::process()
{
string recordName = pvRecordName->get();
string command = pvCommand->get();
if(command.compare("add")==0) {
epicsGuard<epics::pvData::Mutex> guard(mutex);
std::map<std::string,PVRecordPtr>::iterator iter = pvRecordMap.find(recordName);
if(iter!=pvRecordMap.end()) {
pvResult->put(recordName + " already present");
return;
}
PVRecordPtr pvRecord = pvDatabase->findRecord(recordName);
if(!pvRecord) {
pvResult->put(recordName + " not in pvDatabase");
return;
}
pvRecordMap.insert(PVRecordMap::value_type(recordName,pvRecord));
pvResult->put("success");
return;
} else if(command.compare("remove")==0) {
epicsGuard<epics::pvData::Mutex> guard(mutex);
std::map<std::string,PVRecordPtr>::iterator iter = pvRecordMap.find(recordName);
if(iter==pvRecordMap.end()) {
pvResult->put(recordName + " not found");
return;
}
pvRecordMap.erase(iter);
pvResult->put("success");
return;
} else {
pvResult->put(command + " not a valid command: only add and remove are valid");
return;
}
}
void ProcessRecord::run()
{
while(true) {
if(runStop.tryWait()) {
runReturn.signal();
return;
}
if(delay>0.0) epicsThreadSleep(delay);
epicsGuard<epics::pvData::Mutex> guard(mutex);
PVRecordMap::iterator iter;
for(iter = pvRecordMap.begin(); iter!=pvRecordMap.end(); ++iter) {
PVRecordPtr pvRecord = (*iter).second;
pvRecord->lock();
pvRecord->beginGroupPut();
try {
pvRecord->process();
} catch (std::exception& ex) {
std::cout << "record " << pvRecord->getRecordName() << "exception " << ex.what() << "\n";
} catch (...) {
std::cout<< "record " << pvRecord->getRecordName() << " process exception\n";
}
pvRecord->endGroupPut();
pvRecord->unlock();
}
}
}
}}

View File

@ -0,0 +1,66 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2013.07.24
*/
/* Author: Marty Kraimer */
#include <epicsExport.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <pv/event.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/processRecord.h"
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
using namespace std;
static const iocshArg testArg0 = { "recordName", iocshArgString };
static const iocshArg testArg1 = { "delay", iocshArgDouble };
static const iocshArg *testArgs[] = {
&testArg0,&testArg1};
static const iocshFuncDef processRecordFuncDef = {"processRecordCreate", 2,testArgs};
static void processRecordCallFunc(const iocshArgBuf *args)
{
char *recordName = args[0].sval;
if(!recordName) {
throw std::runtime_error("processRecordCreate invalid number of arguments");
}
double delay = args[1].dval;
if(delay<0.0) delay = 1.0;
ProcessRecordPtr record = ProcessRecord::create(recordName,delay);
bool result = PVDatabase::getMaster()->addRecord(record);
if(!result) cout << "recordname" << " not added" << endl;
}
static void processRecordRegister(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&processRecordFuncDef, processRecordCallFunc);
}
}
extern "C" {
epicsExportRegistrar(processRecordRegister);
}

View File

@ -0,0 +1 @@
registrar("processRecordRegister")

View File

@ -8,9 +8,27 @@
* @author mrk * @author mrk
* @date 2013.04.18 * @date 2013.04.18
*/ */
#define epicsExportSharedSymbols
#include <pv/removeRecord.h> #include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <set>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/timeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/removeRecord.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;

View File

@ -0,0 +1,61 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2013.07.24
*/
/* Author: Marty Kraimer */
#include <epicsExport.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <pv/event.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/removeRecord.h"
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
using namespace std;
static const iocshArg testArg0 = { "recordName", iocshArgString };
static const iocshArg *testArgs[] = {
&testArg0};
static const iocshFuncDef removeRecordFuncDef = {"removeRecordCreate", 1,testArgs};
static void removeRecordCallFunc(const iocshArgBuf *args)
{
char *recordName = args[0].sval;
if(!recordName) {
throw std::runtime_error("removeRecordCreate invalid number of arguments");
}
RemoveRecordPtr record = RemoveRecord::create(recordName);
bool result = PVDatabase::getMaster()->addRecord(record);
if(!result) cout << "recordname" << " not added" << endl;
}
static void removeRecordRegister(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&removeRecordFuncDef, removeRecordCallFunc);
}
}
extern "C" {
epicsExportRegistrar(removeRecordRegister);
}

View File

@ -0,0 +1 @@
registrar("removeRecordRegister")

View File

@ -8,9 +8,27 @@
* @author mrk * @author mrk
* @date 2013.04.18 * @date 2013.04.18
*/ */
#define epicsExportSharedSymbols
#include <pv/traceRecord.h> #include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <set>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/timeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "pv/channelProviderLocal.h"
#include "pv/traceRecord.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;

View File

@ -0,0 +1,62 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2013.07.24
*/
/* Author: Marty Kraimer */
#include <epicsExport.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <pv/event.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/traceRecord.h"
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
using namespace std;
static const iocshArg testArg0 = { "recordName", iocshArgString };
static const iocshArg *testArgs[] = {
&testArg0};
static const iocshFuncDef traceRecordFuncDef = {"traceRecordCreate", 1,testArgs};
static void traceRecordCallFunc(const iocshArgBuf *args)
{
char *recordName = args[0].sval;
if(!recordName) {
throw std::runtime_error("traceRecordCreate invalid number of arguments");
}
TraceRecordPtr record = TraceRecord::create(recordName);
bool result = PVDatabase::getMaster()->addRecord(record);
if(!result) cout << "recordname" << " not added" << endl;
}
static void traceRecordRegister(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&traceRecordFuncDef, traceRecordCallFunc);
}
}
extern "C" {
epicsExportRegistrar(traceRecordRegister);
}

View File

@ -0,0 +1 @@
registrar("traceRecordRegister")

6
src/support/Makefile Normal file
View File

@ -0,0 +1,6 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATABASE_SRC)/support
LIBSRCS += controlSupport.cpp
LIBSRCS += scalarAlarmSupport.cpp

View File

@ -0,0 +1,137 @@
/* controlSupport.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#include <pv/convert.h>
#include <pv/standardField.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include <pv/pvSupport.h>
#include "pv/pvDatabase.h"
#include "pv/controlSupport.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
ControlSupport::~ControlSupport()
{
cout << "ControlSupport::~ControlSupport()\n";
}
epics::pvData::StructureConstPtr ControlSupport::controlField(ScalarType scalarType)
{
return FieldBuilder::begin()
->setId("control_t")
->add("limitLow", pvDouble)
->add("limitHigh", pvDouble)
->add("minStep", pvDouble)
->add("outputValue", scalarType)
->createStructure();
}
ControlSupportPtr ControlSupport::create(PVRecordPtr const & pvRecord)
{
ControlSupportPtr support(new ControlSupport(pvRecord));
return support;
}
ControlSupport::ControlSupport(PVRecordPtr const & pvRecord)
: pvRecord(pvRecord)
{}
bool ControlSupport::init(PVFieldPtr const & pv,PVFieldPtr const & pvsup)
{
if(pv) {
if(pv->getField()->getType()==epics::pvData::scalar) {
ScalarConstPtr s = static_pointer_cast<const Scalar>(pv->getField());
if(ScalarTypeFunc::isNumeric(s->getScalarType())) {
pvValue = static_pointer_cast<PVScalar>(pv);
}
}
}
if(!pvValue) {
cout << "ControlSupport for record " << pvRecord->getRecordName()
<< " failed because not numeric scalar\n";
return false;
}
pvControl = static_pointer_cast<PVStructure>(pvsup);
if(pvControl) {
pvLimitLow = pvControl->getSubField<PVDouble>("limitLow");
pvLimitHigh = pvControl->getSubField<PVDouble>("limitHigh");
pvMinStep = pvControl->getSubField<PVDouble>("minStep");
pvOutputValue = pvControl->getSubField<PVScalar>("outputValue");
}
if(!pvControl || !pvLimitLow || !pvLimitHigh || !pvMinStep || !pvOutputValue) {
cout << "ControlSupport for record " << pvRecord->getRecordName()
<< " failed because pvSupport not a valid control structure\n";
return false;
}
ConvertPtr convert = getConvert();
currentValue = convert->toDouble(pvValue);
isMinStep = false;
return true;
}
bool ControlSupport::process()
{
ConvertPtr convert = getConvert();
double value = convert->toDouble(pvValue);
if(!isMinStep && value==currentValue) return false;
double limitLow = pvLimitLow->get();
double limitHigh = pvLimitHigh->get();
double minStep = pvMinStep->get();
bool setValue = false;
if(limitHigh>limitLow) {
if(value>limitHigh) {value = limitHigh;setValue=true;}
if(value<limitLow) {value = limitLow;setValue=true;}
}
if(setValue) convert->fromDouble(pvValue,value);
double diff = value - currentValue;
double outputValue = value;
if(minStep>0.0) {
if(diff<0.0) {
outputValue = currentValue - minStep;
if(limitHigh>limitLow && outputValue<=limitLow) outputValue = limitLow;
isMinStep = true;
if(outputValue<value) {
outputValue = value;
isMinStep = false;
}
} else {
outputValue = currentValue + minStep;
if(limitHigh>limitLow && outputValue>=limitHigh) outputValue = limitHigh;
isMinStep = true;
if(outputValue>value) {
outputValue = value;
isMinStep = false;
}
}
}
if(outputValue==currentValue) return false;
currentValue = outputValue;
convert->fromDouble(pvOutputValue,outputValue);
return true;
}
void ControlSupport::reset()
{
isMinStep = false;
}
}}

View File

@ -0,0 +1,219 @@
/* scalarAlarmSupport.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#include <pv/convert.h>
#include <pv/standardField.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include <pv/pvSupport.h>
#include "pv/pvDatabase.h"
#include "pv/scalarAlarmSupport.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
ScalarAlarmSupport::~ScalarAlarmSupport()
{
cout << "ScalarAlarmSupport::~ScalarAlarmSupport()\n";
}
epics::pvData::StructureConstPtr ScalarAlarmSupport::scalarAlarmField()
{
return FieldBuilder::begin()
->setId("scalarAlarm_t")
->add("lowAlarmLimit", pvDouble)
->add("lowWarningLimit", pvDouble)
->add("highWarningLimit", pvDouble)
->add("highAlarmLimit", pvDouble)
->add("hysteresis", pvDouble)
->createStructure();
}
ScalarAlarmSupportPtr ScalarAlarmSupport::create(PVRecordPtr const & pvRecord)
{
ScalarAlarmSupportPtr support(new ScalarAlarmSupport(pvRecord));
return support;
}
ScalarAlarmSupport::ScalarAlarmSupport(PVRecordPtr const & pvRecord)
: pvRecord(pvRecord),
prevAlarmRange(range_Undefined)
{}
bool ScalarAlarmSupport::init(
PVFieldPtr const & pvval,
PVStructurePtr const & pvalarm,
PVFieldPtr const & pvsup)
{
if(pvval->getField()->getType()==epics::pvData::scalar) {
ScalarConstPtr s = static_pointer_cast<const Scalar>(pvval->getField());
if(ScalarTypeFunc::isNumeric(s->getScalarType())) {
pvValue = static_pointer_cast<PVScalar>(pvval);
}
}
if(!pvValue) {
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
<< " failed because not numeric scalar\n";
return false;
}
pvScalarAlarm = static_pointer_cast<PVStructure>(pvsup);
if(pvScalarAlarm) {
pvLowAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("lowAlarmLimit");
pvLowWarningLimit = pvScalarAlarm->getSubField<PVDouble>("lowWarningLimit");
pvHighWarningLimit = pvScalarAlarm->getSubField<PVDouble>("highWarningLimit");
pvHighAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("highAlarmLimit");
pvHysteresis = pvScalarAlarm->getSubField<PVDouble>("hysteresis");
}
if(!pvScalarAlarm
|| !pvLowAlarmLimit || !pvLowWarningLimit
|| !pvLowWarningLimit || !pvHighAlarmLimit
|| !pvHysteresis)
{
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
<< " failed because pvSupport not a valid scalarAlarm structure\n";
return false;
}
pvAlarm = pvalarm;
ConvertPtr convert = getConvert();
requestedValue = convert->toDouble(pvValue);
currentValue = requestedValue;
isHystersis = false;
setAlarm(pvAlarm,range_Undefined);
return true;
}
bool ScalarAlarmSupport::process()
{
ConvertPtr convert = getConvert();
double value = convert->toDouble(pvValue);
double lowAlarmLimit = pvLowAlarmLimit->get();
double lowWarningLimit = pvLowWarningLimit->get();
double highWarningLimit = pvHighWarningLimit->get();
double highAlarmLimit = pvHighAlarmLimit->get();
double hysteresis = pvHysteresis->get();
int alarmRange = range_Normal;
if(highAlarmLimit>lowAlarmLimit) {
if(value>=highAlarmLimit
||(prevAlarmRange==range_Hihi && value>=highAlarmLimit-hysteresis)) {
alarmRange = range_Hihi;
} else if(value<=lowAlarmLimit
||(prevAlarmRange==range_Lolo && value<=lowAlarmLimit+hysteresis)) {
alarmRange = range_Lolo;
}
}
if(alarmRange==range_Normal && (highWarningLimit>lowWarningLimit)) {
if(value>=highWarningLimit
||(prevAlarmRange==range_High && value>=highWarningLimit-hysteresis)) {
alarmRange = range_High;
} else if(value<=lowWarningLimit
||(prevAlarmRange==range_Low && value<=lowWarningLimit+hysteresis)) {
alarmRange = range_Low;
}
}
bool retValue = false;
if(alarmRange!=prevAlarmRange) {
setAlarm(pvAlarm,alarmRange);
retValue = true;
}
prevAlarmRange = alarmRange;
currentValue = value;
return retValue;
}
void ScalarAlarmSupport::reset()
{
isHystersis = false;
}
void ScalarAlarmSupport::setAlarm(
epics::pvData::PVStructurePtr const & pva,
int alarmRange)
{
Alarm alarm;
PVAlarm pvAlarm;
if(!pvAlarm.attach(pva)) throw std::logic_error("bad alarm field");
epics::pvData::AlarmStatus status(epics::pvData::noStatus);
epics::pvData::AlarmSeverity severity(epics::pvData::noAlarm);
string message;
switch (alarmRange) {
case range_Lolo :
{
severity = epics::pvData::majorAlarm;
status = epics::pvData::recordStatus;
message = "major low alarm";
break;
}
case range_Low :
{
severity = epics::pvData::minorAlarm;
status = epics::pvData::recordStatus;
message = "minor low alarm";
break;
}
case range_Normal :
{
break;
}
case range_High :
{
severity = epics::pvData::minorAlarm;
status = epics::pvData::recordStatus;
message = "minor high alarm";
break;
}
case range_Hihi :
{
severity = epics::pvData::majorAlarm;
status = epics::pvData::recordStatus;
message = "major high alarm";
break;
}
case range_Invalid :
{
severity = epics::pvData::invalidAlarm;
status = epics::pvData::recordStatus;
message = "invalid alarm";
break;
}
case range_Undefined :
{
severity = epics::pvData::undefinedAlarm;
status = epics::pvData::recordStatus;
message = "undefined alarm";
break;
}
default:
{
severity = epics::pvData::undefinedAlarm;
status = epics::pvData::recordStatus;
message = "bad alarm definition";
break;
}
}
alarm.setStatus(status);
alarm.setSeverity(severity);
alarm.setMessage(message);
pvAlarm.set(alarm);
}
}}

View File

@ -6,6 +6,7 @@ include $(TOP)/configure/CONFIG
PVDATABASE_TEST = $(TOP)/test PVDATABASE_TEST = $(TOP)/test
PROD_LIBS += pvDatabase PROD_LIBS += pvDatabase
PROD_LIBS += pvCopy
PROD_LIBS += $(EPICS_BASE_PVA_CORE_LIBS) PROD_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
PROD_LIBS += $(EPICS_BASE_IOC_LIBS) PROD_LIBS += $(EPICS_BASE_IOC_LIBS)