72 Commits
4.4.2 ... 4.5.2

Author SHA1 Message Date
Andrew Johnson
3f5bfd067f Update version numbers for release 2020-05-28 16:14:30 -05:00
mrkraimer
85165e6579 get ready for next epics7 release 2020-05-20 14:03:13 -04:00
Marty Kraimer
476a8f1e32 Merge pull request #56 from dirk-zimoch/CleanupWhitespace
Cleanup whitespace
2020-05-20 08:47:32 -04:00
31e883dbbc removed empty lines at end of file 2020-04-15 18:00:08 +02:00
57cbf66833 removed spaces at end of line 2020-04-15 17:58:14 +02:00
7f31332a80 replaced tabs with spaces 2020-04-15 17:54:47 +02:00
Marty Kraimer
12015309d8 Merge pull request #55 from epics-base/arrayfilterforunion
Arrayfilterforunion
2020-04-13 06:27:41 -04:00
mrkraimer
1e62844a22 testPlugin found bug: added unionArrayTest 2020-04-12 14:01:22 -04:00
mrkraimer
ad479309b0 fix bitset bug 2020-04-08 11:06:59 -04:00
mrkraimer
2f7c82757f pvArrayPlugin now supports union scalarArray 2020-04-07 12:53:01 -04:00
Marty Kraimer
634153a28d Merge pull request #54 from epics-base/issue53
Issue53
2020-02-18 05:39:58 -05:00
Heesterman, Peter J
e664037063 static analysis during the Codathon at Diamond. 2020-02-17 12:06:08 +00:00
mrkraimer
75c16bd423 pvDatabase::removeRecord and pvRecord::remove no longer call eachother directly 2020-02-12 09:13:19 -05:00
mrkraimer
083dffac3c pvDatabase::removeRecord and pvRecord::remove changes;descructors now have at most a print statement 2020-02-10 06:15:59 -05:00
mrkraimer
42ba054e5f add createdestroy example 2020-02-07 10:58:55 -05:00
mrkraimer
3173e9aeae problems with examples 2020-02-07 09:17:08 -05:00
mrkraimer
785d654129 first attempt to fix issue 53; add example 2020-02-07 08:54:18 -05:00
Ralph Lange
22ce4440b7 Fix bug preventing "whole structure" bitset(0) copy
(fixes #52)
(this should have a test added, but I am not familiar enough with the code)
2020-01-28 15:44:27 +01:00
Andrew Johnson
80baccfd9c Incr version and set development flag after release 2019-11-01 12:52:23 -05:00
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
67 changed files with 2389 additions and 425 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=7.0 RTEMS=4.9 TEST=NO
- BRBASE=3.16 - BRBASE=3.16
- BRBASE=3.15 - 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 # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = PROJECT_NUMBER = 4.5.2
# Using the PROJECT_BRIEF tag one can provide an optional one line description # 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 # 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 # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched. # 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 # 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 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1035,7 +1035,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # 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 = 2
# 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 include $(TOP)/configure/CONFIG
CFG += CONFIG_PVDATABASE_VERSION
TARGETS = $(CONFIG_TARGETS) TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@@ -2,6 +2,23 @@
This document summarizes the changes to the module between releases. This document summarizes the changes to the module between releases.
## Release 4.5.2 (EPICS 7.0.3.2 May 2020)
* plugin support is new
* fixed issues #53 and #52
## 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) ## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019)
Formerly if a client makes a request for a subfield of a non structure field Formerly if a client makes a request for a subfield of a non structure field
@@ -15,6 +32,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 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 c) if type is not the same an exception is thrown
## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019) ## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019)
* Cleaned up some build warnings. * Cleaned up some build warnings.

View File

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

View File

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

25
example/createdestroy/Makefile Executable file
View File

@@ -0,0 +1,25 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#=============================
# Build the application
TESTPROD_HOST = createdestroy
createdestroy_SRCS += createdestroy.cpp
# Add all the support libraries needed by this application
#pvatest_LIBS += xxx
# Finally link to the EPICS Base libraries
createdestroy_LIBS += pvDatabase pvAccess pvData
createdestroy_LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@@ -0,0 +1,20 @@
# pvDatabaseCPP/example/createdestroy
This is an example that:
1) Gets the master PVDatabase
2) Create ChannelProviderLocal
3) Creates a ServerContext
Then it executes a forever loop that:
1) creates a pvRecord and adds it to the pvDatabase.
2) creates a pvac::ClientProvider
3) creates a pvac::ClientChannel
4) creates a monitor on the channel
5) runs a loop 10 times that: does a put to the channel, and then gets the data for any outstanding monitors
6) removes the pvRecord from the pvDatabase
It also has options to set trace level for the pvRecord and to periodically pause by asking for input.

View File

@@ -0,0 +1,179 @@
/******************************************************************************
* This is modeled after a test program created by Bertrand Bauvir from the ITER Organization
******************************************************************************/
#include <iostream>
#include <epicsGetopt.h>
#include <pv/pvData.h>
#include <pv/pvDatabase.h>
#include <pv/serverContext.h>
#include <pv/channelProviderLocal.h>
#include <pva/client.h>
#include <epicsEvent.h>
// Local header files
// Constants
#define DEFAULT_RECORD_NAME "examplechannel"
using std::tr1::static_pointer_cast;
class Record : public ::epics::pvDatabase::PVRecord
{
public:
std::shared_ptr<::epics::pvData::PVStructure> __pv;
static std::shared_ptr<Record> create (std::string const & name, std::shared_ptr<::epics::pvData::PVStructure> const & pvstruct);
Record (std::string const & name, std::shared_ptr<epics::pvData::PVStructure> const & pvstruct)
: epics::pvDatabase::PVRecord(name, pvstruct) { __pv = pvstruct; };
virtual void process (void);
};
std::shared_ptr<Record> Record::create (std::string const & name, std::shared_ptr<::epics::pvData::PVStructure> const & pvstruct)
{
std::shared_ptr<Record> pvrecord (new Record (name, pvstruct));
// Need to be explicitly called .. not part of the base constructor
if(!pvrecord->init()) pvrecord.reset();
return pvrecord;
}
void Record::process (void)
{
PVRecord::process();
std::string name = this->getRecordName();
std::cout << this->getRecordName()
<< " process\n";
}
class MyMonitor
{
private:
std::tr1::shared_ptr<::pvac::MonitorSync> monitor;
MyMonitor(std::tr1::shared_ptr<::pvac::ClientChannel> const &channel)
{
monitor = std::tr1::shared_ptr<::pvac::MonitorSync>(new ::pvac::MonitorSync(channel->monitor()));
}
public:
static std::tr1::shared_ptr<MyMonitor> create(std::tr1::shared_ptr<::pvac::ClientChannel> const &channel)
{
return std::tr1::shared_ptr<MyMonitor>(new MyMonitor(channel));
}
void getData();
};
void MyMonitor::getData()
{
while (true) {
if(!monitor->wait(.001)) break;
switch(monitor->event.event) {
case pvac::MonitorEvent::Fail:
std::cerr<<monitor->name()<<" : Error : "<<monitor->event.message<<"\n";
return;
case pvac::MonitorEvent::Cancel:
std::cout<<monitor->name()<<" <Cancel>\n";
return;
case pvac::MonitorEvent::Disconnect:
std::cout<<monitor->name()<<" <Disconnect>\n";
return;
case pvac::MonitorEvent::Data:
while(monitor->poll()) {
std::cout<<monitor->name()<<" : "<<monitor->root;
}
if(monitor->complete()) {
return;
}
}
}
}
int main (int argc, char** argv)
{
int verbose = 0;
unsigned loopctr = 0;
unsigned pausectr = 0;
bool allowExit = false;
bool callRecord = false;
bool callDatabase = false;
int opt;
while((opt = getopt(argc, argv, "v:ardh")) != -1) {
switch(opt) {
case 'v':
verbose = std::stoi(optarg);
break;
case 'a' :
allowExit = true;
break;
case 'r' :
callRecord = true;
break;
case 'd' :
callDatabase = true;
break;
case 'h':
std::cout << " -v level -a -r -d -h \n";
std::cout << "-r call pvRecord->remove -d call master->removeRecord\n";
std::cout << "default\n";
std::cout << "-v " << verbose
<< " -a false"
<< " -d"
<< "\n";
return 0;
default:
std::cerr<<"Unknown argument: "<<opt<<"\n";
return -1;
}
}
if(!callRecord && !callDatabase) callDatabase = true;
::epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
::epics::pvDatabase::ChannelProviderLocalPtr channelProvider = epics::pvDatabase::getChannelProviderLocal();
epics::pvAccess::ServerContext::shared_pointer context
= epics::pvAccess::startPVAServer(epics::pvAccess::PVACCESS_ALL_PROVIDERS, 0, true, true);
std::string startset("starting set of puts valuectr = ");
while (true) {
loopctr++;
std::string name = DEFAULT_RECORD_NAME + std::to_string(loopctr);
// Create record
// Create record structure
::epics::pvData::FieldBuilderPtr builder = epics::pvData::getFieldCreate()->createFieldBuilder();
builder->add("value", ::epics::pvData::pvULong);
std::shared_ptr<::epics::pvData::PVStructure> pvstruct
= ::epics::pvData::getPVDataCreate()->createPVStructure(builder->createStructure());
std::shared_ptr<Record> pvrecord = Record::create(std::string(name), pvstruct);
master->addRecord(pvrecord);
pvrecord->setTraceLevel(verbose);
// Start PVA (local) client
std::tr1::shared_ptr<::pvac::ClientProvider> provider
= std::tr1::shared_ptr<::pvac::ClientProvider>(new ::pvac::ClientProvider ("pva"));
std::tr1::shared_ptr<::pvac::ClientChannel> channel
= std::tr1::shared_ptr<::pvac::ClientChannel>(new ::pvac::ClientChannel (provider->connect(name)));
std::tr1::shared_ptr<MyMonitor> mymonitor = MyMonitor::create(channel);
unsigned valuectr = loopctr;
std::cout << startset << loopctr << "\n";
for (int ind=0; ind<100; ind++) {
channel->put().set("value",valuectr++).exec();
mymonitor->getData();
}
pausectr++;
if(allowExit && pausectr>10) {
pausectr = 0;
std::cout << "Type exit to stop: \n";
int c = std::cin.peek(); // peek character
if ( c == EOF ) continue;
std::string str;
std::getline(std::cin,str);
if(str.compare("exit")==0) break;
}
if(callRecord) {
std::cout << "callRecord\n";
pvrecord->remove();
}
if(callDatabase) {
std::cout << "callDatabase\n";
master->removeRecord(pvrecord);
}
}
return (0);
}

View File

@@ -3,22 +3,41 @@
TOP = .. TOP = ..
include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG
# needed for Windows
LIB_SYS_LIBS_WIN32 += netapi32 ws2_32
PVDATABASE_SRC = $(TOP)/src PVDATABASE_SRC = $(TOP)/src
LIBRARY += pvDatabase LIBRARY += pvDatabase
# shared library ABI version. # shared library ABI version.
SHRLIB_VERSION ?= 4.4.2 SHRLIB_VERSION ?= $(EPICS_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/channelProviderLocal.h
INC += pv/pvDatabase.h
INC += pv/traceRecord.h INC += pv/traceRecord.h
INC += pv/removeRecord.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)/copy/Makefile
include $(PVDATABASE_SRC)/database/Makefile include $(PVDATABASE_SRC)/database/Makefile
include $(PVDATABASE_SRC)/pvAccess/Makefile include $(PVDATABASE_SRC)/pvAccess/Makefile
include $(PVDATABASE_SRC)/special/Makefile include $(PVDATABASE_SRC)/special/Makefile
include $(PVDATABASE_SRC)/support/Makefile
pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS) pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS) pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)

View File

@@ -1,15 +1,12 @@
# This is a Makefile fragment, see ../Makefile # This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATABASE_SRC)/copy 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 += pvPlugin.cpp
LIBSRCS += pvCopy.cpp
LIBSRCS += pvArrayPlugin.cpp LIBSRCS += pvArrayPlugin.cpp
LIBSRCS += pvDeadbandPlugin.cpp LIBSRCS += pvDeadbandPlugin.cpp
LIBSRCS += pvTimestampPlugin.cpp LIBSRCS += pvTimestampPlugin.cpp

View File

@@ -9,7 +9,7 @@
#include <pv/convert.h> #include <pv/convert.h>
#include <pv/pvSubArrayCopy.h> #include <pv/pvSubArrayCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvArrayPlugin.h> #include "pv/pvArrayPlugin.h"
using std::string; using std::string;
using std::size_t; using std::size_t;
@@ -76,9 +76,19 @@ static vector<string> split(string const & colonSeparatedList) {
PVArrayFilterPtr PVArrayFilter::create( PVArrayFilterPtr PVArrayFilter::create(
const std::string & requestValue, const std::string & requestValue,
const PVFieldPtr & master) const PVFieldPtr & masterField)
{ {
Type type = master->getField()->getType(); bool masterIsUnion = false;
PVUnionPtr pvUnion;
Type type = masterField->getField()->getType();
if(type==epics::pvData::union_) {
pvUnion = std::tr1::static_pointer_cast<PVUnion>(masterField);
PVFieldPtr pvField = pvUnion->get();
if(pvField) {
masterIsUnion = true;
type = pvField->getField()->getType();
}
}
if(type!=scalarArray) { if(type!=scalarArray) {
PVArrayFilterPtr filter = PVArrayFilterPtr(); PVArrayFilterPtr filter = PVArrayFilterPtr();
return filter; return filter;
@@ -112,60 +122,82 @@ PVArrayFilterPtr PVArrayFilter::create(
PVArrayFilterPtr filter = PVArrayFilterPtr(); PVArrayFilterPtr filter = PVArrayFilterPtr();
return filter; return filter;
} }
PVScalarArrayPtr masterArray;
if(masterIsUnion) {
masterArray = static_pointer_cast<PVScalarArray>(pvUnion->get());
} else {
masterArray = static_pointer_cast<PVScalarArray>(masterField);
}
PVArrayFilterPtr filter = PVArrayFilterPtr filter =
PVArrayFilterPtr( PVArrayFilterPtr(
new PVArrayFilter( new PVArrayFilter(start,increment,end,masterField,masterArray));
start,increment,end,static_pointer_cast<PVScalarArray>(master)));
return filter; return filter;
} }
PVArrayFilter::PVArrayFilter(long start,long increment,long end,const PVScalarArrayPtr & masterArray) PVArrayFilter::PVArrayFilter(
long start,long increment,long end,
const PVFieldPtr & masterField,
const epics::pvData::PVScalarArrayPtr masterArray)
: start(start), : start(start),
increment(increment), increment(increment),
end(end), end(end),
masterField(masterField),
masterArray(masterArray) masterArray(masterArray)
{ {
} }
bool PVArrayFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy) bool PVArrayFilter::filter(const PVFieldPtr & pvField,const BitSetPtr & bitSet,bool toCopy)
{ {
PVScalarArrayPtr copyArray = static_pointer_cast<PVScalarArray>(pvCopy); PVFieldPtr pvCopy = pvField;
PVScalarArrayPtr copyArray;
bool isUnion = false;
Type type = masterField->getField()->getType();
if(type==epics::pvData::union_) {
isUnion = true;
PVUnionPtr pvMasterUnion = std::tr1::static_pointer_cast<PVUnion>(masterField);
PVUnionPtr pvCopyUnion = std::tr1::static_pointer_cast<PVUnion>(pvCopy);
if(toCopy) pvCopyUnion->copy(*pvMasterUnion);
PVFieldPtr pvField = pvCopyUnion->get();
copyArray = static_pointer_cast<PVScalarArray>(pvField);
} else {
copyArray = static_pointer_cast<PVScalarArray>(pvCopy);
}
long len = 0; long len = 0;
long start = this->start; long start = this->start;
long end = this->end; long end = this->end;
long no_elements = masterArray->getLength(); long no_elements = masterArray->getLength();
if(start<0) { if(start<0) {
start = no_elements+start; start = no_elements+start;
if(start<0) start = 0; if(start<0) start = 0;
} }
if (end < 0) { if (end < 0) {
end = no_elements + end; end = no_elements + end;
if (end < 0) end = 0; if (end < 0) end = 0;
} }
if(toCopy) { if(toCopy) {
if (end >= no_elements) end = no_elements - 1; if (end >= no_elements) end = no_elements - 1;
if (end - start >= 0) len = 1 + (end - start) / increment; if (end - start >= 0) len = 1 + (end - start) / increment;
if(len<=0 || start>=no_elements) { if(len<=0 || start>=no_elements) {
copyArray->setLength(0); copyArray->setLength(0);
return true; return true;
} }
long indfrom = start; long indfrom = start;
long indto = 0; long indto = 0;
copyArray->setCapacity(len); copyArray->setCapacity(len);
if(increment==1) { if(increment==1) {
copy(*masterArray,indfrom,1,*copyArray,indto,1,len); copy(*masterArray,indfrom,1,*copyArray,indto,1,len);
} else { } else {
for(long i=0; i<len; ++i) { for(long i=0; i<len; ++i) {
copy(*masterArray,indfrom,1,*copyArray,indto,1,1); copy(*masterArray,indfrom,1,*copyArray,indto,1,1);
indfrom += increment; indfrom += increment;
indto += 1; indto += 1;
} }
} }
copyArray->setLength(len); copyArray->setLength(len);
bitSet->set(pvCopy->getFieldOffset()); bitSet->set(pvField->getFieldOffset());
return true; return true;
} }
if (end - start >= 0) len = 1 + (end - start) / increment; if (end - start >= 0) len = 1 + (end - start) / increment;
if(len<=0) return true; if(len<=0) return true;
@@ -173,21 +205,21 @@ bool PVArrayFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bo
long indfrom = 0; long indfrom = 0;
long indto = start; long indto = start;
if(increment==1) { if(increment==1) {
copy(*copyArray,indfrom,1,*masterArray,indto,1,len); copy(*copyArray,indfrom,1,*masterArray,indto,1,len);
} else { } else {
for(long i=0; i<len; ++i) { for(long i=0; i<len; ++i) {
copy(*copyArray,indfrom,1,*masterArray,indto,1,1); copy(*copyArray,indfrom,1,*masterArray,indto,1,1);
indfrom += increment; indfrom += 1;
indto += 1; indto += increment;
} }
} }
if(isUnion) masterField->postPut();
return true; return true;
} }
string PVArrayFilter::getName() string PVArrayFilter::getName()
{ {
return name; return name;
} }
}} }}

View File

@@ -17,8 +17,8 @@
#include <pv/thread.h> #include <pv/thread.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvPlugin.h> #include "pv/pvPlugin.h"
#include <pv/pvStructureCopy.h> #include "pv/pvStructureCopy.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast; using std::tr1::dynamic_pointer_cast;
@@ -29,7 +29,7 @@ using std::endl;
using std::vector; using std::vector;
using namespace epics::pvData; using namespace epics::pvData;
namespace epics { namespace pvCopy { namespace epics { namespace pvCopy {
/** /**
* Convenience method for implementing dump. * Convenience method for implementing dump.
@@ -60,19 +60,19 @@ struct CopyNode {
PVStructurePtr options; PVStructurePtr options;
vector<PVFilterPtr> pvFilters; vector<PVFilterPtr> pvFilters;
}; };
static CopyNodePtr NULLCopyNode; static CopyNodePtr NULLCopyNode;
typedef std::vector<CopyNodePtr> CopyNodePtrArray; typedef std::vector<CopyNodePtr> CopyNodePtrArray;
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr; typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
struct CopyStructureNode : public CopyNode { struct CopyStructureNode : public CopyNode {
CopyNodePtrArrayPtr nodes; CopyNodePtrArrayPtr nodes;
}; };
PVCopyPtr PVCopy::create( PVCopyPtr PVCopy::create(
PVStructurePtr const &pvMaster, PVStructurePtr const &pvMaster,
PVStructurePtr const &pvRequest, PVStructurePtr const &pvRequest,
string const & structureName) string const & structureName)
{ {
PVStructurePtr pvStructure(pvRequest); PVStructurePtr pvStructure(pvRequest);
@@ -114,7 +114,7 @@ PVStructurePtr PVCopy::createPVStructure()
cacheInitStructure.reset(); cacheInitStructure.reset();
return save; return save;
} }
PVStructurePtr pvStructure = PVStructurePtr pvStructure =
getPVDataCreate()->createPVStructure(structure); getPVDataCreate()->createPVStructure(structure);
return pvStructure; return pvStructure;
} }
@@ -212,19 +212,91 @@ bool PVCopy::updateCopyFromBitSet(
return checkIgnore(copyPVStructure,bitSet); 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( void PVCopy::updateMaster(
PVStructurePtr const &copyPVStructure, PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet) BitSetPtr const &bitSet)
{ {
if(bitSet->get(0)) { updateMasterCheckBitSet(copyPVStructure,bitSet,0);
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) { size_t nextSet =0;
bitSet->set(i,true); 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) PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
{ {
if(fieldOffset==0) return headNode->options; if(fieldOffset==0) return headNode->options;
@@ -248,7 +320,7 @@ PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
} }
} }
if(okToContinue) continue; if(okToContinue) continue;
throw std::logic_error("PVCopy logic error: fieldOffset not valid"); throw std::logic_error("PVCopy::getOptions logic error: fieldOffset not valid");
} }
} }
@@ -342,43 +414,13 @@ void PVCopy::updateCopyFromBitSet(
size_t offset = structureNode->structureOffset; size_t offset = structureNode->structureOffset;
size_t nextSet = bitSet->nextSetBit(offset); size_t nextSet = bitSet->nextSetBit(offset);
if(nextSet==string::npos) return; if(nextSet==string::npos) return;
if(offset>=pvCopy->getNextFieldOffset()) return; if(offset>=pvCopy->getNextFieldOffset()) return;
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy); PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields(); PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
for(size_t i=0; i<pvCopyFields.size(); ++i) { for(size_t i=0; i<pvCopyFields.size(); ++i) {
updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet); 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( PVCopy::PVCopy(
PVStructurePtr const &pvMaster) PVStructurePtr const &pvMaster)
@@ -487,13 +529,13 @@ CopyNodePtr PVCopy::createStructureNodes(
for(size_t i=0; i<number; i++) { for(size_t i=0; i<number; i++) {
PVFieldPtr copyPVField = copyPVFields[i]; PVFieldPtr copyPVField = copyPVFields[i];
string fieldName = copyPVField->getFieldName(); string fieldName = copyPVField->getFieldName();
PVStructurePtr requestPVStructure = PVStructurePtr requestPVStructure =
pvFromRequest->getSubField<PVStructure>(fieldName); pvFromRequest->getSubField<PVStructure>(fieldName);
PVStructurePtr pvSubFieldOptions = PVStructurePtr pvSubFieldOptions =
requestPVStructure->getSubField<PVStructure>("_options"); requestPVStructure->getSubField<PVStructure>("_options");
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName); PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
if(!pvMasterField) { 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(); size_t numberRequest = requestPVStructure->getPVFields().size();
bool haveOptions = false; bool haveOptions = false;
@@ -599,14 +641,14 @@ void PVCopy::initPlugin(
void PVCopy::traverseMasterInitPlugin() void PVCopy::traverseMasterInitPlugin()
{ {
traverseMasterInitPlugin(headNode); traverseMasterInitPlugin(headNode);
} }
void PVCopy::traverseMasterInitPlugin(CopyNodePtr const & node) void PVCopy::traverseMasterInitPlugin(CopyNodePtr const & node)
{ {
PVFieldPtr pvField = node->masterPVField; PVFieldPtr pvField = node->masterPVField;
PVStructurePtr pvOptions = node->options; PVStructurePtr pvOptions = node->options;
if(pvOptions) initPlugin(node,pvOptions,pvField); if(pvOptions) initPlugin(node,pvOptions,pvField);
if(!node->isStructure) return; if(!node->isStructure) return;
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node); CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structureNode->nodes; CopyNodePtrArrayPtr nodes = structureNode->nodes;
@@ -625,7 +667,7 @@ CopyNodePtr PVCopy::getCopyOffset(
CopyNodePtr node = (*nodes)[i]; CopyNodePtr node = (*nodes)[i];
if(!node->isStructure) { if(!node->isStructure) {
size_t off = node->masterPVField->getFieldOffset(); size_t off = node->masterPVField->getFieldOffset();
size_t nextOffset = node->masterPVField->getNextFieldOffset(); size_t nextOffset = node->masterPVField->getNextFieldOffset();
if(offset>= off && offset<nextOffset) return node; if(offset>= off && offset<nextOffset) return node;
} else { } else {
CopyStructureNodePtr subNode = CopyStructureNodePtr subNode =
@@ -668,7 +710,7 @@ void PVCopy::setIgnore(CopyNodePtr const &node) {
CopyNodePtrArrayPtr nodes = structureNode->nodes; CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i<nodes->size(); ++i) { for(size_t i=0; i<nodes->size(); ++i) {
CopyNodePtr node = (*nodes)[i]; CopyNodePtr node = (*nodes)[i];
setIgnore(node); } setIgnore(node); }
} else { } else {
size_t num = node->masterPVField->getNumberFields(); size_t num = node->masterPVField->getNumberFields();
if(num>1) { if(num>1) {

View File

@@ -4,12 +4,15 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h> #include <pv/pvData.h>
#include <pv/bitSet.h> #include <pv/bitSet.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <pv/pvSubArrayCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvDeadbandPlugin.h> #include "pv/pvDeadbandPlugin.h"
using std::string; using std::string;
using std::size_t; using std::size_t;
@@ -64,9 +67,9 @@ PVDeadbandFilterPtr PVDeadbandFilter::create(
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field); ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr(); if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr();
bool absolute = false; bool absolute = false;
if(requestValue.find("abs")>=0) { if(requestValue.find("abs")==0) {
absolute = true; absolute = true;
} else if(requestValue.find("rel")>=0) { } else if(requestValue.find("rel")==0) {
absolute = false; absolute = false;
} else { } else {
return PVDeadbandFilterPtr(); return PVDeadbandFilterPtr();
@@ -79,7 +82,7 @@ PVDeadbandFilterPtr PVDeadbandFilter::create(
PVDeadbandFilterPtr filter = PVDeadbandFilterPtr filter =
PVDeadbandFilterPtr( PVDeadbandFilterPtr(
new PVDeadbandFilter( new PVDeadbandFilter(
absolute,deadband,static_pointer_cast<PVScalar>(master))); absolute,deadband,static_pointer_cast<PVScalar>(master)));
return filter; return filter;
} }
@@ -88,7 +91,7 @@ PVDeadbandFilter::PVDeadbandFilter(bool absolute,double deadband,PVScalarPtr con
deadband(deadband), deadband(deadband),
master(master), master(master),
firstTime(true), firstTime(true),
lastReportedValue(0.0) lastReportedValue(0.0)
{ {
} }
@@ -125,8 +128,7 @@ bool PVDeadbandFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet
string PVDeadbandFilter::getName() string PVDeadbandFilter::getName()
{ {
return name; return name;
} }
}} }}

View File

@@ -4,13 +4,17 @@
*/ */
#include <pv/pvData.h> #include <pv/pvData.h>
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/bitSet.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvStructureCopy.h> #include "pv/pvPlugin.h"
#include <pv/pvPlugin.h>
using namespace epics::pvData; using namespace epics::pvData;
namespace epics { namespace pvCopy{ namespace epics { namespace pvCopy{
typedef std::map<std::string,PVPluginPtr> PVPluginMap; typedef std::map<std::string,PVPluginPtr> PVPluginMap;
@@ -34,4 +38,3 @@ PVPluginPtr PVPluginRegistry::find(const std::string & name)
} }
}} }}

View File

@@ -3,14 +3,17 @@
* The License for this software can be found in the file LICENSE that is included with the distribution. * The License for this software can be found in the file LICENSE that is included with the distribution.
*/ */
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h> #include <pv/pvData.h>
#include <pv/bitSet.h> #include <pv/bitSet.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <pv/pvTimeStamp.h> #include <pv/pvTimeStamp.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvTimestampPlugin.h> #include "pv/pvPlugin.h"
#include <pv/pvStructureCopy.h> #include "pv/pvTimestampPlugin.h"
using std::string; using std::string;
using std::size_t; using std::size_t;
@@ -86,7 +89,7 @@ PVTimestampFilter::PVTimestampFilter(bool current,bool copy,PVFieldPtr const & m
bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy) bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
{ {
if(current) { if(current) {
timeStamp.getCurrent(); timeStamp.getCurrent();
if(toCopy) { if(toCopy) {
if(!pvTimeStamp.attach(pvCopy)) return false; if(!pvTimeStamp.attach(pvCopy)) return false;
@@ -97,7 +100,7 @@ bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSe
bitSet->set(pvCopy->getFieldOffset()); bitSet->set(pvCopy->getFieldOffset());
return true; return true;
} }
if(copy) { if(copy) {
if(toCopy) { if(toCopy) {
if(!pvTimeStamp.attach(master)) return false; if(!pvTimeStamp.attach(master)) return false;
pvTimeStamp.get(timeStamp); pvTimeStamp.get(timeStamp);
@@ -117,8 +120,7 @@ bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSe
string PVTimestampFilter::getName() string PVTimestampFilter::getName()
{ {
return name; return name;
} }
}} }}

View File

@@ -10,13 +10,19 @@
*/ */
#include <epicsGuard.h> #include <epicsGuard.h>
#include <list>
#include <map>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvDatabase.h> #include "pv/pvStructureCopy.h"
#include <pv/pvStructureCopy.h> #include "pv/pvDatabase.h"
#include <pv/pvPlugin.h> #include "pv/pvPlugin.h"
#include <pv/pvArrayPlugin.h> #include "pv/pvArrayPlugin.h"
#include <pv/pvTimestampPlugin.h> #include "pv/pvTimestampPlugin.h"
#include <pv/pvDeadbandPlugin.h> #include "pv/pvDeadbandPlugin.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
@@ -38,7 +44,7 @@ PVDatabasePtr PVDatabase::getMaster()
PVArrayPlugin::create(); PVArrayPlugin::create();
PVTimestampPlugin::create(); PVTimestampPlugin::create();
PVDeadbandPlugin::create(); PVDeadbandPlugin::create();
} }
return pvDatabaseMaster; return pvDatabaseMaster;
} }
@@ -50,14 +56,6 @@ PVDatabase::PVDatabase()
PVDatabase::~PVDatabase() PVDatabase::~PVDatabase()
{ {
if(DEBUG_LEVEL>0) cout << "PVDatabase::~PVDatabase()\n"; if(DEBUG_LEVEL>0) cout << "PVDatabase::~PVDatabase()\n";
size_t len = recordMap.size();
shared_vector<string> names(len);
PVRecordMap::iterator iter;
size_t i = 0;
for(iter = recordMap.begin(); iter!=recordMap.end(); ++iter) {
names[i++] = (*iter).first;
}
for(size_t i=0; i<len; ++i) removeRecord(findRecord(names[i]));
} }
void PVDatabase::lock() { void PVDatabase::lock() {
@@ -94,17 +92,28 @@ bool PVDatabase::addRecord(PVRecordPtr const & record)
return true; return true;
} }
bool PVDatabase::removeRecord(PVRecordPtr const & record) PVRecordWPtr PVDatabase::removeFromMap(PVRecordPtr const & record)
{ {
if(record->getTraceLevel()>0) {
cout << "PVDatabase::removeRecord " << record->getRecordName() << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex); epicsGuard<epics::pvData::Mutex> guard(mutex);
string recordName = record->getRecordName(); string recordName = record->getRecordName();
PVRecordMap::iterator iter = recordMap.find(recordName); PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) { if(iter!=recordMap.end()) {
PVRecordPtr pvRecord = (*iter).second; PVRecordPtr pvRecord = (*iter).second;
recordMap.erase(iter); recordMap.erase(iter);
return pvRecord->shared_from_this();
}
return PVRecordWPtr();
}
bool PVDatabase::removeRecord(PVRecordPtr const & record)
{
if(record->getTraceLevel()>0) {
cout << "PVDatabase::removeRecord " << record->getRecordName() << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
PVRecordWPtr pvRecord = removeFromMap(record);
if(pvRecord.use_count()!=0) {
pvRecord.lock()->unlistenClients();
return true; return true;
} }
return false; return false;

View File

@@ -8,13 +8,25 @@
* @author mrk * @author mrk
* @date 2012.11.21 * @date 2012.11.21
*/ */
#include <list>
#include <epicsGuard.h> #include <epicsGuard.h>
#include <epicsThread.h> #include <epicsThread.h>
#include <pv/status.h>
#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 #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 std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
@@ -46,16 +58,16 @@ PVRecord::PVRecord(
{ {
} }
void PVRecord::notifyClients() PVRecord::~PVRecord()
{ {
{ if(traceLevel>0) {
epicsGuard<epics::pvData::Mutex> guard(mutex); cout << "~PVRecord() " << recordName << endl;
if(traceLevel>0) {
cout << "PVRecord::notifyClients() " << recordName
<< endl;
}
} }
pvTimeStamp.detach(); }
void PVRecord::unlistenClients()
{
epicsGuard<epics::pvData::Mutex> guard(mutex);
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin(); for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
iter!=pvListenerList.end(); iter!=pvListenerList.end();
iter++ ) iter++ )
@@ -63,8 +75,7 @@ void PVRecord::notifyClients()
PVListenerPtr listener = iter->lock(); PVListenerPtr listener = iter->lock();
if(!listener) continue; if(!listener) continue;
if(traceLevel>0) { if(traceLevel>0) {
cout << "PVRecord::notifyClients() calling listener->unlisten " cout << "PVRecord::remove() calling listener->unlisten " << recordName << endl;
<< recordName << endl;
} }
listener->unlisten(shared_from_this()); listener->unlisten(shared_from_this());
} }
@@ -76,27 +87,24 @@ void PVRecord::notifyClients()
PVRecordClientPtr client = iter->lock(); PVRecordClientPtr client = iter->lock();
if(!client) continue; if(!client) continue;
if(traceLevel>0) { if(traceLevel>0) {
cout << "PVRecord::notifyClients() calling client->detach " cout << "PVRecord::remove() calling client->detach " << recordName << endl;
<< recordName << endl;
} }
client->detach(shared_from_this()); client->detach(shared_from_this());
} }
if(traceLevel>0) {
cout << "PVRecord::notifyClients() calling clientList.clear() "
<< recordName << endl;
}
clientList.clear(); clientList.clear();
if(traceLevel>0) {
cout << "PVRecord::notifyClients() returning " << recordName << endl;
}
} }
PVRecord::~PVRecord()
void PVRecord::remove()
{ {
if(traceLevel>0) { if(traceLevel>0) {
cout << "~PVRecord() " << recordName << endl; cout << "PVRecord::remove() " << recordName << endl;
} }
notifyClients(); unlistenClients();
epicsGuard<epics::pvData::Mutex> guard(mutex);
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
if(pvDatabase) pvDatabase->removeFromMap(shared_from_this());
pvTimeStamp.detach();
} }
void PVRecord::initPVRecord() void PVRecord::initPVRecord()
@@ -240,7 +248,7 @@ void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
PVRecordFieldPtr pvRecordField = findPVRecordField(pvField); PVRecordFieldPtr pvRecordField = findPVRecordField(pvField);
PVListenerPtr listener = pvListener.lock(); PVListenerPtr listener = pvListener.lock();
if(!listener.get()) return; if(!listener.get()) return;
if(isAddListener) { if(isAddListener) {
pvRecordField->addListener(listener); pvRecordField->addListener(listener);
} else { } else {
pvRecordField->removeListener(listener); pvRecordField->removeListener(listener);
@@ -369,7 +377,7 @@ bool PVRecordField::addListener(PVListenerPtr const & pvListener)
void PVRecordField::removeListener(PVListenerPtr const & pvListener) void PVRecordField::removeListener(PVListenerPtr const & pvListener)
{ {
PVRecordPtr pvRecord(this->pvRecord.lock()); PVRecordPtr pvRecord(this->pvRecord.lock());
if(pvRecord && pvRecord->getTraceLevel()>1) { if(pvRecord && pvRecord->getTraceLevel()>1) {
cout << "PVRecordField::removeListener() " << getFullName() << endl; cout << "PVRecordField::removeListener() " << getFullName() << endl;
} }
@@ -411,7 +419,7 @@ void PVRecordField::postSubField()
{ {
callListener(); callListener();
if(isStructure) { if(isStructure) {
PVRecordStructurePtr pvrs = PVRecordStructurePtr pvrs =
static_pointer_cast<PVRecordStructure>(shared_from_this()); static_pointer_cast<PVRecordStructure>(shared_from_this());
PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields(); PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields();
PVRecordFieldPtrArray::iterator iter; PVRecordFieldPtrArray::iterator iter;
@@ -451,7 +459,7 @@ void PVRecordStructure::init()
PVRecordStructurePtr self = PVRecordStructurePtr self =
static_pointer_cast<PVRecordStructure>(shared_from_this()); static_pointer_cast<PVRecordStructure>(shared_from_this());
PVRecordPtr pvRecord = getPVRecord(); PVRecordPtr pvRecord = getPVRecord();
for(size_t i=0; i<numFields; i++) { for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i]; PVFieldPtr pvField = pvFields[i];
if(pvField->getField()->getType()==structure) { if(pvField->getField()->getType()==structure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField); PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);

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 #ifndef CHANNELPROVIDERLOCAL_H
#define CHANNELPROVIDERLOCAL_H #define CHANNELPROVIDERLOCAL_H
#ifdef epicsExportSharedSymbols
# define channelProviderLocalEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
@@ -28,18 +23,12 @@
#include <pv/pvAccess.h> #include <pv/pvAccess.h>
#include <pv/status.h> #include <pv/status.h>
#include <pv/serverContext.h> #include <pv/serverContext.h>
#include <pv/pvStructureCopy.h>
#include <pv/pvDatabase.h>
#ifdef channelProviderLocalEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef channelProviderLocalEpicsExportSharedSymbols
#endif
#include <shareLib.h> #include <shareLib.h>
#include <pv/pvDatabase.h>
#include <pv/pvStructureCopy.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
class ChannelProviderLocal; class ChannelProviderLocal;
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr; typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
@@ -104,7 +93,7 @@ public:
virtual epics::pvAccess::ChannelFind::shared_pointer channelFind( virtual epics::pvAccess::ChannelFind::shared_pointer channelFind(
std::string const &channelName, std::string const &channelName,
epics::pvAccess::ChannelFindRequester::shared_pointer const & channelFindRequester); epics::pvAccess::ChannelFindRequester::shared_pointer const & channelFindRequester);
/** /**
* @brief Calls method channelListRequester::channelListResult. * @brief Calls method channelListRequester::channelListResult.
* *
* This provides the caller with a list of the record names on the PVDatabase. * This provides the caller with a list of the record names on the PVDatabase.
@@ -112,7 +101,7 @@ public:
* @param channelListRequester The client callback. * @param channelListRequester The client callback.
* @return shared pointer to ChannelFind. * @return shared pointer to ChannelFind.
* The interface for SyncChannelFind is defined by pvAccessCPP. * The interface for SyncChannelFind is defined by pvAccessCPP.
*/ */
virtual epics::pvAccess::ChannelFind::shared_pointer channelList( virtual epics::pvAccess::ChannelFind::shared_pointer channelList(
epics::pvAccess::ChannelListRequester::shared_pointer const & channelListRequester); epics::pvAccess::ChannelListRequester::shared_pointer const & channelListRequester);
/** /**
@@ -197,28 +186,28 @@ public:
epics::pvAccess::ChannelRequester::shared_pointer const & requester, epics::pvAccess::ChannelRequester::shared_pointer const & requester,
PVRecordPtr const & pvRecord PVRecordPtr const & pvRecord
); );
/** /**
* @brief Destructor * @brief Destructor
*/ */
virtual ~ChannelLocal(); virtual ~ChannelLocal();
/** /**
* @brief DEPRECATED * @brief DEPRECATED
* *
*/ */
virtual void destroy() {}; virtual void destroy() {};
/** /**
* @brief Detach from the record. * @brief Detach from the record.
* *
* This is called when a record is being removed from the database. * This is called when a record is being removed from the database.
* @param pvRecord The record being removed. * @param pvRecord The record being removed.
*/ */
virtual void detach(PVRecordPtr const &pvRecord); virtual void detach(PVRecordPtr const &pvRecord);
/** /**
* @brief Get the requester name. * @brief Get the requester name.
* @return returns the name of the channel requester. * @return returns the name of the channel requester.
*/ */
virtual std::string getRequesterName(); virtual std::string getRequesterName();
/** /**
* @brief Passes the message to the channel requester. * @brief Passes the message to the channel requester.
* @param message The message. * @param message The message.
* @param messageType The message type. * @param messageType The message type.
@@ -226,37 +215,37 @@ public:
virtual void message( virtual void message(
std::string const & message, std::string const & message,
epics::pvData::MessageType messageType); epics::pvData::MessageType messageType);
/** /**
* @brief Get the channel provider * @brief Get the channel provider
* @return The provider. * @return The provider.
*/ */
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider(); virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider();
/** /**
* @brief Get the remote address * @brief Get the remote address
* @return <b>local</b> * @return <b>local</b>
*/ */
virtual std::string getRemoteAddress(); virtual std::string getRemoteAddress();
/** /**
* Get the connection state. * Get the connection state.
* @return Channel::CONNECTED. * @return Channel::CONNECTED.
*/ */
virtual epics::pvAccess::Channel::ConnectionState getConnectionState(); virtual epics::pvAccess::Channel::ConnectionState getConnectionState();
/** /**
* @brief Get the channel name. * @brief Get the channel name.
* @return the record name. * @return the record name.
*/ */
virtual std::string getChannelName(); virtual std::string getChannelName();
/** /**
* @brief Get the channel requester * @brief Get the channel requester
* @return The channel requester. * @return The channel requester.
*/ */
virtual epics::pvAccess::ChannelRequester::shared_pointer getChannelRequester(); virtual epics::pvAccess::ChannelRequester::shared_pointer getChannelRequester();
/** /**
* @brief Is the channel connected? * @brief Is the channel connected?
* @return true. * @return true.
*/ */
virtual bool isConnected(); virtual bool isConnected();
/** /**
* @brief Get the introspection interface for subField. * @brief Get the introspection interface for subField.
* *
* The introspection interface is given via GetFieldRequester::getDone. * The introspection interface is given via GetFieldRequester::getDone.
@@ -268,14 +257,14 @@ public:
virtual void getField( virtual void getField(
epics::pvAccess::GetFieldRequester::shared_pointer const &requester, epics::pvAccess::GetFieldRequester::shared_pointer const &requester,
std::string const & subField); std::string const & subField);
/** /**
* Get the access rights for the record. * Get the access rights for the record.
* This throws an exception because it is assumed that access rights are * This throws an exception because it is assumed that access rights are
* handled by a higher level. * handled by a higher level.
*/ */
virtual epics::pvAccess::AccessRights getAccessRights( virtual epics::pvAccess::AccessRights getAccessRights(
epics::pvData::PVField::shared_pointer const &pvField); epics::pvData::PVField::shared_pointer const &pvField);
/** /**
* @brief Create a channelProcess. * @brief Create a channelProcess.
* *
* @param requester The client callback. * @param requester The client callback.
@@ -286,9 +275,9 @@ public:
virtual epics::pvAccess::ChannelProcess::shared_pointer createChannelProcess( virtual epics::pvAccess::ChannelProcess::shared_pointer createChannelProcess(
epics::pvAccess::ChannelProcessRequester::shared_pointer const &requester, epics::pvAccess::ChannelProcessRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::PVStructurePtr const &pvRequest);
/** /**
* @brief Create a channelGet. * @brief Create a channelGet.
* *
* @param requester The client callback. * @param requester The client callback.
* @param pvRequest The options specified by the client. * @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation. * @return A shared pointer to the newly created implementation.
@@ -297,7 +286,7 @@ public:
virtual epics::pvAccess::ChannelGet::shared_pointer createChannelGet( virtual epics::pvAccess::ChannelGet::shared_pointer createChannelGet(
epics::pvAccess::ChannelGetRequester::shared_pointer const &requester, epics::pvAccess::ChannelGetRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::PVStructurePtr const &pvRequest);
/** /**
* @brief Create a channelPut. * @brief Create a channelPut.
* *
* @param requester The client callback. * @param requester The client callback.
@@ -308,9 +297,9 @@ public:
virtual epics::pvAccess::ChannelPut::shared_pointer createChannelPut( virtual epics::pvAccess::ChannelPut::shared_pointer createChannelPut(
epics::pvAccess::ChannelPutRequester::shared_pointer const &requester, epics::pvAccess::ChannelPutRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::PVStructurePtr const &pvRequest);
/** /**
* @brief Create a channelPutGet. * @brief Create a channelPutGet.
* *
* @param requester The client callback. * @param requester The client callback.
* @param pvRequest The options specified by the client. * @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation. * @return A shared pointer to the newly created implementation.
@@ -319,7 +308,7 @@ public:
virtual epics::pvAccess::ChannelPutGet::shared_pointer createChannelPutGet( virtual epics::pvAccess::ChannelPutGet::shared_pointer createChannelPutGet(
epics::pvAccess::ChannelPutGetRequester::shared_pointer const &requester, epics::pvAccess::ChannelPutGetRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::PVStructurePtr const &pvRequest);
/** /**
* @brief Create a channelRPC. * @brief Create a channelRPC.
* *
* The PVRecord must implement <b>getService</b> or an empty shared pointer is returned. * The PVRecord must implement <b>getService</b> or an empty shared pointer is returned.
@@ -330,9 +319,9 @@ public:
virtual epics::pvAccess::ChannelRPC::shared_pointer createChannelRPC( virtual epics::pvAccess::ChannelRPC::shared_pointer createChannelRPC(
epics::pvAccess::ChannelRPCRequester::shared_pointer const &requester, epics::pvAccess::ChannelRPCRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::PVStructurePtr const &pvRequest);
/** /**
* @brief Create a monitor. * @brief Create a monitor.
* *
* @param requester The client callback. * @param requester The client callback.
* @param pvRequest The options specified by the client. * @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation. * @return A shared pointer to the newly created implementation.
@@ -341,9 +330,9 @@ public:
virtual epics::pvData::Monitor::shared_pointer createMonitor( virtual epics::pvData::Monitor::shared_pointer createMonitor(
epics::pvData::MonitorRequester::shared_pointer const &requester, epics::pvData::MonitorRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::PVStructurePtr const &pvRequest);
/** /**
* @brief Create a channelArray. * @brief Create a channelArray.
* *
* @param requester The client callback. * @param requester The client callback.
* @param pvRequest The options specified by the client. * @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation. * @return A shared pointer to the newly created implementation.
@@ -352,13 +341,13 @@ public:
virtual epics::pvAccess::ChannelArray::shared_pointer createChannelArray( virtual epics::pvAccess::ChannelArray::shared_pointer createChannelArray(
epics::pvAccess::ChannelArrayRequester::shared_pointer const &requester, epics::pvAccess::ChannelArrayRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::PVStructurePtr const &pvRequest);
/** /**
* @brief calls printInfo(std::cout); * @brief calls printInfo(std::cout);
*/ */
virtual void printInfo(); virtual void printInfo();
/** /**
* @brief displays a message * @brief displays a message
* *
* @param out the stream on which the message is displayed. * @param out the stream on which the message is displayed.
*/ */
virtual void printInfo(std::ostream& out); virtual void printInfo(std::ostream& out);

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

@@ -0,0 +1,89 @@
/**
* 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 #ifndef PVARRAYPLUGIN_H
#define PVARRAYPLUGIN_H #define PVARRAYPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>
#include <pv/lock.h> #include <pv/lock.h>
@@ -67,9 +63,13 @@ private:
long start; long start;
long increment; long increment;
long end; long end;
epics::pvData::PVFieldPtr masterField;
epics::pvData::PVScalarArrayPtr masterArray; epics::pvData::PVScalarArrayPtr masterArray;
PVArrayFilter(long start,long increment,long end,const epics::pvData::PVScalarArrayPtr & masterArray); PVArrayFilter(
long start,long increment,long end,
const epics::pvData::PVFieldPtr & masterField,
const epics::pvData::PVScalarArrayPtr masterArray);
public: public:
POINTER_DEFINITIONS(PVArrayFilter); POINTER_DEFINITIONS(PVArrayFilter);
virtual ~PVArrayFilter(); virtual ~PVArrayFilter();
@@ -99,4 +99,3 @@ public:
}} }}
#endif /* PVARRAYPLUGIN_H */ #endif /* PVARRAYPLUGIN_H */

View File

@@ -6,28 +6,17 @@
#ifndef PVDATABASE_H #ifndef PVDATABASE_H
#define PVDATABASE_H #define PVDATABASE_H
#ifdef epicsExportSharedSymbols
# define pvdatabaseEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <list> #include <list>
#include <map> #include <map>
#include <pv/pvData.h> #include <pv/pvData.h>
#include <pv/pvTimeStamp.h> #include <pv/pvTimeStamp.h>
#include <pv/rpcService.h> #include <pv/rpcService.h>
#ifdef pvdatabaseEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef pvdatabaseEpicsExportSharedSymbols
#endif
#include <shareLib.h>
#include <pv/pvStructureCopy.h> #include <pv/pvStructureCopy.h>
namespace epics { namespace pvDatabase { #include <shareLib.h>
namespace epics { namespace pvDatabase {
class PVRecord; class PVRecord;
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr; typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
@@ -101,11 +90,20 @@ public:
* @brief DEPRECATED * @brief DEPRECATED
*/ */
virtual void destroy() {} 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. * @brief Optional method for derived class.
* *
* Return a service corresponding to the specified request PVStructure. * Return a service corresponding to the specified request PVStructure.
* @param pvRequest The request PVStructure * @param pvRequest The request PVStructure
* @return The corresponding service * @return The corresponding service
*/ */
virtual epics::pvAccess::RPCServiceAsync::shared_pointer getService( virtual epics::pvAccess::RPCServiceAsync::shared_pointer getService(
@@ -114,7 +112,7 @@ public:
return epics::pvAccess::RPCServiceAsync::shared_pointer(); return epics::pvAccess::RPCServiceAsync::shared_pointer();
} }
/** /**
* @brief Creates a <b>soft</b> record. * @brief Creates a <b>soft</b> record.
* *
* @param recordName The name of the record, which is also the channelName. * @param recordName The name of the record, which is also the channelName.
* @param pvStructure The top level structure. * @param pvStructure The top level structure.
@@ -249,15 +247,17 @@ protected:
epics::pvData::PVStructurePtr const & pvStructure); epics::pvData::PVStructurePtr const & pvStructure);
/** /**
* @brief Initializes the base class. * @brief Initializes the base class.
* *
* Must be called by derived classes. * Must be called by derived classes.
*/ */
void initPVRecord(); void initPVRecord();
private: private:
friend class PVDatabase;
void unlistenClients();
PVRecordFieldPtr findPVRecordField( PVRecordFieldPtr findPVRecordField(
PVRecordStructurePtr const & pvrs, PVRecordStructurePtr const & pvrs,
epics::pvData::PVFieldPtr const & pvField); epics::pvData::PVFieldPtr const & pvField);
void notifyClients();
std::string recordName; std::string recordName;
epics::pvData::PVStructurePtr pvStructure; epics::pvData::PVStructurePtr pvStructure;
@@ -501,6 +501,7 @@ public:
/** /**
* @brief Remove a record. * @brief Remove a record.
* @param record The record to remove. * @param record The record to remove.
*
* @return <b>true</b> if record was removed. * @return <b>true</b> if record was removed.
*/ */
bool removeRecord(PVRecordPtr const & record); bool removeRecord(PVRecordPtr const & record);
@@ -510,6 +511,9 @@ public:
*/ */
epics::pvData::PVStringArrayPtr getRecordNames(); epics::pvData::PVStringArrayPtr getRecordNames();
private: private:
friend class PVRecord;
PVRecordWPtr removeFromMap(PVRecordPtr const & record);
PVDatabase(); PVDatabase();
void lock(); void lock();
void unlock(); void unlock();
@@ -521,4 +525,3 @@ private:
}} }}
#endif /* PVDATABASE_H */ #endif /* PVDATABASE_H */

View File

@@ -6,9 +6,6 @@
#ifndef PVDEADBANDPLUGIN_H #ifndef PVDEADBANDPLUGIN_H
#define PVDEADBANDPLUGIN_H #define PVDEADBANDPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>
@@ -69,7 +66,7 @@ private:
epics::pvData::PVScalarPtr master; epics::pvData::PVScalarPtr master;
bool firstTime; bool firstTime;
double lastReportedValue; double lastReportedValue;
PVDeadbandFilter(bool absolute,double deadband,epics::pvData::PVScalarPtr const & master); PVDeadbandFilter(bool absolute,double deadband,epics::pvData::PVScalarPtr const & master);
public: public:
@@ -103,4 +100,3 @@ public:
}} }}
#endif /* PVDEADBANDPLUGIN_H */ #endif /* PVDEADBANDPLUGIN_H */

View File

@@ -9,23 +9,22 @@
#ifndef PVPLUGIN_H #ifndef PVPLUGIN_H
#define PVPLUGIN_H #define PVPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>
#include <pv/lock.h> #include <pv/lock.h>
#include <pv/pvStructureCopy.h> #include <pv/bitSet.h>
#include <shareLib.h> #include <shareLib.h>
namespace epics { namespace pvCopy{ namespace epics { namespace pvCopy{
class PVPlugin; class PVPlugin;
class PVFilter; class PVFilter;
class PVPluginRegistry; class PVPluginRegistry;
class PVCopy;
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr; typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr;
typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr; typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr;
typedef std::map<std::string,PVPluginPtr> PVPluginMap; typedef std::map<std::string,PVPluginPtr> PVPluginMap;
@@ -37,7 +36,7 @@ typedef std::map<std::string,PVPluginPtr> PVPluginMap;
* PVCopy looks for plugins defined in pvRequest and calls the filter when a pvCopy is updated. * PVCopy looks for plugins defined in pvRequest and calls the filter when a pvCopy is updated.
* @author mrk * @author mrk
* @since 2017.03.17 * @since 2017.03.17
* *
* Interface for a filter plugin for PVCopy. * Interface for a filter plugin for PVCopy.
* *
*/ */

View File

@@ -10,10 +10,6 @@
#ifndef PVSTRUCTURECOPY_H #ifndef PVSTRUCTURECOPY_H
#define PVSTRUCTURECOPY_H #define PVSTRUCTURECOPY_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
@@ -22,7 +18,7 @@
#include <shareLib.h> #include <shareLib.h>
namespace epics { namespace pvCopy{ namespace epics { namespace pvCopy{
class PVCopyTraverseMasterCallback; class PVCopyTraverseMasterCallback;
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr; typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr;
@@ -66,7 +62,7 @@ typedef std::tr1::shared_ptr<CopyStructureNode> CopyStructureNodePtr;
* Class that manages one or more PVStructures that holds an arbitrary subset of the fields * Class that manages one or more PVStructures that holds an arbitrary subset of the fields
* in another PVStructure called master. * in another PVStructure called master.
*/ */
class epicsShareClass PVCopy : class epicsShareClass PVCopy :
public std::tr1::enable_shared_from_this<PVCopy> public std::tr1::enable_shared_from_this<PVCopy>
{ {
public: public:
@@ -177,12 +173,12 @@ public:
*/ */
std::string dump(); std::string dump();
private: private:
PVCopyPtr getPtrSelf() PVCopyPtr getPtrSelf()
{ {
return shared_from_this(); return shared_from_this();
} }
epics::pvData::PVStructurePtr pvMaster; epics::pvData::PVStructurePtr pvMaster;
epics::pvData::StructureConstPtr structure; epics::pvData::StructureConstPtr structure;
CopyNodePtr headNode; CopyNodePtr headNode;
@@ -204,10 +200,16 @@ private:
epics::pvData::PVFieldPtr const &pvCopy, epics::pvData::PVFieldPtr const &pvCopy,
CopyNodePtr const &node, CopyNodePtr const &node,
epics::pvData::BitSetPtr const &bitSet); epics::pvData::BitSetPtr const &bitSet);
void updateMaster( void updateMasterField(
epics::pvData::PVFieldPtr const &pvCopy, CopyNodePtr const & node,
CopyNodePtr const &node, epics::pvData::PVFieldPtr const & pvCopy,
epics::pvData::PVFieldPtr const &pvMaster,
epics::pvData::BitSetPtr const &bitSet); 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); PVCopy(epics::pvData::PVStructurePtr const &pvMaster);
bool init(epics::pvData::PVStructurePtr const &pvRequest); bool init(epics::pvData::PVStructurePtr const &pvRequest);
@@ -239,7 +241,6 @@ private:
std::string *builder, std::string *builder,
CopyNodePtr const &node, CopyNodePtr const &node,
int indentLevel); int indentLevel);
friend class PVCopyMonitor;
}; };
}} }}

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

@@ -0,0 +1,77 @@
/**
* 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 #ifndef PVTIMESTAMPPLUGIN_H
#define PVTIMESTAMPPLUGIN_H #define PVTIMESTAMPPLUGIN_H
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <string> #include <string>
#include <map> #include <map>
#include <pv/lock.h> #include <pv/lock.h>
@@ -60,7 +56,7 @@ public:
}; };
/** /**
* @brief A filter that sets a timeStamp to the current time. * @brief A filter that sets a timeStamp to/from the current field or pvCopy.
*/ */
class epicsShareClass PVTimestampFilter : public PVFilter class epicsShareClass PVTimestampFilter : public PVFilter
{ {
@@ -70,7 +66,7 @@ private:
bool current; bool current;
bool copy; bool copy;
epics::pvData::PVFieldPtr master; epics::pvData::PVFieldPtr master;
PVTimestampFilter(bool current,bool copy,epics::pvData::PVFieldPtr const & pvField); PVTimestampFilter(bool current,bool copy,epics::pvData::PVFieldPtr const & pvField);
public: public:
@@ -102,4 +98,3 @@ public:
}} }}
#endif /* PVTIMESTAMPPLUGIN_H */ #endif /* PVTIMESTAMPPLUGIN_H */

View File

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

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

@@ -0,0 +1,110 @@
/**
* 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,11 +11,12 @@
#ifndef TRACERECORD_H #ifndef TRACERECORD_H
#define TRACERECORD_H #define TRACERECORD_H
#include <shareLib.h>
#include <pv/channelProviderLocal.h> #include <pv/channelProviderLocal.h>
namespace epics { namespace pvDatabase { #include <shareLib.h>
namespace epics { namespace pvDatabase {
class TraceRecord; class TraceRecord;

View File

@@ -13,12 +13,21 @@
#include <epicsGuard.h> #include <epicsGuard.h>
#include <epicsThread.h> #include <epicsThread.h>
#include <pv/pvData.h>
#include <pv/pvAccess.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h> #include <pv/timeStamp.h>
#include <pv/createRequest.h>
#include <pv/pvaVersion.h>
#include <pv/pvaVersionNum.h>
#include <pv/serverContext.h>
#include <pv/pvSubArrayCopy.h> #include <pv/pvSubArrayCopy.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include <pv/channelProviderLocal.h> #include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
@@ -29,7 +38,7 @@ using std::cout;
using std::endl; using std::endl;
using std::string; using std::string;
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
static StructureConstPtr nullStructure; static StructureConstPtr nullStructure;
@@ -59,7 +68,7 @@ static bool getProcess(PVStructurePtr pvRequest,bool processDefault)
return pvString->get().compare("true")==0 ? true : false; return pvString->get().compare("true")==0 ? true : false;
} else if(scalar->getScalarType()==pvBoolean) { } else if(scalar->getScalarType()==pvBoolean) {
PVBooleanPtr pvBoolean = static_pointer_cast<PVBoolean>(pvField); PVBooleanPtr pvBoolean = static_pointer_cast<PVBoolean>(pvField);
return pvBoolean->get(); return pvBoolean->get();
} }
return processDefault; return processDefault;
} }
@@ -93,7 +102,7 @@ private:
ChannelProcessRequester::shared_pointer const & channelProcessRequester, ChannelProcessRequester::shared_pointer const & channelProcessRequester,
PVRecordPtr const &pvRecord, PVRecordPtr const &pvRecord,
int nProcess) int nProcess)
: :
channelLocal(channelLocal), channelLocal(channelLocal),
channelProcessRequester(channelProcessRequester), channelProcessRequester(channelProcessRequester),
pvRecord(pvRecord), pvRecord(pvRecord),
@@ -123,7 +132,7 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
if(pvField) { if(pvField) {
PVStringPtr pvString = pvOptions->getSubField<PVString>("nProcess"); PVStringPtr pvString = pvOptions->getSubField<PVString>("nProcess");
if(pvString) { if(pvString) {
int size; int size=0;
std::stringstream ss; std::stringstream ss;
ss << pvString->get(); ss << pvString->get();
ss >> size; ss >> size;
@@ -147,10 +156,7 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
ChannelProcessLocal::~ChannelProcessLocal() ChannelProcessLocal::~ChannelProcessLocal()
{ {
PVRecordPtr pvr(pvRecord.lock()); //cout << "~ChannelProcessLocal()\n";
if(pvr && pvr->getTraceLevel()>0) {
cout << "~ChannelProcessLocal() " << pvr->getRecordName() << endl;
}
} }
std::tr1::shared_ptr<Channel> ChannelProcessLocal::getChannel() std::tr1::shared_ptr<Channel> ChannelProcessLocal::getChannel()
@@ -229,7 +235,7 @@ private:
PVStructurePtr const&pvStructure, PVStructurePtr const&pvStructure,
BitSetPtr const & bitSet, BitSetPtr const & bitSet,
PVRecordPtr const &pvRecord) PVRecordPtr const &pvRecord)
: :
firstTime(true), firstTime(true),
callProcess(callProcess), callProcess(callProcess),
channelLocal(channelLocal), channelLocal(channelLocal),
@@ -295,10 +301,7 @@ ChannelGetLocalPtr ChannelGetLocal::create(
ChannelGetLocal::~ChannelGetLocal() ChannelGetLocal::~ChannelGetLocal()
{ {
PVRecordPtr pvr(pvRecord.lock()); //cout << "~ChannelGetLocal()\n";
if(pvr && pvr->getTraceLevel()>0) {
cout << "~ChannelGetLocal() " << pvr->getRecordName() << endl;
}
} }
std::tr1::shared_ptr<Channel> ChannelGetLocal::getChannel() std::tr1::shared_ptr<Channel> ChannelGetLocal::getChannel()
@@ -460,10 +463,7 @@ ChannelPutLocalPtr ChannelPutLocal::create(
ChannelPutLocal::~ChannelPutLocal() ChannelPutLocal::~ChannelPutLocal()
{ {
PVRecordPtr pvr(pvRecord.lock()); //cout << "~ChannelPutLocal()\n";
if(pvr && pvr->getTraceLevel()>0) {
cout << "~ChannelPutLocal() " << pvr->getRecordName() << endl;
}
} }
std::tr1::shared_ptr<Channel> ChannelPutLocal::getChannel() std::tr1::shared_ptr<Channel> ChannelPutLocal::getChannel()
@@ -523,7 +523,7 @@ void ChannelPutLocal::put(
PVRecordPtr pvr(pvRecord.lock()); PVRecordPtr pvr(pvRecord.lock());
if(!pvr) throw std::logic_error("pvRecord is deleted"); if(!pvr) throw std::logic_error("pvRecord is deleted");
try { try {
{ {
epicsGuard <PVRecord> guard(*pvr); epicsGuard <PVRecord> guard(*pvr);
pvr->beginGroupPut(); pvr->beginGroupPut();
pvCopy->updateMaster(pvStructure, bitSet); pvCopy->updateMaster(pvStructure, bitSet);
@@ -534,7 +534,7 @@ void ChannelPutLocal::put(
} }
requester->putDone(Status::Ok,getPtrSelf()); requester->putDone(Status::Ok,getPtrSelf());
if(pvr->getTraceLevel()>1) if(pvr->getTraceLevel()>1)
{ {
cout << "ChannelPutLocal::put" << endl; cout << "ChannelPutLocal::put" << endl;
} }
} catch(std::exception& ex) { } catch(std::exception& ex) {
@@ -581,7 +581,7 @@ private:
PVStructurePtr const&pvGetStructure, PVStructurePtr const&pvGetStructure,
BitSetPtr const & getBitSet, BitSetPtr const & getBitSet,
PVRecordPtr const &pvRecord) PVRecordPtr const &pvRecord)
: :
callProcess(callProcess), callProcess(callProcess),
channelLocal(channelLocal), channelLocal(channelLocal),
channelPutGetRequester(channelPutGetRequester), channelPutGetRequester(channelPutGetRequester),
@@ -653,10 +653,7 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create(
ChannelPutGetLocal::~ChannelPutGetLocal() ChannelPutGetLocal::~ChannelPutGetLocal()
{ {
PVRecordPtr pvr(pvRecord.lock()); //cout << "~ChannelPutGetLocal()\n";
if(pvr && pvr->getTraceLevel()>0) {
cout << "~ChannelPutGetLocal() " << pvr->getRecordName() << endl;
}
} }
std::tr1::shared_ptr<Channel> ChannelPutGetLocal::getChannel() std::tr1::shared_ptr<Channel> ChannelPutGetLocal::getChannel()
@@ -853,10 +850,7 @@ ChannelRPCLocalPtr ChannelRPCLocal::create(
ChannelRPCLocal::~ChannelRPCLocal() ChannelRPCLocal::~ChannelRPCLocal()
{ {
PVRecordPtr pvr(pvRecord.lock()); //cout << "~ChannelRPCLocal()\n";
if(pvr && pvr->getTraceLevel()>0) {
cout << "~ChannelRPCLocal() " << pvr->getRecordName() << endl;
}
} }
std::tr1::shared_ptr<Channel> ChannelRPCLocal::getChannel() std::tr1::shared_ptr<Channel> ChannelRPCLocal::getChannel()
@@ -893,7 +887,7 @@ void ChannelRPCLocal::processRequest(
status = Status(Status::STATUSTYPE_FATAL, "Unexpected exception caught while calling RPCService.request(PVStructure)."); status = Status(Status::STATUSTYPE_FATAL, "Unexpected exception caught while calling RPCService.request(PVStructure).");
ok = false; ok = false;
} }
// check null result // check null result
if (ok && !result) if (ok && !result)
{ {
@@ -992,7 +986,7 @@ private:
PVArrayPtr const &pvArray, PVArrayPtr const &pvArray,
PVArrayPtr const &pvCopy, PVArrayPtr const &pvCopy,
PVRecordPtr const &pvRecord) PVRecordPtr const &pvRecord)
: :
channelLocal(channelLocal), channelLocal(channelLocal),
channelArrayRequester(channelArrayRequester), channelArrayRequester(channelArrayRequester),
pvArray(pvArray), pvArray(pvArray),
@@ -1095,10 +1089,7 @@ ChannelArrayLocalPtr ChannelArrayLocal::create(
ChannelArrayLocal::~ChannelArrayLocal() ChannelArrayLocal::~ChannelArrayLocal()
{ {
PVRecordPtr pvr(pvRecord.lock()); //cout << "~ChannelArrayLocal()\n";
if(pvr && pvr->getTraceLevel()>0) {
cout << "~ChannelArrayLocal() " << pvr->getRecordName() << endl;
}
} }
std::tr1::shared_ptr<Channel> ChannelArrayLocal::getChannel() std::tr1::shared_ptr<Channel> ChannelArrayLocal::getChannel()
@@ -1237,7 +1228,7 @@ ChannelLocal::ChannelLocal(
ChannelProviderLocalPtr const & provider, ChannelProviderLocalPtr const & provider,
ChannelRequester::shared_pointer const & requester, ChannelRequester::shared_pointer const & requester,
PVRecordPtr const & pvRecord) PVRecordPtr const & pvRecord)
: :
requester(requester), requester(requester),
provider(provider), provider(provider),
pvRecord(pvRecord) pvRecord(pvRecord)
@@ -1252,12 +1243,7 @@ ChannelLocal::ChannelLocal(
ChannelLocal::~ChannelLocal() ChannelLocal::~ChannelLocal()
{ {
PVRecordPtr pvr(pvRecord.lock()); // cout << "~ChannelLocal()" << endl;
if(!pvr) return;
if(pvr->getTraceLevel()>0)
{
cout << "~ChannelLocal()" << endl;
}
} }
ChannelProvider::shared_pointer ChannelLocal::getProvider() ChannelProvider::shared_pointer ChannelLocal::getProvider()
@@ -1287,7 +1273,7 @@ string ChannelLocal::getRequesterName()
<< " requester exists " << (requester ? "true" : "false") << " requester exists " << (requester ? "true" : "false")
<< endl; << endl;
} }
if(!requester) return string(); if(!requester) return string();
return requester->getRequesterName(); return requester->getRequesterName();
} }
@@ -1310,7 +1296,7 @@ void ChannelLocal::message(
string recordName("record deleted"); string recordName("record deleted");
if(pvr) recordName = pvr->getRecordName(); if(pvr) recordName = pvr->getRecordName();
cout << recordName cout << recordName
<< " message " << message << " message " << message
<< " messageType " << getMessageTypeName(messageType) << " messageType " << getMessageTypeName(messageType)
<< endl; << endl;
} }
@@ -1353,8 +1339,8 @@ void ChannelLocal::getField(GetFieldRequester::shared_pointer const &requester,
pvr->getPVRecordStructure()->getPVStructure()->getStructure(); pvr->getPVRecordStructure()->getPVStructure()->getStructure();
requester->getDone(Status::Ok,structure); requester->getDone(Status::Ok,structure);
return; return;
} }
PVFieldPtr pvField = PVFieldPtr pvField =
pvr->getPVRecordStructure()->getPVStructure()->getSubField(subField); pvr->getPVRecordStructure()->getPVStructure()->getSubField(subField);
if(pvField) { if(pvField) {
requester->getDone(Status::Ok,pvField->getField()); requester->getDone(Status::Ok,pvField->getField());
@@ -1470,7 +1456,7 @@ ChannelRPC::shared_pointer ChannelLocal::createChannelRPC(
<< endl; << endl;
} }
ChannelRPCLocalPtr channelRPC = ChannelRPCLocalPtr channelRPC =
ChannelRPCLocal::create( ChannelRPCLocal::create(
getPtrSelf(), getPtrSelf(),
channelRPCRequester, channelRPCRequester,

View File

@@ -1,4 +1,4 @@
/* channelChannelProviderLocal.cpp */ /* channelProviderLocal.cpp */
/** /**
* Copyright - See the COPYRIGHT that is included with this distribution. * Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found * EPICS pvData is distributed subject to a Software License Agreement found
@@ -10,13 +10,16 @@
*/ */
#include <epicsThread.h> #include <epicsThread.h>
#include <pv/serverContext.h> #include <pv/serverContext.h>
#include <pv/syncChannelFind.h> #include <pv/syncChannelFind.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include <pv/channelProviderLocal.h> #include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
@@ -27,13 +30,13 @@ using std::cout;
using std::endl; using std::endl;
using std::string; using std::string;
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
static string providerName("local"); static string providerName("local");
static ChannelProviderLocalPtr channelProvider; static ChannelProviderLocalPtr channelProvider;
class LocalChannelProviderFactory : public ChannelProviderFactory class LocalChannelProviderFactory : public ChannelProviderFactory
{ {
public: public:
POINTER_DEFINITIONS(LocalChannelProviderFactory); POINTER_DEFINITIONS(LocalChannelProviderFactory);
virtual string getFactoryName() { return providerName;} virtual string getFactoryName() { return providerName;}
@@ -111,7 +114,7 @@ ChannelFind::shared_pointer ChannelProviderLocal::channelFind(
Status::Ok, Status::Ok,
shared_from_this(), shared_from_this(),
true); true);
} else { } else {
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found"); Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found");
channelFindRequester->channelFindResult( channelFindRequester->channelFindResult(

View File

@@ -14,11 +14,17 @@
#include <epicsGuard.h> #include <epicsGuard.h>
#include <pv/thread.h> #include <pv/thread.h>
#include <pv/bitSetUtil.h> #include <pv/bitSetUtil.h>
#include <pv/pvData.h>
#include <pv/pvAccess.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/serverContext.h>
#include <pv/timeStamp.h> #include <pv/timeStamp.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include <pv/channelProviderLocal.h> #include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
@@ -28,7 +34,7 @@ using std::cout;
using std::endl; using std::endl;
using std::string; using std::string;
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
class MonitorLocal; class MonitorLocal;
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr; typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
@@ -82,7 +88,7 @@ public:
nextGetUsed = 0; nextGetUsed = 0;
nextReleaseUsed = 0; nextReleaseUsed = 0;
} }
MonitorElementPtr getFree() MonitorElementPtr getFree()
{ {
if(numberFree==0) return MonitorElementPtr(); if(numberFree==0) return MonitorElementPtr();
@@ -92,7 +98,7 @@ public:
if(nextGetFree>=size) nextGetFree = 0; if(nextGetFree>=size) nextGetFree = 0;
return elements[ind]; return elements[ind];
} }
void setUsed(MonitorElementPtr const &element) void setUsed(MonitorElementPtr const &element)
{ {
if(element!=elements[nextSetUsed++]) { if(element!=elements[nextSetUsed++]) {
@@ -101,7 +107,7 @@ public:
numberUsed++; numberUsed++;
if(nextSetUsed>=size) nextSetUsed = 0; if(nextSetUsed>=size) nextSetUsed = 0;
} }
MonitorElementPtr getUsed() MonitorElementPtr getUsed()
{ {
if(numberUsed==0) return MonitorElementPtr(); if(numberUsed==0) return MonitorElementPtr();
@@ -125,7 +131,7 @@ public:
typedef std::tr1::shared_ptr<MonitorRequester> MonitorRequesterPtr; typedef std::tr1::shared_ptr<MonitorRequester> MonitorRequesterPtr;
class MonitorLocal : class MonitorLocal :
public Monitor, public Monitor,
public PVListener, public PVListener,
@@ -185,10 +191,7 @@ MonitorLocal::MonitorLocal(
MonitorLocal::~MonitorLocal() MonitorLocal::~MonitorLocal()
{ {
if(pvRecord->getTraceLevel()>0) //cout << "MonitorLocal::~MonitorLocal()" << endl;
{
cout << "MonitorLocal::~MonitorLocal()" << endl;
}
} }
@@ -288,7 +291,7 @@ void MonitorLocal::dataPut(PVRecordFieldPtr const & pvRecordField)
{ {
if(pvRecord->getTraceLevel()>1) if(pvRecord->getTraceLevel()>1)
{ {
cout << "PVCopyMonitor::dataPut(pvRecordField)" << endl; cout << "MonitorLocal::dataPut(pvRecordField)" << endl;
} }
if(state!=active) return; if(state!=active) return;
{ {
@@ -313,7 +316,7 @@ void MonitorLocal::dataPut(
{ {
if(pvRecord->getTraceLevel()>1) if(pvRecord->getTraceLevel()>1)
{ {
cout << "PVCopyMonitor::dataPut(requested,pvRecordField)" << endl; cout << "MonitorLocal::dataPut(requested,pvRecordField)" << endl;
} }
if(state!=active) return; if(state!=active) return;
{ {
@@ -340,7 +343,7 @@ void MonitorLocal::beginGroupPut(PVRecordPtr const & pvRecord)
{ {
if(pvRecord->getTraceLevel()>1) if(pvRecord->getTraceLevel()>1)
{ {
cout << "PVCopyMonitor::beginGroupPut()" << endl; cout << "MonitorLocal::beginGroupPut()" << endl;
} }
if(state!=active) return; if(state!=active) return;
{ {
@@ -354,7 +357,7 @@ void MonitorLocal::endGroupPut(PVRecordPtr const & pvRecord)
{ {
if(pvRecord->getTraceLevel()>1) if(pvRecord->getTraceLevel()>1)
{ {
cout << "PVCopyMonitor::endGroupPut dataChanged " << dataChanged << endl; cout << "MonitorLocal::endGroupPut dataChanged " << dataChanged << endl;
} }
if(state!=active) return; if(state!=active) return;
{ {
@@ -371,7 +374,7 @@ void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
{ {
if(pvRecord->getTraceLevel()>1) if(pvRecord->getTraceLevel()>1)
{ {
cout << "PVCopyMonitor::unlisten\n"; cout << "MonitorLocal::unlisten\n";
} }
{ {
Lock xx(mutex); Lock xx(mutex);
@@ -381,7 +384,7 @@ void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
if(requester) { if(requester) {
if(pvRecord->getTraceLevel()>1) if(pvRecord->getTraceLevel()>1)
{ {
cout << "PVCopyMonitor::unlisten calling requester->unlisten\n"; cout << "MonitorLocal::unlisten calling requester->unlisten\n";
} }
requester->unlisten(getPtrSelf()); requester->unlisten(getPtrSelf());
} }

View File

@@ -11,30 +11,19 @@
/* Author: Marty Kraimer */ /* 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 <iocsh.h>
#include <shareLib.h>
#include <epicsExit.h>
#include <pv/pvAccess.h> #include <pv/pvAccess.h>
#include <pv/serverContext.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 <epicsExport.h>
#define epicsExportSharedSymbols
#include <pv/channelProviderLocal.h> #include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using std::cout; using std::cout;
using std::endl; using std::endl;

View File

@@ -4,3 +4,15 @@ SRC_DIRS += $(PVDATABASE_SRC)/special
LIBSRCS += traceRecord.cpp LIBSRCS += traceRecord.cpp
LIBSRCS += removeRecord.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

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

@@ -0,0 +1,117 @@
/* 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,166 @@
/* 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,16 +8,35 @@
* @author mrk * @author mrk
* @date 2013.04.18 * @date 2013.04.18
*/ */
#define epicsExportSharedSymbols
#include <pv/removeRecord.h> #include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <set>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/timeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
#include "pv/removeRecord.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
RemoveRecordPtr RemoveRecord::create( RemoveRecordPtr RemoveRecord::create(
std::string const & recordName) std::string const & recordName)
@@ -65,10 +84,9 @@ void RemoveRecord::process()
pvResult->put(name + " not found"); pvResult->put(name + " not found");
return; return;
} }
pvRecord->destroy(); pvRecord->remove();
pvResult->put("success"); 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,16 +8,34 @@
* @author mrk * @author mrk
* @date 2013.04.18 * @date 2013.04.18
*/ */
#define epicsExportSharedSymbols
#include <pv/traceRecord.h> #include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <set>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/timeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include "pv/channelProviderLocal.h"
#include "pv/traceRecord.h"
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
TraceRecordPtr TraceRecord::create( TraceRecordPtr TraceRecord::create(
std::string const & recordName) std::string const & recordName)
@@ -75,4 +93,3 @@ void TraceRecord::process()
}} }}

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,137 @@
/* controlSupport.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#include <pv/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,218 @@
/* 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);
}
}}

View File

@@ -26,14 +26,14 @@
#ifdef listenerEpicsExportSharedSymbols #ifdef listenerEpicsExportSharedSymbols
# define epicsExportSharedSymbols # define epicsExportSharedSymbols
# undef listenerEpicsExportSharedSymbols # undef listenerEpicsExportSharedSymbols
#endif #endif
#include <shareLib.h> #include <shareLib.h>
//epicsShareFunc epics::pvData::PVStructurePtr createListener(); //epicsShareFunc epics::pvData::PVStructurePtr createListener();
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
using namespace epics::pvData; using namespace epics::pvData;
using namespace std; using namespace std;
@@ -59,7 +59,7 @@ public:
} }
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) virtual void dataPut(PVRecordFieldPtr const & pvRecordField)
{ {
cout << "Listener::dataPut record " << recordName cout << "Listener::dataPut record " << recordName
<< " pvRecordField " << pvRecordField->getPVField()->getFullName() << " pvRecordField " << pvRecordField->getPVField()->getFullName()
<< endl; << endl;
} }
@@ -67,7 +67,7 @@ public:
PVRecordStructurePtr const & requested, PVRecordStructurePtr const & requested,
PVRecordFieldPtr const & pvRecordField) PVRecordFieldPtr const & pvRecordField)
{ {
cout << "Listener::dataPut record " << recordName cout << "Listener::dataPut record " << recordName
<< " requested " << requested->getPVStructure()->getFullName() << " requested " << requested->getPVStructure()->getFullName()
<< " pvRecordField " << pvRecordField->getPVField()->getFullName() << " pvRecordField " << pvRecordField->getPVField()->getFullName()
<< endl; << endl;
@@ -84,7 +84,7 @@ public:
{ {
cout << "Listener::unlisten record " << recordName << endl; cout << "Listener::unlisten record " << recordName << endl;
} }
private: private:
Listener(PVRecordPtr const & pvRecord) Listener(PVRecordPtr const & pvRecord)
: pvCopy( : pvCopy(

View File

@@ -25,14 +25,14 @@
#ifdef powerSupplyEpicsExportSharedSymbols #ifdef powerSupplyEpicsExportSharedSymbols
# define epicsExportSharedSymbols # define epicsExportSharedSymbols
# undef powerSupplyEpicsExportSharedSymbols # undef powerSupplyEpicsExportSharedSymbols
#endif #endif
#include <shareLib.h> #include <shareLib.h>
//epicsShareFunc epics::pvData::PVStructurePtr createPowerSupply(); //epicsShareFunc epics::pvData::PVStructurePtr createPowerSupply();
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
class PowerSupply; class PowerSupply;
typedef std::tr1::shared_ptr<PowerSupply> PowerSupplyPtr; typedef std::tr1::shared_ptr<PowerSupply> PowerSupplyPtr;

View File

@@ -25,12 +25,12 @@
#ifdef pvRecordClientEpicsExportSharedSymbols #ifdef pvRecordClientEpicsExportSharedSymbols
# define epicsExportSharedSymbols # define epicsExportSharedSymbols
# undef pvRecordClientEpicsExportSharedSymbols # undef pvRecordClientEpicsExportSharedSymbols
#endif #endif
#include <shareLib.h> #include <shareLib.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
class RecordClient; class RecordClient;
typedef std::tr1::shared_ptr<RecordClient> RecordClientPtr; typedef std::tr1::shared_ptr<RecordClient> RecordClientPtr;
@@ -59,7 +59,7 @@ public:
std::cout << "RecordClient::detach record " << pvRecord->getRecordName() << std::endl; std::cout << "RecordClient::detach record " << pvRecord->getRecordName() << std::endl;
this->pvRecord.reset(); this->pvRecord.reset();
} }
private: private:
RecordClient(PVRecordPtr const & pvRecord) RecordClient(PVRecordPtr const & pvRecord)
: pvRecord(pvRecord) : pvRecord(pvRecord)

View File

@@ -134,4 +134,3 @@ MAIN(testExampleRecord)
test(); test();
return 0; return 0;
} }

View File

@@ -79,4 +79,3 @@ MAIN(testLocalProvider)
test(); test();
return 0; return 0;
} }

View File

@@ -75,4 +75,3 @@ MAIN(testPVAServer)
test(); test();
return 0; return 0;
} }

View File

@@ -273,7 +273,7 @@ static void testPVScalarArray(
cout << endl; cout << endl;
} }
} }
static void scalarTest() static void scalarTest()
{ {
if(debug) {cout << endl << endl << "****scalarTest****" << endl;} if(debug) {cout << endl << endl << "****scalarTest****" << endl;}
@@ -401,4 +401,3 @@ MAIN(testPVCopy)
powerSupplyTest(); powerSupplyTest();
return 0; return 0;
} }

View File

@@ -103,4 +103,3 @@ MAIN(testPVRecord)
powerSupplyTest(); powerSupplyTest();
return 0; return 0;
} }

View File

@@ -107,7 +107,7 @@ static void arrayTest()
uint32 nset = 0; uint32 nset = 0;
size_t n = 10; size_t n = 10;
shared_vector<double> values(n); shared_vector<double> values(n);
PVStructurePtr pvRecordStructure(getStandardPVField()->scalarArray(pvDouble,"")); PVStructurePtr pvRecordStructure(getStandardPVField()->scalarArray(pvDouble,""));
PVRecordPtr pvRecord(PVRecord::create("doubleArrayRecord",pvRecordStructure)); PVRecordPtr pvRecord(PVRecord::create("doubleArrayRecord",pvRecordStructure));
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]")); PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
@@ -145,6 +145,73 @@ static void arrayTest()
testOk1(nset==1); testOk1(nset==1);
} }
static void unionArrayTest()
{
if(debug) {cout << endl << endl << "****unionArrayTest****" << endl;}
bool result = false;
uint32 nset = 0;
size_t n = 10;
shared_vector<double> values(n);
for(size_t i=0; i<n; i++) values[i] = i + .06;
PVDoubleArrayPtr pvDoubleArray =
static_pointer_cast<PVDoubleArray>(PVDataCreate::getPVDataCreate()->createPVScalarArray(pvDouble));
const shared_vector<const double> yyy(freeze(values));
pvDoubleArray->putFrom(yyy);
StandardFieldPtr standardField = getStandardField();
FieldCreatePtr fieldCreate = getFieldCreate();
StructureConstPtr top = fieldCreate->createFieldBuilder()->
add("value",fieldCreate->createVariantUnion()) ->
add("timeStamp", standardField->timeStamp()) ->
addNestedStructure("subfield") ->
add("value",fieldCreate->createVariantUnion()) ->
endNested()->
createStructure();
PVStructurePtr pvRecordStructure(PVDataCreate::getPVDataCreate()->createPVStructure(top));
PVRecordPtr pvRecord(PVRecord::create("unionArrayRecord",pvRecordStructure));
PVUnionPtr pvUnion = pvRecord->getPVStructure()->getSubField<PVUnion>("value");
pvUnion->set(pvDoubleArray);
pvUnion = pvRecord->getPVStructure()->getSubField<PVUnion>("subfield.value");
pvUnion->set(pvDoubleArray);
if(debug) { cout << "initial\n" << pvRecordStructure << "\n";}
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
PVDoubleArrayPtr pvValue(pvRecordStructure->getSubField<PVDoubleArray>("value"));
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after get value"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
pvRequest = CreateRequest::create()->createRequest("subfield.value[array=1:3]");
pvCopy = PVCopy::create(pvRecordStructure,pvRequest,"");
pvStructureCopy = pvCopy->createPVStructure();
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
pvValue = pvRecordStructure->getSubField<PVDoubleArray>("subfield.value");
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after get subfield.value"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
}
static void timeStampTest() static void timeStampTest()
{ {
if(debug) {cout << endl << endl << "****timeStampTest****" << endl;} if(debug) {cout << endl << endl << "****timeStampTest****" << endl;}
@@ -267,12 +334,12 @@ static void ignoreTest()
MAIN(testPlugin) MAIN(testPlugin)
{ {
testPlan(22); testPlan(26);
PVDatabasePtr pvDatabase(PVDatabase::getMaster()); PVDatabasePtr pvDatabase(PVDatabase::getMaster());
deadbandTest(); deadbandTest();
arrayTest(); arrayTest();
unionArrayTest();
timeStampTest(); timeStampTest();
ignoreTest(); ignoreTest();
return 0; return 0;
} }