59 Commits
4.4.1 ... 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
Andrew Johnson
2715f585e0 Update version numbers to 4.4.2 for EPICS 7.0.2.2 release 2019-04-15 11:48:15 -05:00
mrkraimer
c2e3315f54 update RELEASE_NOTES 2019-04-11 13:59:57 -04:00
Marty Kraimer
d0ddcead24 Merge pull request #42 from mrkraimer/master
pvRequest - asking for subfield of non structure field crashes IOC; allow subfield of union
2019-04-04 05:27:41 -04:00
mrkraimer
5f42eec15a better exception messages 2019-03-31 15:38:13 -04:00
mrkraimer
20e55d5bca minor changes 2019-03-31 07:33:51 -04:00
mrkraimer
6d2d63621e address issue 41 2019-03-29 11:22:49 -04:00
55 changed files with 1968 additions and 197 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,32 @@
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
it resulted in a crash.
Now if a request is made for a subfield of a non structure field
1) if the field is not a union an exception is thrown which is passed to the client.
2) if the field is a union
a) if more than one subfield is requested an exception is thrown
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.
@@ -35,5 +61,3 @@ The test is now a regression test which can be run using:
This is the first release of pvDatabaseCPP.
It provides functionality equivalent to pvDatabaseJava.

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.1
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;
@@ -168,7 +168,7 @@ PVFieldPtr PVCopy::getMasterPVField(size_t structureOffset)
node = getMasterNode(snode,structureOffset);
}
if(!node) {
throw std::invalid_argument(
throw std::logic_error(
"PVCopy::getMasterPVField: structureOffset not valid");
}
size_t diff = structureOffset - node->structureOffset;
@@ -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::invalid_argument("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)
@@ -464,7 +506,13 @@ StructureConstPtr PVCopy::createStructure(
fields.push_back(field);
}
size_t numsubfields = fields.size();
if(numsubfields==0) return NULLStructure;
if(numsubfields==0) {
std::stringstream ss;
ss << pvFromRequest << "\n";
string val("no fields from the following request were found\n");
val += ss.str();
throw std::invalid_argument(val);
}
return getFieldCreate()->createStructure(fieldNames, fields);
}
@@ -487,16 +535,65 @@ CopyNodePtr PVCopy::createStructureNodes(
requestPVStructure->getSubField<PVStructure>("_options");
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
if(!pvMasterField) {
throw std::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();
if(pvSubFieldOptions) numberRequest--;
bool haveOptions = false;
if(pvSubFieldOptions) {
numberRequest--;
haveOptions = true;
}
if(numberRequest>0) {
nodes->push_back(createStructureNodes(
static_pointer_cast<PVStructure>(pvMasterField),
requestPVStructure,
static_pointer_cast<PVStructure>(copyPVField)));
continue;
Type copyType = copyPVField->getField()->getType();
if(copyType==epics::pvData::structure) {
nodes->push_back(createStructureNodes(
static_pointer_cast<PVStructure>(pvMasterField),
requestPVStructure,
static_pointer_cast<PVStructure>(copyPVField)));
continue;
}
if(copyType==epics::pvData::union_) {
if(numberRequest!=1) {
std::stringstream ss;
ss << pvFromRequest << "\n";
string val("In the following request a union field has more than one subfield in\n");
val += ss.str();
throw std::invalid_argument(val);
}
PVUnionPtr pvUnion = static_pointer_cast<PVUnion>(pvMasterField);
std::string selectedName = pvUnion->getSelectedFieldName();
PVFieldPtrArray const & pvFields = requestPVStructure->getPVFields();
size_t len = pvFields.size();
if(len>2 || (haveOptions && len!=2)) {
std::stringstream ss;
ss << pvFromRequest << "\n";
string val("PVCopy logic error: pvRequest is\n");
val += ss.str();
throw std::logic_error(val);
}
size_t indRequestValue = 0;
if((pvFields[0]->getFieldName().compare("_options"))==0) indRequestValue = 1;
PVFieldPtr pvRequestValue = pvFields[indRequestValue];
if(pvRequestValue) {
string requestName = pvRequestValue->getFieldName();
if(requestName.compare(selectedName)!=0) {
std::stringstream ss;
ss << pvFromCopy << "\n";
string requestName = pvRequestValue->getFieldName();
string val("field ");
val += requestName + " does not match union type in\n";
val += ss.str();
throw std::invalid_argument(val);
}
}
} else {
std::stringstream ss;
ss << pvFromCopy << "\n";
string val("requested a subfield of field ");
val += fieldName + " which does not have type structure in\n";
val += ss.str();
throw std::invalid_argument(val);
}
}
CopyNodePtr node(new CopyNode());
node->options = pvSubFieldOptions;

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