@ -1,3 +1,8 @@
|
||||
LATEST
|
||||
======
|
||||
|
||||
* pvCopy is now implemented in pvDatabaseCPP. The version in pvDatacPP can be deprecated.
|
||||
* plugin support is implemented.
|
||||
|
||||
EPICS V4 release 4.6
|
||||
====================
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<h2 class="nocount">Release 4.2-SNAPSHOT - 2016.07.14</h2>
|
||||
<h2 class="nocount">Master - 2018.09.18</h2>
|
||||
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
@ -66,9 +66,7 @@ The minimum that an extension must provide is a top level PVStructure and a proc
|
||||
<h2>Overview</h2>
|
||||
<p>
|
||||
pvDatabaseCPP is one of the components of
|
||||
<a href="http://epics-pvdata.sourceforge.net">
|
||||
EPICS Version 4
|
||||
</a>
|
||||
EPICS Version 7
|
||||
</p>
|
||||
<p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP
|
||||
</p>
|
||||
@ -78,7 +76,7 @@ It is intended for developers that want to use pvDatabaseCPP.
|
||||
<h2>Developer Guide</h2>
|
||||
<p>A guide for developers is available at
|
||||
<a
|
||||
href="http://epics-pvdata.sourceforge.net/informative/developerGuide/developerGuide.html">
|
||||
href="https://mrkraimer.github.io/website/developerGuide/developerGuide.html">
|
||||
developerGuide
|
||||
</a>
|
||||
</p>
|
||||
@ -87,6 +85,18 @@ Some understanding of the components and how they are related is necessary in or
|
||||
develop code that uses pvDatabaseCPP.
|
||||
In particular read everything related to pvDatabase.
|
||||
</p>
|
||||
<p>pvDatabase has plugin support, which is implemented in <b>pvCopy</b>.
|
||||
<b>pvCopy</b> was originally implemented in <b>pvDataCPP</b>,
|
||||
but pvDatabaseCPP now implemnents its own version and adds plugin support.
|
||||
</p>
|
||||
<p>
|
||||
See
|
||||
<a
|
||||
href="https://mrkraimer.github.io/website/pvRequest/pvRequest.html">
|
||||
pvRequest
|
||||
</a>
|
||||
for details.
|
||||
</p>
|
||||
<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.
|
||||
</p>
|
||||
@ -169,7 +179,7 @@ provided by iocCore.
|
||||
The following provide EPICS V4 shell commands:</p>
|
||||
<pre>
|
||||
pvAccessCPP
|
||||
pvaSrv
|
||||
qsrv
|
||||
pvDatabaseCPP
|
||||
</pre>
|
||||
|
||||
|
@ -18,6 +18,7 @@ INC += pv/removeRecord.h
|
||||
include $(PVDATABASE_SRC)/database/Makefile
|
||||
include $(PVDATABASE_SRC)/pvAccess/Makefile
|
||||
include $(PVDATABASE_SRC)/special/Makefile
|
||||
include $(PVDATABASE_SRC)/copy/Makefile
|
||||
|
||||
pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
|
||||
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
15
src/copy/Makefile
Normal file
15
src/copy/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
# This is a Makefile fragment, see ../Makefile
|
||||
|
||||
SRC_DIRS += $(PVDATABASE_SRC)/copy
|
||||
|
||||
INC += pv/pvCopy.h
|
||||
INC += pv/pvPlugin.h
|
||||
INC += pv/pvArrayPlugin.h
|
||||
INC += pv/pvDeadbandPlugin.h
|
||||
INC += pv/pvTimestampPlugin.h
|
||||
|
||||
LIBSRCS += pvCopy.cpp
|
||||
LIBSRCS += pvPlugin.cpp
|
||||
LIBSRCS += pvArrayPlugin.cpp
|
||||
LIBSRCS += pvDeadbandPlugin.cpp
|
||||
LIBSRCS += pvTimestampPlugin.cpp
|
100
src/copy/pv/pvArrayPlugin.h
Normal file
100
src/copy/pv/pvArrayPlugin.h
Normal file
@ -0,0 +1,100 @@
|
||||
/* pvArrayPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#ifndef PVARRAYPLUGIN_H
|
||||
#define PVARRAYPLUGIN_H
|
||||
|
||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvPlugin.h>
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
class PVArrayPlugin;
|
||||
class PVArrayFilter;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVArrayPlugin> PVArrayPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVArrayFilter> PVArrayFilterPtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A plugin for a filter that gets a sub array from a PVScalarArray.
|
||||
*
|
||||
* @author mrk
|
||||
* @since date 2017.02.23
|
||||
*/
|
||||
class PVArrayPlugin : public PVPlugin
|
||||
{
|
||||
private:
|
||||
PVArrayPlugin();
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVArrayPlugin);
|
||||
virtual ~PVArrayPlugin();
|
||||
/**
|
||||
* Factory
|
||||
*/
|
||||
static void create();
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached
|
||||
* @return The PVFilter.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A filter that gets a sub array from a PVScalarArray.
|
||||
*/
|
||||
class PVArrayFilter : public PVFilter
|
||||
{
|
||||
private:
|
||||
long start;
|
||||
long increment;
|
||||
long end;
|
||||
epics::pvData::PVScalarArrayPtr masterArray;
|
||||
|
||||
PVArrayFilter(long start,long increment,long end,const epics::pvData::PVScalarArrayPtr & masterArray);
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVArrayFilter);
|
||||
virtual ~PVArrayFilter();
|
||||
/**
|
||||
* Create a PVArrayFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
static PVArrayFilterPtr create(const std::string & requestValue,const epics::pvData::PVFieldPtr & master);
|
||||
/**
|
||||
* Perform a filter operation
|
||||
* @param pvCopy The field in the copy PVStructure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return if filter (modified, did not modify) destination.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
|
||||
/**
|
||||
* Get the filter name.
|
||||
* @return The name.
|
||||
*/
|
||||
std::string getName();
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* PVARRAYPLUGIN_H */
|
||||
|
238
src/copy/pv/pvCopy.h
Normal file
238
src/copy/pv/pvCopy.h
Normal file
@ -0,0 +1,238 @@
|
||||
/* pvCopy.h */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#ifndef PVCOPY_H
|
||||
#define PVCOPY_H
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
class PVCopyTraverseMasterCallback;
|
||||
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr;
|
||||
|
||||
/**
|
||||
* @brief Callback for traversing master structure
|
||||
*
|
||||
* Must be implemented by code that creates pvCopy.
|
||||
*/
|
||||
class epicsShareClass PVCopyTraverseMasterCallback
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVCopyTraverseMasterCallback);
|
||||
virtual ~PVCopyTraverseMasterCallback() {}
|
||||
/**
|
||||
* Called once for each field in master.
|
||||
* @param pvField The field in master.
|
||||
*/
|
||||
virtual void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField) = 0;
|
||||
};
|
||||
|
||||
|
||||
class PVCopy;
|
||||
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
|
||||
|
||||
struct CopyNode;
|
||||
typedef std::tr1::shared_ptr<CopyNode> CopyNodePtr;
|
||||
|
||||
struct CopyStructureNode;
|
||||
typedef std::tr1::shared_ptr<CopyStructureNode> CopyStructureNodePtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Support for subset of fields in a pvStructure.
|
||||
*
|
||||
* Class that manages one or more PVStructures that holds an arbitrary subset of the fields
|
||||
* in another PVStructure called master.
|
||||
*/
|
||||
class epicsShareClass PVCopy :
|
||||
public std::tr1::enable_shared_from_this<PVCopy>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVCopy);
|
||||
/**
|
||||
* Create a new pvCopy
|
||||
* @param pvMaster The top-level structure for which a copy of
|
||||
* an arbitrary subset of the fields in master will be created and managed.
|
||||
* @param pvRequest Selects the set of subfields desired and options for each field.
|
||||
* @param structureName The name for the top level of any PVStructure created.
|
||||
*/
|
||||
static PVCopyPtr create(
|
||||
epics::pvData::PVStructurePtr const &pvMaster,
|
||||
epics::pvData::PVStructurePtr const &pvRequest,
|
||||
std::string const & structureName);
|
||||
virtual ~PVCopy(){}
|
||||
virtual void destroy();
|
||||
/**
|
||||
* Get the top-level structure of master
|
||||
* @returns The master top-level structure.
|
||||
* This should not be modified.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr getPVMaster();
|
||||
/**
|
||||
* Traverse all the fields in master.
|
||||
* @param callback This is called for each field on master.
|
||||
*/
|
||||
void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
|
||||
/**
|
||||
* Get the introspection interface for a PVStructure for e copy.
|
||||
*/
|
||||
epics::pvData::StructureConstPtr getStructure();
|
||||
/**
|
||||
* Create a copy instance. Monitors keep a queue of monitor elements.
|
||||
* Since each element needs a PVStructure, multiple top-level structures will be created.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr createPVStructure();
|
||||
/**
|
||||
* Given a field in pvMaster. return the offset in copy for the same field.
|
||||
* A value of std::string::npos means that the copy does not have this field.
|
||||
* @param masterPVField The field in master.
|
||||
*/
|
||||
std::size_t getCopyOffset(epics::pvData::PVFieldPtr const &masterPVField);
|
||||
/**
|
||||
* Given a field in pvMaster. return the offset in copy for the same field.
|
||||
* A value of std::string::npos means that the copy does not have this field.
|
||||
* @param masterPVStructure A structure in master that has masterPVField.
|
||||
* @param masterPVField The field in master.
|
||||
*/
|
||||
std::size_t getCopyOffset(
|
||||
epics::pvData::PVStructurePtr const &masterPVStructure,
|
||||
epics::pvData::PVFieldPtr const &masterPVField);
|
||||
/**
|
||||
* Given an offset in the copy get the corresponding field in pvMaster.
|
||||
* @param structureOffset The offset in the copy.
|
||||
*/
|
||||
epics::pvData::PVFieldPtr getMasterPVField(std::size_t structureOffset);
|
||||
/**
|
||||
* Initialize the fields in copyPVStructure by giving each field
|
||||
* the value from the corresponding field in pvMaster.
|
||||
* bitSet will be set to show that all fields are changed.
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
*/
|
||||
void initCopy(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* Set all fields in copyPVStructure to the value of the corresponding field in pvMaster.
|
||||
* Each field that is changed has it's corresponding bit set in bitSet.
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @returns (false,true) if client (should not,should) receive changes.
|
||||
*/
|
||||
bool updateCopySetBitSet(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* For each set bit in bitSet
|
||||
* set the field in copyPVStructure to the value of the corresponding field in pvMaster.
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @returns (false,true) if client (should not,should) receive changes.
|
||||
*/
|
||||
bool updateCopyFromBitSet(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* For each set bit in bitSet
|
||||
* set the field in pvMaster to the value of the corresponding field in copyPVStructure
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
*/
|
||||
void updateMaster(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* Get the options for the field at the specified offset.
|
||||
* @param fieldOffset the offset in copy.
|
||||
* @returns A NULL is returned if no options were specified for the field.
|
||||
* If options were specified,PVStructurePtr is a structures
|
||||
* with a set of PVString subfields that specify name,value pairs.s
|
||||
* name is the subField name and value is the subField value.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr getOptions(std::size_t fieldOffset);
|
||||
/**
|
||||
* For debugging.
|
||||
*/
|
||||
std::string dump();
|
||||
private:
|
||||
|
||||
PVCopyPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
epics::pvData::PVStructurePtr pvMaster;
|
||||
epics::pvData::StructureConstPtr structure;
|
||||
CopyNodePtr headNode;
|
||||
epics::pvData::PVStructurePtr cacheInitStructure;
|
||||
epics::pvData::BitSetPtr ignorechangeBitSet;
|
||||
|
||||
void traverseMaster(
|
||||
CopyNodePtr const &node,
|
||||
PVCopyTraverseMasterCallbackPtr const & callback);
|
||||
void updateCopySetBitSet(
|
||||
epics::pvData::PVFieldPtr const &pvCopy,
|
||||
epics::pvData::PVFieldPtr const &pvMaster,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateCopySetBitSet(
|
||||
epics::pvData::PVFieldPtr const &pvCopy,
|
||||
CopyNodePtr const &node,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateCopyFromBitSet(
|
||||
epics::pvData::PVFieldPtr const &pvCopy,
|
||||
CopyNodePtr const &node,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateMaster(
|
||||
epics::pvData::PVFieldPtr const &pvCopy,
|
||||
CopyNodePtr const &node,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
|
||||
PVCopy(epics::pvData::PVStructurePtr const &pvMaster);
|
||||
bool init(epics::pvData::PVStructurePtr const &pvRequest);
|
||||
epics::pvData::StructureConstPtr createStructure(
|
||||
epics::pvData::PVStructurePtr const &pvMaster,
|
||||
epics::pvData::PVStructurePtr const &pvFromRequest);
|
||||
CopyNodePtr createStructureNodes(
|
||||
epics::pvData::PVStructurePtr const &pvMasterStructure,
|
||||
epics::pvData::PVStructurePtr const &pvFromRequest,
|
||||
epics::pvData::PVStructurePtr const &pvFromField);
|
||||
void initPlugin(
|
||||
CopyNodePtr const & node,
|
||||
epics::pvData::PVStructurePtr const & pvOptions,
|
||||
epics::pvData::PVFieldPtr const & pvMasterField);
|
||||
void traverseMasterInitPlugin();
|
||||
void traverseMasterInitPlugin(CopyNodePtr const & node);
|
||||
|
||||
CopyNodePtr getCopyOffset(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
epics::pvData::PVFieldPtr const &masterPVField);
|
||||
bool checkIgnore(
|
||||
epics::pvData::PVStructurePtr const & copyPVStructure,
|
||||
epics::pvData::BitSetPtr const & bitSet);
|
||||
void setIgnore(CopyNodePtr const & node);
|
||||
CopyNodePtr getMasterNode(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
std::size_t structureOffset);
|
||||
void dump(
|
||||
std::string *builder,
|
||||
CopyNodePtr const &node,
|
||||
int indentLevel);
|
||||
friend class PVCopyMonitor;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* PVCOPY_H */
|
104
src/copy/pv/pvDeadbandPlugin.h
Normal file
104
src/copy/pv/pvDeadbandPlugin.h
Normal file
@ -0,0 +1,104 @@
|
||||
/* pvDeadbandPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#ifndef PVDEADBANDPLUGIN_H
|
||||
#define PVDEADBANDPLUGIN_H
|
||||
|
||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvPlugin.h>
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
class PVDeadbandPlugin;
|
||||
class PVDeadbandFilter;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVDeadbandPlugin> PVDeadbandPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVDeadbandFilter> PVDeadbandFilterPtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A plugin for a filter that gets a sub array from a PVScalarDeadband.
|
||||
*
|
||||
* @author mrk
|
||||
* @since date 2017.02.23
|
||||
*/
|
||||
class PVDeadbandPlugin : public PVPlugin
|
||||
{
|
||||
private:
|
||||
PVDeadbandPlugin();
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDeadbandPlugin);
|
||||
virtual ~PVDeadbandPlugin();
|
||||
/**
|
||||
* Factory
|
||||
*/
|
||||
static void create();
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached
|
||||
* @return The PVFilter.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A Plugin for a filter that gets a sub array from a PVScalarDeadband.
|
||||
*/
|
||||
class PVDeadbandFilter : public PVFilter
|
||||
{
|
||||
private:
|
||||
bool absolute;
|
||||
double deadband;
|
||||
epics::pvData::PVScalarPtr master;
|
||||
bool firstTime;
|
||||
double lastReportedValue;
|
||||
|
||||
|
||||
PVDeadbandFilter(bool absolute,double deadband,epics::pvData::PVScalarPtr const & master);
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDeadbandFilter);
|
||||
virtual ~PVDeadbandFilter();
|
||||
/**
|
||||
* Create a PVDeadbandFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
static PVDeadbandFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
/**
|
||||
* Perform a filter operation
|
||||
* @param pvCopy The field in the copy PVStructure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return if filter (modified, did not modify) destination.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
|
||||
/**
|
||||
* Get the filter name.
|
||||
* @return The name.
|
||||
*/
|
||||
std::string getName();
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* PVDEADBANDPLUGIN_H */
|
||||
|
108
src/copy/pv/pvPlugin.h
Normal file
108
src/copy/pv/pvPlugin.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* pvPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @date 2017.03
|
||||
*/
|
||||
#ifndef PVPLUGIN_H
|
||||
#define PVPLUGIN_H
|
||||
|
||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvCopy.h>
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
class PVPlugin;
|
||||
class PVFilter;
|
||||
class PVPluginRegistry;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr;
|
||||
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A filter plugin that attaches to a field of a PVStrcture.
|
||||
*
|
||||
* PVCopy looks for plugins defined in pvRequest and calls the filter when a pvCopy is updated.
|
||||
* @author mrk
|
||||
* @since 2017.03.17
|
||||
*
|
||||
* Interface for a filter plugin for PVCopy.
|
||||
*
|
||||
*/
|
||||
|
||||
class epicsShareClass PVPlugin {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVPlugin);
|
||||
virtual ~PVPlugin() {}
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A Filter that is called when a copy PVStructure is being updated.
|
||||
*
|
||||
* This interface defines a filter to update a copy of a field from a master PVStructure.
|
||||
* of the data in the master.
|
||||
*/
|
||||
class epicsShareClass PVFilter {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVFilter);
|
||||
virtual ~PVFilter() {}
|
||||
/**
|
||||
* Update copy or master.
|
||||
* @param copy The data for copy.
|
||||
* @param bitSet The BitSet for copy.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return (true,false) if filter modified destination.
|
||||
*/
|
||||
virtual bool filter(const epics::pvData::PVFieldPtr & copy,const epics::pvData::BitSetPtr & bitSet,bool toCopy) = 0;
|
||||
/**
|
||||
* Get the filter name.
|
||||
* This is the name part of a request name=value pair.
|
||||
* @return The name.
|
||||
*/
|
||||
virtual std::string getName() = 0;
|
||||
};
|
||||
/**
|
||||
* @brief A registry for filter plugins for PVCopy.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass PVPluginRegistry {
|
||||
public:
|
||||
/**
|
||||
* Register a plugin.
|
||||
* @param name The name that appears in [name=value] of a field request option.
|
||||
* @param pvPlugin The implementation for the plugin.
|
||||
*/
|
||||
static void registerPlugin(const std::string & name,const PVPluginPtr & pvPlugin);
|
||||
/**
|
||||
* Find a plugin.
|
||||
* @param name The name that appears in [name=value] of a field request option.
|
||||
* @return The plugin implementation or null if no pluging by that name has been registered.
|
||||
*/
|
||||
static PVPluginPtr find(const std::string & name);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* PVPLUGIN_H */
|
103
src/copy/pv/pvTimestampPlugin.h
Normal file
103
src/copy/pv/pvTimestampPlugin.h
Normal file
@ -0,0 +1,103 @@
|
||||
/* pvTimeStampPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#ifndef PVTIMESTAMPPLUGIN_H
|
||||
#define PVTIMESTAMPPLUGIN_H
|
||||
|
||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvPlugin.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
class PVTimestampPlugin;
|
||||
class PVTimestampFilter;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVTimestampPlugin> PVTimestampPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVTimestampFilter> PVTimestampFilterPtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A plugin for a filter that sets a timeStamp to the current time.
|
||||
*
|
||||
* @author mrk
|
||||
* @since date 2017.03.24
|
||||
*/
|
||||
class PVTimestampPlugin : public PVPlugin
|
||||
{
|
||||
private:
|
||||
PVTimestampPlugin();
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVTimestampPlugin);
|
||||
virtual ~PVTimestampPlugin();
|
||||
/**
|
||||
* Factory
|
||||
*/
|
||||
static void create();
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached
|
||||
* @return The PVFilter.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A filter that sets a timeStamp to the current time.
|
||||
*/
|
||||
class PVTimestampFilter : public PVFilter
|
||||
{
|
||||
private:
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
bool current;
|
||||
bool copy;
|
||||
epics::pvData::PVFieldPtr master;
|
||||
|
||||
|
||||
PVTimestampFilter(bool current,bool copy,epics::pvData::PVFieldPtr const & pvField);
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVTimestampFilter);
|
||||
virtual ~PVTimestampFilter();
|
||||
/**
|
||||
* Create a PVTimestampFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
static PVTimestampFilterPtr create(const std::string & requestValue,const epics::pvData::PVFieldPtr & master);
|
||||
/**
|
||||
* Perform a filter operation
|
||||
* @param pvCopy The field in the copy PVStructure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return if filter (modified, did not modify) destination.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
|
||||
/**
|
||||
* Get the filter name.
|
||||
* @return The name.
|
||||
*/
|
||||
std::string getName();
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* PVTIMESTAMPPLUGIN_H */
|
||||
|
189
src/copy/pvArrayPlugin.cpp
Normal file
189
src/copy/pvArrayPlugin.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
/* pvArrayPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/pvSubArrayCopy.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvArrayPlugin.h>
|
||||
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
static std::string name("array");
|
||||
|
||||
PVArrayPlugin::PVArrayPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
PVArrayPlugin::~PVArrayPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void PVArrayPlugin::create()
|
||||
{
|
||||
PVArrayPluginPtr pvPlugin = PVArrayPluginPtr(new PVArrayPlugin());
|
||||
PVPluginRegistry::registerPlugin(name,pvPlugin);
|
||||
}
|
||||
|
||||
PVFilterPtr PVArrayPlugin::create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
return PVArrayFilter::create(requestValue,master);
|
||||
}
|
||||
|
||||
PVArrayFilter::~PVArrayFilter()
|
||||
{
|
||||
}
|
||||
|
||||
static vector<string> split(string const & colonSeparatedList) {
|
||||
string::size_type numValues = 1;
|
||||
string::size_type index=0;
|
||||
while(true) {
|
||||
string::size_type pos = colonSeparatedList.find(':',index);
|
||||
if(pos==string::npos) break;
|
||||
numValues++;
|
||||
index = pos +1;
|
||||
}
|
||||
vector<string> valueList(numValues,"");
|
||||
index=0;
|
||||
for(size_t i=0; i<numValues; i++) {
|
||||
size_t pos = colonSeparatedList.find(':',index);
|
||||
string value = colonSeparatedList.substr(index,pos-index);
|
||||
valueList[i] = value;
|
||||
index = pos +1;
|
||||
}
|
||||
return valueList;
|
||||
}
|
||||
|
||||
PVArrayFilterPtr PVArrayFilter::create(
|
||||
const std::string & requestValue,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
Type type = master->getField()->getType();
|
||||
if(type!=scalarArray) {
|
||||
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
||||
return filter;
|
||||
}
|
||||
long start =0;
|
||||
long increment =1;
|
||||
long end = -1;
|
||||
vector<string> values(split(requestValue));
|
||||
long num = values.size();
|
||||
bool ok = true;
|
||||
string value;
|
||||
if(num==1) {
|
||||
value = values[0];
|
||||
start = strtol(value.c_str(),0,10);
|
||||
} else if(num==2) {
|
||||
value = values[0];
|
||||
start = strtol(value.c_str(),0,10);
|
||||
value = values[1];
|
||||
end = strtol(value.c_str(),0,10);
|
||||
} else if(num==3) {
|
||||
value = values[0];
|
||||
start = strtol(value.c_str(),0,10);
|
||||
value = values[1];
|
||||
increment = strtol(value.c_str(),0,10);
|
||||
value = values[2];
|
||||
end = strtol(value.c_str(),0,10);
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
if(!ok) {
|
||||
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
||||
return filter;
|
||||
}
|
||||
PVArrayFilterPtr filter =
|
||||
PVArrayFilterPtr(
|
||||
new PVArrayFilter(
|
||||
start,increment,end,static_pointer_cast<PVScalarArray>(master)));
|
||||
return filter;
|
||||
}
|
||||
|
||||
PVArrayFilter::PVArrayFilter(long start,long increment,long end,const PVScalarArrayPtr & masterArray)
|
||||
: start(start),
|
||||
increment(increment),
|
||||
end(end),
|
||||
masterArray(masterArray)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PVArrayFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
||||
{
|
||||
PVScalarArrayPtr copyArray = static_pointer_cast<PVScalarArray>(pvCopy);
|
||||
long len = 0;
|
||||
long start = this->start;
|
||||
long end = this->end;
|
||||
long no_elements = masterArray->getLength();
|
||||
if(start<0) {
|
||||
start = no_elements+start;
|
||||
if(start<0) start = 0;
|
||||
}
|
||||
if (end < 0) {
|
||||
end = no_elements + end;
|
||||
if (end < 0) end = 0;
|
||||
|
||||
}
|
||||
if(toCopy) {
|
||||
if (end >= no_elements) end = no_elements - 1;
|
||||
if (end - start >= 0) len = 1 + (end - start) / increment;
|
||||
if(len<=0 || start>=no_elements) {
|
||||
copyArray->setLength(0);
|
||||
return true;
|
||||
}
|
||||
long indfrom = start;
|
||||
long indto = 0;
|
||||
copyArray->setCapacity(len);
|
||||
if(increment==1) {
|
||||
copy(*masterArray,indfrom,1,*copyArray,indto,1,len);
|
||||
} else {
|
||||
for(long i=0; i<len; ++i) {
|
||||
copy(*masterArray,indfrom,1,*copyArray,indto,1,1);
|
||||
indfrom += increment;
|
||||
indto += 1;
|
||||
}
|
||||
}
|
||||
copyArray->setLength(len);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
return true;
|
||||
}
|
||||
if (end - start >= 0) len = 1 + (end - start) / increment;
|
||||
if(len<=0) return true;
|
||||
if(no_elements<=end) masterArray->setLength(end+1);
|
||||
long indfrom = 0;
|
||||
long indto = start;
|
||||
if(increment==1) {
|
||||
copy(*copyArray,indfrom,1,*masterArray,indto,1,len);
|
||||
} else {
|
||||
for(long i=0; i<len; ++i) {
|
||||
copy(*copyArray,indfrom,1,*masterArray,indto,1,1);
|
||||
indfrom += increment;
|
||||
indto += 1;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string PVArrayFilter::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
}}
|
||||
|
701
src/copy/pvCopy.cpp
Normal file
701
src/copy/pvCopy.cpp
Normal file
@ -0,0 +1,701 @@
|
||||
/* pvCopy.cpp */
|
||||
/*
|
||||
* License terms for this software can be found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/thread.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvArrayPlugin.h>
|
||||
#include <pv/pvTimestampPlugin.h>
|
||||
#include <pv/pvDeadbandPlugin.h>
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
/**
|
||||
* Convenience method for implementing dump.
|
||||
* It generates a newline and inserts blanks at the beginning of the newline.
|
||||
* @param builder The std::string * being constructed.
|
||||
* @param indentLevel Indent level, Each level is four spaces.
|
||||
*/
|
||||
static void newLine(string *buffer, int indentLevel)
|
||||
{
|
||||
*buffer += "\n";
|
||||
*buffer += string(indentLevel*4, ' ');
|
||||
}
|
||||
|
||||
static PVCopyPtr NULLPVCopy;
|
||||
static StructureConstPtr NULLStructure;
|
||||
static PVStructurePtr NULLPVStructure;
|
||||
|
||||
struct CopyNode {
|
||||
CopyNode()
|
||||
: isStructure(false),
|
||||
structureOffset(0),
|
||||
nfields(0)
|
||||
{}
|
||||
PVFieldPtr masterPVField;
|
||||
bool isStructure;
|
||||
size_t structureOffset; // In the copy
|
||||
size_t nfields;
|
||||
PVStructurePtr options;
|
||||
vector<PVFilterPtr> pvFilters;
|
||||
};
|
||||
|
||||
static CopyNodePtr NULLCopyNode;
|
||||
|
||||
typedef std::vector<CopyNodePtr> CopyNodePtrArray;
|
||||
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
|
||||
|
||||
struct CopyStructureNode : public CopyNode {
|
||||
CopyNodePtrArrayPtr nodes;
|
||||
};
|
||||
|
||||
PVCopyPtr PVCopy::create(
|
||||
PVStructurePtr const &pvMaster,
|
||||
PVStructurePtr const &pvRequest,
|
||||
string const & structureName)
|
||||
{
|
||||
static bool firstTime = true;
|
||||
if(firstTime) {
|
||||
firstTime = false;
|
||||
PVArrayPlugin::create();
|
||||
PVTimestampPlugin::create();
|
||||
PVDeadbandPlugin::create();
|
||||
}
|
||||
PVStructurePtr pvStructure(pvRequest);
|
||||
if(structureName.size()>0) {
|
||||
if(pvStructure->getStructure()->getNumberFields()>0) {
|
||||
pvStructure = pvRequest->getSubField<PVStructure>(structureName);
|
||||
if(!pvStructure) return NULLPVCopy;
|
||||
}
|
||||
} else if(pvRequest->getSubField<PVStructure>("field")) {
|
||||
pvStructure = pvRequest->getSubField<PVStructure>("field");
|
||||
}
|
||||
PVCopyPtr pvCopy = PVCopyPtr(new PVCopy(pvMaster));
|
||||
bool result = pvCopy->init(pvStructure);
|
||||
if(!result) return PVCopyPtr();
|
||||
pvCopy->traverseMasterInitPlugin();
|
||||
//cout << pvCopy->dump() << endl;
|
||||
return pvCopy;
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::getPVMaster()
|
||||
{
|
||||
return pvMaster;
|
||||
}
|
||||
|
||||
void PVCopy::traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback)
|
||||
{
|
||||
traverseMaster(headNode,callback);
|
||||
}
|
||||
|
||||
StructureConstPtr PVCopy::getStructure()
|
||||
{
|
||||
return structure;
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::createPVStructure()
|
||||
{
|
||||
if(cacheInitStructure) {
|
||||
PVStructurePtr save = cacheInitStructure;
|
||||
cacheInitStructure.reset();
|
||||
return save;
|
||||
}
|
||||
PVStructurePtr pvStructure =
|
||||
getPVDataCreate()->createPVStructure(structure);
|
||||
return pvStructure;
|
||||
}
|
||||
|
||||
|
||||
size_t PVCopy::getCopyOffset(PVFieldPtr const &masterPVField)
|
||||
{
|
||||
if(!headNode->isStructure) {
|
||||
CopyNodePtr node = static_pointer_cast<CopyNode>(headNode);
|
||||
if((node->masterPVField.get())==masterPVField.get()) {
|
||||
return headNode->structureOffset;
|
||||
}
|
||||
PVStructure * parent = masterPVField->getParent();
|
||||
size_t offsetParent = parent->getFieldOffset();
|
||||
size_t off = masterPVField->getFieldOffset();
|
||||
size_t offdiff = off -offsetParent;
|
||||
if(offdiff<node->nfields) return headNode->structureOffset + offdiff;
|
||||
return string::npos;
|
||||
}
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(headNode);
|
||||
CopyNodePtr node = getCopyOffset(structNode,masterPVField);
|
||||
if(node) return node->structureOffset;
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
size_t PVCopy::getCopyOffset(
|
||||
PVStructurePtr const &masterPVStructure,
|
||||
PVFieldPtr const &masterPVField)
|
||||
{
|
||||
CopyNodePtr node;
|
||||
if(!headNode->isStructure) {
|
||||
node = static_pointer_cast<CopyNode>(headNode);
|
||||
if(node->masterPVField.get()!=masterPVStructure.get()) return string::npos;
|
||||
} else {
|
||||
CopyStructureNodePtr snode = static_pointer_cast<CopyStructureNode>(headNode);
|
||||
node = getCopyOffset(snode,masterPVField);
|
||||
}
|
||||
if(!node) return string::npos;
|
||||
size_t diff = masterPVField->getFieldOffset()
|
||||
- masterPVStructure->getFieldOffset();
|
||||
return node->structureOffset + diff;
|
||||
}
|
||||
|
||||
PVFieldPtr PVCopy::getMasterPVField(size_t structureOffset)
|
||||
{
|
||||
CopyNodePtr node;
|
||||
if(!headNode->isStructure) {
|
||||
node = headNode;
|
||||
} else {
|
||||
CopyStructureNodePtr snode = static_pointer_cast<CopyStructureNode>(headNode);
|
||||
node = getMasterNode(snode,structureOffset);
|
||||
}
|
||||
if(!node) {
|
||||
throw std::invalid_argument(
|
||||
"PVCopy::getMasterPVField: structureOffset not valid");
|
||||
}
|
||||
size_t diff = structureOffset - node->structureOffset;
|
||||
PVFieldPtr pvMasterField = node->masterPVField;
|
||||
if(diff==0) return pvMasterField;
|
||||
PVStructurePtr pvStructure
|
||||
= static_pointer_cast<PVStructure>(pvMasterField);
|
||||
return pvStructure->getSubField(
|
||||
pvMasterField->getFieldOffset() + diff);
|
||||
}
|
||||
|
||||
void PVCopy::initCopy(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
|
||||
bitSet->set(i,true);
|
||||
}
|
||||
updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
|
||||
}
|
||||
|
||||
|
||||
bool PVCopy::updateCopySetBitSet(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
updateCopySetBitSet(copyPVStructure,headNode,bitSet);
|
||||
return checkIgnore(copyPVStructure,bitSet);
|
||||
}
|
||||
|
||||
bool PVCopy::updateCopyFromBitSet(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
if(bitSet->get(0)) {
|
||||
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
|
||||
bitSet->set(i,true);
|
||||
}
|
||||
}
|
||||
updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
|
||||
return checkIgnore(copyPVStructure,bitSet);
|
||||
}
|
||||
|
||||
void PVCopy::updateMaster(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
if(bitSet->get(0)) {
|
||||
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
|
||||
bitSet->set(i,true);
|
||||
}
|
||||
}
|
||||
updateMaster(copyPVStructure,headNode,bitSet);
|
||||
}
|
||||
|
||||
|
||||
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
|
||||
{
|
||||
if(fieldOffset==0) return headNode->options;
|
||||
CopyNodePtr node = headNode;
|
||||
while(true) {
|
||||
if(node->structureOffset==fieldOffset) return node->options;
|
||||
if(!node->isStructure) return NULLPVStructure;
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structNode->nodes;
|
||||
boolean okToContinue = false;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
node = (*nodes)[i];
|
||||
size_t soff = node->structureOffset;
|
||||
if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
|
||||
if(fieldOffset==soff) return node->options;
|
||||
if(!node->isStructure) {
|
||||
return NULLPVStructure;
|
||||
}
|
||||
okToContinue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(okToContinue) continue;
|
||||
throw std::invalid_argument("fieldOffset not valid");
|
||||
}
|
||||
}
|
||||
|
||||
string PVCopy::dump()
|
||||
{
|
||||
string builder;
|
||||
dump(&builder,headNode,0);
|
||||
return builder;
|
||||
}
|
||||
|
||||
void PVCopy::traverseMaster(
|
||||
CopyNodePtr const &innode,
|
||||
PVCopyTraverseMasterCallbackPtr const & callback)
|
||||
{
|
||||
CopyNodePtr node = innode;
|
||||
if(!node->isStructure) {
|
||||
callback->nextMasterPVField(node->masterPVField);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
node = (*nodes)[i];
|
||||
traverseMaster(node,callback);
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopy::updateCopySetBitSet(
|
||||
PVFieldPtr const & pvCopy,
|
||||
PVFieldPtr const & pvMaster,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
if(pvCopy->getField()->getType()!=epics::pvData::structure) {
|
||||
if(*pvCopy==*pvMaster) return;
|
||||
pvCopy->copy(*pvMaster);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
return;
|
||||
}
|
||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||
PVFieldPtr master = getMasterPVField(pvCopyFields[i]->getFieldOffset());
|
||||
updateCopySetBitSet(pvCopyFields[i],master,bitSet);
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopy::updateCopySetBitSet(
|
||||
PVFieldPtr const & pvCopy,
|
||||
CopyNodePtr const & node,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
bool result = false;
|
||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||
if(pvFilter->filter(pvCopy,bitSet,true)) result = true;
|
||||
}
|
||||
if(!node->isStructure) {
|
||||
if(result) return;
|
||||
updateCopySetBitSet(pvCopy,node->masterPVField,bitSet);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||
updateCopySetBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PVCopy::updateCopyFromBitSet(
|
||||
PVFieldPtr const & pvCopy,
|
||||
CopyNodePtr const & node,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
bool result = false;
|
||||
bool update = bitSet->get(pvCopy->getFieldOffset());
|
||||
if(update) {
|
||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||
if(pvFilter->filter(pvCopy,bitSet,true)) result = true;
|
||||
}
|
||||
}
|
||||
if(!node->isStructure) {
|
||||
if(result) return;
|
||||
PVFieldPtr pvMaster = node->masterPVField;
|
||||
pvCopy->copy(*pvMaster);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
size_t offset = structureNode->structureOffset;
|
||||
size_t nextSet = bitSet->nextSetBit(offset);
|
||||
if(nextSet==string::npos) return;
|
||||
if(offset>=pvCopy->getNextFieldOffset()) return;
|
||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||
updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
||||
}
|
||||
}
|
||||
void PVCopy::updateMaster(
|
||||
PVFieldPtr const & pvCopy,
|
||||
CopyNodePtr const & node,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
bool result = false;
|
||||
bool update = bitSet->get(pvCopy->getFieldOffset());
|
||||
if(update) {
|
||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||
if(pvFilter->filter(pvCopy,bitSet,false)) result = true;
|
||||
}
|
||||
}
|
||||
if(!node->isStructure) {
|
||||
if(result) return;
|
||||
PVFieldPtr pvMaster = node->masterPVField;
|
||||
pvMaster->copy(*pvCopy);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
size_t offset = structureNode->structureOffset;
|
||||
size_t nextSet = bitSet->nextSetBit(offset);
|
||||
if(nextSet==string::npos) return;
|
||||
if(offset>=pvCopy->getNextFieldOffset()) return;
|
||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||
updateMaster(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
||||
}
|
||||
}
|
||||
|
||||
PVCopy::PVCopy(
|
||||
PVStructurePtr const &pvMaster)
|
||||
: pvMaster(pvMaster)
|
||||
{
|
||||
}
|
||||
|
||||
void PVCopy::destroy()
|
||||
{
|
||||
headNode.reset();
|
||||
}
|
||||
|
||||
bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
|
||||
{
|
||||
PVStructurePtr pvMasterStructure = pvMaster;
|
||||
size_t len = pvRequest->getPVFields().size();
|
||||
bool entireMaster = false;
|
||||
if(len==0) entireMaster = true;
|
||||
PVStructurePtr pvOptions;
|
||||
if(len==1) {
|
||||
pvOptions = pvRequest->getSubField<PVStructure>("_options");
|
||||
}
|
||||
if(entireMaster) {
|
||||
structure = pvMasterStructure->getStructure();
|
||||
CopyNodePtr node(new CopyNode());
|
||||
headNode = node;
|
||||
node->options = pvOptions;
|
||||
node->isStructure = false;
|
||||
node->structureOffset = 0;
|
||||
node->masterPVField = pvMasterStructure;
|
||||
node->nfields = pvMasterStructure->getNumberFields();
|
||||
return true;
|
||||
}
|
||||
structure = createStructure(pvMasterStructure,pvRequest);
|
||||
if(!structure) return false;
|
||||
cacheInitStructure = createPVStructure();
|
||||
ignorechangeBitSet = BitSetPtr(new BitSet(cacheInitStructure->getNumberFields()));
|
||||
headNode = createStructureNodes(
|
||||
pvMaster,
|
||||
pvRequest,
|
||||
cacheInitStructure);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
StructureConstPtr PVCopy::createStructure(
|
||||
PVStructurePtr const &pvMaster,
|
||||
PVStructurePtr const &pvFromRequest)
|
||||
{
|
||||
if(pvFromRequest->getStructure()->getNumberFields()==0) {
|
||||
return pvMaster->getStructure();
|
||||
}
|
||||
PVFieldPtrArray const &pvFromRequestFields = pvFromRequest->getPVFields();
|
||||
StringArray const &fromRequestFieldNames = pvFromRequest->getStructure()->getFieldNames();
|
||||
size_t length = pvFromRequestFields.size();
|
||||
if(length==0) return NULLStructure;
|
||||
FieldConstPtrArray fields; fields.reserve(length);
|
||||
StringArray fieldNames; fieldNames.reserve(length);
|
||||
for(size_t i=0; i<length; ++i) {
|
||||
string const &fieldName = fromRequestFieldNames[i];
|
||||
PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
|
||||
if(!pvMasterField) continue;
|
||||
FieldConstPtr field = pvMasterField->getField();
|
||||
if(field->getType()==epics::pvData::structure) {
|
||||
PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
|
||||
pvFromRequestFields[i]);
|
||||
if(pvRequestStructure->getNumberFields()>0) {
|
||||
StringArray const &names = pvRequestStructure->getStructure()->
|
||||
getFieldNames();
|
||||
size_t num = names.size();
|
||||
if(num>0 && names[0].compare("_options")==0) --num;
|
||||
if(num>0) {
|
||||
if(pvMasterField->getField()->getType()!=epics::pvData::structure) continue;
|
||||
fieldNames.push_back(fieldName);
|
||||
fields.push_back(createStructure(
|
||||
static_pointer_cast<PVStructure>(pvMasterField),
|
||||
pvRequestStructure));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
fieldNames.push_back(fieldName);
|
||||
fields.push_back(field);
|
||||
}
|
||||
size_t numsubfields = fields.size();
|
||||
if(numsubfields==0) return NULLStructure;
|
||||
return getFieldCreate()->createStructure(fieldNames, fields);
|
||||
}
|
||||
|
||||
CopyNodePtr PVCopy::createStructureNodes(
|
||||
PVStructurePtr const &pvMasterStructure,
|
||||
PVStructurePtr const &pvFromRequest,
|
||||
PVStructurePtr const &pvFromCopy)
|
||||
{
|
||||
PVFieldPtrArray const & copyPVFields = pvFromCopy->getPVFields();
|
||||
PVStructurePtr pvOptions = pvFromRequest->getSubField<PVStructure>("_options");
|
||||
size_t number = copyPVFields.size();
|
||||
CopyNodePtrArrayPtr nodes(new CopyNodePtrArray());
|
||||
nodes->reserve(number);
|
||||
for(size_t i=0; i<number; i++) {
|
||||
PVFieldPtr copyPVField = copyPVFields[i];
|
||||
string fieldName = copyPVField->getFieldName();
|
||||
PVStructurePtr requestPVStructure =
|
||||
pvFromRequest->getSubField<PVStructure>(fieldName);
|
||||
PVStructurePtr pvSubFieldOptions =
|
||||
requestPVStructure->getSubField<PVStructure>("_options");
|
||||
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
|
||||
if(!pvMasterField) {
|
||||
throw std::logic_error("did not find field in master");
|
||||
}
|
||||
size_t numberRequest = requestPVStructure->getPVFields().size();
|
||||
if(pvSubFieldOptions) numberRequest--;
|
||||
if(numberRequest>0) {
|
||||
nodes->push_back(createStructureNodes(
|
||||
static_pointer_cast<PVStructure>(pvMasterField),
|
||||
requestPVStructure,
|
||||
static_pointer_cast<PVStructure>(copyPVField)));
|
||||
continue;
|
||||
}
|
||||
CopyNodePtr node(new CopyNode());
|
||||
node->options = pvSubFieldOptions;
|
||||
node->isStructure = false;
|
||||
node->masterPVField = pvMasterField;
|
||||
node->nfields = copyPVField->getNumberFields();
|
||||
node->structureOffset = copyPVField->getFieldOffset();
|
||||
nodes->push_back(node);
|
||||
}
|
||||
CopyStructureNodePtr structureNode(new CopyStructureNode());
|
||||
structureNode->masterPVField = pvMasterStructure;
|
||||
structureNode->isStructure = true;
|
||||
structureNode->nodes = nodes;
|
||||
structureNode->structureOffset = pvFromCopy->getFieldOffset();
|
||||
structureNode->nfields = pvFromCopy->getNumberFields();
|
||||
structureNode->options = pvOptions;
|
||||
return structureNode;
|
||||
}
|
||||
|
||||
void PVCopy::initPlugin(
|
||||
CopyNodePtr const & node,
|
||||
PVStructurePtr const & pvOptions,
|
||||
PVFieldPtr const & pvMasterField)
|
||||
{
|
||||
PVFieldPtrArray const & pvFields = pvOptions->getPVFields();
|
||||
size_t num = pvFields.size();
|
||||
vector<PVFilterPtr> pvFilters(num);
|
||||
size_t numfilter = 0;
|
||||
for(size_t i=0; i<num; ++i) {
|
||||
PVStringPtr pvOption = static_pointer_cast<PVString>(pvFields[i]);
|
||||
string name = pvOption->getFieldName();
|
||||
string value = pvOption->get();
|
||||
PVPluginPtr pvPlugin = PVPluginRegistry::find(name);
|
||||
if(!pvPlugin) {
|
||||
if(name.compare("ignore")==0) setIgnore(node);
|
||||
continue;
|
||||
}
|
||||
pvFilters[numfilter] = pvPlugin->create(value,shared_from_this(),pvMasterField);
|
||||
if(pvFilters[numfilter]) ++numfilter;
|
||||
}
|
||||
if(numfilter==0) return;
|
||||
node->pvFilters.resize(numfilter);
|
||||
for(size_t i=0; i<numfilter; ++i) node->pvFilters[i] = pvFilters[i];
|
||||
}
|
||||
|
||||
void PVCopy::traverseMasterInitPlugin()
|
||||
{
|
||||
traverseMasterInitPlugin(headNode);
|
||||
}
|
||||
|
||||
void PVCopy::traverseMasterInitPlugin(CopyNodePtr const & node)
|
||||
{
|
||||
PVFieldPtr pvField = node->masterPVField;
|
||||
PVStructurePtr pvOptions = node->options;
|
||||
if(pvOptions) initPlugin(node,pvOptions,pvField);
|
||||
if(!node->isStructure) return;
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
traverseMasterInitPlugin((*nodes)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CopyNodePtr PVCopy::getCopyOffset(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
PVFieldPtr const &masterPVField)
|
||||
{
|
||||
size_t offset = masterPVField->getFieldOffset();
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
if(!node->isStructure) {
|
||||
size_t off = node->masterPVField->getFieldOffset();
|
||||
size_t nextOffset = node->masterPVField->getNextFieldOffset();
|
||||
if(offset>= off && offset<nextOffset) return node;
|
||||
} else {
|
||||
CopyStructureNodePtr subNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtr node =
|
||||
getCopyOffset(subNode,masterPVField);
|
||||
if(node) return node;
|
||||
}
|
||||
}
|
||||
return NULLCopyNode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PVCopy::checkIgnore(
|
||||
PVStructurePtr const & copyPVStructure,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
if(!ignorechangeBitSet) {
|
||||
return (bitSet->nextSetBit(0)<0) ? false : true;
|
||||
}
|
||||
int32 numFields = copyPVStructure->getNumberFields();
|
||||
BitSet temp(numFields);
|
||||
temp = *bitSet;
|
||||
int32 ind = 0;
|
||||
while(true) {
|
||||
ind = ignorechangeBitSet->nextSetBit(ind);
|
||||
if(ind<0) break;
|
||||
temp.clear(ind);
|
||||
ind++;
|
||||
if(ind>=numFields) break;
|
||||
}
|
||||
return (temp.nextSetBit(0)<0) ? false : true;
|
||||
}
|
||||
|
||||
void PVCopy::setIgnore(CopyNodePtr const &node) {
|
||||
ignorechangeBitSet->set(node->structureOffset);
|
||||
if(node->isStructure) {
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i<nodes->size(); ++i) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
setIgnore(node); }
|
||||
} else {
|
||||
size_t num = node->masterPVField->getNumberFields();
|
||||
if(num>1) {
|
||||
for(size_t i=1; i<num; ++i) {
|
||||
ignorechangeBitSet->set(node->structureOffset+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CopyNodePtr PVCopy::getMasterNode(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
std::size_t structureOffset)
|
||||
{
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i<nodes->size(); ++i) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
if(structureOffset>=(node->structureOffset + node->nfields)) continue;
|
||||
if(!node->isStructure) return node;
|
||||
CopyStructureNodePtr subNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
return getMasterNode(subNode,structureOffset);
|
||||
}
|
||||
return NULLCopyNode;
|
||||
}
|
||||
|
||||
void PVCopy::dump(string *builder,CopyNodePtr const &node,int indentLevel)
|
||||
{
|
||||
newLine(builder,indentLevel);
|
||||
std::stringstream ss;
|
||||
ss << (node->isStructure ? "structureNode" : "node");
|
||||
ss << " structureOffset " << node->structureOffset;
|
||||
ss << " nfields " << node->nfields;
|
||||
*builder += ss.str();
|
||||
PVStructurePtr options = node->options;
|
||||
if(options) {
|
||||
newLine(builder,indentLevel +1);
|
||||
*builder += options->getFieldName();
|
||||
PVFieldPtrArray pvFields = options->getPVFields();
|
||||
for(size_t i=0; i< pvFields.size() ; ++i) {
|
||||
PVStringPtr pvString = static_pointer_cast<PVString>(pvFields[i]);
|
||||
newLine(builder,indentLevel +2);
|
||||
*builder += pvString->getFieldName() + " " + pvString->get();
|
||||
}
|
||||
}
|
||||
string name = node->masterPVField->getFullName();
|
||||
newLine(builder,indentLevel +1);
|
||||
*builder += "masterField " + name;
|
||||
if(node->pvFilters.size()>0) {
|
||||
newLine(builder,indentLevel +2);
|
||||
*builder += "filters:";
|
||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||
*builder += " " + pvFilter->getName();
|
||||
}
|
||||
}
|
||||
if(!node->isStructure) return;
|
||||
CopyStructureNodePtr structureNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i<nodes->size(); ++i) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
if(!node) {
|
||||
newLine(builder,indentLevel +1);
|
||||
ss.str("");
|
||||
ss << "node[" << i << "] is null";
|
||||
*builder += ss.str();
|
||||
continue;
|
||||
}
|
||||
dump(builder,node,indentLevel+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
128
src/copy/pvDeadbandPlugin.cpp
Normal file
128
src/copy/pvDeadbandPlugin.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/* pvDeadbandPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/pvSubArrayCopy.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvDeadbandPlugin.h>
|
||||
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
static std::string name("deadband");
|
||||
|
||||
PVDeadbandPlugin::PVDeadbandPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
PVDeadbandPlugin::~PVDeadbandPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void PVDeadbandPlugin::create()
|
||||
{
|
||||
PVDeadbandPluginPtr pvPlugin = PVDeadbandPluginPtr(new PVDeadbandPlugin());
|
||||
PVPluginRegistry::registerPlugin(name,pvPlugin);
|
||||
}
|
||||
|
||||
PVFilterPtr PVDeadbandPlugin::create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
return PVDeadbandFilter::create(requestValue,master);
|
||||
}
|
||||
|
||||
PVDeadbandFilter::~PVDeadbandFilter()
|
||||
{
|
||||
}
|
||||
|
||||
PVDeadbandFilterPtr PVDeadbandFilter::create(
|
||||
const std::string & requestValue,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
FieldConstPtr field =master->getField();
|
||||
Type type = field->getType();
|
||||
if(type!=scalar) return PVDeadbandFilterPtr();
|
||||
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
|
||||
if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr();
|
||||
bool absolute = false;
|
||||
if(requestValue.find("abs")>=0) {
|
||||
absolute = true;
|
||||
} else if(requestValue.find("rel")>=0) {
|
||||
absolute = false;
|
||||
} else {
|
||||
return PVDeadbandFilterPtr();
|
||||
}
|
||||
size_t ind = requestValue.find(':');
|
||||
if(ind==string::npos) return PVDeadbandFilterPtr();
|
||||
string svalue = requestValue.substr(ind+1);
|
||||
double deadband = atof(svalue.c_str());
|
||||
if(deadband==0.0) return PVDeadbandFilterPtr();
|
||||
PVDeadbandFilterPtr filter =
|
||||
PVDeadbandFilterPtr(
|
||||
new PVDeadbandFilter(
|
||||
absolute,deadband,static_pointer_cast<PVScalar>(master)));
|
||||
return filter;
|
||||
}
|
||||
|
||||
PVDeadbandFilter::PVDeadbandFilter(bool absolute,double deadband,PVScalarPtr const & master)
|
||||
: absolute(absolute),
|
||||
deadband(deadband),
|
||||
master(master),
|
||||
firstTime(true),
|
||||
lastReportedValue(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PVDeadbandFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
||||
{
|
||||
if(!toCopy) return false;
|
||||
double value = convert->toDouble(master);
|
||||
double diff = value - lastReportedValue;
|
||||
if(diff<0.0) diff = - diff;
|
||||
bool report = true;
|
||||
if(firstTime) {
|
||||
firstTime = false;
|
||||
} else if(absolute) {
|
||||
if(diff<deadband) report = false;
|
||||
} else {
|
||||
double last = lastReportedValue;
|
||||
if(last<0.0) last = -last;
|
||||
if(last>1e-20) {
|
||||
double percent = (diff/last)*100.0;
|
||||
if(percent<deadband) report = false;
|
||||
}
|
||||
}
|
||||
PVScalarPtr copy = static_pointer_cast<PVScalar>(pvCopy);
|
||||
convert->fromDouble(copy,value);
|
||||
if(report) {
|
||||
lastReportedValue = value;
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
} else {
|
||||
bitSet->clear(pvCopy->getFieldOffset());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string PVDeadbandFilter::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
}}
|
||||
|
36
src/copy/pvPlugin.cpp
Normal file
36
src/copy/pvPlugin.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/* pvPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvPlugin.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
||||
|
||||
static PVPluginMap pluginMap;
|
||||
static Mutex mutex;
|
||||
|
||||
void PVPluginRegistry::registerPlugin(const std::string & name,const PVPluginPtr & pvPlugin)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
PVPluginMap::iterator iter = pluginMap.find(name);
|
||||
if(iter!=pluginMap.end()) throw std::logic_error("plugin already registered");
|
||||
pluginMap.insert(PVPluginMap::value_type(name,pvPlugin));
|
||||
}
|
||||
|
||||
PVPluginPtr PVPluginRegistry::find(const std::string & name)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
PVPluginMap::iterator iter = pluginMap.find(name);
|
||||
if(iter!=pluginMap.end()) return (*iter).second;
|
||||
return PVPluginPtr();
|
||||
}
|
||||
|
||||
}}
|
||||
|
119
src/copy/pvTimestampPlugin.cpp
Normal file
119
src/copy/pvTimestampPlugin.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* pvTimestampPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/convert.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvTimestampPlugin.h>
|
||||
#include <pv/pvCopy.h>
|
||||
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvDatabase{
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
static std::string name("timestamp");
|
||||
|
||||
PVTimestampPlugin::PVTimestampPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
PVTimestampPlugin::~PVTimestampPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void PVTimestampPlugin::create()
|
||||
{
|
||||
PVTimestampPluginPtr pvPlugin = PVTimestampPluginPtr(new PVTimestampPlugin());
|
||||
PVPluginRegistry::registerPlugin(name,pvPlugin);
|
||||
}
|
||||
|
||||
PVFilterPtr PVTimestampPlugin::create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
return PVTimestampFilter::create(requestValue,master);
|
||||
}
|
||||
|
||||
PVTimestampFilter::~PVTimestampFilter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PVTimestampFilterPtr PVTimestampFilter::create(
|
||||
const std::string & requestValue,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
PVTimeStamp pvTimeStamp;
|
||||
if(!pvTimeStamp.attach(master)) return PVTimestampFilterPtr();
|
||||
bool current = false;
|
||||
bool copy = false;
|
||||
if(requestValue.compare("current")==0) {
|
||||
current = true;
|
||||
} else if(requestValue.compare("copy")==0){
|
||||
copy = true;
|
||||
} else {
|
||||
return PVTimestampFilterPtr();
|
||||
}
|
||||
PVTimestampFilterPtr filter = PVTimestampFilterPtr(
|
||||
new PVTimestampFilter(current,copy,master));
|
||||
return filter;
|
||||
}
|
||||
|
||||
PVTimestampFilter::PVTimestampFilter(bool current,bool copy,PVFieldPtr const & master)
|
||||
: current(current),
|
||||
copy(copy),
|
||||
master(master)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
||||
{
|
||||
if(current) {
|
||||
timeStamp.getCurrent();
|
||||
if(toCopy) {
|
||||
if(!pvTimeStamp.attach(pvCopy)) return false;
|
||||
} else {
|
||||
if(!pvTimeStamp.attach(master)) return false;
|
||||
}
|
||||
pvTimeStamp.set(timeStamp);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
return true;
|
||||
}
|
||||
if(copy) {
|
||||
if(toCopy) {
|
||||
if(!pvTimeStamp.attach(master)) return false;
|
||||
pvTimeStamp.get(timeStamp);
|
||||
if(!pvTimeStamp.attach(pvCopy)) return false;
|
||||
pvTimeStamp.set(timeStamp);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
} else {
|
||||
if(!pvTimeStamp.attach(pvCopy)) return false;
|
||||
pvTimeStamp.get(timeStamp);
|
||||
if(!pvTimeStamp.attach(master)) return false;
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string PVTimestampFilter::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/serverContext.h>
|
||||
@ -36,7 +35,7 @@
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <map>
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
|
||||
@ -25,6 +24,7 @@
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
#include <pv/pvCopy.h>
|
||||
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
@ -65,7 +65,7 @@ typedef std::tr1::weak_ptr<PVDatabase> PVDatabaseWPtr;
|
||||
* @date 2012.11.20
|
||||
*/
|
||||
class epicsShareClass PVRecord :
|
||||
public epics::pvData::PVCopyTraverseMasterCallback,
|
||||
public PVCopyTraverseMasterCallback,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
@ -210,7 +210,7 @@ public:
|
||||
*/
|
||||
bool addListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
epics::pvData::PVCopyPtr const & pvCopy);
|
||||
PVCopyPtr const & pvCopy);
|
||||
/**
|
||||
* @brief PVCopyTraverseMasterCallback method
|
||||
*
|
||||
@ -226,7 +226,7 @@ public:
|
||||
*/
|
||||
bool removeListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
epics::pvData::PVCopyPtr const & pvCopy);
|
||||
PVCopyPtr const & pvCopy);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -327,6 +327,7 @@ void ChannelGetLocal::get()
|
||||
PVRecordPtr pvr(pvRecord.lock());
|
||||
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
||||
try {
|
||||
bool notifyClient = true;
|
||||
bitSet->clear();
|
||||
{
|
||||
epicsGuard <PVRecord> guard(*pvr);
|
||||
@ -335,18 +336,29 @@ void ChannelGetLocal::get()
|
||||
pvr->process();
|
||||
pvr->endGroupPut();
|
||||
}
|
||||
pvCopy->updateCopySetBitSet(pvStructure, bitSet);
|
||||
notifyClient = pvCopy->updateCopySetBitSet(pvStructure, bitSet);
|
||||
}
|
||||
if(firstTime) {
|
||||
bitSet->clear();
|
||||
bitSet->set(0);
|
||||
firstTime = false;
|
||||
notifyClient = true;
|
||||
}
|
||||
if(notifyClient) {
|
||||
requester->getDone(
|
||||
Status::Ok,
|
||||
getPtrSelf(),
|
||||
pvStructure,
|
||||
bitSet);
|
||||
bitSet->clear();
|
||||
} else {
|
||||
BitSetPtr temp(new BitSet(bitSet->size()));
|
||||
requester->getDone(
|
||||
Status::Ok,
|
||||
getPtrSelf(),
|
||||
pvStructure,
|
||||
temp);
|
||||
}
|
||||
if(pvr->getTraceLevel()>1)
|
||||
{
|
||||
cout << "ChannelGetLocal::get" << endl;
|
||||
|
@ -266,8 +266,8 @@ void MonitorLocal::releaseActiveElement()
|
||||
{
|
||||
Lock xx(queueMutex);
|
||||
if(state!=active) return;
|
||||
pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
|
||||
if(activeElement->changedBitSet->nextSetBit(0)<0) return;
|
||||
bool result = pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
|
||||
if(!result) return;
|
||||
MonitorElementPtr newActive = queue->getFree();
|
||||
if(!newActive) return;
|
||||
BitSetUtil::compress(activeElement->changedBitSet,activeElement->pvStructurePtr);
|
||||
|
@ -13,6 +13,7 @@
|
||||
/* src */
|
||||
int testExampleRecord(void);
|
||||
int testPVCopy(void);
|
||||
int testPlugin(void);
|
||||
int testPVRecord(void);
|
||||
int testLocalProvider(void);
|
||||
int testPVAServer(void);
|
||||
@ -24,6 +25,7 @@ void pvDatabaseAllTests(void)
|
||||
/* src */
|
||||
runTest(testExampleRecord);
|
||||
runTest(testPVCopy);
|
||||
runTest(testPlugin);
|
||||
runTest(testPVRecord);
|
||||
runTest(testLocalProvider);
|
||||
runTest(testPVAServer);
|
||||
|
@ -3,6 +3,12 @@
|
||||
|
||||
SRC_DIRS += $(PVDATABASE_TEST)/src
|
||||
|
||||
|
||||
TESTPROD_HOST += testPlugin
|
||||
testPlugin_SRCS += testPlugin.cpp
|
||||
testHarness_SRCS += testPlugin.cpp
|
||||
TESTS += testPlugin
|
||||
|
||||
TESTPROD_HOST += testPVCopy
|
||||
testPVCopy_SRCS += testPVCopy.cpp
|
||||
testHarness_SRCS += testPVCopy.cpp
|
||||
@ -23,7 +29,6 @@ testLocalProvider_SRCS += testLocalProvider.cpp
|
||||
testHarness_SRCS += testLocalProvider.cpp
|
||||
TESTS += testLocalProvider
|
||||
|
||||
|
||||
TESTPROD_HOST += testPVAServer
|
||||
testPVAServer_SRCS += testPVAServer.cpp
|
||||
testHarness_SRCS += testPVAServer.cpp
|
||||
|
@ -68,7 +68,6 @@ static void test()
|
||||
exampleRecord->unlock();
|
||||
}
|
||||
if(debug) {cout << "processed exampleDouble " << endl; }
|
||||
exampleRecord->destroy();
|
||||
recordName = "powerSupplyExample";
|
||||
PowerSupplyPtr psr;
|
||||
pvStructure = createPowerSupply();
|
||||
@ -127,7 +126,6 @@ static void test()
|
||||
testOk1(psr->getVoltage()==1.0);
|
||||
testOk1(psr->getPower()==1.0);
|
||||
testOk1(psr->getCurrent()==1.0);
|
||||
psr->destroy();
|
||||
}
|
||||
|
||||
MAIN(testExampleRecord)
|
||||
|
@ -71,7 +71,6 @@ static void test()
|
||||
pvRecord->unlock();
|
||||
}
|
||||
if(debug) {cout << "processed exampleDouble " << endl; }
|
||||
channelProvider->destroy();
|
||||
}
|
||||
|
||||
MAIN(testLocalProvider)
|
||||
|
@ -281,7 +281,6 @@ static void scalarTest()
|
||||
string request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVCopyPtr pvCopy;
|
||||
string builder;
|
||||
string valueNameRecord;
|
||||
string valueNameCopy;
|
||||
|
||||
@ -313,7 +312,6 @@ static void scalarTest()
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
@ -324,7 +322,6 @@ static void arrayTest()
|
||||
string request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVCopyPtr pvCopy;
|
||||
string builder;
|
||||
string valueNameRecord;
|
||||
string valueNameCopy;
|
||||
|
||||
@ -350,7 +347,6 @@ static void arrayTest()
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void powerSupplyTest()
|
||||
@ -361,7 +357,6 @@ static void powerSupplyTest()
|
||||
string request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVCopyPtr pvCopy;
|
||||
string builder;
|
||||
string valueNameRecord;
|
||||
string valueNameCopy;
|
||||
|
||||
@ -395,7 +390,6 @@ static void powerSupplyTest()
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "power.value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
MAIN(testPVCopy)
|
||||
|
@ -69,7 +69,6 @@ static void scalarTest()
|
||||
if(pvRecord && debug) {
|
||||
cout << pvRecord << endl;
|
||||
}
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
@ -81,7 +80,6 @@ static void arrayTest()
|
||||
if(pvRecord && debug) {
|
||||
cout << pvRecord << endl;
|
||||
}
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void powerSupplyTest()
|
||||
@ -94,7 +92,6 @@ static void powerSupplyTest()
|
||||
if(pvRecord && debug) {
|
||||
cout << pvRecord << endl;
|
||||
}
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
MAIN(testPVRecord)
|
||||
|
274
test/src/testPlugin.cpp
Normal file
274
test/src/testPlugin.cpp
Normal file
@ -0,0 +1,274 @@
|
||||
/*testPluginMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/convert.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "powerSupply.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
static bool debug = true;
|
||||
|
||||
static void deadbandTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****deadbandTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,""));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[deadband=abs:1.0]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
pvValue->put(.1);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==0);
|
||||
pvValue->put(1.0);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****arrayTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
size_t n = 10;
|
||||
shared_vector<double> values(n);
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalarArray(pvDouble,""));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleArrayRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoubleArrayPtr pvValue(pvRecordStructure->getSubField<PVDoubleArray>("value"));
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==0);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + .06;
|
||||
const shared_vector<const double> yyy(freeze(values));
|
||||
pvValue->putFrom(yyy);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
}
|
||||
|
||||
static void timeStampTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****timeStampTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,"timeStamp"));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value,timeStamp[timestamp=current]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after update"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
pvRecord->process();
|
||||
pvValue->put(1.0);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==2);
|
||||
}
|
||||
|
||||
static void ignoreTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****ignoreTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,"alarm,timeStamp"));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value,alarm[ignore=true],timeStamp[ignore=true]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
|
||||
PVStringPtr pvMessage(pvRecordStructure->getSubField<PVString>("alarm.message"));
|
||||
PVIntPtr pvUserTag(pvRecordStructure->getSubField<PVInt>("timeStamp.userTag"));
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==0);
|
||||
pvMessage->put("test message");
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvMessage"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==1);
|
||||
pvUserTag->put(50);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvMessage"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==2);
|
||||
pvValue->put(1.0);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==3);
|
||||
}
|
||||
|
||||
MAIN(testPlugin)
|
||||
{
|
||||
testPlan(22);
|
||||
deadbandTest();
|
||||
arrayTest();
|
||||
timeStampTest();
|
||||
ignoreTest();
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user