53 Commits
4.4.2 ... 4.5.1

Author SHA1 Message Date
Andrew Johnson
0c92f07749 Clear development flag for 4.5.1 release 2019-11-01 12:50:11 -05:00
Andrew Johnson
73a9f1f84f Release notes for 4.5.1 2019-11-01 12:48:58 -05:00
Marty Kraimer
3c3f0ab7f1 Merge pull request #51 from mrkraimer/master
addRecord is new
2019-09-13 10:00:22 -04:00
Marty Kraimer
803098922a Update .travis.yml 2019-09-13 09:04:54 -04:00
mrkraimer
c028af8b6d addRecord is new 2019-09-11 10:17:09 -04:00
Ralph Lange
d33d03189e rtd-ci: add read-the-docs integration 2019-09-06 14:19:00 +02:00
Andrew Johnson
d7bd5628d4 Update version number to 4.5.1 DEVELOPMENT 2019-08-13 11:04:36 -05:00
Andrew Johnson
70ee857782 Set version number in Release Notes 2019-07-30 14:26:56 -05:00
Andrew Johnson
07f09e0759 Set SHRLIB_VERSION from new CONFIG_PVDATABASE_VERSION file 2019-07-30 14:26:37 -05:00
Marty Kraimer
ba832ddfd0 Merge pull request #50 from mrkraimer/master
another attempt to fix jenkins win64 build
2019-07-10 10:37:58 -04:00
mrkraimer
93c2284091 another attempt to fix jenkins win64 build 2019-07-10 10:09:30 -04:00
Marty Kraimer
cc5b6f6351 Merge pull request #49 from mrkraimer/master
try to fix jenkins win64 build that fails
2019-07-10 09:44:30 -04:00
mrkraimer
a26a625e49 try to fix jenkins win64 build that fails 2019-07-10 09:14:58 -04:00
Marty Kraimer
93b4892528 Merge pull request #48 from mrkraimer/master
copy lib now part of pvDatabase
2019-06-26 13:03:07 -04:00
mrkraimer
e57348a4c5 copy lib now part of pvDatabase 2019-06-26 10:47:58 -04:00
Marty Kraimer
7059cb0354 Merge pull request #46 from mrkraimer/master
add record support and processRecord
2019-06-25 09:17:35 -04:00
mrkraimer
f2d6e05816 WIN32 follow Michael's advice about O.yyy/*.d files 2019-06-24 15:23:19 -04:00
mrkraimer
e949493722 WIN32 DLL; copy build. now for pvDatabase 2019-06-24 09:53:56 -04:00
mrkraimer
6969bbd571 WIN32 DLL another try 2019-06-23 15:30:29 -04:00
mrkraimer
9edea59ab9 WIN32 DLL making progresss but still not there 2019-06-23 14:41:34 -04:00
mrkraimer
1928b87634 pvCopy depends of pvPlugin not the other way 2019-06-23 14:03:16 -04:00
mrkraimer
d9ed321298 WIN32 another try 2019-06-23 10:40:09 -04:00
mrkraimer
935f915e5d WIN32 another try 2019-06-23 09:55:52 -04:00
mrkraimer
6263f4c335 WIN32 another try 2019-06-23 09:24:09 -04:00
mrkraimer
62134efd19 WIN32 another try 2019-06-23 08:40:09 -04:00
mrkraimer
8a06b9ee8e win32 yet another try 2019-06-23 08:08:33 -04:00
mrkraimer
bc6fd2b9ff wrong ifdef 2019-06-23 07:22:27 -04:00
mrkraimer
3b6f23515f pvCopy first 2019-06-23 06:18:28 -04:00
mrkraimer
3c5f419ce7 src depends on configure src/copy 2019-06-22 17:00:41 -04:00
mrkraimer
3418c22cde WIN32 make pvCopy be a seperate lib instead of part of pvDatabase 2019-06-22 16:14:40 -04:00
mrkraimer
22806c5301 almost running out of ideas to make WIN32 build 2019-06-22 13:01:31 -04:00
mrkraimer
62fb27fdf8 WIN32 is really a pain 2019-06-22 11:48:01 -04:00
mrkraimer
6250625036 yet one more attempt to make WIN32 build 2019-06-22 10:16:57 -04:00
mrkraimer
d77ec8a978 yet one more time to make WIN32 build 2019-06-22 07:53:01 -04:00
mrkraimer
322bb4800b another attempt to build for WIN32 2019-06-22 06:38:28 -04:00
mrkraimer
0437602236 fix bug in deadband plugin; attempt to make support build on win32 2019-06-21 15:53:31 -04:00
mrkraimer
bd37756ba3 fix bug in processRecord; attempt to make support build on WINE 2019-06-21 13:39:50 -04:00
mrkraimer
fb4e7f0fc1 update doc; fix bug in scalarAlarmSupport 2019-06-19 09:36:52 -04:00
mrkraimer
5279e4e739 array plugin for put failed if increment not 1 2019-06-14 14:13:52 -04:00
mrkraimer
ffef21e58c doc changes; processRecord catch exceptions 2019-06-10 10:41:08 -04:00
mrkraimer
e901ae3ea0 handle out of control limits better 2019-06-09 16:14:25 -04:00
mrkraimer
8a050e0f81 add processRecord 2019-06-08 13:24:20 -04:00
mrkraimer
a72112f928 process reports if it changed fields 2019-06-08 05:52:03 -04:00
mrkraimer
be701cc98a still more work on support 2019-06-06 09:52:39 -04:00
mrkraimer
9b000ffe6c support hysteresis 2019-06-04 14:56:18 -04:00
mrkraimer
6c91249340 add scalarAlarmSupport 2019-06-04 14:21:38 -04:00
mrkraimer
b052e28788 add support 2019-06-01 12:28:21 -04:00
mrkraimer
247839b94d add numericRecord, removeRecordRegister, traceRecordRegister 2019-06-01 06:59:23 -04:00
Marty Kraimer
ecdf70d858 Merge pull request #45 from mrkraimer/master
remove new method for PVRecord
2019-05-22 14:22:11 -04:00
mrkraimer
a004f7ea08 remove new method for PVRecord 2019-05-22 10:41:55 -04:00
Marty Kraimer
898868d5f4 Merge pull request #43 from mrkraimer/master
PVCOPY::updateMaster put to fields that did not change
2019-05-21 09:43:11 -04:00
mrkraimer
eb4dab73e9 another fix for updateMaster nug 2019-05-18 10:56:30 -04:00
mrkraimer
e1adfe30df updateMaster was putting to every client field instead of only changed fields 2019-05-18 10:11:00 -04:00
55 changed files with 1892 additions and 187 deletions

17
.readthedocs.yml Normal file
View File

@@ -0,0 +1,17 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation in the documentation/ directory with Sphinx
sphinx:
configuration: documentation/conf.py
# Build documentation with MkDocs
#mkdocs:
# configuration: mkdocs.yml
# Optionally build your docs in additional formats such as PDF and ePub
formats: all

View File

@@ -28,4 +28,4 @@ env:
- BRBASE=7.0 RTEMS=4.9 TEST=NO
- BRBASE=3.16
- BRBASE=3.15
- BRBASE=3.14

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = pvDatabaseCPP
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
PROJECT_NUMBER = 4.5.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -765,7 +765,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = include
INPUT = src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1035,7 +1035,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = documentation/html
HTML_OUTPUT = html/doxygen
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).

View File

@@ -0,0 +1,12 @@
# Version number for the PV Database API and shared library
EPICS_PVDATABASE_MAJOR_VERSION = 4
EPICS_PVDATABASE_MINOR_VERSION = 5
EPICS_PVDATABASE_MAINTENANCE_VERSION = 1
# Development flag, set to zero for release versions
EPICS_PVDATABASE_DEVELOPMENT_FLAG = 0
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -2,6 +2,8 @@ TOP=..
include $(TOP)/configure/CONFIG
CFG += CONFIG_PVDATABASE_VERSION
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@@ -2,6 +2,18 @@
This document summarizes the changes to the module between releases.
## Release 4.5.1 (EPICS 7.0.3.1, Nov 2019)
* addRecord is new.
* Doxygen updates and read-the-docs integration.
## Release 4.5.0 (EPICS 7.0.3, Jul 2019)
* support is a new feature.
* processRecord is new.
## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019)
Formerly if a client makes a request for a subfield of a non structure field
@@ -15,6 +27,7 @@ Now if a request is made for a subfield of a non structure field
b) if the subfield is the type for the current union the request succeeds
c) if type is not the same an exception is thrown
## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019)
* Cleaned up some build warnings.

View File

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

View File

@@ -0,0 +1,7 @@
.wy-side-nav-search {
background-color: #18334B;
}
.wy-side-nav-search input[type="text"] {
border-color: #18334b;
}

80
documentation/conf.py Normal file
View File

@@ -0,0 +1,80 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- Project information -----------------------------------------------------
project = 'normativeTypes (C++)'
copyright = '2019, EPICS Controls.'
author = 'EPICS'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.intersphinx',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# Intersphinx links to subprojects
intersphinx_mapping = {
}
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_css_files = [
'css/custom.css',
]
master_doc = 'index'
html_theme_options = {
'logo_only': True,
}
html_logo = "images/EPICS_white_logo_v02.png"
html_extra_path = [
'../html',
'pvDatabaseCPP.html',
]
# -- Run Doxygen ------------------------------------------------------------
import subprocess
subprocess.call('cd ..; mkdir -p html/doxygen; doxygen', shell=True)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

17
documentation/index.rst Normal file
View File

@@ -0,0 +1,17 @@
pvDatabase (C++) Library
========================
.. toctree::
:hidden:
EPICS Website <https://epics-controls.org>
EPICS Documentation Home <https://docs.epics-controls.org>
.. toctree::
:maxdepth: 1
:caption: pvDatabaseCPP
Reference Manual <https://docs.epics-controls.org/projects/pvdatabase-cpp/en/latest/pvDatabaseCPP.html>
API Documentation <https://docs.epics-controls.org/projects/pvdatabase-cpp/en/latest/doxygen>
Source Code Repository on GitHub <https://github.com/epics-base/pvDatabaseCPP>

View File

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

View File

@@ -3,22 +3,41 @@
TOP = ..
include $(TOP)/configure/CONFIG
# needed for Windows
LIB_SYS_LIBS_WIN32 += netapi32 ws2_32
PVDATABASE_SRC = $(TOP)/src
LIBRARY += pvDatabase
# shared library ABI version.
SHRLIB_VERSION ?= 4.4.2
SHRLIB_VERSION ?= $(EPICS_PVDATABASE_MAJOR_VERSION).$(EPICS_PVDATABASE_MINOR_VERSION).$(EPICS_PVDATABASE_MAINTENANCE_VERSION)
INC += pv/pvPlugin.h
INC += pv/pvStructureCopy.h
INC += pv/pvArrayPlugin.h
INC += pv/pvDeadbandPlugin.h
INC += pv/pvTimestampPlugin.h
INC += pv/pvDatabase.h
INC += pv/channelProviderLocal.h
INC += pv/pvDatabase.h
INC += pv/traceRecord.h
INC += pv/removeRecord.h
INC += pv/addRecord.h
INC += pv/processRecord.h
INC += pv/pvSupport.h
INC += pv/controlSupport.h
INC += pv/scalarAlarmSupport.h
include $(PVDATABASE_SRC)/copy/Makefile
include $(PVDATABASE_SRC)/database/Makefile
include $(PVDATABASE_SRC)/pvAccess/Makefile
include $(PVDATABASE_SRC)/special/Makefile
include $(PVDATABASE_SRC)/support/Makefile
pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)

View File

@@ -1,15 +1,12 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATABASE_SRC)/copy
INC += pv/pvStructureCopy.h
INC += pv/pvPlugin.h
INC += pv/pvArrayPlugin.h
INC += pv/pvDeadbandPlugin.h
INC += pv/pvTimestampPlugin.h
LIBSRCS += pvCopy.cpp
LIBSRCS += pvPlugin.cpp
LIBSRCS += pvCopy.cpp
LIBSRCS += pvArrayPlugin.cpp
LIBSRCS += pvDeadbandPlugin.cpp
LIBSRCS += pvTimestampPlugin.cpp

View File

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

View File

@@ -17,8 +17,8 @@
#include <pv/thread.h>
#define epicsExportSharedSymbols
#include <pv/pvPlugin.h>
#include <pv/pvStructureCopy.h>
#include "pv/pvPlugin.h"
#include "pv/pvStructureCopy.h"
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
@@ -212,19 +212,91 @@ bool PVCopy::updateCopyFromBitSet(
return checkIgnore(copyPVStructure,bitSet);
}
void PVCopy::updateMasterField(
CopyNodePtr const & node,
PVFieldPtr const & pvCopy,
PVFieldPtr const &pvMaster,
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,false)) result = true;
}
if(result) return;
pvMaster->copyUnchecked(*pvCopy);
}
void PVCopy::updateMasterCheckBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet,
size_t nextSet)
{
if(!bitSet->get(nextSet)) {
size_t next = bitSet->nextSetBit(nextSet);
if(next==string::npos) return;
updateMasterCheckBitSet(copyPVStructure,bitSet,next);
return;
}
PVFieldPtr pvField = copyPVStructure;
if(nextSet!=0) pvField = copyPVStructure->getSubField(nextSet);
if(pvField->getField()->getType()==epics::pvData::structure) {
bitSet->clear(nextSet);
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvField);
PVFieldPtrArray pvFieldArray = pv->getPVFields();
for(size_t i=0; i>pvFieldArray.size(); ++i) {
PVFieldPtr pvField = pvFieldArray[i];
bitSet->set(pvField->getFieldOffset());
}
}
size_t next = bitSet->nextSetBit(nextSet+1);
if(next==string::npos) return;
updateMasterCheckBitSet(copyPVStructure,bitSet,next);
}
CopyNodePtr PVCopy::getCopyNode(std::size_t fieldOffset)
{
if(fieldOffset==0) return headNode;
CopyNodePtr node = headNode;
while(true) {
if(!node->isStructure) return node;
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structNode->nodes;
bool 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) {
okToContinue = true;
break;
}
}
if(okToContinue) continue;
}
throw std::logic_error("PVCopy::getCopyNode fieldOffset not valid");
}
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);
updateMasterCheckBitSet(copyPVStructure,bitSet,0);
size_t nextSet =0;
while(true) {
nextSet = bitSet->nextSetBit(nextSet);
if(nextSet==string::npos) return;
PVFieldPtr pvCopy = copyPVStructure->getSubField(nextSet);
PVFieldPtr pvMaster = headNode->masterPVField;
if(pvMaster->getField()->getType()==epics::pvData::structure) {
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvMaster);
pvMaster = pv->getSubField(pvCopy->getFullName());
}
updateMasterField(getCopyNode(nextSet),pvCopy,pvMaster,bitSet);
bitSet->clear(nextSet);
}
updateMaster(copyPVStructure,headNode,bitSet);
}
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
{
if(fieldOffset==0) return headNode->options;
@@ -248,7 +320,7 @@ PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
}
}
if(okToContinue) continue;
throw std::logic_error("PVCopy logic error: fieldOffset not valid");
throw std::logic_error("PVCopy::getOptions logic error: fieldOffset not valid");
}
}
@@ -349,36 +421,6 @@ void PVCopy::updateCopyFromBitSet(
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)
@@ -493,7 +535,7 @@ CopyNodePtr PVCopy::createStructureNodes(
requestPVStructure->getSubField<PVStructure>("_options");
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
if(!pvMasterField) {
throw std::logic_error("PVCopy logic error: did not find field in master");
throw std::logic_error("PVCopy::createStructureNodes did not find field in master");
}
size_t numberRequest = requestPVStructure->getPVFields().size();
bool haveOptions = false;

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,13 +8,25 @@
* @author mrk
* @date 2012.11.21
*/
#include <list>
#include <epicsGuard.h>
#include <epicsThread.h>
#include <pv/status.h>
#include <pv/pvAccess.h>
#include <pv/createRequest.h>
#include <pv/pvaVersion.h>
#include <pv/pvaVersionNum.h>
#include <pv/monitor.h>
#include <pv/convert.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
#include <pv/pvData.h>
#include <pv/rpcService.h>
#include <pv/pvTimeStamp.h>
#define epicsExportSharedSymbols
#include <pv/pvDatabase.h>
#include <pv/pvStructureCopy.h>
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
@@ -99,6 +111,37 @@ PVRecord::~PVRecord()
notifyClients();
}
void PVRecord::remove()
{
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
if(pvDatabase) pvDatabase->removeRecord(shared_from_this());
pvTimeStamp.detach();
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
iter!=pvListenerList.end();
iter++ )
{
PVListenerPtr listener = iter->lock();
if(!listener) continue;
if(traceLevel>0) {
cout << "PVRecord::remove() calling listener->unlisten " << recordName << endl;
}
listener->unlisten(shared_from_this());
}
pvListenerList.clear();
for (std::list<PVRecordClientWPtr>::iterator iter = clientList.begin();
iter!=clientList.end();
iter++ )
{
PVRecordClientPtr client = iter->lock();
if(!client) continue;
if(traceLevel>0) {
cout << "PVRecord::remove() calling client->detach " << recordName << endl;
}
client->detach(shared_from_this());
}
clientList.clear();
}
void PVRecord::initPVRecord()
{
PVRecordStructurePtr parent;

63
src/pv/addRecord.h Normal file
View File

@@ -0,0 +1,63 @@
/* addRecord.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#ifndef ADDRECORD_H
#define ADDRECORD_H
#include <pv/channelProviderLocal.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class AddRecord;
typedef std::tr1::shared_ptr<AddRecord> AddRecordPtr;
/**
* @brief Add another record in the same database.
*
* A record to add another record
* It is meant to be used via a channelPutGet request.
* The argument has one field: recordName.
* The result has a field named status.
*/
class epicsShareClass AddRecord :
public PVRecord
{
public:
POINTER_DEFINITIONS(AddRecord);
/**
* Factory methods to create AddRecord.
* @param recordName The name for the AddRecord.
* @return A shared pointer to AddRecord..
*/
static AddRecordPtr create(
std::string const & recordName);
/**
* standard init method required by PVRecord
* @return true unless record name already exists.
*/
virtual bool init();
/**
* @brief Add the record specified by recordName.
*/
virtual void process();
private:
AddRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure);
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVStringPtr pvResult;
};
}}
#endif /* ADDRECORD_H */

View File

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

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

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

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

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

View File

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

View File

@@ -6,26 +6,15 @@
#ifndef PVDATABASE_H
#define PVDATABASE_H
#ifdef epicsExportSharedSymbols
# define pvdatabaseEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <list>
#include <map>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#ifdef pvdatabaseEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef pvdatabaseEpicsExportSharedSymbols
#endif
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
#include <pv/pvStructureCopy.h>
namespace epics { namespace pvDatabase {
@@ -101,6 +90,15 @@ public:
* @brief DEPRECATED
*/
virtual void destroy() {}
/**
* @brief remove record from database.
*
* Remove the PVRecord. Release any resources used and
* get rid of listeners and requesters.
* If derived class overrides this then it must call PVRecord::remove()
* after it has destroyed any resorces it uses.
*/
virtual void remove();
/**
* @brief Optional method for derived class.
*

View File

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

View File

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

View File

@@ -10,10 +10,6 @@
#ifndef PVSTRUCTURECOPY_H
#define PVSTRUCTURECOPY_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string>
#include <stdexcept>
#include <memory>
@@ -204,10 +200,16 @@ private:
epics::pvData::PVFieldPtr const &pvCopy,
CopyNodePtr const &node,
epics::pvData::BitSetPtr const &bitSet);
void updateMaster(
epics::pvData::PVFieldPtr const &pvCopy,
CopyNodePtr const &node,
void updateMasterField(
CopyNodePtr const & node,
epics::pvData::PVFieldPtr const & pvCopy,
epics::pvData::PVFieldPtr const &pvMaster,
epics::pvData::BitSetPtr const &bitSet);
void updateMasterCheckBitSet(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet,
size_t nextSet);
CopyNodePtr getCopyNode(std::size_t fieldOffset);
PVCopy(epics::pvData::PVStructurePtr const &pvMaster);
bool init(epics::pvData::PVStructurePtr const &pvRequest);
@@ -239,7 +241,6 @@ private:
std::string *builder,
CopyNodePtr const &node,
int indentLevel);
friend class PVCopyMonitor;
};
}}

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

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,30 +11,19 @@
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <cantProceed.h>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <shareLib.h>
#include <epicsExit.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/syncChannelFind.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
// this declared epicsExportSharedSymbols
// The following must be the last include for code pvDatabase uses
#include <epicsExport.h>
#include <pv/channelProviderLocal.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using std::cout;
using std::endl;

View File

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

118
src/special/addRecord.cpp Normal file
View File

@@ -0,0 +1,118 @@
/* addRecord.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <set>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/standardField.h>
#include <pv/pvTimeStamp.h>
#include <pv/timeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
#include "pv/addRecord.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
AddRecordPtr AddRecord::create(
std::string const & recordName)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("recordName",pvString)->
addNestedUnion("union") ->
endNested()->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
AddRecordPtr pvRecord(
new AddRecord(recordName,pvStructure));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
AddRecord::AddRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure)
: PVRecord(recordName,pvStructure)
{
}
bool AddRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
return true;
}
void AddRecord::process()
{
PVDataCreatePtr pvDataCreate = getPVDataCreate();
string name = pvRecordName->get();
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
if(pvRecord) {
pvResult->put(name + " already exists");
return;
}
PVUnionPtr pvUnion = getPVStructure()->getSubField<PVUnion>("argument.union");
if(!pvUnion) {
pvResult->put(name + " argument.union is NULL");
return;
}
PVFieldPtr pvField(pvUnion->get());
if(!pvField) {
pvResult->put(name + " union has no value");
return;
}
if(pvField->getField()->getType()!=epics::pvData::structure) {
pvResult->put(name + " union most be a structure");
return;
}
StructureConstPtr st = static_pointer_cast<const Structure>(pvField->getField());
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(st);
PVRecordPtr pvRec = PVRecord::create(name,pvStructure);
bool result = PVDatabase::getMaster()->addRecord(pvRec);
if(result) {
pvResult->put("success");
} else {
pvResult->put("failure");
}
}
}}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,9 +8,28 @@
* @author mrk
* @date 2013.04.18
*/
#define epicsExportSharedSymbols
#include <pv/removeRecord.h>
#include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <set>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/timeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
#include "pv/removeRecord.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
@@ -65,7 +84,7 @@ void RemoveRecord::process()
pvResult->put(name + " not found");
return;
}
pvRecord->destroy();
pvRecord->remove();
pvResult->put("success");
}

View File

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

View File

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

View File

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

View File

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

View File

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

6
src/support/Makefile Normal file
View File

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

View File

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

View File

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