Merge pull request #36 from mrkraimer/master

plugin support
This commit is contained in:
Marty Kraimer
2018-09-22 11:13:31 -04:00
committed by GitHub
25 changed files with 2171 additions and 34 deletions

View File

@ -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
====================

View File

@ -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>

View File

@ -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
View 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
View 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
View 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 &copyPVStructure,
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 &copyPVStructure,
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 &copyPVStructure,
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 &copyPVStructure,
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 */

View 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
View 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 */

View 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
View 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
View 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 &copyPVStructure,
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 &copyPVStructure,
BitSetPtr const &bitSet)
{
updateCopySetBitSet(copyPVStructure,headNode,bitSet);
return checkIgnore(copyPVStructure,bitSet);
}
bool PVCopy::updateCopyFromBitSet(
PVStructurePtr const &copyPVStructure,
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 &copyPVStructure,
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);
}
}
}}

View 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
View 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();
}
}}

View 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;
}
}}

View File

@ -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 {

View File

@ -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);
/**

View File

@ -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;
}
requester->getDone(
Status::Ok,
getPtrSelf(),
pvStructure,
bitSet);
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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -71,7 +71,6 @@ static void test()
pvRecord->unlock();
}
if(debug) {cout << "processed exampleDouble " << endl; }
channelProvider->destroy();
}
MAIN(testLocalProvider)

View File

@ -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)

View File

@ -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
View 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;
}