Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70ee857782 | ||
|
|
07f09e0759 | ||
|
|
ba832ddfd0 | ||
|
|
93c2284091 | ||
|
|
cc5b6f6351 | ||
|
|
a26a625e49 | ||
|
|
93b4892528 | ||
|
|
e57348a4c5 | ||
|
|
7059cb0354 | ||
|
|
f2d6e05816 | ||
|
|
e949493722 | ||
|
|
6969bbd571 | ||
|
|
9edea59ab9 | ||
|
|
1928b87634 | ||
|
|
d9ed321298 | ||
|
|
935f915e5d | ||
|
|
6263f4c335 | ||
|
|
62134efd19 | ||
|
|
8a06b9ee8e | ||
|
|
bc6fd2b9ff | ||
|
|
3b6f23515f | ||
|
|
3c5f419ce7 | ||
|
|
3418c22cde | ||
|
|
22806c5301 | ||
|
|
62fb27fdf8 | ||
|
|
6250625036 | ||
|
|
d77ec8a978 | ||
|
|
322bb4800b | ||
|
|
0437602236 | ||
|
|
bd37756ba3 | ||
|
|
fb4e7f0fc1 | ||
|
|
5279e4e739 | ||
|
|
ffef21e58c | ||
|
|
e901ae3ea0 | ||
|
|
8a050e0f81 | ||
|
|
a72112f928 | ||
|
|
be701cc98a | ||
|
|
9b000ffe6c | ||
|
|
6c91249340 | ||
|
|
b052e28788 | ||
|
|
247839b94d | ||
|
|
ecdf70d858 | ||
|
|
a004f7ea08 | ||
|
|
898868d5f4 | ||
|
|
eb4dab73e9 | ||
|
|
e1adfe30df | ||
|
|
2715f585e0 | ||
|
|
c2e3315f54 | ||
|
|
d0ddcead24 | ||
|
|
5f42eec15a | ||
|
|
20e55d5bca | ||
|
|
6d2d63621e | ||
|
|
b3f96f730f | ||
|
|
02930b78a0 | ||
|
|
68cc5e3b28 | ||
|
|
0c0a77def5 | ||
|
|
79b05db5e2 | ||
|
|
cd653a809f | ||
|
|
07a951c3a2 | ||
|
|
9cfbc7983c | ||
|
|
761c62050d | ||
|
|
d508792f2a | ||
|
|
4b98e70ce0 | ||
|
|
2450e356f5 | ||
|
|
14442774ab | ||
|
|
3f320fac32 | ||
|
|
4ad470d3f4 | ||
|
|
fd97c9ac8e | ||
|
|
93c6305952 | ||
|
|
7e0bc0c45a | ||
|
|
ebd4e3827c | ||
|
|
11393ce6b1 | ||
|
|
4a13cab5a4 | ||
|
|
7529f58b63 | ||
|
|
7491f3b531 | ||
|
|
595163a1fa | ||
|
|
6fe27251f1 | ||
|
|
a2a07a1d33 | ||
|
|
3e0282d956 | ||
|
|
e667e39573 | ||
|
|
6239ef0c0c | ||
|
|
87ccf78a9b | ||
|
|
bbb5fa2c64 | ||
|
|
8e04875a45 | ||
|
|
83101e210a | ||
|
|
e31aae5f5d | ||
|
|
2469fc04b5 | ||
|
|
e0cb7d7f93 | ||
|
|
2904e00b3d | ||
|
|
b26c0ecd71 | ||
|
|
e06b2b7076 | ||
|
|
63214b98f6 | ||
|
|
a1714c9aab | ||
|
|
64c5fd1e67 | ||
|
|
955947fd0f | ||
|
|
c6339f4f1b | ||
|
|
ae97789beb | ||
|
|
35d4b5c70e | ||
|
|
977f078246 | ||
|
|
063313f246 | ||
|
|
cec282f77f | ||
|
|
24cf1d277e | ||
|
|
1d5e9e7b25 | ||
|
|
f131f0631c | ||
|
|
aa44396a43 | ||
|
|
547df7a2cd | ||
|
|
be6527b01e | ||
|
|
d7486622bf | ||
|
|
974bf061a2 | ||
|
|
d99087d2f6 | ||
|
|
8c2926ad92 | ||
|
|
5b60025b76 | ||
|
|
d080a073b1 | ||
|
|
ff172cc495 | ||
|
|
da00928e7e | ||
|
|
9dcb68669c |
10
.ci/travis-build.sh
Executable file
10
.ci/travis-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
make -j2 $EXTRA
|
||||
|
||||
if [ "$TEST" != "NO" ]
|
||||
then
|
||||
make -j2 tapfiles
|
||||
make -j2 -s test-results
|
||||
fi
|
||||
109
.ci/travis-prepare.sh
Executable file
109
.ci/travis-prepare.sh
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
CURDIR="$PWD"
|
||||
|
||||
cat << EOF > $CURDIR/configure/RELEASE.local
|
||||
EPICS_BASE=$HOME/.source/epics-base
|
||||
EOF
|
||||
|
||||
install -d "$HOME/.source"
|
||||
cd "$HOME/.source"
|
||||
|
||||
add_gh_flat() {
|
||||
MODULE=$1
|
||||
REPOOWNER=$2
|
||||
REPONAME=$3
|
||||
BRANCH=$4
|
||||
MODULE_UC=$(echo $MODULE | tr 'a-z' 'A-Z')
|
||||
( git clone --quiet --depth 5 --branch $BRANCH https://github.com/$REPOOWNER/$REPONAME.git $MODULE && \
|
||||
cd $MODULE && git log -n1 )
|
||||
cat < $CURDIR/configure/RELEASE.local > $MODULE/configure/RELEASE.local
|
||||
cat << EOF >> $CURDIR/configure/RELEASE.local
|
||||
${MODULE_UC}=$HOME/.source/$MODULE
|
||||
EOF
|
||||
}
|
||||
|
||||
# not recursive
|
||||
git clone --quiet --depth 5 --branch "$BRBASE" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
|
||||
(cd epics-base && git log -n1 )
|
||||
add_gh_flat pvData ${REPOPVD:-epics-base} pvDataCPP ${BRPVD:-master}
|
||||
add_gh_flat pvAccess ${REPOPVA:-epics-base} pvAccessCPP ${BRPVA:-master}
|
||||
|
||||
if [ -e $CURDIR/configure/RELEASE.local ]
|
||||
then
|
||||
cat $CURDIR/configure/RELEASE.local
|
||||
fi
|
||||
|
||||
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
|
||||
|
||||
# requires wine and g++-mingw-w64-i686
|
||||
if [ "$WINE" = "32" ]
|
||||
then
|
||||
echo "Cross mingw32"
|
||||
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
CMPLR_PREFIX=i686-w64-mingw32-
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$STATIC" = "YES" ]
|
||||
then
|
||||
echo "Build static libraries/executables"
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
SHARED_LIBRARIES=NO
|
||||
STATIC_BUILD=YES
|
||||
EOF
|
||||
fi
|
||||
|
||||
case "$CMPLR" in
|
||||
clang)
|
||||
echo "Host compiler is clang"
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
|
||||
GNU = NO
|
||||
CMPLR_CLASS = clang
|
||||
CC = clang
|
||||
CCC = clang++
|
||||
EOF
|
||||
|
||||
# hack
|
||||
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
|
||||
|
||||
clang --version
|
||||
;;
|
||||
*)
|
||||
echo "Host compiler is default"
|
||||
gcc --version
|
||||
;;
|
||||
esac
|
||||
|
||||
cat <<EOF >> epics-base/configure/CONFIG_SITE
|
||||
USR_CPPFLAGS += $USR_CPPFLAGS
|
||||
USR_CFLAGS += $USR_CFLAGS
|
||||
USR_CXXFLAGS += $USR_CXXFLAGS
|
||||
EOF
|
||||
|
||||
# set RTEMS to eg. "4.9" or "4.10"
|
||||
# requires qemu, bison, flex, texinfo, install-info
|
||||
if [ -n "$RTEMS" ]
|
||||
then
|
||||
echo "Cross RTEMS${RTEMS} for pc386"
|
||||
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
|
||||
| tar -C / -xmj
|
||||
|
||||
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
RTEMS_VERSION=$RTEMS
|
||||
RTEMS_BASE=$HOME/.rtems
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
|
||||
EOF
|
||||
fi
|
||||
|
||||
make -j2 -C epics-base $EXTRA
|
||||
make -j2 -C pvData $EXTRA
|
||||
make -j2 -C pvAccess $EXTRA
|
||||
28
.gitignore
vendored
28
.gitignore
vendored
@@ -1,13 +1,17 @@
|
||||
bin/
|
||||
lib/
|
||||
doc/
|
||||
include/
|
||||
db/
|
||||
dbd/
|
||||
documentation/html
|
||||
documentation/*.tag
|
||||
/cfg/
|
||||
/bin/
|
||||
/lib/
|
||||
/db/
|
||||
/dbd/
|
||||
/html/
|
||||
/include/
|
||||
/templates/
|
||||
/configure/*.local
|
||||
/documentation/html
|
||||
/documentation/*.tag
|
||||
O.*/
|
||||
/QtC-*
|
||||
envPaths
|
||||
configure/*.local
|
||||
!configure/ExampleRELEASE.local
|
||||
**/O.*
|
||||
QtC-*
|
||||
*.orig
|
||||
*.log
|
||||
.*.swp
|
||||
|
||||
31
.travis.yml
Normal file
31
.travis.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
sudo: false
|
||||
dist: trusty
|
||||
language: c++
|
||||
compiler:
|
||||
- gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libreadline6-dev
|
||||
- libncurses5-dev
|
||||
- perl
|
||||
- clang
|
||||
- g++-mingw-w64-i686
|
||||
- qemu-system-x86
|
||||
install:
|
||||
- ./.ci/travis-prepare.sh
|
||||
script:
|
||||
- ./.ci/travis-build.sh
|
||||
env:
|
||||
- BRBASE=7.0
|
||||
- BRBASE=7.0 CMPLR=clang
|
||||
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++98"
|
||||
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
- BRBASE=7.0 CMPLR=clang EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
- BRBASE=7.0 WINE=32 TEST=NO STATIC=YES
|
||||
- BRBASE=7.0 WINE=32 TEST=NO STATIC=NO
|
||||
- BRBASE=7.0 RTEMS=4.10 TEST=NO
|
||||
- BRBASE=7.0 RTEMS=4.9 TEST=NO
|
||||
- BRBASE=3.16
|
||||
- BRBASE=3.15
|
||||
- BRBASE=3.14
|
||||
43
README.md
43
README.md
@@ -1,38 +1,21 @@
|
||||
pvaDatabaseCPP
|
||||
============
|
||||
# pvDatabaseCPP
|
||||
|
||||
The EPICS **pvDatabase** module provides a set of network accessible, smart, memory resident records with a C++ API. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider gives access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.
|
||||
|
||||
A brief description of a pvDatabase is that it is a set of network accessible, smart, memory resident records. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider provides access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.
|
||||
pvaDatabase is a synchronous Database interface to pvAccess,
|
||||
which is callback based.
|
||||
pvaDatabase is thus easier to use than pvAccess itself.
|
||||
The pvDatabase module implements a synchronous C++ server interface to pvAccessCPP that was designed to be easier to use than the basic pvAccess server API.
|
||||
|
||||
See documentation/pvaDatabaseCPP.html for details.
|
||||
## Links
|
||||
|
||||
Building
|
||||
--------
|
||||
- General information about EPICS can be found at the
|
||||
[EPICS Controls website](https://epics-controls.org).
|
||||
- API documentation for this module can be found in its
|
||||
documentation directory, in particular the file
|
||||
pvDatabaseCPP.html
|
||||
|
||||
If a proper RELEASE.local file exists one directory level above pvaDatabaseCPP
|
||||
then just type:
|
||||
## Building
|
||||
|
||||
make
|
||||
|
||||
It can also be built by:
|
||||
|
||||
cp configure/ExampleRELEASE.local configure/RELEASE.local
|
||||
edit configure/RELEASE.local
|
||||
make
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
------------
|
||||
|
||||
Examples are available in exampleCPP.
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
* The API is for EPICS Version 4 release 4.6.0
|
||||
This module is included as a submodule of a full EPICS 7 release and will be compiled during builds of that software.
|
||||
|
||||
## Examples
|
||||
|
||||
Some examples are available in the separate exampleCPP module.
|
||||
|
||||
3
configure/CONFIG_PVDATABASE_VERSION
Normal file
3
configure/CONFIG_PVDATABASE_VERSION
Normal file
@@ -0,0 +1,3 @@
|
||||
EPICS_PVDATABASE_MAJOR_VERSION = 4
|
||||
EPICS_PVDATABASE_MINOR_VERSION = 5
|
||||
EPICS_PVDATABASE_MAINTENANCE_VERSION = 0
|
||||
@@ -1,8 +0,0 @@
|
||||
EPICS4_DIR=/home/epicsv4/master
|
||||
|
||||
PVACCESS=${EPICS4_DIR}/pvAccessCPP
|
||||
PVDATA=${EPICS4_DIR}/pvDataCPP
|
||||
PVCOMMON=${EPICS4_DIR}/pvCommonCPP
|
||||
|
||||
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
||||
EPICS_BASE=/home/install/epics/base
|
||||
@@ -2,6 +2,8 @@ TOP=..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
CFG += CONFIG_PVDATABASE_VERSION
|
||||
|
||||
TARGETS = $(CONFIG_TARGETS)
|
||||
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||
|
||||
|
||||
@@ -1,27 +1,43 @@
|
||||
# pvDatabaseCPP RELEASE - Location of external support modules
|
||||
# RELEASE - Location of external support modules
|
||||
#
|
||||
# IF YOU CHANGE this file or any file it includes you must
|
||||
# subsequently do a "gnumake rebuild" in the application's
|
||||
# top level directory.
|
||||
# IF YOU CHANGE ANY PATHS in this file or make API changes to
|
||||
# any modules it refers to, you should do a "make rebuild" in
|
||||
# this application's top level directory.
|
||||
#
|
||||
# The build process does not check dependencies against files
|
||||
# that are outside this application, thus you should also do a
|
||||
# "gnumake rebuild" in the top level directory after EPICS_BASE
|
||||
# or any other external module pointed to below is rebuilt.
|
||||
# The EPICS build process does not check dependencies against
|
||||
# any files from outside the application, so it is safest to
|
||||
# rebuild it completely if any modules it depends on change.
|
||||
#
|
||||
# Host- or target-specific settings can be given in files named
|
||||
# RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
# RELEASE.Common.$(T_A)
|
||||
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
# EPICS V4 Developers: Do not edit the locations in this file!
|
||||
#
|
||||
# Create a file RELEASE.local pointing to your PVASRV, PVACCESS,
|
||||
# PVDATA, PVCOMMON and EPICS_BASE build directories, e.g.
|
||||
# PVACCESS = /path/to/epics/pvAccessCPP
|
||||
# PVDATA = /path/to/epics/pvDataCPP
|
||||
# PVCOMMON = /path/to/epics/pvCommonCPP
|
||||
# EPICS_BASE = /path/to/epics/base
|
||||
# This file is parsed by both GNUmake and an EPICS Perl script,
|
||||
# so it may ONLY contain definititions of paths to other support
|
||||
# modules, variable definitions that are used in module paths,
|
||||
# and include statements that pull in other RELEASE files.
|
||||
# Variables may be used before their values have been set.
|
||||
# Build variables that are NOT used in paths should be set in
|
||||
# the CONFIG_SITE file.
|
||||
|
||||
# Variables and paths to dependent modules:
|
||||
#MODULES = /path/to/modules
|
||||
#MYMODULE = $(MODULES)/my-module
|
||||
|
||||
# If building the EPICS modules individually, set these:
|
||||
#EPICS_PVACCESS = $(MODULES)/pvAccess
|
||||
#EPICS_PVDATA = $(MODULES)/pvData
|
||||
#EPICS_DATABASE = $(MODULES)/database
|
||||
#EPICS_CA = $(MODULES)/ca
|
||||
#EPICS_LIBCOM = $(MODULES)/libcom
|
||||
#EPICS_BASE = $(MODULES)/core
|
||||
|
||||
# Set RULES here if you want to use build rules from elsewhere:
|
||||
#RULES = $(MODULES)/build-rules
|
||||
|
||||
# These allow developers to override the RELEASE variable settings
|
||||
# without having to modify the configure/RELEASE file itself.
|
||||
-include $(TOP)/../RELEASE.local
|
||||
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
|
||||
-include $(TOP)/configure/RELEASE.local
|
||||
|
||||
@@ -1,23 +1,57 @@
|
||||
# pvDatabaseCPP Module
|
||||
|
||||
EPICS V4 release 4.6
|
||||
====================
|
||||
This document summarizes the changes to the module between releases.
|
||||
|
||||
## Release 4.5.0 (EPICS 7.0.3, Jul 2019)
|
||||
|
||||
1) support is a new feature.
|
||||
2) processRecord is new
|
||||
|
||||
|
||||
## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019)
|
||||
|
||||
Formerly if a client makes a request for a subfield of a non structure field
|
||||
it resulted in a crash.
|
||||
|
||||
Now if a request is made for a subfield of a non structure field
|
||||
|
||||
1) if the field is not a union an exception is thrown which is passed to the client.
|
||||
2) if the field is a union
|
||||
a) if more than one subfield is requested an exception is thrown
|
||||
b) if the subfield is the type for the current union the request succeeds
|
||||
c) if type is not the same an exception is thrown
|
||||
|
||||
|
||||
## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019)
|
||||
|
||||
* Cleaned up some build warnings.
|
||||
* RTEMS test harness simplified.
|
||||
|
||||
|
||||
## Release 4.4 (EPICS 7.0.2, Dec 2018)
|
||||
|
||||
* pvCopy is now implemented in pvDatabaseCPP. The version in pvDatacPP can be deprecated.
|
||||
* plugin support is implemented.
|
||||
|
||||
|
||||
## Release 4.3 (EPICS 7.0.1, Dec 2017)
|
||||
|
||||
* Updates for pvAccess API and build system changes.
|
||||
|
||||
|
||||
## Release 4.2 (EPICS V4.6, Aug 2016)
|
||||
|
||||
* The examples are moved to exampleCPP
|
||||
* Support for channelRPC is now available.
|
||||
* removeRecord and traceRecord are now available.
|
||||
|
||||
The test is now a regression test the can be ran via
|
||||
The test is now a regression test which can be run using:
|
||||
|
||||
make runtests
|
||||
|
||||
|
||||
EPICS V4 release 4.5
|
||||
====================
|
||||
|
||||
This release is one component of EPICS V4 release 4.5.
|
||||
## Release 4.1 (EPICS V4.5, Oct 2015)
|
||||
|
||||
This is the first release of pvDatabaseCPP.
|
||||
|
||||
It provides functionality equivalent to pvDatabaseJava.
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
TODO
|
||||
===========
|
||||
|
||||
monitorPlugin
|
||||
-------------
|
||||
|
||||
A debate is on-going about what semantics should be.
|
||||
|
||||
Must test record delete.
|
||||
-------------------
|
||||
|
||||
Must test removing a record from the PVDatabase while a pvAccess client
|
||||
is attached. Also why do both unlisten and detach exists?
|
||||
|
||||
|
||||
create more regression tests
|
||||
----------------
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<h2 class="nocount">Release 4.2-SNAPSHOT - 2016.07.14</h2>
|
||||
<h2 class="nocount">Release ? - TBD</h2>
|
||||
Latest update 2019.06.19.
|
||||
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
@@ -60,25 +61,21 @@ The minimum that an extension must provide is a top level PVStructure and a proc
|
||||
<h2 class="nocount">Table of Contents</h2>
|
||||
</div>
|
||||
|
||||
<div id="contents" class="contents">
|
||||
<div id="contents" class="contents">
|
||||
<hr />
|
||||
|
||||
<h2>Overview</h2>
|
||||
<p>
|
||||
pvDatabaseCPP is one of the components of
|
||||
<a href="http://epics-pvdata.sourceforge.net">
|
||||
EPICS Version 4
|
||||
</a>
|
||||
pvDatabaseCPP is one of the components of
|
||||
EPICS Version 7
|
||||
</p>
|
||||
<p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP
|
||||
</p>
|
||||
<p>
|
||||
It is intended for developers that want to use pvDatabaseCPP.
|
||||
</p>
|
||||
<h2>Developer Guide</h2>
|
||||
<p>A guide for developers is available at
|
||||
<a
|
||||
href="http://epics-pvdata.sourceforge.net/informative/developerGuide/developerGuide.html">
|
||||
href="https://mrkraimer.github.io/website/developerGuide/developerGuide.html">
|
||||
developerGuide
|
||||
</a>
|
||||
</p>
|
||||
@@ -87,8 +84,20 @@ Some understanding of the components and how they are related is necessary in or
|
||||
develop code that uses pvDatabaseCPP.
|
||||
In particular read everything related to pvDatabase.
|
||||
</p>
|
||||
<p>pvDatabase has plugin support, which is implemented in <b>pvCopy</b>.
|
||||
<b>pvCopy</b> was originally implemented in <b>pvDataCPP</b>,
|
||||
but pvDatabaseCPP now implements its own version and adds plugin support.
|
||||
</p>
|
||||
<p>
|
||||
See
|
||||
<a
|
||||
href="https://mrkraimer.github.io/website/pvRequest/pvRequest.html">
|
||||
pvRequest
|
||||
</a>
|
||||
for details.
|
||||
</p>
|
||||
<p>The developerGuide discusses code in a way that applies to both CPP and C++.
|
||||
For the descriptions of the CPP specific code consult the next section.
|
||||
For the descriptions of the CPP specific code consult the following sections.
|
||||
</p>
|
||||
|
||||
<h2>doxygen</h2>
|
||||
@@ -98,22 +107,82 @@ href="./html/index.html">doxgen</a>
|
||||
</p>
|
||||
|
||||
<h2>pvDatabaseCPP</h2>
|
||||
<p>pvDatabaseCPP itself has the following implementations of a <b>PVRecord</b></p>
|
||||
<h3>include/pv</h3>
|
||||
<p>The header files that describe the various components implemented by pvDatabase.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>RemoveRecord.cpp</dt>
|
||||
<dd>
|
||||
This is the code that is used to delete another record in the same <b>IOC</b>.
|
||||
</dd>
|
||||
<dt>TraceRecord.cpp</dt>
|
||||
<dd>
|
||||
This is the code that is used to set the trace level
|
||||
in another record in the same <b>IOC</b>.
|
||||
</dd>
|
||||
<dt>pvDatabase.h</dt>
|
||||
<dd>
|
||||
This describes PVRecord and PVDatabase.
|
||||
</dd>
|
||||
<dt>channelProviderLocal.h </dt>
|
||||
<dd>
|
||||
This describes a channel provider for PVDatabase
|
||||
</dd>
|
||||
<dt>pvSupport.h</dt>
|
||||
<dd>
|
||||
This is the base class for support attached to a field of a record.
|
||||
</dd>
|
||||
<dt>controlSupport.h</dt>
|
||||
<dd>
|
||||
This is support that implements control limits.
|
||||
</dd>
|
||||
<dt>scalarAlarmSupport.h</dt>
|
||||
<dd>
|
||||
This is support for a alarm limits for a scalar numeric field.
|
||||
</dd>
|
||||
<dt>processRecord.h</dt>
|
||||
<dd>
|
||||
This is a PVRecord that periodical processes a set of PVRecords in the local PVDatabase.
|
||||
</dd>
|
||||
<dt>removeRecord.h</dt>
|
||||
<dd>
|
||||
This is a PVRecord that removes a PVRecord in the local PVDatabase.
|
||||
</dd>
|
||||
<dt>traceRecord.h</dt>
|
||||
<dd>
|
||||
This is a PVRecord that sets the trace value for another PVRecord in the local PVDatabase.
|
||||
</dd>
|
||||
<dt>pvStructureCopy.h</dt>
|
||||
<dd>
|
||||
This is a facility that allows a client to access a subfield of the fields in a PVRecord.
|
||||
It also provides record and field options an plugin support.
|
||||
</dd>
|
||||
<dt>pvPlugin.h</dt>
|
||||
<dd>
|
||||
This is the base class for a plugin attached to a record or field of PVRecord.
|
||||
</dd>
|
||||
<dt>pvArrayPlugin.h</dt>
|
||||
<dd>
|
||||
A plugin for accessing a subset of the elements in an array field.
|
||||
</dd>
|
||||
<dt>pvDeadbandPlugin.h</dt>
|
||||
<dd>
|
||||
A deadband plugin for monitors.
|
||||
</dd>
|
||||
<dt>pvTimestampPlugin.h</dt>
|
||||
<dd>
|
||||
A plugin for timeStamp.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>src/database</h3>
|
||||
<p>This has the code that implements pvDatabase and pvRecord.</p>
|
||||
<h3>src/pvAccess</h3>
|
||||
<p>This has the code for the channel provider for pvDatabase.
|
||||
</p>
|
||||
<h3>src/support</h3>
|
||||
<p>This has the pvSupport code.</p>
|
||||
<h3>src/special</h3>
|
||||
<p>
|
||||
This has the code for processRecord, removeRecord, and traceRecord.
|
||||
</p>
|
||||
<h3>src/copy</h3>
|
||||
<p>This has the code for pvStructureCopy and all the plugin support.
|
||||
</p>
|
||||
<h2>exampleCPP</h2>
|
||||
<p>Example code is available as part of this release.
|
||||
<a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/exampleCPP/tip/documentation/exampleCPP.html">
|
||||
href="https://github.com/epics-base/exampleCPP">
|
||||
exampleCPP
|
||||
</a>
|
||||
</p>
|
||||
@@ -123,7 +192,7 @@ exampleCPP
|
||||
<h3>database</h3>
|
||||
<p>This has many examples of how to create both soft records and records that implement
|
||||
other functionality.</p>
|
||||
<dl>
|
||||
<dl>
|
||||
<dt>exampleDatabase.cpp</dt>
|
||||
<dd>
|
||||
This shows how to create soft records of each pvData type.<br />
|
||||
@@ -148,7 +217,7 @@ other functionality.</p>
|
||||
</dl>
|
||||
<h3>exampleLink</h3>
|
||||
<p>This shows how to implement a record that has a link to another record</p>
|
||||
<dl>
|
||||
<dl>
|
||||
<dt>exampleMonitorLinkRecord</dt>
|
||||
<dd>
|
||||
This creates a monitor link to another record.
|
||||
@@ -163,13 +232,31 @@ other functionality.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h3>support</h3>
|
||||
<p>This creates records that have the following features:</p>
|
||||
<dl>
|
||||
<dt>value</dt>
|
||||
<dd>
|
||||
Each record has a value field the is a numeric scalar field.
|
||||
In addition each has the following fields:
|
||||
alarm,timeStamp,control,scalarAlarm, and display.
|
||||
</dd>
|
||||
<dt>support</dt>
|
||||
<dd>
|
||||
Each record uses the control and scalarAlarm support provided by pvDatabaseCPP.
|
||||
</dd>
|
||||
</dl>
|
||||
<p>
|
||||
It also creates records that can be used by clients to show example of the plugin support.
|
||||
</p>
|
||||
|
||||
<h2>iocshell commands</h2>
|
||||
<p>Shell commands are made available via the standard DBD include mechanism
|
||||
provided by iocCore.
|
||||
The following provide EPICS V4 shell commands:</p>
|
||||
<pre>
|
||||
pvAccessCPP
|
||||
pvaSrv
|
||||
qsrv
|
||||
pvDatabaseCPP
|
||||
</pre>
|
||||
|
||||
@@ -184,7 +271,7 @@ pvDatabaseCPP
|
||||
</dd>
|
||||
</dl>
|
||||
<p>In addition any code that implements a PVRecord must implement an ioc command.
|
||||
Look at any of the examples in <b>exampleCPP</b> to see how to implement shell commands.</p>
|
||||
Look at the examples in <b>exampleCPP/support</b> to see how to implement shell commands.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -21,28 +21,19 @@ installE4 () {
|
||||
local module=$1
|
||||
local branch=$2
|
||||
|
||||
# If microbench version does not exist, try without
|
||||
if [ "${MB}" = "WITH_MICROBENCH" ]; then
|
||||
if ! wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
else
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
tar -xzf ${module}.CB-dist.tar.gz
|
||||
}
|
||||
|
||||
###########################################
|
||||
# Defaults for EPICS Base and MB
|
||||
# Defaults for EPICS Base
|
||||
|
||||
DEFAULT_BASE=3.15.4
|
||||
BASE=${BASE:-${DEFAULT_BASE}}
|
||||
MB=${MB:-"NO_MICROBENCH"}
|
||||
|
||||
###########################################
|
||||
# Dependent module branches
|
||||
|
||||
PVCOMMON_BRANCH="master"
|
||||
PVDATA_BRANCH="master"
|
||||
PVACCESS_BRANCH="master"
|
||||
|
||||
@@ -58,7 +49,6 @@ cd ${STUFF}
|
||||
installTool Boost 1.61.0
|
||||
installTool Base ${BASE}
|
||||
|
||||
installE4 pvCommon ${PVCOMMON_BRANCH}
|
||||
installE4 pvData ${PVDATA_BRANCH}
|
||||
installE4 pvAccess ${PVACCESS_BRANCH}
|
||||
|
||||
@@ -84,6 +74,6 @@ make distclean all
|
||||
make runtests
|
||||
|
||||
###########################################
|
||||
# Create distribution
|
||||
# Create cache
|
||||
|
||||
tar -czf pvDatabase.CB-dist.tar.gz lib include dbd LICENSE
|
||||
|
||||
@@ -21,14 +21,7 @@ installE4 () {
|
||||
local module=$1
|
||||
local branch=$2
|
||||
|
||||
# If microbench version does not exist, try without
|
||||
if [ "${MB}" = "WITH_MICROBENCH" ]; then
|
||||
if ! wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
else
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
tar -xzf ${module}.CB-dist.tar.gz
|
||||
}
|
||||
|
||||
@@ -38,7 +31,6 @@ installE4 () {
|
||||
BASE=3.15.4
|
||||
PUBLISH=${PUBLISH:-NO}
|
||||
BRANCH=${BRANCH:-master}
|
||||
MB=NO_MICROBENCH
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
|
||||
30
src/Makefile
30
src/Makefile
@@ -3,28 +3,42 @@
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PVDATABASE_SRC = $(TOP)/src
|
||||
# needed for Windows
|
||||
LIB_SYS_LIBS_WIN32 += netapi32 ws2_32
|
||||
|
||||
PVDATABASE_SRC = $(TOP)/src
|
||||
|
||||
LIBRARY += pvDatabase
|
||||
|
||||
# shared library ABI version.
|
||||
SHRLIB_VERSION ?= 4.2.0
|
||||
SHRLIB_VERSION ?= $(EPICS_PVDATABASE_MAJOR_VERSION).$(EPICS_PVDATABASE_MINOR_VERSION).$(EPICS_PVDATABASE_MAINTENANCE_VERSION)
|
||||
|
||||
INC += pv/pvPlugin.h
|
||||
INC += pv/pvStructureCopy.h
|
||||
INC += pv/pvArrayPlugin.h
|
||||
INC += pv/pvDeadbandPlugin.h
|
||||
INC += pv/pvTimestampPlugin.h
|
||||
|
||||
INC += pv/pvDatabase.h
|
||||
|
||||
INC += pv/channelProviderLocal.h
|
||||
INC += pv/pvDatabase.h
|
||||
|
||||
INC += pv/traceRecord.h
|
||||
INC += pv/removeRecord.h
|
||||
INC += pv/processRecord.h
|
||||
|
||||
INC += pv/pvSupport.h
|
||||
INC += pv/controlSupport.h
|
||||
INC += pv/scalarAlarmSupport.h
|
||||
|
||||
|
||||
include $(PVDATABASE_SRC)/copy/Makefile
|
||||
include $(PVDATABASE_SRC)/database/Makefile
|
||||
include $(PVDATABASE_SRC)/pvAccess/Makefile
|
||||
include $(PVDATABASE_SRC)/special/Makefile
|
||||
include $(PVDATABASE_SRC)/support/Makefile
|
||||
|
||||
|
||||
pvDatabase_LIBS += pvAccess pvData Com
|
||||
pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
|
||||
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
12
src/copy/Makefile
Normal file
12
src/copy/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
# This is a Makefile fragment, see ../Makefile
|
||||
|
||||
SRC_DIRS += $(PVDATABASE_SRC)/copy
|
||||
|
||||
LIBSRCS += pvPlugin.cpp
|
||||
LIBSRCS += pvCopy.cpp
|
||||
LIBSRCS += pvArrayPlugin.cpp
|
||||
LIBSRCS += pvDeadbandPlugin.cpp
|
||||
LIBSRCS += pvTimestampPlugin.cpp
|
||||
|
||||
|
||||
193
src/copy/pvArrayPlugin.cpp
Normal file
193
src/copy/pvArrayPlugin.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/* pvArrayPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/pvSubArrayCopy.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvArrayPlugin.h"
|
||||
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
static std::string name("array");
|
||||
|
||||
PVArrayPlugin::PVArrayPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
PVArrayPlugin::~PVArrayPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void PVArrayPlugin::create()
|
||||
{
|
||||
static bool firstTime = true;
|
||||
if(firstTime) {
|
||||
firstTime = false;
|
||||
PVArrayPluginPtr pvPlugin = PVArrayPluginPtr(new PVArrayPlugin());
|
||||
PVPluginRegistry::registerPlugin(name,pvPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
PVFilterPtr PVArrayPlugin::create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
return PVArrayFilter::create(requestValue,master);
|
||||
}
|
||||
|
||||
PVArrayFilter::~PVArrayFilter()
|
||||
{
|
||||
}
|
||||
|
||||
static vector<string> split(string const & colonSeparatedList) {
|
||||
string::size_type numValues = 1;
|
||||
string::size_type index=0;
|
||||
while(true) {
|
||||
string::size_type pos = colonSeparatedList.find(':',index);
|
||||
if(pos==string::npos) break;
|
||||
numValues++;
|
||||
index = pos +1;
|
||||
}
|
||||
vector<string> valueList(numValues,"");
|
||||
index=0;
|
||||
for(size_t i=0; i<numValues; i++) {
|
||||
size_t pos = colonSeparatedList.find(':',index);
|
||||
string value = colonSeparatedList.substr(index,pos-index);
|
||||
valueList[i] = value;
|
||||
index = pos +1;
|
||||
}
|
||||
return valueList;
|
||||
}
|
||||
|
||||
PVArrayFilterPtr PVArrayFilter::create(
|
||||
const std::string & requestValue,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
Type type = master->getField()->getType();
|
||||
if(type!=scalarArray) {
|
||||
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
||||
return filter;
|
||||
}
|
||||
long start =0;
|
||||
long increment =1;
|
||||
long end = -1;
|
||||
vector<string> values(split(requestValue));
|
||||
long num = values.size();
|
||||
bool ok = true;
|
||||
string value;
|
||||
if(num==1) {
|
||||
value = values[0];
|
||||
start = strtol(value.c_str(),0,10);
|
||||
} else if(num==2) {
|
||||
value = values[0];
|
||||
start = strtol(value.c_str(),0,10);
|
||||
value = values[1];
|
||||
end = strtol(value.c_str(),0,10);
|
||||
} else if(num==3) {
|
||||
value = values[0];
|
||||
start = strtol(value.c_str(),0,10);
|
||||
value = values[1];
|
||||
increment = strtol(value.c_str(),0,10);
|
||||
value = values[2];
|
||||
end = strtol(value.c_str(),0,10);
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
if(!ok) {
|
||||
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
||||
return filter;
|
||||
}
|
||||
PVArrayFilterPtr filter =
|
||||
PVArrayFilterPtr(
|
||||
new PVArrayFilter(
|
||||
start,increment,end,static_pointer_cast<PVScalarArray>(master)));
|
||||
return filter;
|
||||
}
|
||||
|
||||
PVArrayFilter::PVArrayFilter(long start,long increment,long end,const PVScalarArrayPtr & masterArray)
|
||||
: start(start),
|
||||
increment(increment),
|
||||
end(end),
|
||||
masterArray(masterArray)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PVArrayFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
||||
{
|
||||
PVScalarArrayPtr copyArray = static_pointer_cast<PVScalarArray>(pvCopy);
|
||||
long len = 0;
|
||||
long start = this->start;
|
||||
long end = this->end;
|
||||
long no_elements = masterArray->getLength();
|
||||
if(start<0) {
|
||||
start = no_elements+start;
|
||||
if(start<0) start = 0;
|
||||
}
|
||||
if (end < 0) {
|
||||
end = no_elements + end;
|
||||
if (end < 0) end = 0;
|
||||
|
||||
}
|
||||
if(toCopy) {
|
||||
if (end >= no_elements) end = no_elements - 1;
|
||||
if (end - start >= 0) len = 1 + (end - start) / increment;
|
||||
if(len<=0 || start>=no_elements) {
|
||||
copyArray->setLength(0);
|
||||
return true;
|
||||
}
|
||||
long indfrom = start;
|
||||
long indto = 0;
|
||||
copyArray->setCapacity(len);
|
||||
if(increment==1) {
|
||||
copy(*masterArray,indfrom,1,*copyArray,indto,1,len);
|
||||
} else {
|
||||
for(long i=0; i<len; ++i) {
|
||||
copy(*masterArray,indfrom,1,*copyArray,indto,1,1);
|
||||
indfrom += increment;
|
||||
indto += 1;
|
||||
}
|
||||
}
|
||||
copyArray->setLength(len);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
return true;
|
||||
}
|
||||
if (end - start >= 0) len = 1 + (end - start) / increment;
|
||||
if(len<=0) return true;
|
||||
if(no_elements<=end) masterArray->setLength(end+1);
|
||||
long indfrom = 0;
|
||||
long indto = start;
|
||||
if(increment==1) {
|
||||
copy(*copyArray,indfrom,1,*masterArray,indto,1,len);
|
||||
} else {
|
||||
for(long i=0; i<len; ++i) {
|
||||
copy(*copyArray,indfrom,1,*masterArray,indto,1,1);
|
||||
indfrom += 1;
|
||||
indto += increment;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string PVArrayFilter::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
789
src/copy/pvCopy.cpp
Normal file
789
src/copy/pvCopy.cpp
Normal file
@@ -0,0 +1,789 @@
|
||||
/* pvCopy.cpp */
|
||||
/*
|
||||
* License terms for this software can be found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/thread.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvPlugin.h"
|
||||
#include "pv/pvStructureCopy.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvCopy {
|
||||
|
||||
/**
|
||||
* Convenience method for implementing dump.
|
||||
* It generates a newline and inserts blanks at the beginning of the newline.
|
||||
* @param builder The std::string * being constructed.
|
||||
* @param indentLevel Indent level, Each level is four spaces.
|
||||
*/
|
||||
static void newLine(string *buffer, int indentLevel)
|
||||
{
|
||||
*buffer += "\n";
|
||||
*buffer += string(indentLevel*4, ' ');
|
||||
}
|
||||
|
||||
static PVCopyPtr NULLPVCopy;
|
||||
static StructureConstPtr NULLStructure;
|
||||
static PVStructurePtr NULLPVStructure;
|
||||
|
||||
struct CopyNode {
|
||||
CopyNode()
|
||||
: isStructure(false),
|
||||
structureOffset(0),
|
||||
nfields(0)
|
||||
{}
|
||||
PVFieldPtr masterPVField;
|
||||
bool isStructure;
|
||||
size_t structureOffset; // In the copy
|
||||
size_t nfields;
|
||||
PVStructurePtr options;
|
||||
vector<PVFilterPtr> pvFilters;
|
||||
};
|
||||
|
||||
static CopyNodePtr NULLCopyNode;
|
||||
|
||||
typedef std::vector<CopyNodePtr> CopyNodePtrArray;
|
||||
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
|
||||
|
||||
struct CopyStructureNode : public CopyNode {
|
||||
CopyNodePtrArrayPtr nodes;
|
||||
};
|
||||
|
||||
PVCopyPtr PVCopy::create(
|
||||
PVStructurePtr const &pvMaster,
|
||||
PVStructurePtr const &pvRequest,
|
||||
string const & structureName)
|
||||
{
|
||||
PVStructurePtr pvStructure(pvRequest);
|
||||
if(structureName.size()>0) {
|
||||
if(pvStructure->getStructure()->getNumberFields()>0) {
|
||||
pvStructure = pvRequest->getSubField<PVStructure>(structureName);
|
||||
if(!pvStructure) return NULLPVCopy;
|
||||
}
|
||||
} else if(pvRequest->getSubField<PVStructure>("field")) {
|
||||
pvStructure = pvRequest->getSubField<PVStructure>("field");
|
||||
}
|
||||
PVCopyPtr pvCopy = PVCopyPtr(new PVCopy(pvMaster));
|
||||
bool result = pvCopy->init(pvStructure);
|
||||
if(!result) return PVCopyPtr();
|
||||
pvCopy->traverseMasterInitPlugin();
|
||||
//cout << pvCopy->dump() << endl;
|
||||
return pvCopy;
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::getPVMaster()
|
||||
{
|
||||
return pvMaster;
|
||||
}
|
||||
|
||||
void PVCopy::traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback)
|
||||
{
|
||||
traverseMaster(headNode,callback);
|
||||
}
|
||||
|
||||
StructureConstPtr PVCopy::getStructure()
|
||||
{
|
||||
return structure;
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::createPVStructure()
|
||||
{
|
||||
if(cacheInitStructure) {
|
||||
PVStructurePtr save = cacheInitStructure;
|
||||
cacheInitStructure.reset();
|
||||
return save;
|
||||
}
|
||||
PVStructurePtr pvStructure =
|
||||
getPVDataCreate()->createPVStructure(structure);
|
||||
return pvStructure;
|
||||
}
|
||||
|
||||
|
||||
size_t PVCopy::getCopyOffset(PVFieldPtr const &masterPVField)
|
||||
{
|
||||
if(!headNode->isStructure) {
|
||||
CopyNodePtr node = static_pointer_cast<CopyNode>(headNode);
|
||||
if((node->masterPVField.get())==masterPVField.get()) {
|
||||
return headNode->structureOffset;
|
||||
}
|
||||
PVStructure * parent = masterPVField->getParent();
|
||||
size_t offsetParent = parent->getFieldOffset();
|
||||
size_t off = masterPVField->getFieldOffset();
|
||||
size_t offdiff = off -offsetParent;
|
||||
if(offdiff<node->nfields) return headNode->structureOffset + offdiff;
|
||||
return string::npos;
|
||||
}
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(headNode);
|
||||
CopyNodePtr node = getCopyOffset(structNode,masterPVField);
|
||||
if(node) return node->structureOffset;
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
size_t PVCopy::getCopyOffset(
|
||||
PVStructurePtr const &masterPVStructure,
|
||||
PVFieldPtr const &masterPVField)
|
||||
{
|
||||
CopyNodePtr node;
|
||||
if(!headNode->isStructure) {
|
||||
node = static_pointer_cast<CopyNode>(headNode);
|
||||
if(node->masterPVField.get()!=masterPVStructure.get()) return string::npos;
|
||||
} else {
|
||||
CopyStructureNodePtr snode = static_pointer_cast<CopyStructureNode>(headNode);
|
||||
node = getCopyOffset(snode,masterPVField);
|
||||
}
|
||||
if(!node) return string::npos;
|
||||
size_t diff = masterPVField->getFieldOffset()
|
||||
- masterPVStructure->getFieldOffset();
|
||||
return node->structureOffset + diff;
|
||||
}
|
||||
|
||||
PVFieldPtr PVCopy::getMasterPVField(size_t structureOffset)
|
||||
{
|
||||
CopyNodePtr node;
|
||||
if(!headNode->isStructure) {
|
||||
node = headNode;
|
||||
} else {
|
||||
CopyStructureNodePtr snode = static_pointer_cast<CopyStructureNode>(headNode);
|
||||
node = getMasterNode(snode,structureOffset);
|
||||
}
|
||||
if(!node) {
|
||||
throw std::logic_error(
|
||||
"PVCopy::getMasterPVField: structureOffset not valid");
|
||||
}
|
||||
size_t diff = structureOffset - node->structureOffset;
|
||||
PVFieldPtr pvMasterField = node->masterPVField;
|
||||
if(diff==0) return pvMasterField;
|
||||
PVStructurePtr pvStructure
|
||||
= static_pointer_cast<PVStructure>(pvMasterField);
|
||||
return pvStructure->getSubField(
|
||||
pvMasterField->getFieldOffset() + diff);
|
||||
}
|
||||
|
||||
void PVCopy::initCopy(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
|
||||
bitSet->set(i,true);
|
||||
}
|
||||
updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
|
||||
}
|
||||
|
||||
|
||||
bool PVCopy::updateCopySetBitSet(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
updateCopySetBitSet(copyPVStructure,headNode,bitSet);
|
||||
return checkIgnore(copyPVStructure,bitSet);
|
||||
}
|
||||
|
||||
bool PVCopy::updateCopyFromBitSet(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
if(bitSet->get(0)) {
|
||||
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
|
||||
bitSet->set(i,true);
|
||||
}
|
||||
}
|
||||
updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
|
||||
return checkIgnore(copyPVStructure,bitSet);
|
||||
}
|
||||
|
||||
void PVCopy::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 ©PVStructure,
|
||||
BitSetPtr const &bitSet,
|
||||
size_t nextSet)
|
||||
{
|
||||
if(!bitSet->get(nextSet)) {
|
||||
size_t next = bitSet->nextSetBit(nextSet);
|
||||
if(next==string::npos) return;
|
||||
updateMasterCheckBitSet(copyPVStructure,bitSet,next);
|
||||
return;
|
||||
}
|
||||
PVFieldPtr pvField = copyPVStructure;
|
||||
if(nextSet!=0) pvField = copyPVStructure->getSubField(nextSet);
|
||||
if(pvField->getField()->getType()==epics::pvData::structure) {
|
||||
bitSet->clear(nextSet);
|
||||
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvField);
|
||||
PVFieldPtrArray pvFieldArray = pv->getPVFields();
|
||||
for(size_t i=0; i>pvFieldArray.size(); ++i) {
|
||||
PVFieldPtr pvField = pvFieldArray[i];
|
||||
bitSet->set(pvField->getFieldOffset());
|
||||
}
|
||||
}
|
||||
size_t next = bitSet->nextSetBit(nextSet+1);
|
||||
if(next==string::npos) return;
|
||||
updateMasterCheckBitSet(copyPVStructure,bitSet,next);
|
||||
}
|
||||
|
||||
CopyNodePtr PVCopy::getCopyNode(std::size_t fieldOffset)
|
||||
{
|
||||
if(fieldOffset==0) return headNode;
|
||||
CopyNodePtr node = headNode;
|
||||
while(true) {
|
||||
if(!node->isStructure) return node;
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structNode->nodes;
|
||||
bool okToContinue = false;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
node = (*nodes)[i];
|
||||
size_t soff = node->structureOffset;
|
||||
if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
|
||||
okToContinue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(okToContinue) continue;
|
||||
}
|
||||
throw std::logic_error("PVCopy::getCopyNode fieldOffset not valid");
|
||||
}
|
||||
|
||||
|
||||
void PVCopy::updateMaster(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
updateMasterCheckBitSet(copyPVStructure,bitSet,0);
|
||||
size_t nextSet =0;
|
||||
while(true) {
|
||||
nextSet = bitSet->nextSetBit(nextSet);
|
||||
if(nextSet==string::npos) return;
|
||||
PVFieldPtr pvCopy = copyPVStructure->getSubField(nextSet);
|
||||
PVFieldPtr pvMaster = headNode->masterPVField;
|
||||
if(pvMaster->getField()->getType()==epics::pvData::structure) {
|
||||
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvMaster);
|
||||
pvMaster = pv->getSubField(pvCopy->getFullName());
|
||||
}
|
||||
updateMasterField(getCopyNode(nextSet),pvCopy,pvMaster,bitSet);
|
||||
bitSet->clear(nextSet);
|
||||
}
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
|
||||
{
|
||||
if(fieldOffset==0) return headNode->options;
|
||||
CopyNodePtr node = headNode;
|
||||
while(true) {
|
||||
if(node->structureOffset==fieldOffset) return node->options;
|
||||
if(!node->isStructure) return NULLPVStructure;
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structNode->nodes;
|
||||
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) {
|
||||
if(fieldOffset==soff) return node->options;
|
||||
if(!node->isStructure) {
|
||||
return NULLPVStructure;
|
||||
}
|
||||
okToContinue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(okToContinue) continue;
|
||||
throw std::logic_error("PVCopy::getOptions logic error: fieldOffset not valid");
|
||||
}
|
||||
}
|
||||
|
||||
string PVCopy::dump()
|
||||
{
|
||||
string builder;
|
||||
dump(&builder,headNode,0);
|
||||
return builder;
|
||||
}
|
||||
|
||||
void PVCopy::traverseMaster(
|
||||
CopyNodePtr const &innode,
|
||||
PVCopyTraverseMasterCallbackPtr const & callback)
|
||||
{
|
||||
CopyNodePtr node = innode;
|
||||
if(!node->isStructure) {
|
||||
callback->nextMasterPVField(node->masterPVField);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
node = (*nodes)[i];
|
||||
traverseMaster(node,callback);
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopy::updateCopySetBitSet(
|
||||
PVFieldPtr const & pvCopy,
|
||||
PVFieldPtr const & pvMaster,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
if(pvCopy->getField()->getType()!=epics::pvData::structure) {
|
||||
if(*pvCopy==*pvMaster) return;
|
||||
pvCopy->copy(*pvMaster);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
return;
|
||||
}
|
||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||
PVFieldPtr master = getMasterPVField(pvCopyFields[i]->getFieldOffset());
|
||||
updateCopySetBitSet(pvCopyFields[i],master,bitSet);
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopy::updateCopySetBitSet(
|
||||
PVFieldPtr const & pvCopy,
|
||||
CopyNodePtr const & node,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
bool result = false;
|
||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||
if(pvFilter->filter(pvCopy,bitSet,true)) result = true;
|
||||
}
|
||||
if(!node->isStructure) {
|
||||
if(result) return;
|
||||
updateCopySetBitSet(pvCopy,node->masterPVField,bitSet);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||
updateCopySetBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PVCopy::updateCopyFromBitSet(
|
||||
PVFieldPtr const & pvCopy,
|
||||
CopyNodePtr const & node,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
bool result = false;
|
||||
bool update = bitSet->get(pvCopy->getFieldOffset());
|
||||
if(update) {
|
||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||
if(pvFilter->filter(pvCopy,bitSet,true)) result = true;
|
||||
}
|
||||
}
|
||||
if(!node->isStructure) {
|
||||
if(result) return;
|
||||
PVFieldPtr pvMaster = node->masterPVField;
|
||||
pvCopy->copy(*pvMaster);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
size_t offset = structureNode->structureOffset;
|
||||
size_t nextSet = bitSet->nextSetBit(offset);
|
||||
if(nextSet==string::npos) return;
|
||||
if(offset>=pvCopy->getNextFieldOffset()) return;
|
||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||
updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
||||
}
|
||||
}
|
||||
|
||||
PVCopy::PVCopy(
|
||||
PVStructurePtr const &pvMaster)
|
||||
: pvMaster(pvMaster)
|
||||
{
|
||||
}
|
||||
|
||||
void PVCopy::destroy()
|
||||
{
|
||||
headNode.reset();
|
||||
}
|
||||
|
||||
bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
|
||||
{
|
||||
PVStructurePtr pvMasterStructure = pvMaster;
|
||||
size_t len = pvRequest->getPVFields().size();
|
||||
bool entireMaster = false;
|
||||
if(len==0) entireMaster = true;
|
||||
PVStructurePtr pvOptions;
|
||||
if(len==1) {
|
||||
pvOptions = pvRequest->getSubField<PVStructure>("_options");
|
||||
}
|
||||
if(entireMaster) {
|
||||
structure = pvMasterStructure->getStructure();
|
||||
CopyNodePtr node(new CopyNode());
|
||||
headNode = node;
|
||||
node->options = pvOptions;
|
||||
node->isStructure = false;
|
||||
node->structureOffset = 0;
|
||||
node->masterPVField = pvMasterStructure;
|
||||
node->nfields = pvMasterStructure->getNumberFields();
|
||||
return true;
|
||||
}
|
||||
structure = createStructure(pvMasterStructure,pvRequest);
|
||||
if(!structure) return false;
|
||||
cacheInitStructure = createPVStructure();
|
||||
ignorechangeBitSet = BitSetPtr(new BitSet(cacheInitStructure->getNumberFields()));
|
||||
headNode = createStructureNodes(
|
||||
pvMaster,
|
||||
pvRequest,
|
||||
cacheInitStructure);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
StructureConstPtr PVCopy::createStructure(
|
||||
PVStructurePtr const &pvMaster,
|
||||
PVStructurePtr const &pvFromRequest)
|
||||
{
|
||||
if(pvFromRequest->getStructure()->getNumberFields()==0) {
|
||||
return pvMaster->getStructure();
|
||||
}
|
||||
PVFieldPtrArray const &pvFromRequestFields = pvFromRequest->getPVFields();
|
||||
StringArray const &fromRequestFieldNames = pvFromRequest->getStructure()->getFieldNames();
|
||||
size_t length = pvFromRequestFields.size();
|
||||
if(length==0) return NULLStructure;
|
||||
FieldConstPtrArray fields; fields.reserve(length);
|
||||
StringArray fieldNames; fieldNames.reserve(length);
|
||||
for(size_t i=0; i<length; ++i) {
|
||||
string const &fieldName = fromRequestFieldNames[i];
|
||||
PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
|
||||
if(!pvMasterField) continue;
|
||||
FieldConstPtr field = pvMasterField->getField();
|
||||
if(field->getType()==epics::pvData::structure) {
|
||||
PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
|
||||
pvFromRequestFields[i]);
|
||||
if(pvRequestStructure->getNumberFields()>0) {
|
||||
StringArray const &names = pvRequestStructure->getStructure()->
|
||||
getFieldNames();
|
||||
size_t num = names.size();
|
||||
if(num>0 && names[0].compare("_options")==0) --num;
|
||||
if(num>0) {
|
||||
if(pvMasterField->getField()->getType()!=epics::pvData::structure) continue;
|
||||
fieldNames.push_back(fieldName);
|
||||
fields.push_back(createStructure(
|
||||
static_pointer_cast<PVStructure>(pvMasterField),
|
||||
pvRequestStructure));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
fieldNames.push_back(fieldName);
|
||||
fields.push_back(field);
|
||||
}
|
||||
size_t numsubfields = fields.size();
|
||||
if(numsubfields==0) {
|
||||
std::stringstream ss;
|
||||
ss << pvFromRequest << "\n";
|
||||
string val("no fields from the following request were found\n");
|
||||
val += ss.str();
|
||||
throw std::invalid_argument(val);
|
||||
}
|
||||
return getFieldCreate()->createStructure(fieldNames, fields);
|
||||
}
|
||||
|
||||
CopyNodePtr PVCopy::createStructureNodes(
|
||||
PVStructurePtr const &pvMasterStructure,
|
||||
PVStructurePtr const &pvFromRequest,
|
||||
PVStructurePtr const &pvFromCopy)
|
||||
{
|
||||
PVFieldPtrArray const & copyPVFields = pvFromCopy->getPVFields();
|
||||
PVStructurePtr pvOptions = pvFromRequest->getSubField<PVStructure>("_options");
|
||||
size_t number = copyPVFields.size();
|
||||
CopyNodePtrArrayPtr nodes(new CopyNodePtrArray());
|
||||
nodes->reserve(number);
|
||||
for(size_t i=0; i<number; i++) {
|
||||
PVFieldPtr copyPVField = copyPVFields[i];
|
||||
string fieldName = copyPVField->getFieldName();
|
||||
PVStructurePtr requestPVStructure =
|
||||
pvFromRequest->getSubField<PVStructure>(fieldName);
|
||||
PVStructurePtr pvSubFieldOptions =
|
||||
requestPVStructure->getSubField<PVStructure>("_options");
|
||||
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
|
||||
if(!pvMasterField) {
|
||||
throw std::logic_error("PVCopy::createStructureNodes did not find field in master");
|
||||
}
|
||||
size_t numberRequest = requestPVStructure->getPVFields().size();
|
||||
bool haveOptions = false;
|
||||
if(pvSubFieldOptions) {
|
||||
numberRequest--;
|
||||
haveOptions = true;
|
||||
}
|
||||
if(numberRequest>0) {
|
||||
Type copyType = copyPVField->getField()->getType();
|
||||
if(copyType==epics::pvData::structure) {
|
||||
nodes->push_back(createStructureNodes(
|
||||
static_pointer_cast<PVStructure>(pvMasterField),
|
||||
requestPVStructure,
|
||||
static_pointer_cast<PVStructure>(copyPVField)));
|
||||
continue;
|
||||
}
|
||||
if(copyType==epics::pvData::union_) {
|
||||
if(numberRequest!=1) {
|
||||
std::stringstream ss;
|
||||
ss << pvFromRequest << "\n";
|
||||
string val("In the following request a union field has more than one subfield in\n");
|
||||
val += ss.str();
|
||||
throw std::invalid_argument(val);
|
||||
}
|
||||
PVUnionPtr pvUnion = static_pointer_cast<PVUnion>(pvMasterField);
|
||||
std::string selectedName = pvUnion->getSelectedFieldName();
|
||||
PVFieldPtrArray const & pvFields = requestPVStructure->getPVFields();
|
||||
size_t len = pvFields.size();
|
||||
if(len>2 || (haveOptions && len!=2)) {
|
||||
std::stringstream ss;
|
||||
ss << pvFromRequest << "\n";
|
||||
string val("PVCopy logic error: pvRequest is\n");
|
||||
val += ss.str();
|
||||
throw std::logic_error(val);
|
||||
}
|
||||
size_t indRequestValue = 0;
|
||||
if((pvFields[0]->getFieldName().compare("_options"))==0) indRequestValue = 1;
|
||||
PVFieldPtr pvRequestValue = pvFields[indRequestValue];
|
||||
if(pvRequestValue) {
|
||||
string requestName = pvRequestValue->getFieldName();
|
||||
if(requestName.compare(selectedName)!=0) {
|
||||
std::stringstream ss;
|
||||
ss << pvFromCopy << "\n";
|
||||
string requestName = pvRequestValue->getFieldName();
|
||||
string val("field ");
|
||||
val += requestName + " does not match union type in\n";
|
||||
val += ss.str();
|
||||
throw std::invalid_argument(val);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << pvFromCopy << "\n";
|
||||
string val("requested a subfield of field ");
|
||||
val += fieldName + " which does not have type structure in\n";
|
||||
val += ss.str();
|
||||
throw std::invalid_argument(val);
|
||||
}
|
||||
}
|
||||
CopyNodePtr node(new CopyNode());
|
||||
node->options = pvSubFieldOptions;
|
||||
node->isStructure = false;
|
||||
node->masterPVField = pvMasterField;
|
||||
node->nfields = copyPVField->getNumberFields();
|
||||
node->structureOffset = copyPVField->getFieldOffset();
|
||||
nodes->push_back(node);
|
||||
}
|
||||
CopyStructureNodePtr structureNode(new CopyStructureNode());
|
||||
structureNode->masterPVField = pvMasterStructure;
|
||||
structureNode->isStructure = true;
|
||||
structureNode->nodes = nodes;
|
||||
structureNode->structureOffset = pvFromCopy->getFieldOffset();
|
||||
structureNode->nfields = pvFromCopy->getNumberFields();
|
||||
structureNode->options = pvOptions;
|
||||
return structureNode;
|
||||
}
|
||||
|
||||
void PVCopy::initPlugin(
|
||||
CopyNodePtr const & node,
|
||||
PVStructurePtr const & pvOptions,
|
||||
PVFieldPtr const & pvMasterField)
|
||||
{
|
||||
PVFieldPtrArray const & pvFields = pvOptions->getPVFields();
|
||||
size_t num = pvFields.size();
|
||||
vector<PVFilterPtr> pvFilters(num);
|
||||
size_t numfilter = 0;
|
||||
for(size_t i=0; i<num; ++i) {
|
||||
PVStringPtr pvOption = static_pointer_cast<PVString>(pvFields[i]);
|
||||
string name = pvOption->getFieldName();
|
||||
string value = pvOption->get();
|
||||
PVPluginPtr pvPlugin = PVPluginRegistry::find(name);
|
||||
if(!pvPlugin) {
|
||||
if(name.compare("ignore")==0) setIgnore(node);
|
||||
continue;
|
||||
}
|
||||
pvFilters[numfilter] = pvPlugin->create(value,shared_from_this(),pvMasterField);
|
||||
if(pvFilters[numfilter]) ++numfilter;
|
||||
}
|
||||
if(numfilter==0) return;
|
||||
node->pvFilters.resize(numfilter);
|
||||
for(size_t i=0; i<numfilter; ++i) node->pvFilters[i] = pvFilters[i];
|
||||
}
|
||||
|
||||
void PVCopy::traverseMasterInitPlugin()
|
||||
{
|
||||
traverseMasterInitPlugin(headNode);
|
||||
}
|
||||
|
||||
void PVCopy::traverseMasterInitPlugin(CopyNodePtr const & node)
|
||||
{
|
||||
PVFieldPtr pvField = node->masterPVField;
|
||||
PVStructurePtr pvOptions = node->options;
|
||||
if(pvOptions) initPlugin(node,pvOptions,pvField);
|
||||
if(!node->isStructure) return;
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
traverseMasterInitPlugin((*nodes)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CopyNodePtr PVCopy::getCopyOffset(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
PVFieldPtr const &masterPVField)
|
||||
{
|
||||
size_t offset = masterPVField->getFieldOffset();
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
if(!node->isStructure) {
|
||||
size_t off = node->masterPVField->getFieldOffset();
|
||||
size_t nextOffset = node->masterPVField->getNextFieldOffset();
|
||||
if(offset>= off && offset<nextOffset) return node;
|
||||
} else {
|
||||
CopyStructureNodePtr subNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtr node =
|
||||
getCopyOffset(subNode,masterPVField);
|
||||
if(node) return node;
|
||||
}
|
||||
}
|
||||
return NULLCopyNode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PVCopy::checkIgnore(
|
||||
PVStructurePtr const & copyPVStructure,
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
if(!ignorechangeBitSet) {
|
||||
return (bitSet->nextSetBit(0)<0) ? false : true;
|
||||
}
|
||||
int32 numFields = copyPVStructure->getNumberFields();
|
||||
BitSet temp(numFields);
|
||||
temp = *bitSet;
|
||||
int32 ind = 0;
|
||||
while(true) {
|
||||
ind = ignorechangeBitSet->nextSetBit(ind);
|
||||
if(ind<0) break;
|
||||
temp.clear(ind);
|
||||
ind++;
|
||||
if(ind>=numFields) break;
|
||||
}
|
||||
return (temp.nextSetBit(0)<0) ? false : true;
|
||||
}
|
||||
|
||||
void PVCopy::setIgnore(CopyNodePtr const &node) {
|
||||
ignorechangeBitSet->set(node->structureOffset);
|
||||
if(node->isStructure) {
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i<nodes->size(); ++i) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
setIgnore(node); }
|
||||
} else {
|
||||
size_t num = node->masterPVField->getNumberFields();
|
||||
if(num>1) {
|
||||
for(size_t i=1; i<num; ++i) {
|
||||
ignorechangeBitSet->set(node->structureOffset+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CopyNodePtr PVCopy::getMasterNode(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
std::size_t structureOffset)
|
||||
{
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i<nodes->size(); ++i) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
if(structureOffset>=(node->structureOffset + node->nfields)) continue;
|
||||
if(!node->isStructure) return node;
|
||||
CopyStructureNodePtr subNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
return getMasterNode(subNode,structureOffset);
|
||||
}
|
||||
return NULLCopyNode;
|
||||
}
|
||||
|
||||
void PVCopy::dump(string *builder,CopyNodePtr const &node,int indentLevel)
|
||||
{
|
||||
newLine(builder,indentLevel);
|
||||
std::stringstream ss;
|
||||
ss << (node->isStructure ? "structureNode" : "node");
|
||||
ss << " structureOffset " << node->structureOffset;
|
||||
ss << " nfields " << node->nfields;
|
||||
*builder += ss.str();
|
||||
PVStructurePtr options = node->options;
|
||||
if(options) {
|
||||
newLine(builder,indentLevel +1);
|
||||
*builder += options->getFieldName();
|
||||
PVFieldPtrArray pvFields = options->getPVFields();
|
||||
for(size_t i=0; i< pvFields.size() ; ++i) {
|
||||
PVStringPtr pvString = static_pointer_cast<PVString>(pvFields[i]);
|
||||
newLine(builder,indentLevel +2);
|
||||
*builder += pvString->getFieldName() + " " + pvString->get();
|
||||
}
|
||||
}
|
||||
string name = node->masterPVField->getFullName();
|
||||
newLine(builder,indentLevel +1);
|
||||
*builder += "masterField " + name;
|
||||
if(node->pvFilters.size()>0) {
|
||||
newLine(builder,indentLevel +2);
|
||||
*builder += "filters:";
|
||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||
*builder += " " + pvFilter->getName();
|
||||
}
|
||||
}
|
||||
if(!node->isStructure) return;
|
||||
CopyStructureNodePtr structureNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i<nodes->size(); ++i) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
if(!node) {
|
||||
newLine(builder,indentLevel +1);
|
||||
ss.str("");
|
||||
ss << "node[" << i << "] is null";
|
||||
*builder += ss.str();
|
||||
continue;
|
||||
}
|
||||
dump(builder,node,indentLevel+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
135
src/copy/pvDeadbandPlugin.cpp
Normal file
135
src/copy/pvDeadbandPlugin.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/* pvDeadbandPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/convert.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvDeadbandPlugin.h"
|
||||
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
static std::string name("deadband");
|
||||
|
||||
PVDeadbandPlugin::PVDeadbandPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
PVDeadbandPlugin::~PVDeadbandPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void PVDeadbandPlugin::create()
|
||||
{
|
||||
static bool firstTime = true;
|
||||
if(firstTime) {
|
||||
firstTime = false;
|
||||
PVDeadbandPluginPtr pvPlugin = PVDeadbandPluginPtr(new PVDeadbandPlugin());
|
||||
PVPluginRegistry::registerPlugin(name,pvPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
PVFilterPtr PVDeadbandPlugin::create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
return PVDeadbandFilter::create(requestValue,master);
|
||||
}
|
||||
|
||||
PVDeadbandFilter::~PVDeadbandFilter()
|
||||
{
|
||||
}
|
||||
|
||||
PVDeadbandFilterPtr PVDeadbandFilter::create(
|
||||
const std::string & requestValue,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
FieldConstPtr field =master->getField();
|
||||
Type type = field->getType();
|
||||
if(type!=scalar) return PVDeadbandFilterPtr();
|
||||
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
|
||||
if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr();
|
||||
bool absolute = false;
|
||||
if(requestValue.find("abs")==0) {
|
||||
absolute = true;
|
||||
} else if(requestValue.find("rel")==0) {
|
||||
absolute = false;
|
||||
} else {
|
||||
return PVDeadbandFilterPtr();
|
||||
}
|
||||
size_t ind = requestValue.find(':');
|
||||
if(ind==string::npos) return PVDeadbandFilterPtr();
|
||||
string svalue = requestValue.substr(ind+1);
|
||||
double deadband = atof(svalue.c_str());
|
||||
if(deadband==0.0) return PVDeadbandFilterPtr();
|
||||
PVDeadbandFilterPtr filter =
|
||||
PVDeadbandFilterPtr(
|
||||
new PVDeadbandFilter(
|
||||
absolute,deadband,static_pointer_cast<PVScalar>(master)));
|
||||
return filter;
|
||||
}
|
||||
|
||||
PVDeadbandFilter::PVDeadbandFilter(bool absolute,double deadband,PVScalarPtr const & master)
|
||||
: absolute(absolute),
|
||||
deadband(deadband),
|
||||
master(master),
|
||||
firstTime(true),
|
||||
lastReportedValue(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PVDeadbandFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
||||
{
|
||||
if(!toCopy) return false;
|
||||
double value = convert->toDouble(master);
|
||||
double diff = value - lastReportedValue;
|
||||
if(diff<0.0) diff = - diff;
|
||||
bool report = true;
|
||||
if(firstTime) {
|
||||
firstTime = false;
|
||||
} else if(absolute) {
|
||||
if(diff<deadband) report = false;
|
||||
} else {
|
||||
double last = lastReportedValue;
|
||||
if(last<0.0) last = -last;
|
||||
if(last>1e-20) {
|
||||
double percent = (diff/last)*100.0;
|
||||
if(percent<deadband) report = false;
|
||||
}
|
||||
}
|
||||
PVScalarPtr copy = static_pointer_cast<PVScalar>(pvCopy);
|
||||
convert->fromDouble(copy,value);
|
||||
if(report) {
|
||||
lastReportedValue = value;
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
} else {
|
||||
bitSet->clear(pvCopy->getFieldOffset());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string PVDeadbandFilter::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
41
src/copy/pvPlugin.cpp
Normal file
41
src/copy/pvPlugin.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/* pvPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/bitSet.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvPlugin.h"
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
||||
|
||||
static PVPluginMap pluginMap;
|
||||
static Mutex mutex;
|
||||
|
||||
void PVPluginRegistry::registerPlugin(const std::string & name,const PVPluginPtr & pvPlugin)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
PVPluginMap::iterator iter = pluginMap.find(name);
|
||||
if(iter!=pluginMap.end()) throw std::logic_error("plugin already registered");
|
||||
pluginMap.insert(PVPluginMap::value_type(name,pvPlugin));
|
||||
}
|
||||
|
||||
PVPluginPtr PVPluginRegistry::find(const std::string & name)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
PVPluginMap::iterator iter = pluginMap.find(name);
|
||||
if(iter!=pluginMap.end()) return (*iter).second;
|
||||
return PVPluginPtr();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
127
src/copy/pvTimestampPlugin.cpp
Normal file
127
src/copy/pvTimestampPlugin.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/* pvTimestampPlugin.cpp */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvPlugin.h"
|
||||
#include "pv/pvTimestampPlugin.h"
|
||||
|
||||
|
||||
using std::string;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::vector;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
static std::string name("timestamp");
|
||||
|
||||
PVTimestampPlugin::PVTimestampPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
PVTimestampPlugin::~PVTimestampPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void PVTimestampPlugin::create()
|
||||
{
|
||||
static bool firstTime = true;
|
||||
if(firstTime) {
|
||||
firstTime = false;
|
||||
PVTimestampPluginPtr pvPlugin = PVTimestampPluginPtr(new PVTimestampPlugin());
|
||||
PVPluginRegistry::registerPlugin(name,pvPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
PVFilterPtr PVTimestampPlugin::create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
return PVTimestampFilter::create(requestValue,master);
|
||||
}
|
||||
|
||||
PVTimestampFilter::~PVTimestampFilter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PVTimestampFilterPtr PVTimestampFilter::create(
|
||||
const std::string & requestValue,
|
||||
const PVFieldPtr & master)
|
||||
{
|
||||
PVTimeStamp pvTimeStamp;
|
||||
if(!pvTimeStamp.attach(master)) return PVTimestampFilterPtr();
|
||||
bool current = false;
|
||||
bool copy = false;
|
||||
if(requestValue.compare("current")==0) {
|
||||
current = true;
|
||||
} else if(requestValue.compare("copy")==0){
|
||||
copy = true;
|
||||
} else {
|
||||
return PVTimestampFilterPtr();
|
||||
}
|
||||
PVTimestampFilterPtr filter = PVTimestampFilterPtr(
|
||||
new PVTimestampFilter(current,copy,master));
|
||||
return filter;
|
||||
}
|
||||
|
||||
PVTimestampFilter::PVTimestampFilter(bool current,bool copy,PVFieldPtr const & master)
|
||||
: current(current),
|
||||
copy(copy),
|
||||
master(master)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
||||
{
|
||||
if(current) {
|
||||
timeStamp.getCurrent();
|
||||
if(toCopy) {
|
||||
if(!pvTimeStamp.attach(pvCopy)) return false;
|
||||
} else {
|
||||
if(!pvTimeStamp.attach(master)) return false;
|
||||
}
|
||||
pvTimeStamp.set(timeStamp);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
return true;
|
||||
}
|
||||
if(copy) {
|
||||
if(toCopy) {
|
||||
if(!pvTimeStamp.attach(master)) return false;
|
||||
pvTimeStamp.get(timeStamp);
|
||||
if(!pvTimeStamp.attach(pvCopy)) return false;
|
||||
pvTimeStamp.set(timeStamp);
|
||||
bitSet->set(pvCopy->getFieldOffset());
|
||||
} else {
|
||||
if(!pvTimeStamp.attach(pvCopy)) return false;
|
||||
pvTimeStamp.get(timeStamp);
|
||||
if(!pvTimeStamp.attach(master)) return false;
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string PVTimestampFilter::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -10,54 +10,60 @@
|
||||
*/
|
||||
|
||||
#include <epicsGuard.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/pvPlugin.h"
|
||||
#include "pv/pvArrayPlugin.h"
|
||||
#include "pv/pvTimestampPlugin.h"
|
||||
#include "pv/pvDeadbandPlugin.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvCopy;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
#define DEBUG_LEVEL 0
|
||||
|
||||
static PVDatabasePtr pvDatabaseMaster;
|
||||
|
||||
PVDatabasePtr PVDatabase::getMaster()
|
||||
{
|
||||
static PVDatabasePtr master;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
if(master.get()==NULL) {
|
||||
master = PVDatabasePtr(new PVDatabase());
|
||||
}
|
||||
return master;
|
||||
static bool firstTime = true;
|
||||
if(firstTime) {
|
||||
firstTime = false;
|
||||
pvDatabaseMaster = PVDatabasePtr(new PVDatabase());
|
||||
PVArrayPlugin::create();
|
||||
PVTimestampPlugin::create();
|
||||
PVDeadbandPlugin::create();
|
||||
}
|
||||
return pvDatabaseMaster;
|
||||
}
|
||||
|
||||
PVDatabase::PVDatabase()
|
||||
: isDestroyed(false)
|
||||
{
|
||||
if(DEBUG_LEVEL>0) cout << "PVDatabase::PVDatabase()\n";
|
||||
}
|
||||
|
||||
PVDatabase::~PVDatabase()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void PVDatabase::destroy()
|
||||
{
|
||||
{
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(isDestroyed) {
|
||||
return;
|
||||
}
|
||||
isDestroyed = true;
|
||||
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(PVRecordMap::iterator iter = recordMap.begin(); iter != recordMap.end(); iter++) {
|
||||
PVRecordPtr pvRecord = (*iter).second;
|
||||
if(pvRecord) {
|
||||
pvRecord->destroy();
|
||||
}
|
||||
}
|
||||
recordMap.clear();
|
||||
for(size_t i=0; i<len; ++i) removeRecord(findRecord(names[i]));
|
||||
}
|
||||
|
||||
void PVDatabase::lock() {
|
||||
@@ -71,23 +77,19 @@ void PVDatabase::unlock() {
|
||||
PVRecordPtr PVDatabase::findRecord(string const& recordName)
|
||||
{
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
PVRecordPtr xxx;
|
||||
if(isDestroyed) {
|
||||
return xxx;
|
||||
}
|
||||
PVRecordMap::iterator iter = recordMap.find(recordName);
|
||||
if(iter!=recordMap.end()) {
|
||||
return (*iter).second;
|
||||
}
|
||||
return xxx;
|
||||
return PVRecordPtr();
|
||||
}
|
||||
|
||||
bool PVDatabase::addRecord(PVRecordPtr const & record)
|
||||
{
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(isDestroyed) {
|
||||
return false;
|
||||
if(record->getTraceLevel()>0) {
|
||||
cout << "PVDatabase::addRecord " << record->getRecordName() << endl;
|
||||
}
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
string recordName = record->getRecordName();
|
||||
PVRecordMap::iterator iter = recordMap.find(recordName);
|
||||
if(iter!=recordMap.end()) {
|
||||
@@ -100,16 +102,15 @@ bool PVDatabase::addRecord(PVRecordPtr const & record)
|
||||
|
||||
bool PVDatabase::removeRecord(PVRecordPtr const & record)
|
||||
{
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(isDestroyed) {
|
||||
return false;
|
||||
if(record->getTraceLevel()>0) {
|
||||
cout << "PVDatabase::removeRecord " << record->getRecordName() << endl;
|
||||
}
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
string recordName = record->getRecordName();
|
||||
PVRecordMap::iterator iter = recordMap.find(recordName);
|
||||
if(iter!=recordMap.end()) {
|
||||
PVRecordPtr pvRecord = (*iter).second;
|
||||
recordMap.erase(iter);
|
||||
if(pvRecord) pvRecord->destroy();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -119,9 +120,6 @@ PVStringArrayPtr PVDatabase::getRecordNames()
|
||||
{
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
PVStringArrayPtr xxx;
|
||||
if(isDestroyed) {
|
||||
return xxx;
|
||||
}
|
||||
PVStringArrayPtr pvStringArray = static_pointer_cast<PVStringArray>
|
||||
(getPVDataCreate()->createPVScalarArray(pvString));
|
||||
size_t len = recordMap.size();
|
||||
|
||||
@@ -8,16 +8,29 @@
|
||||
* @author mrk
|
||||
* @date 2012.11.21
|
||||
*/
|
||||
#include <list>
|
||||
#include <epicsGuard.h>
|
||||
#include <epicsThread.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/createRequest.h>
|
||||
#include <pv/pvaVersion.h>
|
||||
#include <pv/pvaVersionNum.h>
|
||||
#include <pv/monitor.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/pvDatabase.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvDatabase;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
@@ -41,17 +54,92 @@ PVRecord::PVRecord(
|
||||
pvStructure(pvStructure),
|
||||
depthGroupPut(0),
|
||||
traceLevel(0),
|
||||
isDestroyed(false),
|
||||
isAddListener(false)
|
||||
{
|
||||
}
|
||||
|
||||
void PVRecord::notifyClients()
|
||||
{
|
||||
{
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::notifyClients() " << recordName
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
pvTimeStamp.detach();
|
||||
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
|
||||
iter!=pvListenerList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVListenerPtr listener = iter->lock();
|
||||
if(!listener) continue;
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::notifyClients() calling listener->unlisten "
|
||||
<< recordName << endl;
|
||||
}
|
||||
listener->unlisten(shared_from_this());
|
||||
}
|
||||
pvListenerList.clear();
|
||||
for (std::list<PVRecordClientWPtr>::iterator iter = clientList.begin();
|
||||
iter!=clientList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVRecordClientPtr client = iter->lock();
|
||||
if(!client) continue;
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::notifyClients() calling client->detach "
|
||||
<< recordName << endl;
|
||||
}
|
||||
client->detach(shared_from_this());
|
||||
}
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::notifyClients() calling clientList.clear() "
|
||||
<< recordName << endl;
|
||||
}
|
||||
clientList.clear();
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::notifyClients() returning " << recordName << endl;
|
||||
}
|
||||
}
|
||||
|
||||
PVRecord::~PVRecord()
|
||||
{
|
||||
if(traceLevel>0) {
|
||||
cout << "~PVRecord() " << recordName << endl;
|
||||
}
|
||||
destroy();
|
||||
notifyClients();
|
||||
}
|
||||
|
||||
void PVRecord::remove()
|
||||
{
|
||||
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
|
||||
if(pvDatabase) pvDatabase->removeRecord(shared_from_this());
|
||||
pvTimeStamp.detach();
|
||||
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
|
||||
iter!=pvListenerList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVListenerPtr listener = iter->lock();
|
||||
if(!listener) continue;
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::remove() calling listener->unlisten " << recordName << endl;
|
||||
}
|
||||
listener->unlisten(shared_from_this());
|
||||
}
|
||||
pvListenerList.clear();
|
||||
for (std::list<PVRecordClientWPtr>::iterator iter = clientList.begin();
|
||||
iter!=clientList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVRecordClientPtr client = iter->lock();
|
||||
if(!client) continue;
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::remove() calling client->detach " << recordName << endl;
|
||||
}
|
||||
client->detach(shared_from_this());
|
||||
}
|
||||
clientList.clear();
|
||||
}
|
||||
|
||||
void PVRecord::initPVRecord()
|
||||
@@ -64,55 +152,13 @@ void PVRecord::initPVRecord()
|
||||
if(pvField) pvTimeStamp.attach(pvField);
|
||||
}
|
||||
|
||||
void PVRecord::destroy()
|
||||
{
|
||||
{
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::destroy() " << recordName
|
||||
<< " isDestroyed " << (isDestroyed ? "true" : "false")
|
||||
<< endl;
|
||||
}
|
||||
if(isDestroyed) {
|
||||
return;
|
||||
}
|
||||
isDestroyed = true;
|
||||
}
|
||||
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
|
||||
if(pvDatabase) pvDatabase->removeRecord(shared_from_this());
|
||||
pvTimeStamp.detach();
|
||||
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
|
||||
iter!=pvListenerList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVListenerPtr listener = iter->lock();
|
||||
if(!listener) continue;
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::destroy() calling listener->unlisten " << recordName << endl;
|
||||
}
|
||||
listener->unlisten(shared_from_this());
|
||||
}
|
||||
pvListenerList.clear();
|
||||
for (std::list<PVRecordClientPtr>::iterator iter = clientList.begin();
|
||||
iter!=clientList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVRecordClientPtr client = *iter;
|
||||
if(!client) continue;
|
||||
if(traceLevel>0) {
|
||||
cout << "PVRecord::destroy() calling client->detach " << recordName << endl;
|
||||
}
|
||||
client->detach(shared_from_this());
|
||||
}
|
||||
clientList.clear();
|
||||
}
|
||||
|
||||
void PVRecord::process()
|
||||
{
|
||||
if(traceLevel>2) {
|
||||
cout << "PVRecord::process() " << recordName << endl;
|
||||
}
|
||||
if(pvTimeStamp.isAttached()) {
|
||||
pvTimeStamp.get(timeStamp);
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
@@ -191,70 +237,39 @@ bool PVRecord::addPVRecordClient(PVRecordClientPtr const & pvRecordClient)
|
||||
cout << "PVRecord::addPVRecordClient() " << recordName << endl;
|
||||
}
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(isDestroyed) {
|
||||
return false;
|
||||
}
|
||||
std::list<PVRecordClientPtr>::iterator iter;
|
||||
for (iter = clientList.begin();
|
||||
iter!=clientList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVRecordClientPtr client = *iter;
|
||||
if(client==pvRecordClient) {
|
||||
return false;
|
||||
// clean clientList
|
||||
bool clientListClean = false;
|
||||
while(!clientListClean) {
|
||||
if(clientList.empty()) break;
|
||||
clientListClean = true;
|
||||
std::list<PVRecordClientWPtr>::iterator iter;
|
||||
for (iter = clientList.begin();
|
||||
iter!=clientList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVRecordClientPtr client = iter->lock();
|
||||
if(client) continue;
|
||||
if(traceLevel>1) {
|
||||
cout << "PVRecord::addPVRecordClient() erasing client"
|
||||
<< recordName << endl;
|
||||
}
|
||||
clientList.erase(iter);
|
||||
clientListClean = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(traceLevel>1) {
|
||||
cout << "PVRecord::addPVRecordClient() calling clientList.push_back(pvRecordClient)" << recordName << endl;
|
||||
}
|
||||
clientList.push_back(pvRecordClient);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PVRecord::removePVRecordClient(PVRecordClientPtr const & pvRecordClient)
|
||||
{
|
||||
if(traceLevel>1) {
|
||||
cout << "PVRecord::removePVRecordClient() " << recordName << endl;
|
||||
}
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(isDestroyed) {
|
||||
return false;
|
||||
}
|
||||
std::list<PVRecordClientPtr>::iterator iter;
|
||||
for (iter = clientList.begin();
|
||||
iter!=clientList.end();
|
||||
iter++ )
|
||||
{
|
||||
PVRecordClientPtr client = *iter;
|
||||
if(!client) continue;
|
||||
if(client==pvRecordClient) {
|
||||
clientList.erase(iter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PVRecord::addListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
PVCopyPtr const & pvCopy)
|
||||
epics::pvCopy::PVCopyPtr const & pvCopy)
|
||||
{
|
||||
if(traceLevel>1) {
|
||||
cout << "PVRecord::addListener() " << recordName << endl;
|
||||
}
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(isDestroyed) {
|
||||
return false;
|
||||
}
|
||||
std::list<PVListenerWPtr>::iterator iter;
|
||||
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
|
||||
{
|
||||
PVListenerPtr listener = iter->lock();
|
||||
if(!listener.get()) continue;
|
||||
if(listener.get()==pvListener.get()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pvListenerList.push_back(pvListener);
|
||||
this->pvListener = pvListener;
|
||||
isAddListener = true;
|
||||
@@ -277,15 +292,12 @@ void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
|
||||
|
||||
bool PVRecord::removeListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
PVCopyPtr const & pvCopy)
|
||||
epics::pvCopy::PVCopyPtr const & pvCopy)
|
||||
{
|
||||
if(traceLevel>1) {
|
||||
cout << "PVRecord::removeListener() " << recordName << endl;
|
||||
}
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
if(isDestroyed) {
|
||||
return false;
|
||||
}
|
||||
std::list<PVListenerWPtr>::iterator iter;
|
||||
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
|
||||
{
|
||||
@@ -394,14 +406,6 @@ bool PVRecordField::addListener(PVListenerPtr const & pvListener)
|
||||
if(pvRecord && pvRecord->getTraceLevel()>1) {
|
||||
cout << "PVRecordField::addListener() " << getFullName() << endl;
|
||||
}
|
||||
std::list<PVListenerWPtr>::iterator iter;
|
||||
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
|
||||
PVListenerPtr listener = iter->lock();
|
||||
if(!listener.get()) continue;
|
||||
if(listener.get()==pvListener.get()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pvListenerList.push_back(pvListener);
|
||||
return true;
|
||||
}
|
||||
@@ -450,7 +454,8 @@ void PVRecordField::postSubField()
|
||||
{
|
||||
callListener();
|
||||
if(isStructure) {
|
||||
PVRecordStructurePtr pvrs = static_pointer_cast<PVRecordStructure>(shared_from_this());
|
||||
PVRecordStructurePtr pvrs =
|
||||
static_pointer_cast<PVRecordStructure>(shared_from_this());
|
||||
PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields();
|
||||
PVRecordFieldPtrArray::iterator iter;
|
||||
for(iter = pvRecordFields->begin() ; iter !=pvRecordFields->end(); iter++) {
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
#ifndef CHANNELPROVIDERLOCAL_H
|
||||
#define CHANNELPROVIDERLOCAL_H
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define channelProviderLocalEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
@@ -25,79 +20,28 @@
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
#ifdef channelProviderLocalEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef channelProviderLocalEpicsExportSharedSymbols
|
||||
#endif
|
||||
#include <pv/pvStructureCopy.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class MonitorFactory;
|
||||
typedef std::tr1::shared_ptr<MonitorFactory> MonitorFactoryPtr;
|
||||
|
||||
class MonitorLocal;
|
||||
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
||||
|
||||
|
||||
class ChannelProviderLocal;
|
||||
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
|
||||
typedef std::tr1::weak_ptr<ChannelProviderLocal> ChannelProviderLocalWPtr;
|
||||
class ChannelLocal;
|
||||
typedef std::tr1::shared_ptr<ChannelLocal> ChannelLocalPtr;
|
||||
typedef std::tr1::weak_ptr<ChannelLocal> ChannelLocalWPtr;
|
||||
|
||||
epicsShareFunc MonitorFactoryPtr getMonitorFactory();
|
||||
|
||||
/**
|
||||
* @brief MonitorFactory
|
||||
*
|
||||
* This class provides a static method to create a monitor for a PVRecord
|
||||
*/
|
||||
class epicsShareClass MonitorFactory
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorFactory);
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~MonitorFactory();
|
||||
/**
|
||||
* @brief Destroy the monitor factory.
|
||||
*/
|
||||
virtual void destroy();
|
||||
/**
|
||||
* @brief Create a monitor on a record.
|
||||
*
|
||||
* This is called by the local channel provider.
|
||||
* @param pvRecord The record to monitor.
|
||||
* @param monitorRequester The client callback.
|
||||
* @param pvRequest Options specified by the client.
|
||||
* This includes the subset of the fields in the record to monitor.
|
||||
* @return A shared pointer to the newly created monitor.
|
||||
* If the monitor can not be created a null monitor is returned.
|
||||
* This means the pvRequest specified options that could not be satisfied.
|
||||
*/
|
||||
epics::pvData::MonitorPtr createMonitor(
|
||||
PVRecordPtr const & pvRecord,
|
||||
epics::pvData::MonitorRequester::shared_pointer const & monitorRequester,
|
||||
epics::pvData::PVStructurePtr const & pvRequest);
|
||||
private:
|
||||
MonitorFactory();
|
||||
friend class MonitorLocal;
|
||||
friend epicsShareFunc MonitorFactoryPtr getMonitorFactory();
|
||||
bool isDestroyed;
|
||||
epics::pvData::Mutex mutex;
|
||||
};
|
||||
|
||||
epicsShareFunc epics::pvData::MonitorPtr createMonitorLocal(
|
||||
PVRecordPtr const & pvRecord,
|
||||
epics::pvData::MonitorRequester::shared_pointer const & monitorRequester,
|
||||
epics::pvData::PVStructurePtr const & pvRequest);
|
||||
|
||||
epicsShareFunc ChannelProviderLocalPtr getChannelProviderLocal();
|
||||
|
||||
@@ -109,27 +53,33 @@ epicsShareFunc ChannelProviderLocalPtr getChannelProviderLocal();
|
||||
*/
|
||||
class epicsShareClass ChannelProviderLocal :
|
||||
public epics::pvAccess::ChannelProvider,
|
||||
public epics::pvAccess::ChannelFind,
|
||||
public std::tr1::enable_shared_from_this<ChannelProviderLocal>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelProviderLocal);
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
ChannelProviderLocal();
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~ChannelProviderLocal();
|
||||
/**
|
||||
* @brief Destroy the channel provider.
|
||||
* @brief DEPRECATED
|
||||
*
|
||||
* Probably never called.
|
||||
*/
|
||||
virtual void destroy();
|
||||
virtual void destroy(){};
|
||||
/**
|
||||
* @brief Returns the channel provider name.
|
||||
*
|
||||
* @return <b>local</b>
|
||||
*/
|
||||
virtual std::string getProviderName();
|
||||
/**
|
||||
* @brief Returns either a null channelFind or a channelFind for records in the PVDatabase.
|
||||
*
|
||||
* @param channelName The name of the channel desired.
|
||||
* @param channelFindRequester The client callback.
|
||||
* @return shared pointer to ChannelFind.
|
||||
@@ -185,17 +135,31 @@ public:
|
||||
epics::pvAccess::ChannelRequester::shared_pointer const &channelRequester,
|
||||
short priority,
|
||||
std::string const &address);
|
||||
/**
|
||||
* @brief get trace level (0,1,2) means (nothing,lifetime,process)
|
||||
* @return the level
|
||||
*/
|
||||
int getTraceLevel() {return traceLevel;}
|
||||
/**
|
||||
* @brief set trace level (0,1,2) means (nothing,lifetime,process)
|
||||
* @param level The level
|
||||
*/
|
||||
void setTraceLevel(int level) {traceLevel = level;}
|
||||
/**
|
||||
* @brief ChannelFind method.
|
||||
*
|
||||
* @return pointer to self.
|
||||
*/
|
||||
virtual std::tr1::shared_ptr<ChannelProvider> getChannelProvider();
|
||||
/**
|
||||
* @brief ChannelFind method.
|
||||
*
|
||||
*/
|
||||
virtual void cancel() {}
|
||||
private:
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
ChannelProviderLocal();
|
||||
friend epicsShareFunc ChannelProviderLocalPtr getChannelProviderLocal();
|
||||
PVDatabasePtr pvDatabase;
|
||||
epics::pvData::Mutex mutex;
|
||||
bool beingDestroyed;
|
||||
epics::pvAccess::ChannelFind::shared_pointer channelFinder;
|
||||
PVDatabaseWPtr pvDatabase;
|
||||
int traceLevel;
|
||||
friend class ChannelProviderLocalRun;
|
||||
};
|
||||
|
||||
@@ -227,20 +191,15 @@ public:
|
||||
*/
|
||||
virtual ~ChannelLocal();
|
||||
/**
|
||||
* @brief Destroy the channel.
|
||||
* @brief DEPRECATED
|
||||
*
|
||||
* It cleans up all resources used to access the record.
|
||||
* Note that this assumes that client has destroyed any objects that
|
||||
* have been created for the channel like channelGet, etc.
|
||||
* The remote pvAccess server does this cleanup.
|
||||
*/
|
||||
virtual void destroy();
|
||||
virtual void destroy() {};
|
||||
/**
|
||||
* @brief Detach from the record.
|
||||
*
|
||||
* This is called when a record is being removed from the database.
|
||||
* Calls destroy.
|
||||
* @param pvRecord The record being destroyed.
|
||||
* @param pvRecord The record being removed.
|
||||
*/
|
||||
virtual void detach(PVRecordPtr const &pvRecord);
|
||||
/**
|
||||
@@ -260,10 +219,7 @@ public:
|
||||
* @brief Get the channel provider
|
||||
* @return The provider.
|
||||
*/
|
||||
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider()
|
||||
{
|
||||
return provider;
|
||||
}
|
||||
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider();
|
||||
/**
|
||||
* @brief Get the remote address
|
||||
* @return <b>local</b>
|
||||
@@ -402,9 +358,8 @@ protected:
|
||||
}
|
||||
private:
|
||||
epics::pvAccess::ChannelRequester::shared_pointer requester;
|
||||
ChannelProviderLocalPtr provider;
|
||||
PVRecordPtr pvRecord;
|
||||
bool isDestroyed;
|
||||
ChannelProviderLocalWPtr provider;
|
||||
PVRecordWPtr pvRecord;
|
||||
epics::pvData::Mutex mutex;
|
||||
};
|
||||
|
||||
|
||||
90
src/pv/controlSupport.h
Normal file
90
src/pv/controlSupport.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2019.06.01
|
||||
*/
|
||||
#ifndef CONTROLSUPPORT_H
|
||||
#define CONTROLSUPPORT_H
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/pvSupport.h>
|
||||
#include <pv/pvStructureCopy.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class ControlSupport;
|
||||
typedef std::tr1::shared_ptr<ControlSupport> ControlSupportPtr;
|
||||
|
||||
/**
|
||||
* @brief Base interface for a ControlSupport.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass ControlSupport :
|
||||
PVSupport
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ControlSupport);
|
||||
/**
|
||||
* The Destructor.
|
||||
*/
|
||||
virtual ~ControlSupport();
|
||||
/**
|
||||
* @brief Connects to contol fields.
|
||||
*
|
||||
* @param pvValue The field to support.
|
||||
* @param pvSupport Support specific fields.
|
||||
* @return <b>true</b> for success and <b>false</b> for failure.
|
||||
*/
|
||||
virtual bool init(
|
||||
epics::pvData::PVFieldPtr const & pvValue,
|
||||
epics::pvData::PVFieldPtr const & pvSupport);
|
||||
/**
|
||||
* @brief Honors control fields.
|
||||
*
|
||||
*
|
||||
* @return Returns true is any fields were modified; otherwise false.
|
||||
*/
|
||||
virtual bool process();
|
||||
/**
|
||||
* @brief If implementing minSteps it sets isMinStep to false.
|
||||
*
|
||||
* @return Returns true is any fields were modified; otherwise false.
|
||||
*/
|
||||
virtual void reset();
|
||||
/**
|
||||
* @brief create a ControlSupport
|
||||
*
|
||||
* @param pvRecord - The pvRecord to which the support is attached.
|
||||
* @return The new ControlSupport
|
||||
*/
|
||||
static ControlSupportPtr create(PVRecordPtr const & pvRecord);
|
||||
/**
|
||||
* @brief create a controlSupport required by ControlSupport
|
||||
*
|
||||
* @param scalarType The type for outputValue.
|
||||
* @return The controlField introspection structure.
|
||||
*/
|
||||
static epics::pvData::StructureConstPtr controlField(epics::pvData::ScalarType scalarType);
|
||||
private:
|
||||
ControlSupport(PVRecordPtr const & pvRecord);
|
||||
PVRecordPtr pvRecord;
|
||||
epics::pvData::PVScalarPtr pvValue;
|
||||
epics::pvData::PVStructurePtr pvControl;
|
||||
epics::pvData::PVDoublePtr pvLimitLow;
|
||||
epics::pvData::PVDoublePtr pvLimitHigh;
|
||||
epics::pvData::PVDoublePtr pvMinStep;
|
||||
epics::pvData::PVScalarPtr pvOutputValue;
|
||||
double currentValue;
|
||||
bool isMinStep;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* CONTROLSUPPORT_H */
|
||||
|
||||
89
src/pv/processRecord.h
Normal file
89
src/pv/processRecord.h
Normal 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 */
|
||||
98
src/pv/pvArrayPlugin.h
Normal file
98
src/pv/pvArrayPlugin.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* pvArrayPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#ifndef PVARRAYPLUGIN_H
|
||||
#define PVARRAYPLUGIN_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvPlugin.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
class PVArrayPlugin;
|
||||
class PVArrayFilter;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVArrayPlugin> PVArrayPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVArrayFilter> PVArrayFilterPtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A plugin for a filter that gets a sub array from a PVScalarArray.
|
||||
*
|
||||
* @author mrk
|
||||
* @since date 2017.02.23
|
||||
*/
|
||||
class epicsShareClass PVArrayPlugin : public PVPlugin
|
||||
{
|
||||
private:
|
||||
PVArrayPlugin();
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVArrayPlugin);
|
||||
virtual ~PVArrayPlugin();
|
||||
/**
|
||||
* Factory
|
||||
*/
|
||||
static void create();
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached
|
||||
* @return The PVFilter.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A filter that gets a sub array from a PVScalarArray.
|
||||
*/
|
||||
class epicsShareClass PVArrayFilter : public PVFilter
|
||||
{
|
||||
private:
|
||||
long start;
|
||||
long increment;
|
||||
long end;
|
||||
epics::pvData::PVScalarArrayPtr masterArray;
|
||||
|
||||
PVArrayFilter(long start,long increment,long end,const epics::pvData::PVScalarArrayPtr & masterArray);
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVArrayFilter);
|
||||
virtual ~PVArrayFilter();
|
||||
/**
|
||||
* Create a PVArrayFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
static PVArrayFilterPtr create(const std::string & requestValue,const epics::pvData::PVFieldPtr & master);
|
||||
/**
|
||||
* Perform a filter operation
|
||||
* @param pvCopy The field in the copy PVStructure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return if filter (modified, did not modify) destination.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
|
||||
/**
|
||||
* Get the filter name.
|
||||
* @return The name.
|
||||
*/
|
||||
std::string getName();
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* PVARRAYPLUGIN_H */
|
||||
|
||||
@@ -6,28 +6,16 @@
|
||||
#ifndef PVDATABASE_H
|
||||
#define PVDATABASE_H
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define pvdatabaseEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
|
||||
#ifdef pvdatabaseEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef pvdatabaseEpicsExportSharedSymbols
|
||||
#endif
|
||||
#include <pv/pvStructureCopy.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVRecord;
|
||||
@@ -46,6 +34,7 @@ typedef std::tr1::weak_ptr<PVRecordStructure> PVRecordStructureWPtr;
|
||||
|
||||
class PVRecordClient;
|
||||
typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
|
||||
typedef std::tr1::weak_ptr<PVRecordClient> PVRecordClientWPtr;
|
||||
|
||||
class PVListener;
|
||||
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
||||
@@ -53,6 +42,7 @@ typedef std::tr1::weak_ptr<PVListener> PVListenerWPtr;
|
||||
|
||||
class PVDatabase;
|
||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
typedef std::tr1::weak_ptr<PVDatabase> PVDatabaseWPtr;
|
||||
|
||||
/**
|
||||
* @brief Base interface for a PVRecord.
|
||||
@@ -64,7 +54,7 @@ typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
* @date 2012.11.20
|
||||
*/
|
||||
class epicsShareClass PVRecord :
|
||||
public epics::pvData::PVCopyTraverseMasterCallback,
|
||||
public epics::pvCopy::PVCopyTraverseMasterCallback,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
@@ -97,14 +87,18 @@ public:
|
||||
*/
|
||||
virtual void process();
|
||||
/**
|
||||
* @brief Optional method for derived class.
|
||||
* @brief DEPRECATED
|
||||
*/
|
||||
virtual void destroy() {}
|
||||
/**
|
||||
* @brief remove record from database.
|
||||
*
|
||||
* Destroy the PVRecord. Release any resources used and
|
||||
* Remove the PVRecord. Release any resources used and
|
||||
* get rid of listeners and requesters.
|
||||
* If derived class overrides this then it must call PVRecord::destroy()
|
||||
* If derived class overrides this then it must call PVRecord::remove()
|
||||
* after it has destroyed any resorces it uses.
|
||||
*/
|
||||
virtual void destroy();
|
||||
virtual void remove();
|
||||
/**
|
||||
* @brief Optional method for derived class.
|
||||
*
|
||||
@@ -112,10 +106,10 @@ public:
|
||||
* @param pvRequest The request PVStructure
|
||||
* @return The corresponding service
|
||||
*/
|
||||
virtual epics::pvAccess::Service::shared_pointer getService(
|
||||
virtual epics::pvAccess::RPCServiceAsync::shared_pointer getService(
|
||||
epics::pvData::PVStructurePtr const & pvRequest)
|
||||
{
|
||||
return epics::pvAccess::Service::shared_pointer();
|
||||
return epics::pvAccess::RPCServiceAsync::shared_pointer();
|
||||
}
|
||||
/**
|
||||
* @brief Creates a <b>soft</b> record.
|
||||
@@ -195,13 +189,6 @@ public:
|
||||
* @return <b>true</b> if the client is added.
|
||||
*/
|
||||
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
/**
|
||||
* @brief Remove a client.
|
||||
*
|
||||
* @param pvRecordClient The client.
|
||||
* @return <b>true</b> if the client is removed.
|
||||
*/
|
||||
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
/**
|
||||
* @brief Add a PVListener.
|
||||
*
|
||||
@@ -212,7 +199,7 @@ public:
|
||||
*/
|
||||
bool addListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
epics::pvData::PVCopyPtr const & pvCopy);
|
||||
epics::pvCopy::PVCopyPtr const & pvCopy);
|
||||
/**
|
||||
* @brief PVCopyTraverseMasterCallback method
|
||||
*
|
||||
@@ -228,7 +215,7 @@ public:
|
||||
*/
|
||||
bool removeListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
epics::pvData::PVCopyPtr const & pvCopy);
|
||||
epics::pvCopy::PVCopyPtr const & pvCopy);
|
||||
|
||||
|
||||
/**
|
||||
@@ -264,35 +251,26 @@ protected:
|
||||
* Must be called by derived classes.
|
||||
*/
|
||||
void initPVRecord();
|
||||
/**
|
||||
* @brief Get shared pointer to self.
|
||||
* @return The shared pointer.
|
||||
*/
|
||||
PVRecordPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
private:
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
PVRecordStructurePtr const & pvrs,
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
void notifyClients();
|
||||
|
||||
std::string recordName;
|
||||
epics::pvData::PVStructurePtr pvStructure;
|
||||
PVRecordStructurePtr pvRecordStructure;
|
||||
std::list<PVListenerWPtr> pvListenerList;
|
||||
std::list<PVRecordClientPtr> clientList;
|
||||
std::list<PVRecordClientWPtr> clientList;
|
||||
epics::pvData::Mutex mutex;
|
||||
std::size_t depthGroupPut;
|
||||
int traceLevel;
|
||||
bool isDestroyed;
|
||||
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
|
||||
// following only valid while addListener or removeListener is active.
|
||||
bool isAddListener;
|
||||
PVListenerWPtr pvListener;
|
||||
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
};
|
||||
|
||||
epicsShareFunc std::ostream& operator<<(std::ostream& o, const PVRecord& record);
|
||||
@@ -504,12 +482,6 @@ public:
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~PVDatabase();
|
||||
/**
|
||||
* @brief Destroy the PVDatabase.
|
||||
*
|
||||
* For each record in the database the record is removed and it's destroy method is called.
|
||||
*/
|
||||
virtual void destroy();
|
||||
/**
|
||||
* Find a record.
|
||||
* An empty pointer is returned if the record is not in the database.
|
||||
@@ -541,7 +513,7 @@ private:
|
||||
void unlock();
|
||||
PVRecordMap recordMap;
|
||||
epics::pvData::Mutex mutex;
|
||||
bool isDestroyed;
|
||||
static bool getMasterFirstCall;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
103
src/pv/pvDeadbandPlugin.h
Normal file
103
src/pv/pvDeadbandPlugin.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* pvDeadbandPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#ifndef PVDEADBANDPLUGIN_H
|
||||
#define PVDEADBANDPLUGIN_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvPlugin.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
class PVDeadbandPlugin;
|
||||
class PVDeadbandFilter;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVDeadbandPlugin> PVDeadbandPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVDeadbandFilter> PVDeadbandFilterPtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A plugin for a filter that gets a sub array from a PVScalarDeadband.
|
||||
*
|
||||
* @author mrk
|
||||
* @since date 2017.02.23
|
||||
*/
|
||||
class epicsShareClass PVDeadbandPlugin : public PVPlugin
|
||||
{
|
||||
private:
|
||||
PVDeadbandPlugin();
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDeadbandPlugin);
|
||||
virtual ~PVDeadbandPlugin();
|
||||
/**
|
||||
* Factory
|
||||
*/
|
||||
static void create();
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached
|
||||
* @return The PVFilter.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A Plugin for a filter that gets a sub array from a PVScalarDeadband.
|
||||
*/
|
||||
class epicsShareClass PVDeadbandFilter : public PVFilter
|
||||
{
|
||||
private:
|
||||
bool absolute;
|
||||
double deadband;
|
||||
epics::pvData::PVScalarPtr master;
|
||||
bool firstTime;
|
||||
double lastReportedValue;
|
||||
|
||||
|
||||
PVDeadbandFilter(bool absolute,double deadband,epics::pvData::PVScalarPtr const & master);
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDeadbandFilter);
|
||||
virtual ~PVDeadbandFilter();
|
||||
/**
|
||||
* Create a PVDeadbandFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
static PVDeadbandFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
/**
|
||||
* Perform a filter operation
|
||||
* @param pvCopy The field in the copy PVStructure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return if filter (modified, did not modify) destination.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
|
||||
/**
|
||||
* Get the filter name.
|
||||
* @return The name.
|
||||
*/
|
||||
std::string getName();
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* PVDEADBANDPLUGIN_H */
|
||||
|
||||
109
src/pv/pvPlugin.h
Normal file
109
src/pv/pvPlugin.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/* pvPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @date 2017.03
|
||||
*/
|
||||
#ifndef PVPLUGIN_H
|
||||
#define PVPLUGIN_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/bitSet.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
class PVPlugin;
|
||||
class PVFilter;
|
||||
class PVPluginRegistry;
|
||||
|
||||
class PVCopy;
|
||||
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr;
|
||||
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A filter plugin that attaches to a field of a PVStrcture.
|
||||
*
|
||||
* PVCopy looks for plugins defined in pvRequest and calls the filter when a pvCopy is updated.
|
||||
* @author mrk
|
||||
* @since 2017.03.17
|
||||
*
|
||||
* Interface for a filter plugin for PVCopy.
|
||||
*
|
||||
*/
|
||||
|
||||
class epicsShareClass PVPlugin {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVPlugin);
|
||||
virtual ~PVPlugin() {}
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A Filter that is called when a copy PVStructure is being updated.
|
||||
*
|
||||
* This interface defines a filter to update a copy of a field from a master PVStructure.
|
||||
* of the data in the master.
|
||||
*/
|
||||
class epicsShareClass PVFilter {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVFilter);
|
||||
virtual ~PVFilter() {}
|
||||
/**
|
||||
* Update copy or master.
|
||||
* @param copy The data for copy.
|
||||
* @param bitSet The BitSet for copy.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return (true,false) if filter modified destination.
|
||||
*/
|
||||
virtual bool filter(const epics::pvData::PVFieldPtr & copy,const epics::pvData::BitSetPtr & bitSet,bool toCopy) = 0;
|
||||
/**
|
||||
* Get the filter name.
|
||||
* This is the name part of a request name=value pair.
|
||||
* @return The name.
|
||||
*/
|
||||
virtual std::string getName() = 0;
|
||||
};
|
||||
/**
|
||||
* @brief A registry for filter plugins for PVCopy.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass PVPluginRegistry {
|
||||
public:
|
||||
/**
|
||||
* Register a plugin.
|
||||
* @param name The name that appears in [name=value] of a field request option.
|
||||
* @param pvPlugin The implementation for the plugin.
|
||||
*/
|
||||
static void registerPlugin(const std::string & name,const PVPluginPtr & pvPlugin);
|
||||
/**
|
||||
* Find a plugin.
|
||||
* @param name The name that appears in [name=value] of a field request option.
|
||||
* @return The plugin implementation or null if no pluging by that name has been registered.
|
||||
*/
|
||||
static PVPluginPtr find(const std::string & name);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* PVPLUGIN_H */
|
||||
248
src/pv/pvStructureCopy.h
Normal file
248
src/pv/pvStructureCopy.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/* pvStructureCopy.h */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#ifndef PVSTRUCTURECOPY_H
|
||||
#define PVSTRUCTURECOPY_H
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/bitSet.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
class PVCopyTraverseMasterCallback;
|
||||
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr;
|
||||
|
||||
/**
|
||||
* @brief Callback for traversing master structure
|
||||
*
|
||||
* Must be implemented by code that creates pvCopy.
|
||||
*
|
||||
* This was originally name pvCopy.h and implemented in pvDataCPP
|
||||
* When it was moved to pvDatabaseCPP it was renamed to prevent conflicts with
|
||||
* the version in pvDataCPP.
|
||||
* Also the namespace was changed from epics::pvData to epics::pvCopy
|
||||
*/
|
||||
class epicsShareClass PVCopyTraverseMasterCallback
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVCopyTraverseMasterCallback);
|
||||
virtual ~PVCopyTraverseMasterCallback() {}
|
||||
/**
|
||||
* Called once for each field in master.
|
||||
* @param pvField The field in master.
|
||||
*/
|
||||
virtual void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField) = 0;
|
||||
};
|
||||
|
||||
|
||||
class PVCopy;
|
||||
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
|
||||
|
||||
struct CopyNode;
|
||||
typedef std::tr1::shared_ptr<CopyNode> CopyNodePtr;
|
||||
|
||||
struct CopyStructureNode;
|
||||
typedef std::tr1::shared_ptr<CopyStructureNode> CopyStructureNodePtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Support for subset of fields in a pvStructure.
|
||||
*
|
||||
* Class that manages one or more PVStructures that holds an arbitrary subset of the fields
|
||||
* in another PVStructure called master.
|
||||
*/
|
||||
class epicsShareClass PVCopy :
|
||||
public std::tr1::enable_shared_from_this<PVCopy>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVCopy);
|
||||
/**
|
||||
* Create a new pvCopy
|
||||
* @param pvMaster The top-level structure for which a copy of
|
||||
* an arbitrary subset of the fields in master will be created and managed.
|
||||
* @param pvRequest Selects the set of subfields desired and options for each field.
|
||||
* @param structureName The name for the top level of any PVStructure created.
|
||||
*/
|
||||
static PVCopyPtr create(
|
||||
epics::pvData::PVStructurePtr const &pvMaster,
|
||||
epics::pvData::PVStructurePtr const &pvRequest,
|
||||
std::string const & structureName);
|
||||
virtual ~PVCopy(){}
|
||||
virtual void destroy();
|
||||
/**
|
||||
* Get the top-level structure of master
|
||||
* @returns The master top-level structure.
|
||||
* This should not be modified.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr getPVMaster();
|
||||
/**
|
||||
* Traverse all the fields in master.
|
||||
* @param callback This is called for each field on master.
|
||||
*/
|
||||
void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
|
||||
/**
|
||||
* Get the introspection interface for a PVStructure for e copy.
|
||||
*/
|
||||
epics::pvData::StructureConstPtr getStructure();
|
||||
/**
|
||||
* Create a copy instance. Monitors keep a queue of monitor elements.
|
||||
* Since each element needs a PVStructure, multiple top-level structures will be created.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr createPVStructure();
|
||||
/**
|
||||
* Given a field in pvMaster. return the offset in copy for the same field.
|
||||
* A value of std::string::npos means that the copy does not have this field.
|
||||
* @param masterPVField The field in master.
|
||||
*/
|
||||
std::size_t getCopyOffset(epics::pvData::PVFieldPtr const &masterPVField);
|
||||
/**
|
||||
* Given a field in pvMaster. return the offset in copy for the same field.
|
||||
* A value of std::string::npos means that the copy does not have this field.
|
||||
* @param masterPVStructure A structure in master that has masterPVField.
|
||||
* @param masterPVField The field in master.
|
||||
*/
|
||||
std::size_t getCopyOffset(
|
||||
epics::pvData::PVStructurePtr const &masterPVStructure,
|
||||
epics::pvData::PVFieldPtr const &masterPVField);
|
||||
/**
|
||||
* Given an offset in the copy get the corresponding field in pvMaster.
|
||||
* @param structureOffset The offset in the copy.
|
||||
*/
|
||||
epics::pvData::PVFieldPtr getMasterPVField(std::size_t structureOffset);
|
||||
/**
|
||||
* Initialize the fields in copyPVStructure by giving each field
|
||||
* the value from the corresponding field in pvMaster.
|
||||
* bitSet will be set to show that all fields are changed.
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
*/
|
||||
void initCopy(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* Set all fields in copyPVStructure to the value of the corresponding field in pvMaster.
|
||||
* Each field that is changed has it's corresponding bit set in bitSet.
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @returns (false,true) if client (should not,should) receive changes.
|
||||
*/
|
||||
bool updateCopySetBitSet(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* For each set bit in bitSet
|
||||
* set the field in copyPVStructure to the value of the corresponding field in pvMaster.
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @returns (false,true) if client (should not,should) receive changes.
|
||||
*/
|
||||
bool updateCopyFromBitSet(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* For each set bit in bitSet
|
||||
* set the field in pvMaster to the value of the corresponding field in copyPVStructure
|
||||
* @param copyPVStructure A copy top-level structure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
*/
|
||||
void updateMaster(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
/**
|
||||
* Get the options for the field at the specified offset.
|
||||
* @param fieldOffset the offset in copy.
|
||||
* @returns A NULL is returned if no options were specified for the field.
|
||||
* If options were specified,PVStructurePtr is a structures
|
||||
* with a set of PVString subfields that specify name,value pairs.s
|
||||
* name is the subField name and value is the subField value.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr getOptions(std::size_t fieldOffset);
|
||||
/**
|
||||
* For debugging.
|
||||
*/
|
||||
std::string dump();
|
||||
private:
|
||||
|
||||
PVCopyPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
epics::pvData::PVStructurePtr pvMaster;
|
||||
epics::pvData::StructureConstPtr structure;
|
||||
CopyNodePtr headNode;
|
||||
epics::pvData::PVStructurePtr cacheInitStructure;
|
||||
epics::pvData::BitSetPtr ignorechangeBitSet;
|
||||
|
||||
void traverseMaster(
|
||||
CopyNodePtr const &node,
|
||||
PVCopyTraverseMasterCallbackPtr const & callback);
|
||||
void updateCopySetBitSet(
|
||||
epics::pvData::PVFieldPtr const &pvCopy,
|
||||
epics::pvData::PVFieldPtr const &pvMaster,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateCopySetBitSet(
|
||||
epics::pvData::PVFieldPtr const &pvCopy,
|
||||
CopyNodePtr const &node,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateCopyFromBitSet(
|
||||
epics::pvData::PVFieldPtr const &pvCopy,
|
||||
CopyNodePtr const &node,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateMasterField(
|
||||
CopyNodePtr const & node,
|
||||
epics::pvData::PVFieldPtr const & pvCopy,
|
||||
epics::pvData::PVFieldPtr const &pvMaster,
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateMasterCheckBitSet(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet,
|
||||
size_t nextSet);
|
||||
CopyNodePtr getCopyNode(std::size_t fieldOffset);
|
||||
|
||||
PVCopy(epics::pvData::PVStructurePtr const &pvMaster);
|
||||
bool init(epics::pvData::PVStructurePtr const &pvRequest);
|
||||
epics::pvData::StructureConstPtr createStructure(
|
||||
epics::pvData::PVStructurePtr const &pvMaster,
|
||||
epics::pvData::PVStructurePtr const &pvFromRequest);
|
||||
CopyNodePtr createStructureNodes(
|
||||
epics::pvData::PVStructurePtr const &pvMasterStructure,
|
||||
epics::pvData::PVStructurePtr const &pvFromRequest,
|
||||
epics::pvData::PVStructurePtr const &pvFromField);
|
||||
void initPlugin(
|
||||
CopyNodePtr const & node,
|
||||
epics::pvData::PVStructurePtr const & pvOptions,
|
||||
epics::pvData::PVFieldPtr const & pvMasterField);
|
||||
void traverseMasterInitPlugin();
|
||||
void traverseMasterInitPlugin(CopyNodePtr const & node);
|
||||
|
||||
CopyNodePtr getCopyOffset(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
epics::pvData::PVFieldPtr const &masterPVField);
|
||||
bool checkIgnore(
|
||||
epics::pvData::PVStructurePtr const & copyPVStructure,
|
||||
epics::pvData::BitSetPtr const & bitSet);
|
||||
void setIgnore(CopyNodePtr const & node);
|
||||
CopyNodePtr getMasterNode(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
std::size_t structureOffset);
|
||||
void dump(
|
||||
std::string *builder,
|
||||
CopyNodePtr const &node,
|
||||
int indentLevel);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* PVSTRUCTURECOPY_H */
|
||||
78
src/pv/pvSupport.h
Normal file
78
src/pv/pvSupport.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2019.06.01
|
||||
*/
|
||||
#ifndef PVSUPPORT_H
|
||||
#define PVSUPPORT_H
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/pvStructureCopy.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVSupport;
|
||||
typedef std::tr1::shared_ptr<PVSupport> PVSupportPtr;
|
||||
|
||||
/**
|
||||
* @brief Base interface for a PVSupport.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass PVSupport
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVSupport);
|
||||
/**
|
||||
* The Destructor.
|
||||
*/
|
||||
virtual ~PVSupport(){}
|
||||
/**
|
||||
* @brief Optional initialization method.
|
||||
*
|
||||
* Called after PVRecord is created but before record is installed into PVDatabase.
|
||||
*
|
||||
* @param pvValue The field to support.
|
||||
* @param pvSupport Support specific fields.
|
||||
* @return <b>true</b> for success and <b>false</b> for failure.
|
||||
*/
|
||||
virtual bool init(
|
||||
epics::pvData::PVFieldPtr const & pvValue,
|
||||
epics::pvData::PVFieldPtr const & pvSupport) {return true;}
|
||||
/**
|
||||
* @brief Optional method for derived class.
|
||||
*
|
||||
* It is called before record is added to database.
|
||||
*/
|
||||
virtual void start() {}
|
||||
/**
|
||||
* @brief Virtual method for derived class.
|
||||
*
|
||||
* Called when record is processed.
|
||||
* It is the method that implements support.
|
||||
* It is called each time the record is processed.
|
||||
*
|
||||
* @return Returns true is any fields were modified; otherwise false.
|
||||
*/
|
||||
virtual bool process() = 0;
|
||||
/**
|
||||
* @brief Optional method for derived class.
|
||||
*
|
||||
*/
|
||||
virtual void reset() {};
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* PVSUPPORT_H */
|
||||
|
||||
101
src/pv/pvTimestampPlugin.h
Normal file
101
src/pv/pvTimestampPlugin.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* pvTimeStampPlugin.h */
|
||||
/*
|
||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||
*/
|
||||
|
||||
#ifndef PVTIMESTAMPPLUGIN_H
|
||||
#define PVTIMESTAMPPLUGIN_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvPlugin.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvCopy{
|
||||
|
||||
class PVTimestampPlugin;
|
||||
class PVTimestampFilter;
|
||||
|
||||
typedef std::tr1::shared_ptr<PVTimestampPlugin> PVTimestampPluginPtr;
|
||||
typedef std::tr1::shared_ptr<PVTimestampFilter> PVTimestampFilterPtr;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A plugin for a filter that sets a timeStamp to the current time.
|
||||
*
|
||||
* @author mrk
|
||||
* @since date 2017.03.24
|
||||
*/
|
||||
class epicsShareClass PVTimestampPlugin : public PVPlugin
|
||||
{
|
||||
private:
|
||||
PVTimestampPlugin();
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVTimestampPlugin);
|
||||
virtual ~PVTimestampPlugin();
|
||||
/**
|
||||
* Factory
|
||||
*/
|
||||
static void create();
|
||||
/**
|
||||
* Create a PVFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param pvCopy The PVCopy to which the PVFilter will be attached.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached
|
||||
* @return The PVFilter.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
virtual PVFilterPtr create(
|
||||
const std::string & requestValue,
|
||||
const PVCopyPtr & pvCopy,
|
||||
const epics::pvData::PVFieldPtr & master);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A filter that sets a timeStamp to/from the current field or pvCopy.
|
||||
*/
|
||||
class epicsShareClass PVTimestampFilter : public PVFilter
|
||||
{
|
||||
private:
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
bool current;
|
||||
bool copy;
|
||||
epics::pvData::PVFieldPtr master;
|
||||
|
||||
|
||||
PVTimestampFilter(bool current,bool copy,epics::pvData::PVFieldPtr const & pvField);
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVTimestampFilter);
|
||||
virtual ~PVTimestampFilter();
|
||||
/**
|
||||
* Create a PVTimestampFilter.
|
||||
* @param requestValue The value part of a name=value request option.
|
||||
* @param master The field in the master PVStructure to which the PVFilter will be attached.
|
||||
* @return The PVFilter.
|
||||
* A null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
static PVTimestampFilterPtr create(const std::string & requestValue,const epics::pvData::PVFieldPtr & master);
|
||||
/**
|
||||
* Perform a filter operation
|
||||
* @param pvCopy The field in the copy PVStructure.
|
||||
* @param bitSet A bitSet for copyPVStructure.
|
||||
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
|
||||
* @return if filter (modified, did not modify) destination.
|
||||
* Null is returned if master or requestValue is not appropriate for the plugin.
|
||||
*/
|
||||
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
|
||||
/**
|
||||
* Get the filter name.
|
||||
* @return The name.
|
||||
*/
|
||||
std::string getName();
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* PVTIMESTAMPPLUGIN_H */
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
#ifndef REMOVERECORD_H
|
||||
#define REMOVERECORD_H
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ private:
|
||||
RemoveRecord(
|
||||
std::string const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
PVDatabasePtr pvDatabase;
|
||||
epics::pvData::PVStringPtr pvRecordName;
|
||||
epics::pvData::PVStringPtr pvResult;
|
||||
};
|
||||
|
||||
111
src/pv/scalarAlarmSupport.h
Normal file
111
src/pv/scalarAlarmSupport.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2019.06.01
|
||||
*/
|
||||
#ifndef SCALARALARMSUPPORT_H
|
||||
#define SCALARALARMSUPPORT_H
|
||||
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/pvSupport.h>
|
||||
#include <pv/alarm.h>
|
||||
#include <pv/pvAlarm.h>
|
||||
#include <pv/pvStructureCopy.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class ScalarAlarmSupport;
|
||||
typedef std::tr1::shared_ptr<ScalarAlarmSupport> ScalarAlarmSupportPtr;
|
||||
|
||||
/**
|
||||
* @brief Base interface for a ScalarAlarmSupport.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass ScalarAlarmSupport :
|
||||
PVSupport
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ScalarAlarmSupport);
|
||||
/**
|
||||
* The Destructor.
|
||||
*/
|
||||
virtual ~ScalarAlarmSupport();
|
||||
/**
|
||||
* @brief Connects to contol fields.
|
||||
*
|
||||
* @param pvValue The field to support.
|
||||
* @param pvAlarm The alarm field.
|
||||
* @param pvSupport Support specific fields.
|
||||
* @return <b>true</b> for success and <b>false</b> for failure.
|
||||
*/
|
||||
virtual bool init(
|
||||
epics::pvData::PVFieldPtr const & pvValue,
|
||||
epics::pvData::PVStructurePtr const & pvAlarm,
|
||||
epics::pvData::PVFieldPtr const & pvSupport);
|
||||
/**
|
||||
* @brief Honors scalarAlarm fields.
|
||||
*
|
||||
*
|
||||
* @return Returns true is any fields were modified; otherwise false.
|
||||
*/
|
||||
virtual bool process();
|
||||
/**
|
||||
* @brief If implementing minSteps it sets isMinStep to false.
|
||||
*
|
||||
*/
|
||||
virtual void reset();
|
||||
/**
|
||||
* @brief create a ScalarAlarm
|
||||
*
|
||||
* @param pvRecord - The pvRecord to which the support is attached.
|
||||
* @return The new ScalarAlarm
|
||||
*/
|
||||
static ScalarAlarmSupportPtr create(PVRecordPtr const & pvRecord);
|
||||
/**
|
||||
* @brief create a scalarAlarm required by ScalarAlarm
|
||||
*
|
||||
* @return The scalarAlarmField introspection structure.
|
||||
*/
|
||||
static epics::pvData::StructureConstPtr scalarAlarmField();
|
||||
private:
|
||||
|
||||
ScalarAlarmSupport(PVRecordPtr const & pvRecord);
|
||||
enum {
|
||||
range_Lolo = 0,
|
||||
range_Low,
|
||||
range_Normal,
|
||||
range_High,
|
||||
range_Hihi,
|
||||
range_Invalid,
|
||||
range_Undefined
|
||||
} AlarmRange;
|
||||
void setAlarm(
|
||||
epics::pvData::PVStructurePtr const & pvAlarm,
|
||||
int alarmRange);
|
||||
PVRecordPtr pvRecord;
|
||||
int prevAlarmRange;
|
||||
epics::pvData::PVScalarPtr pvValue;
|
||||
epics::pvData::PVStructurePtr pvAlarm;
|
||||
epics::pvData::PVStructurePtr pvScalarAlarm;
|
||||
epics::pvData::PVBooleanPtr pvActive;
|
||||
epics::pvData::PVDoublePtr pvLowAlarmLimit;
|
||||
epics::pvData::PVDoublePtr pvLowWarningLimit;
|
||||
epics::pvData::PVDoublePtr pvHighWarningLimit;
|
||||
epics::pvData::PVDoublePtr pvHighAlarmLimit;
|
||||
epics::pvData::PVDoublePtr pvHysteresis;
|
||||
double requestedValue;
|
||||
double currentValue;
|
||||
bool isHystersis;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* SCALARALARMSUPPORT_H */
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#ifndef TRACERECORD_H
|
||||
#define TRACERECORD_H
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
@@ -55,7 +56,6 @@ private:
|
||||
TraceRecord(
|
||||
std::string const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
PVDatabasePtr pvDatabase;
|
||||
epics::pvData::PVStringPtr pvRecordName;
|
||||
epics::pvData::PVIntPtr pvLevel;
|
||||
epics::pvData::PVStringPtr pvResult;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* channelChannelProviderLocal.cpp */
|
||||
/* channelProviderLocal.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
@@ -9,16 +9,21 @@
|
||||
* @date 2013.04
|
||||
*/
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/syncChannelFind.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/timeStamp.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/channelProviderLocal.h"
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvCopy;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
@@ -28,77 +33,59 @@ using std::string;
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
static string providerName("local");
|
||||
|
||||
|
||||
class LocalChannelProviderFactory;
|
||||
typedef std::tr1::shared_ptr<LocalChannelProviderFactory> LocalChannelProviderFactoryPtr;
|
||||
static ChannelProviderLocalPtr channelProvider;
|
||||
|
||||
class LocalChannelProviderFactory : public ChannelProviderFactory
|
||||
{
|
||||
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(LocalChannelProviderFactory);
|
||||
virtual string getFactoryName() { return providerName;}
|
||||
static LocalChannelProviderFactoryPtr create(
|
||||
ChannelProviderLocalPtr const &channelProvider)
|
||||
{
|
||||
LocalChannelProviderFactoryPtr xxx(
|
||||
new LocalChannelProviderFactory(channelProvider));
|
||||
registerChannelProviderFactory(xxx);
|
||||
return xxx;
|
||||
}
|
||||
virtual ChannelProvider::shared_pointer sharedInstance()
|
||||
{
|
||||
if(!channelProvider) channelProvider = ChannelProviderLocalPtr(new ChannelProviderLocal());
|
||||
return channelProvider;
|
||||
}
|
||||
virtual ChannelProvider::shared_pointer newInstance()
|
||||
{
|
||||
throw std::logic_error("newInstance not Implemented");
|
||||
throw std::logic_error(
|
||||
"LocalChannelProviderFactory::newInstance() not Implemented");
|
||||
}
|
||||
private:
|
||||
LocalChannelProviderFactory(
|
||||
ChannelProviderLocalPtr const &channelProvider)
|
||||
: channelProvider(channelProvider)
|
||||
{}
|
||||
ChannelProviderLocalPtr channelProvider;
|
||||
};
|
||||
|
||||
|
||||
ChannelProviderLocalPtr getChannelProviderLocal()
|
||||
{
|
||||
static ChannelProviderLocalPtr channelProviderLocal;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
if(!channelProviderLocal) {
|
||||
channelProviderLocal = ChannelProviderLocalPtr(
|
||||
new ChannelProviderLocal());
|
||||
ChannelProvider::shared_pointer xxx =
|
||||
dynamic_pointer_cast<ChannelProvider>(channelProviderLocal);
|
||||
channelProviderLocal->channelFinder =
|
||||
SyncChannelFind::shared_pointer(new SyncChannelFind(xxx));
|
||||
LocalChannelProviderFactoryPtr factory(LocalChannelProviderFactory::create(channelProviderLocal));
|
||||
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
ChannelProviderFactory::shared_pointer factory(
|
||||
new LocalChannelProviderFactory());
|
||||
ChannelProviderRegistry::servers()->add(factory);
|
||||
}
|
||||
return channelProviderLocal;
|
||||
ChannelProvider::shared_pointer channelProvider =
|
||||
ChannelProviderRegistry::servers()->getProvider(providerName);
|
||||
return std::tr1::dynamic_pointer_cast<ChannelProviderLocal>(channelProvider);
|
||||
}
|
||||
|
||||
ChannelProviderLocal::ChannelProviderLocal()
|
||||
: pvDatabase(PVDatabase::getMaster()),
|
||||
beingDestroyed(false)
|
||||
traceLevel(0)
|
||||
{
|
||||
if(traceLevel>0) {
|
||||
cout << "ChannelProviderLocal::ChannelProviderLocal()\n";
|
||||
}
|
||||
}
|
||||
|
||||
ChannelProviderLocal::~ChannelProviderLocal()
|
||||
{
|
||||
destroy();
|
||||
if(traceLevel>0) {
|
||||
cout << "ChannelProviderLocal::~ChannelProviderLocal()\n";
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelProviderLocal::destroy()
|
||||
std::tr1::shared_ptr<ChannelProvider> ChannelProviderLocal::getChannelProvider()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
beingDestroyed = true;
|
||||
pvDatabase->destroy();
|
||||
pvDatabase.reset();
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
string ChannelProviderLocal::getProviderName()
|
||||
@@ -110,35 +97,46 @@ ChannelFind::shared_pointer ChannelProviderLocal::channelFind(
|
||||
string const & channelName,
|
||||
ChannelFindRequester::shared_pointer const &channelFindRequester)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
PVRecordPtr pvRecord = pvDatabase->findRecord(channelName);
|
||||
if(traceLevel>1) {
|
||||
cout << "ChannelProviderLocal::channelFind " << "channelName" << endl;
|
||||
}
|
||||
PVDatabasePtr pvdb(pvDatabase.lock());
|
||||
if(!pvdb) {
|
||||
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pvDatabase was deleted");
|
||||
channelFindRequester->channelFindResult(
|
||||
notFoundStatus,
|
||||
shared_from_this(),
|
||||
false);
|
||||
}
|
||||
PVRecordPtr pvRecord = pvdb->findRecord(channelName);
|
||||
if(pvRecord) {
|
||||
channelFindRequester->channelFindResult(
|
||||
Status::Ok,
|
||||
channelFinder,
|
||||
shared_from_this(),
|
||||
true);
|
||||
|
||||
} else {
|
||||
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found");
|
||||
channelFindRequester->channelFindResult(
|
||||
notFoundStatus,
|
||||
channelFinder,
|
||||
shared_from_this(),
|
||||
false);
|
||||
}
|
||||
return channelFinder;
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
ChannelFind::shared_pointer ChannelProviderLocal::channelList(
|
||||
ChannelListRequester::shared_pointer const & channelListRequester)
|
||||
{
|
||||
PVStringArrayPtr records;
|
||||
{
|
||||
Lock guard(mutex);
|
||||
records = pvDatabase->getRecordNames();
|
||||
if(traceLevel>1) {
|
||||
cout << "ChannelProviderLocal::channelList\n";
|
||||
}
|
||||
|
||||
channelListRequester->channelListResult(Status::Ok, channelFinder, records->view(), false);
|
||||
return channelFinder;
|
||||
PVDatabasePtr pvdb(pvDatabase.lock());
|
||||
if(!pvdb)throw std::logic_error("pvDatabase was deleted");
|
||||
PVStringArrayPtr records(pvdb->getRecordNames());
|
||||
channelListRequester->channelListResult(
|
||||
Status::Ok, shared_from_this(), records->view(), false);
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
Channel::shared_pointer ChannelProviderLocal::createChannel(
|
||||
@@ -146,23 +144,26 @@ Channel::shared_pointer ChannelProviderLocal::createChannel(
|
||||
ChannelRequester::shared_pointer const &channelRequester,
|
||||
short priority)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
PVRecordPtr pvRecord = pvDatabase->findRecord(channelName);
|
||||
if(pvRecord) {
|
||||
ChannelLocalPtr channel(new ChannelLocal(
|
||||
getPtrSelf(),channelRequester,pvRecord));
|
||||
channelRequester->channelCreated(
|
||||
Status::Ok,
|
||||
channel);
|
||||
pvRecord->addPVRecordClient(channel);
|
||||
return channel;
|
||||
}
|
||||
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found");
|
||||
channelRequester->channelCreated(
|
||||
notFoundStatus,
|
||||
Channel::shared_pointer());
|
||||
return Channel::shared_pointer();
|
||||
|
||||
if(traceLevel>1) {
|
||||
cout << "ChannelProviderLocal::createChannel " << "channelName" << endl;
|
||||
}
|
||||
ChannelLocalPtr channel;
|
||||
Status status = Status::Ok;
|
||||
PVDatabasePtr pvdb(pvDatabase.lock());
|
||||
if(!pvdb) {
|
||||
status = Status::error("pvDatabase was deleted");
|
||||
} else {
|
||||
PVRecordPtr pvRecord = pvdb->findRecord(channelName);
|
||||
if(pvRecord) {
|
||||
channel = ChannelLocalPtr(new ChannelLocal(
|
||||
shared_from_this(),channelRequester,pvRecord));
|
||||
pvRecord->addPVRecordClient(channel);
|
||||
} else {
|
||||
status = Status::error("pv not found");
|
||||
}
|
||||
}
|
||||
channelRequester->channelCreated(status,channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
Channel::shared_pointer ChannelProviderLocal::createChannel(
|
||||
|
||||
@@ -14,15 +14,21 @@
|
||||
#include <epicsGuard.h>
|
||||
#include <pv/thread.h>
|
||||
#include <pv/bitSetUtil.h>
|
||||
#include <pv/queue.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/timeStamp.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/channelProviderLocal.h"
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvCopy;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@@ -30,20 +36,100 @@ using std::string;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class MonitorLocal;
|
||||
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
||||
|
||||
static MonitorPtr nullMonitor;
|
||||
static MonitorElementPtr NULLMonitorElement;
|
||||
static Status failedToCreateMonitorStatus(Status::STATUSTYPE_ERROR,"failed to create monitor");
|
||||
static Status wasDestroyedStatus(Status::STATUSTYPE_ERROR,"was destroyed");
|
||||
static Status failedToCreateMonitorStatus(
|
||||
Status::STATUSTYPE_ERROR,"failed to create monitor");
|
||||
static Status alreadyStartedStatus(Status::STATUSTYPE_ERROR,"already started");
|
||||
static Status notStartedStatus(Status::STATUSTYPE_ERROR,"not started");
|
||||
static Status deletedStatus(Status::STATUSTYPE_ERROR,"record is deleted");
|
||||
|
||||
|
||||
|
||||
typedef Queue<MonitorElement> MonitorElementQueue;
|
||||
class MonitorElementQueue;
|
||||
typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
|
||||
typedef std::tr1::shared_ptr<MonitorRequester> MonitorRequesterPtr;
|
||||
|
||||
class MonitorElementQueue
|
||||
{
|
||||
private:
|
||||
MonitorElementPtrArray elements;
|
||||
// TODO use size_t instead
|
||||
int size;
|
||||
int numberFree;
|
||||
int numberUsed;
|
||||
int nextGetFree;
|
||||
int nextSetUsed;
|
||||
int nextGetUsed;
|
||||
int nextReleaseUsed;
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorElementQueue);
|
||||
|
||||
MonitorElementQueue(std::vector<MonitorElementPtr> monitorElementArray)
|
||||
: elements(monitorElementArray),
|
||||
size(monitorElementArray.size()),
|
||||
numberFree(size),
|
||||
numberUsed(0),
|
||||
nextGetFree(0),
|
||||
nextSetUsed(0),
|
||||
nextGetUsed(0),
|
||||
nextReleaseUsed(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MonitorElementQueue() {}
|
||||
|
||||
void clear()
|
||||
{
|
||||
numberFree = size;
|
||||
numberUsed = 0;
|
||||
nextGetFree = 0;
|
||||
nextSetUsed = 0;
|
||||
nextGetUsed = 0;
|
||||
nextReleaseUsed = 0;
|
||||
}
|
||||
|
||||
MonitorElementPtr getFree()
|
||||
{
|
||||
if(numberFree==0) return MonitorElementPtr();
|
||||
numberFree--;
|
||||
int ind = nextGetFree;
|
||||
MonitorElementPtr queueElement = elements[nextGetFree++];
|
||||
if(nextGetFree>=size) nextGetFree = 0;
|
||||
return elements[ind];
|
||||
}
|
||||
|
||||
void setUsed(MonitorElementPtr const &element)
|
||||
{
|
||||
if(element!=elements[nextSetUsed++]) {
|
||||
throw std::logic_error("not correct queueElement");
|
||||
}
|
||||
numberUsed++;
|
||||
if(nextSetUsed>=size) nextSetUsed = 0;
|
||||
}
|
||||
|
||||
MonitorElementPtr getUsed()
|
||||
{
|
||||
if(numberUsed==0) return MonitorElementPtr();
|
||||
int ind = nextGetUsed;
|
||||
MonitorElementPtr queueElement = elements[nextGetUsed++];
|
||||
if(nextGetUsed>=size) nextGetUsed = 0;
|
||||
return elements[ind];
|
||||
}
|
||||
void releaseUsed(MonitorElementPtr const &element)
|
||||
{
|
||||
if(element!=elements[nextReleaseUsed++]) {
|
||||
throw std::logic_error(
|
||||
"not queueElement returned by last call to getUsed");
|
||||
}
|
||||
if(nextReleaseUsed>=size) nextReleaseUsed = 0;
|
||||
numberUsed--;
|
||||
numberFree++;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::tr1::shared_ptr<MonitorRequester> MonitorRequesterPtr;
|
||||
|
||||
|
||||
class MonitorLocal :
|
||||
@@ -51,15 +137,15 @@ class MonitorLocal :
|
||||
public PVListener,
|
||||
public std::tr1::enable_shared_from_this<MonitorLocal>
|
||||
{
|
||||
enum MonitorState {idle,active, destroyed};
|
||||
enum MonitorState {idle,active,deleted};
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorLocal);
|
||||
virtual ~MonitorLocal();
|
||||
virtual void destroy() {} // DEPRECATED
|
||||
virtual Status start();
|
||||
virtual Status stop();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void destroy();
|
||||
virtual void detach(PVRecordPtr const & pvRecord){destroy();}
|
||||
virtual void detach(PVRecordPtr const & pvRecord){}
|
||||
virtual void release(MonitorElementPtr const & monitorElement);
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);
|
||||
virtual void dataPut(
|
||||
@@ -109,25 +195,8 @@ MonitorLocal::~MonitorLocal()
|
||||
{
|
||||
cout << "MonitorLocal::~MonitorLocal()" << endl;
|
||||
}
|
||||
destroy();
|
||||
}
|
||||
|
||||
void MonitorLocal::destroy()
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "MonitorLocal::destroy state " << state << endl;
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(state==destroyed) return;
|
||||
}
|
||||
if(state==active) stop();
|
||||
{
|
||||
Lock xx(mutex);
|
||||
state = destroyed;
|
||||
}
|
||||
}
|
||||
|
||||
Status MonitorLocal::start()
|
||||
{
|
||||
@@ -137,8 +206,8 @@ Status MonitorLocal::start()
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(state==destroyed) return wasDestroyedStatus;
|
||||
if(state==active) return alreadyStartedStatus;
|
||||
if(state==deleted) return deletedStatus;
|
||||
}
|
||||
pvRecord->addListener(getPtrSelf(),pvCopy);
|
||||
epicsGuard <PVRecord> guard(*pvRecord);
|
||||
@@ -161,10 +230,10 @@ Status MonitorLocal::stop()
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(state==destroyed) return wasDestroyedStatus;
|
||||
if(state==idle) return notStartedStatus;
|
||||
if(state==deleted) return deletedStatus;
|
||||
state = idle;
|
||||
}
|
||||
}
|
||||
pvRecord->removeListener(getPtrSelf(),pvCopy);
|
||||
return Status::Ok;
|
||||
}
|
||||
@@ -204,9 +273,10 @@ void MonitorLocal::releaseActiveElement()
|
||||
{
|
||||
Lock xx(queueMutex);
|
||||
if(state!=active) return;
|
||||
bool result = pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
|
||||
if(!result) return;
|
||||
MonitorElementPtr newActive = queue->getFree();
|
||||
if(!newActive) return;
|
||||
pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
|
||||
BitSetUtil::compress(activeElement->changedBitSet,activeElement->pvStructurePtr);
|
||||
BitSetUtil::compress(activeElement->overrunBitSet,activeElement->pvStructurePtr);
|
||||
queue->setUsed(activeElement);
|
||||
@@ -309,6 +379,10 @@ void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
cout << "PVCopyMonitor::unlisten\n";
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
state = deleted;
|
||||
}
|
||||
MonitorRequesterPtr requester = monitorRequester.lock();
|
||||
if(requester) {
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
@@ -317,7 +391,6 @@ void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
|
||||
}
|
||||
requester->unlisten(getPtrSelf());
|
||||
}
|
||||
pvRecord->removeListener(getPtrSelf(),pvCopy);
|
||||
}
|
||||
|
||||
|
||||
@@ -382,62 +455,27 @@ bool MonitorLocal::init(PVStructurePtr const & pvRequest)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MonitorFactory::MonitorFactory()
|
||||
: isDestroyed(false)
|
||||
{
|
||||
}
|
||||
|
||||
MonitorFactory::~MonitorFactory()
|
||||
{
|
||||
}
|
||||
|
||||
void MonitorFactory::destroy()
|
||||
{
|
||||
Lock lock(mutex);
|
||||
isDestroyed = true;
|
||||
}
|
||||
|
||||
MonitorPtr MonitorFactory::createMonitor(
|
||||
MonitorPtr createMonitorLocal(
|
||||
PVRecordPtr const & pvRecord,
|
||||
MonitorRequester::shared_pointer const & monitorRequester,
|
||||
PVStructurePtr const & pvRequest)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) {
|
||||
monitorRequester->message("MonitorFactory is destroyed",errorMessage);
|
||||
return nullMonitor;
|
||||
}
|
||||
MonitorLocalPtr monitor(new MonitorLocal(
|
||||
monitorRequester,pvRecord));
|
||||
bool result = monitor->init(pvRequest);
|
||||
if(!result) {
|
||||
MonitorPtr monitor;
|
||||
StructureConstPtr structure;
|
||||
monitorRequester->monitorConnect(failedToCreateMonitorStatus,monitor,structure);
|
||||
monitorRequester->monitorConnect(
|
||||
failedToCreateMonitorStatus,monitor,structure);
|
||||
return nullMonitor;
|
||||
}
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "MonitorFactory::createMonitor";
|
||||
cout << " recordName " << pvRecord->getRecordName() << endl;
|
||||
cout << "MonitorFactory::createMonitor"
|
||||
<< " recordName " << pvRecord->getRecordName() << endl;
|
||||
}
|
||||
return monitor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MonitorFactoryPtr getMonitorFactory()
|
||||
{
|
||||
static MonitorFactoryPtr monitorFactoryPtr;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
|
||||
if(!monitorFactoryPtr) {
|
||||
monitorFactoryPtr = MonitorFactoryPtr(
|
||||
new MonitorFactory());
|
||||
}
|
||||
return monitorFactoryPtr;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -11,30 +11,19 @@
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <cantProceed.h>
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
#include <iocsh.h>
|
||||
#include <shareLib.h>
|
||||
#include <epicsExit.h>
|
||||
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/syncChannelFind.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/timeStamp.h>
|
||||
|
||||
// this declared epicsExportSharedSymbols
|
||||
// The following must be the last include for code pvDatabase uses
|
||||
#include <epicsExport.h>
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/channelProviderLocal.h"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@@ -53,18 +42,15 @@ extern "C" void pvdbl(const iocshArgBuf *args)
|
||||
for(size_t i=0; i<xxx.size(); ++i) cout<< xxx[i] << endl;
|
||||
}
|
||||
|
||||
static void channelProviderLocalExitHandler(void* /*pPrivate*/) {
|
||||
getChannelProviderLocal()->destroy();
|
||||
}
|
||||
|
||||
static void registerChannelProviderLocal(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
cout << "registerChannelProviderLocal firstTime " << (firstTime ? "true" : "false") << endl;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&pvdblFuncDef, pvdbl);
|
||||
getChannelProviderLocal();
|
||||
epicsAtExit(channelProviderLocalExitHandler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,3 +4,12 @@ SRC_DIRS += $(PVDATABASE_SRC)/special
|
||||
|
||||
LIBSRCS += traceRecord.cpp
|
||||
LIBSRCS += removeRecord.cpp
|
||||
LIBSRCS += processRecord.cpp
|
||||
|
||||
DBD += traceRecordRegister.dbd
|
||||
DBD += removeRecordRegister.dbd
|
||||
DBD += processRecordRegister.dbd
|
||||
|
||||
LIBSRCS += traceRecordRegister.cpp
|
||||
LIBSRCS += removeRecordRegister.cpp
|
||||
LIBSRCS += processRecordRegister.cpp
|
||||
|
||||
167
src/special/processRecord.cpp
Normal file
167
src/special/processRecord.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/* processRecord.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.04.18
|
||||
*/
|
||||
#include <map>
|
||||
#include <epicsThread.h>
|
||||
#include <pv/event.h>
|
||||
#include <shareLib.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/processRecord.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
ProcessRecordPtr ProcessRecord::create(
|
||||
std::string const & recordName,double delay)
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||
addNestedStructure("argument")->
|
||||
add("command",pvString)->
|
||||
add("recordName",pvString)->
|
||||
endNested()->
|
||||
addNestedStructure("result") ->
|
||||
add("status",pvString) ->
|
||||
endNested()->
|
||||
createStructure();
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||
ProcessRecordPtr pvRecord(
|
||||
new ProcessRecord(recordName,pvStructure,delay));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
void ProcessRecord::startThread()
|
||||
{
|
||||
thread = EpicsThreadPtr(new epicsThread(
|
||||
*this,
|
||||
"processRecord",
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
epicsThreadPriorityLow));
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void ProcessRecord::stop()
|
||||
{
|
||||
runStop.signal();
|
||||
runReturn.wait();
|
||||
}
|
||||
|
||||
|
||||
ProcessRecord::ProcessRecord(
|
||||
std::string const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure,double delay)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
delay(delay),
|
||||
pvDatabase(PVDatabase::getMaster())
|
||||
{
|
||||
}
|
||||
|
||||
bool ProcessRecord::init()
|
||||
{
|
||||
initPVRecord();
|
||||
PVStructurePtr pvStructure = getPVStructure();
|
||||
pvCommand = pvStructure->getSubField<PVString>("argument.command");
|
||||
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
|
||||
if(!pvRecordName) return false;
|
||||
pvResult = pvStructure->getSubField<PVString>("result.status");
|
||||
if(!pvResult) return false;
|
||||
startThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProcessRecord::process()
|
||||
{
|
||||
string recordName = pvRecordName->get();
|
||||
string command = pvCommand->get();
|
||||
if(command.compare("add")==0) {
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
std::map<std::string,PVRecordPtr>::iterator iter = pvRecordMap.find(recordName);
|
||||
if(iter!=pvRecordMap.end()) {
|
||||
pvResult->put(recordName + " already present");
|
||||
return;
|
||||
}
|
||||
PVRecordPtr pvRecord = pvDatabase->findRecord(recordName);
|
||||
if(!pvRecord) {
|
||||
pvResult->put(recordName + " not in pvDatabase");
|
||||
return;
|
||||
}
|
||||
pvRecordMap.insert(PVRecordMap::value_type(recordName,pvRecord));
|
||||
pvResult->put("success");
|
||||
return;
|
||||
} else if(command.compare("remove")==0) {
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
std::map<std::string,PVRecordPtr>::iterator iter = pvRecordMap.find(recordName);
|
||||
if(iter==pvRecordMap.end()) {
|
||||
pvResult->put(recordName + " not found");
|
||||
return;
|
||||
}
|
||||
pvRecordMap.erase(iter);
|
||||
pvResult->put("success");
|
||||
return;
|
||||
} else {
|
||||
pvResult->put(command + " not a valid command: only add and remove are valid");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessRecord::run()
|
||||
{
|
||||
while(true) {
|
||||
if(runStop.tryWait()) {
|
||||
runReturn.signal();
|
||||
return;
|
||||
}
|
||||
if(delay>0.0) epicsThreadSleep(delay);
|
||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||
PVRecordMap::iterator iter;
|
||||
for(iter = pvRecordMap.begin(); iter!=pvRecordMap.end(); ++iter) {
|
||||
PVRecordPtr pvRecord = (*iter).second;
|
||||
pvRecord->lock();
|
||||
pvRecord->beginGroupPut();
|
||||
try {
|
||||
pvRecord->process();
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << "record " << pvRecord->getRecordName() << "exception " << ex.what() << "\n";
|
||||
} catch (...) {
|
||||
std::cout<< "record " << pvRecord->getRecordName() << " process exception\n";
|
||||
}
|
||||
pvRecord->endGroupPut();
|
||||
pvRecord->unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
67
src/special/processRecordRegister.cpp
Normal file
67
src/special/processRecordRegister.cpp
Normal 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);
|
||||
}
|
||||
1
src/special/processRecordRegister.dbd
Normal file
1
src/special/processRecordRegister.dbd
Normal file
@@ -0,0 +1 @@
|
||||
registrar("processRecordRegister")
|
||||
@@ -8,9 +8,28 @@
|
||||
* @author mrk
|
||||
* @date 2013.04.18
|
||||
*/
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/removeRecord.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/removeRecord.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
@@ -42,8 +61,7 @@ RemoveRecordPtr RemoveRecord::create(
|
||||
RemoveRecord::RemoveRecord(
|
||||
std::string const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
pvDatabase(PVDatabase::getMaster())
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -61,12 +79,12 @@ bool RemoveRecord::init()
|
||||
void RemoveRecord::process()
|
||||
{
|
||||
string name = pvRecordName->get();
|
||||
PVRecordPtr pvRecord = pvDatabase->findRecord(name);
|
||||
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
|
||||
if(!pvRecord) {
|
||||
pvResult->put(name + " not found");
|
||||
return;
|
||||
}
|
||||
pvRecord->destroy();
|
||||
pvRecord->remove();
|
||||
pvResult->put("success");
|
||||
}
|
||||
|
||||
|
||||
62
src/special/removeRecordRegister.cpp
Normal file
62
src/special/removeRecordRegister.cpp
Normal 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);
|
||||
}
|
||||
1
src/special/removeRecordRegister.dbd
Normal file
1
src/special/removeRecordRegister.dbd
Normal file
@@ -0,0 +1 @@
|
||||
registrar("removeRecordRegister")
|
||||
@@ -8,9 +8,27 @@
|
||||
* @author mrk
|
||||
* @date 2013.04.18
|
||||
*/
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/traceRecord.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/channelProviderLocal.h"
|
||||
#include "pv/traceRecord.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
@@ -43,8 +61,7 @@ TraceRecordPtr TraceRecord::create(
|
||||
TraceRecord::TraceRecord(
|
||||
std::string const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
pvDatabase(PVDatabase::getMaster())
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -65,7 +82,7 @@ bool TraceRecord::init()
|
||||
void TraceRecord::process()
|
||||
{
|
||||
string name = pvRecordName->get();
|
||||
PVRecordPtr pvRecord = pvDatabase->findRecord(name);
|
||||
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
|
||||
if(!pvRecord) {
|
||||
pvResult->put(name + " not found");
|
||||
return;
|
||||
|
||||
63
src/special/traceRecordRegister.cpp
Normal file
63
src/special/traceRecordRegister.cpp
Normal 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);
|
||||
}
|
||||
1
src/special/traceRecordRegister.dbd
Normal file
1
src/special/traceRecordRegister.dbd
Normal file
@@ -0,0 +1 @@
|
||||
registrar("traceRecordRegister")
|
||||
6
src/support/Makefile
Normal file
6
src/support/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
# This is a Makefile fragment, see ../Makefile
|
||||
|
||||
SRC_DIRS += $(PVDATABASE_SRC)/support
|
||||
|
||||
LIBSRCS += controlSupport.cpp
|
||||
LIBSRCS += scalarAlarmSupport.cpp
|
||||
138
src/support/controlSupport.cpp
Normal file
138
src/support/controlSupport.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* controlSupport.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2019.06.01
|
||||
*/
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/standardField.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include <pv/pvSupport.h>
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/controlSupport.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
ControlSupport::~ControlSupport()
|
||||
{
|
||||
cout << "ControlSupport::~ControlSupport()\n";
|
||||
}
|
||||
|
||||
epics::pvData::StructureConstPtr ControlSupport::controlField(ScalarType scalarType)
|
||||
{
|
||||
return FieldBuilder::begin()
|
||||
->setId("control_t")
|
||||
->add("limitLow", pvDouble)
|
||||
->add("limitHigh", pvDouble)
|
||||
->add("minStep", pvDouble)
|
||||
->add("outputValue", scalarType)
|
||||
->createStructure();
|
||||
}
|
||||
|
||||
|
||||
ControlSupportPtr ControlSupport::create(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
ControlSupportPtr support(new ControlSupport(pvRecord));
|
||||
return support;
|
||||
}
|
||||
|
||||
ControlSupport::ControlSupport(PVRecordPtr const & pvRecord)
|
||||
: pvRecord(pvRecord)
|
||||
{}
|
||||
|
||||
bool ControlSupport::init(PVFieldPtr const & pv,PVFieldPtr const & pvsup)
|
||||
{
|
||||
if(pv) {
|
||||
if(pv->getField()->getType()==epics::pvData::scalar) {
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(pv->getField());
|
||||
if(ScalarTypeFunc::isNumeric(s->getScalarType())) {
|
||||
pvValue = static_pointer_cast<PVScalar>(pv);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!pvValue) {
|
||||
cout << "ControlSupport for record " << pvRecord->getRecordName()
|
||||
<< " failed because not numeric scalar\n";
|
||||
return false;
|
||||
}
|
||||
pvControl = static_pointer_cast<PVStructure>(pvsup);
|
||||
if(pvControl) {
|
||||
pvLimitLow = pvControl->getSubField<PVDouble>("limitLow");
|
||||
pvLimitHigh = pvControl->getSubField<PVDouble>("limitHigh");
|
||||
pvMinStep = pvControl->getSubField<PVDouble>("minStep");
|
||||
pvOutputValue = pvControl->getSubField<PVScalar>("outputValue");
|
||||
}
|
||||
if(!pvControl || !pvLimitLow || !pvLimitHigh || !pvMinStep || !pvOutputValue) {
|
||||
cout << "ControlSupport for record " << pvRecord->getRecordName()
|
||||
<< " failed because pvSupport not a valid control structure\n";
|
||||
return false;
|
||||
}
|
||||
ConvertPtr convert = getConvert();
|
||||
currentValue = convert->toDouble(pvValue);
|
||||
isMinStep = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ControlSupport::process()
|
||||
{
|
||||
ConvertPtr convert = getConvert();
|
||||
double value = convert->toDouble(pvValue);
|
||||
if(!isMinStep && value==currentValue) return false;
|
||||
double limitLow = pvLimitLow->get();
|
||||
double limitHigh = pvLimitHigh->get();
|
||||
double minStep = pvMinStep->get();
|
||||
bool setValue = false;
|
||||
if(limitHigh>limitLow) {
|
||||
if(value>limitHigh) {value = limitHigh;setValue=true;}
|
||||
if(value<limitLow) {value = limitLow;setValue=true;}
|
||||
}
|
||||
if(setValue) convert->fromDouble(pvValue,value);
|
||||
double diff = value - currentValue;
|
||||
double outputValue = value;
|
||||
if(minStep>0.0) {
|
||||
if(diff<0.0) {
|
||||
outputValue = currentValue - minStep;
|
||||
if(limitHigh>limitLow && outputValue<=limitLow) outputValue = limitLow;
|
||||
isMinStep = true;
|
||||
if(outputValue<value) {
|
||||
outputValue = value;
|
||||
isMinStep = false;
|
||||
}
|
||||
} else {
|
||||
outputValue = currentValue + minStep;
|
||||
if(limitHigh>limitLow && outputValue>=limitHigh) outputValue = limitHigh;
|
||||
isMinStep = true;
|
||||
if(outputValue>value) {
|
||||
outputValue = value;
|
||||
isMinStep = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(outputValue==currentValue) return false;
|
||||
currentValue = outputValue;
|
||||
convert->fromDouble(pvOutputValue,outputValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControlSupport::reset()
|
||||
{
|
||||
isMinStep = false;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
219
src/support/scalarAlarmSupport.cpp
Normal file
219
src/support/scalarAlarmSupport.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
/* scalarAlarmSupport.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2019.06.01
|
||||
*/
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/rpcService.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/alarm.h>
|
||||
#include <pv/pvAlarm.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "pv/pvStructureCopy.h"
|
||||
#include "pv/pvSupport.h"
|
||||
#include "pv/pvDatabase.h"
|
||||
#include "pv/scalarAlarmSupport.h"
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
ScalarAlarmSupport::~ScalarAlarmSupport()
|
||||
{
|
||||
cout << "ScalarAlarmSupport::~ScalarAlarmSupport()\n";
|
||||
}
|
||||
|
||||
|
||||
epics::pvData::StructureConstPtr ScalarAlarmSupport::scalarAlarmField()
|
||||
{
|
||||
return FieldBuilder::begin()
|
||||
->setId("scalarAlarm_t")
|
||||
->add("lowAlarmLimit", pvDouble)
|
||||
->add("lowWarningLimit", pvDouble)
|
||||
->add("highWarningLimit", pvDouble)
|
||||
->add("highAlarmLimit", pvDouble)
|
||||
->add("hysteresis", pvDouble)
|
||||
->createStructure();
|
||||
}
|
||||
|
||||
ScalarAlarmSupportPtr ScalarAlarmSupport::create(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
ScalarAlarmSupportPtr support(new ScalarAlarmSupport(pvRecord));
|
||||
return support;
|
||||
}
|
||||
|
||||
ScalarAlarmSupport::ScalarAlarmSupport(PVRecordPtr const & pvRecord)
|
||||
: pvRecord(pvRecord),
|
||||
prevAlarmRange(range_Undefined)
|
||||
{}
|
||||
|
||||
|
||||
bool ScalarAlarmSupport::init(
|
||||
PVFieldPtr const & pvval,
|
||||
PVStructurePtr const & pvalarm,
|
||||
PVFieldPtr const & pvsup)
|
||||
{
|
||||
if(pvval->getField()->getType()==epics::pvData::scalar) {
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(pvval->getField());
|
||||
if(ScalarTypeFunc::isNumeric(s->getScalarType())) {
|
||||
pvValue = static_pointer_cast<PVScalar>(pvval);
|
||||
}
|
||||
}
|
||||
if(!pvValue) {
|
||||
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
|
||||
<< " failed because not numeric scalar\n";
|
||||
return false;
|
||||
}
|
||||
pvScalarAlarm = static_pointer_cast<PVStructure>(pvsup);
|
||||
if(pvScalarAlarm) {
|
||||
pvLowAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("lowAlarmLimit");
|
||||
pvLowWarningLimit = pvScalarAlarm->getSubField<PVDouble>("lowWarningLimit");
|
||||
pvHighWarningLimit = pvScalarAlarm->getSubField<PVDouble>("highWarningLimit");
|
||||
pvHighAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("highAlarmLimit");
|
||||
pvHysteresis = pvScalarAlarm->getSubField<PVDouble>("hysteresis");
|
||||
}
|
||||
if(!pvScalarAlarm
|
||||
|| !pvLowAlarmLimit || !pvLowWarningLimit
|
||||
|| !pvLowWarningLimit || !pvHighAlarmLimit
|
||||
|| !pvHysteresis)
|
||||
{
|
||||
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
|
||||
<< " failed because pvSupport not a valid scalarAlarm structure\n";
|
||||
return false;
|
||||
}
|
||||
pvAlarm = pvalarm;
|
||||
ConvertPtr convert = getConvert();
|
||||
requestedValue = convert->toDouble(pvValue);
|
||||
currentValue = requestedValue;
|
||||
isHystersis = false;
|
||||
setAlarm(pvAlarm,range_Undefined);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScalarAlarmSupport::process()
|
||||
{
|
||||
ConvertPtr convert = getConvert();
|
||||
double value = convert->toDouble(pvValue);
|
||||
double lowAlarmLimit = pvLowAlarmLimit->get();
|
||||
double lowWarningLimit = pvLowWarningLimit->get();
|
||||
double highWarningLimit = pvHighWarningLimit->get();
|
||||
double highAlarmLimit = pvHighAlarmLimit->get();
|
||||
double hysteresis = pvHysteresis->get();
|
||||
int alarmRange = range_Normal;
|
||||
if(highAlarmLimit>lowAlarmLimit) {
|
||||
if(value>=highAlarmLimit
|
||||
||(prevAlarmRange==range_Hihi && value>=highAlarmLimit-hysteresis)) {
|
||||
alarmRange = range_Hihi;
|
||||
} else if(value<=lowAlarmLimit
|
||||
||(prevAlarmRange==range_Lolo && value<=lowAlarmLimit+hysteresis)) {
|
||||
alarmRange = range_Lolo;
|
||||
}
|
||||
}
|
||||
if(alarmRange==range_Normal && (highWarningLimit>lowWarningLimit)) {
|
||||
if(value>=highWarningLimit
|
||||
||(prevAlarmRange==range_High && value>=highWarningLimit-hysteresis)) {
|
||||
alarmRange = range_High;
|
||||
} else if(value<=lowWarningLimit
|
||||
||(prevAlarmRange==range_Low && value<=lowWarningLimit+hysteresis)) {
|
||||
alarmRange = range_Low;
|
||||
}
|
||||
}
|
||||
bool retValue = false;
|
||||
if(alarmRange!=prevAlarmRange) {
|
||||
setAlarm(pvAlarm,alarmRange);
|
||||
retValue = true;
|
||||
}
|
||||
prevAlarmRange = alarmRange;
|
||||
currentValue = value;
|
||||
return retValue;
|
||||
}
|
||||
|
||||
void ScalarAlarmSupport::reset()
|
||||
{
|
||||
isHystersis = false;
|
||||
}
|
||||
|
||||
void ScalarAlarmSupport::setAlarm(
|
||||
epics::pvData::PVStructurePtr const & pva,
|
||||
int alarmRange)
|
||||
{
|
||||
Alarm alarm;
|
||||
PVAlarm pvAlarm;
|
||||
if(!pvAlarm.attach(pva)) throw std::logic_error("bad alarm field");
|
||||
epics::pvData::AlarmStatus status(epics::pvData::noStatus);
|
||||
epics::pvData::AlarmSeverity severity(epics::pvData::noAlarm);
|
||||
string message;
|
||||
switch (alarmRange) {
|
||||
case range_Lolo :
|
||||
{
|
||||
severity = epics::pvData::majorAlarm;
|
||||
status = epics::pvData::recordStatus;
|
||||
message = "major low alarm";
|
||||
break;
|
||||
}
|
||||
case range_Low :
|
||||
{
|
||||
severity = epics::pvData::minorAlarm;
|
||||
status = epics::pvData::recordStatus;
|
||||
message = "minor low alarm";
|
||||
break;
|
||||
}
|
||||
case range_Normal :
|
||||
{
|
||||
break;
|
||||
}
|
||||
case range_High :
|
||||
{
|
||||
severity = epics::pvData::minorAlarm;
|
||||
status = epics::pvData::recordStatus;
|
||||
message = "minor high alarm";
|
||||
break;
|
||||
}
|
||||
case range_Hihi :
|
||||
{
|
||||
severity = epics::pvData::majorAlarm;
|
||||
status = epics::pvData::recordStatus;
|
||||
message = "major high alarm";
|
||||
break;
|
||||
}
|
||||
case range_Invalid :
|
||||
{
|
||||
severity = epics::pvData::invalidAlarm;
|
||||
status = epics::pvData::recordStatus;
|
||||
message = "invalid alarm";
|
||||
break;
|
||||
}
|
||||
case range_Undefined :
|
||||
{
|
||||
severity = epics::pvData::undefinedAlarm;
|
||||
status = epics::pvData::recordStatus;
|
||||
message = "undefined alarm";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
severity = epics::pvData::undefinedAlarm;
|
||||
status = epics::pvData::recordStatus;
|
||||
message = "bad alarm definition";
|
||||
break;
|
||||
}
|
||||
}
|
||||
alarm.setStatus(status);
|
||||
alarm.setSeverity(severity);
|
||||
alarm.setMessage(message);
|
||||
pvAlarm.set(alarm);
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -5,24 +5,28 @@ include $(TOP)/configure/CONFIG
|
||||
|
||||
PVDATABASE_TEST = $(TOP)/test
|
||||
|
||||
PROD_LIBS += pvDatabase pvAccess pvData Com
|
||||
PROD_LIBS += pvDatabase
|
||||
PROD_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
|
||||
PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
include $(PVDATABASE_TEST)/src/Makefile
|
||||
|
||||
# The testHarness runs all the test programs in a known working order.
|
||||
# pvDatabaseAllTests runs all the test programs in a known working order.
|
||||
testHarness_SRCS += pvDatabaseAllTests.c
|
||||
|
||||
PROD_vxWorks = vxTestHarness
|
||||
vxTestHarness_SRCS += $(testHarness_SRCS)
|
||||
TESTSPEC_vxWorks = vxTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
|
||||
# Name the application pvDbTestHarness
|
||||
pvDbTestHarness_SRCS = $(testHarness_SRCS)
|
||||
|
||||
PROD_RTEMS += rtemsTestHarness
|
||||
rtemsTestHarness_SRCS += rtemsTestHarness.c rtemsConfig.c
|
||||
rtemsTestHarness_SRCS += $(testHarness_SRCS)
|
||||
TESTSPEC_RTEMS = rtemsTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
|
||||
# Build for vxWorks
|
||||
PROD_vxWorks = pvDbTestHarness
|
||||
TESTSPEC_vxWorks = pvDbTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
|
||||
|
||||
# Build for RTEMS, with harness code & configuration
|
||||
PROD_RTEMS += pvDbTestHarness
|
||||
pvDbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
|
||||
TESTSPEC_RTEMS = pvDbTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
|
||||
|
||||
# Build test scripts for hosts
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
#include <stdio.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsUnitTest.h>
|
||||
#include <epicsExit.h>
|
||||
|
||||
/* src */
|
||||
int testExampleRecord(void);
|
||||
int testPVCopy(void);
|
||||
int testPlugin(void);
|
||||
int testPVRecord(void);
|
||||
int testLocalProvider(void);
|
||||
int testPVAServer(void);
|
||||
@@ -23,8 +25,10 @@ void pvDatabaseAllTests(void)
|
||||
/* src */
|
||||
runTest(testExampleRecord);
|
||||
runTest(testPVCopy);
|
||||
runTest(testPlugin);
|
||||
runTest(testPVRecord);
|
||||
runTest(testLocalProvider);
|
||||
runTest(testPVAServer);
|
||||
}
|
||||
|
||||
epicsExit(0); /* Trigger test harness */
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS configuration for EPICS
|
||||
* Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd
|
||||
* Author: W. Eric Norum
|
||||
* norume@aps.anl.gov
|
||||
* (630) 252-4793
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
* RTEMS CONFIGURATION *
|
||||
***********************************************************************
|
||||
*/
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#if __RTEMS_MAJOR__>4 || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
|
||||
# define CONFIGURE_UNIFIED_WORK_AREAS
|
||||
#else
|
||||
# define CONFIGURE_EXECUTIVE_RAM_SIZE (2000*1024)
|
||||
#endif
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30)
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500)
|
||||
#define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20)
|
||||
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5)
|
||||
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
|
||||
|
||||
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 150
|
||||
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
|
||||
#define CONFIGURE_MAXIMUM_DRIVERS 8
|
||||
|
||||
#define CONFIGURE_MICROSECONDS_PER_TICK 20000
|
||||
|
||||
#define CONFIGURE_INIT_TASK_PRIORITY 80
|
||||
|
||||
#define CONFIGURE_MALLOC_STATISTICS 1
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
#define CONFIGURE_INIT_TASK_INITIAL_MODES (RTEMS_PREEMPT | \
|
||||
RTEMS_NO_TIMESLICE | \
|
||||
RTEMS_NO_ASR | \
|
||||
RTEMS_INTERRUPT_LEVEL(0))
|
||||
#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_FLOATING_POINT | RTEMS_LOCAL)
|
||||
#define CONFIGURE_INIT_TASK_STACK_SIZE (16*1024)
|
||||
rtems_task Init (rtems_task_argument argument);
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
|
||||
#define CONFIGURE_FILESYSTEM_NFS
|
||||
#define CONFIGURE_FILESYSTEM_IMFS
|
||||
|
||||
/*
|
||||
* This should be made BSP dependent, not CPU dependent but I know of no
|
||||
* appropriate conditionals to use.
|
||||
* The new general time support makes including the RTC driver less important.
|
||||
*/
|
||||
#if !defined(mpc604) && !defined(__mc68040__) && !defined(__mcf5200__) && !defined(mpc7455) && !defined(__arm__) /* don't have RTC code */
|
||||
#define CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
|
||||
#endif
|
||||
|
||||
|
||||
#include <bsp.h>
|
||||
#include <rtems/confdefs.h>
|
||||
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* Network configuration -- QEMU NOT using DHCP
|
||||
*
|
||||
************************************************************
|
||||
* EDIT THIS FILE TO REFLECT YOUR NETWORK CONFIGURATION *
|
||||
* BEFORE RUNNING ANY RTEMS PROGRAMS WHICH USE THE NETWORK! *
|
||||
************************************************************
|
||||
*
|
||||
* The dynamic probing is based upon the EPICS network
|
||||
* configuration file written by:
|
||||
* W. Eric Norum
|
||||
* eric.norum@usask.ca
|
||||
* (306) 966-5394
|
||||
*/
|
||||
|
||||
#ifndef _RTEMS_NETWORKCONFIG_H_
|
||||
#define _RTEMS_NETWORKCONFIG_H_
|
||||
|
||||
/* #define USE_LIBBSDPORT */
|
||||
|
||||
#if defined(USE_LIBBSDPORT)
|
||||
#include <bsp/libbsdport_api.h>
|
||||
#define CONFIGURE_MAXIMUM_TIMERS 10
|
||||
#endif
|
||||
/*
|
||||
* For TFTP test application
|
||||
*/
|
||||
#if (defined (RTEMS_USE_BOOTP))
|
||||
#define RTEMS_TFTP_TEST_HOST_NAME "BOOTP_HOST"
|
||||
#define RTEMS_TFTP_TEST_FILE_NAME "BOOTP_FILE"
|
||||
#else
|
||||
#define RTEMS_TFTP_TEST_HOST_NAME "XXX.YYY.ZZZ.XYZ"
|
||||
#define RTEMS_TFTP_TEST_FILE_NAME "tftptest"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For NFS test application
|
||||
*
|
||||
* NFS mount and a directory to ls once mounted
|
||||
*/
|
||||
#define RTEMS_NFS_SERVER "192.168.1.210"
|
||||
#define RTEMS_NFS_SERVER_PATH "/home"
|
||||
#define RTEMS_NFS_LS_PATH "/mnt/nfstest"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This file can be copied to an application source directory
|
||||
* and modified to override the values shown below.
|
||||
*
|
||||
* The following CPP symbols may be passed from the Makefile:
|
||||
*
|
||||
* symbol default description
|
||||
*
|
||||
* NETWORK_TASK_PRIORITY 150 can be read by app from public
|
||||
* var 'gesysNetworkTaskPriority'
|
||||
* FIXED_IP_ADDR <undefined> hardcoded IP address (e.g.,
|
||||
* "192.168.0.10"); disables BOOTP;
|
||||
* must also define FIXED_NETMASK
|
||||
* FIXED_NETMASK <undefined> IP netmask string
|
||||
* (e.g. "255.255.255.0")
|
||||
* MULTI_NETDRIVER <undefined> ugly hack; if defined try to probe
|
||||
* a variety of PCI and ISA drivers
|
||||
* (i386 ONLY) use is discouraged!
|
||||
* NIC_NAME <undefined> Ethernet driver name (e.g. "pcn1");
|
||||
* must also define NIC_ATTACH
|
||||
* NIC_ATTACH <undefined> Ethernet driver attach function
|
||||
* (e.g., rtems_fxp_attach).
|
||||
* If these are undefined then
|
||||
* a) MULTI_NETDRIVER is used
|
||||
* (if defined)
|
||||
* b) RTEMS_BSP_NETWORK_DRIVER_NAME/
|
||||
* RTEMS_BSP_NETWORK_DRIVER_ATTACH
|
||||
* are tried
|
||||
* MEMORY_CUSTOM <undefined> Allocate the defined amount of
|
||||
* memory for mbufs and mbuf clusters,
|
||||
* respectively. Define to a comma ','
|
||||
* separated pair of two numerical
|
||||
* values, e.g: 100*1024,200*1024
|
||||
* MEMORY_SCARCE <undefined> Allocate few memory for mbufs
|
||||
* (hint for how much memory the
|
||||
* board has)
|
||||
* MEMORY_HUGE <undefined> Allocate a lot of memory for mbufs
|
||||
* (hint for how much memory the
|
||||
* board has)
|
||||
* If none of MEMORY_CUSTOM/
|
||||
* MEMORY_SCARCE/MEMORY_HUGE are
|
||||
* defined then a medium amount of
|
||||
* memory is allocated for mbufs.
|
||||
*/
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
#include <bsp.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
|
||||
#if 0
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#else
|
||||
#include "verscheck.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//#define MULTI_NETDRIVER
|
||||
//#define RTEMS_BSP_NETWORK_DRIVER_NAME 1
|
||||
|
||||
#define FIXED_IP_ADDR "192.168.1.249"
|
||||
#define FIXED_NETMASK "255.255.255.0"
|
||||
|
||||
#ifndef NETWORK_TASK_PRIORITY
|
||||
#define NETWORK_TASK_PRIORITY 150 /* within EPICS' range */
|
||||
#endif
|
||||
|
||||
/* make publicly available for startup scripts... */
|
||||
const int gesysNetworkTaskPriority = NETWORK_TASK_PRIORITY;
|
||||
|
||||
#ifdef FIXED_IP_ADDR
|
||||
#define RTEMS_DO_BOOTP 0
|
||||
#else
|
||||
#define RTEMS_DO_BOOTP rtems_bsdnet_do_bootp
|
||||
#define FIXED_IP_ADDR 0
|
||||
#undef FIXED_NETMASK
|
||||
#define FIXED_NETMASK 0
|
||||
#endif
|
||||
|
||||
#if !defined(NIC_NAME)
|
||||
|
||||
#ifdef MULTI_NETDRIVER
|
||||
|
||||
#if 0
|
||||
#if RTEMS_VERSION_ATLEAST(4,6,99)
|
||||
#define pcib_init pci_initialize
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
extern int rtems_fxp_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
extern int rtems_elnk_driver_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
extern int rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
|
||||
/* these don't probe and will be used even if there's no device :-( */
|
||||
extern int rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
extern int rtems_wd_driver_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
|
||||
static struct rtems_bsdnet_ifconfig isa_netdriver_config[] = {
|
||||
{
|
||||
"ep0", rtems_3c509_driver_attach, isa_netdriver_config + 1,
|
||||
},
|
||||
{
|
||||
"ne1", rtems_ne_driver_attach, 0, irno: 9 /* qemu cannot configure irq-no :-(; has it hardwired to 9 */
|
||||
},
|
||||
};
|
||||
|
||||
static struct rtems_bsdnet_ifconfig pci_netdriver_config[]={
|
||||
{
|
||||
"dc1", rtems_dec21140_driver_attach, pci_netdriver_config+1,
|
||||
},
|
||||
#if !defined(USE_LIBBSDPORT)
|
||||
{
|
||||
"fxp1", rtems_fxp_attach, pci_netdriver_config+2,
|
||||
},
|
||||
#else
|
||||
{
|
||||
"", libbsdport_netdriver_attach, pci_netdriver_config+2,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
"elnk1", rtems_elnk_driver_attach, isa_netdriver_config,
|
||||
},
|
||||
};
|
||||
|
||||
static int pci_check(struct rtems_bsdnet_ifconfig *ocfg, int attaching)
|
||||
{
|
||||
struct rtems_bsdnet_ifconfig *cfg;
|
||||
int if_index_pre;
|
||||
extern int if_index;
|
||||
if ( attaching ) {
|
||||
cfg = pci_initialize() ?
|
||||
isa_netdriver_config : pci_netdriver_config;
|
||||
}
|
||||
while ( cfg ) {
|
||||
printk("Probing '%s'", cfg->name);
|
||||
/* unfortunately, the return value is unreliable - some drivers report
|
||||
* success even if they fail.
|
||||
* Check if they chained an interface (ifnet) structure instead
|
||||
*/
|
||||
if_index_pre = if_index;
|
||||
cfg->attach(cfg, attaching);
|
||||
if ( if_index > if_index_pre ) {
|
||||
/* assume success */
|
||||
printk(" .. seemed to work\n");
|
||||
ocfg->name = cfg->name;
|
||||
ocfg->attach = cfg->attach;
|
||||
return 0;
|
||||
}
|
||||
printk(" .. failed\n");
|
||||
cfg = cfg->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#define NIC_NAME "dummy"
|
||||
#define NIC_ATTACH pci_check
|
||||
|
||||
#else
|
||||
|
||||
#if defined(RTEMS_BSP_NETWORK_DRIVER_NAME) /* Use NIC provided by BSP */
|
||||
|
||||
/* force ne2k_isa on i386 for qemu */
|
||||
#if defined(__i386__)
|
||||
# define NIC_NAME BSP_NE2000_NETWORK_DRIVER_NAME
|
||||
# define NIC_ATTACH BSP_NE2000_NETWORK_DRIVER_ATTACH
|
||||
|
||||
#else
|
||||
|
||||
# define NIC_NAME RTEMS_BSP_NETWORK_DRIVER_NAME
|
||||
# define NIC_ATTACH RTEMS_BSP_NETWORK_DRIVER_ATTACH
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* ifdef MULTI_NETDRIVER */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NIC_NAME
|
||||
|
||||
extern int NIC_ATTACH();
|
||||
|
||||
#if RTEMS_BSP_NETWORK_DRIVER_ATTACH == BSP_NE2000_NETWORK_DRIVER_ATTACH
|
||||
static char ethernet_address[6] = { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x34 };
|
||||
#endif
|
||||
|
||||
static struct rtems_bsdnet_ifconfig netdriver_config[1] = {{
|
||||
NIC_NAME, /* name */
|
||||
(int (*)(struct rtems_bsdnet_ifconfig*,int))NIC_ATTACH, /* attach function */
|
||||
0, /* link to next interface */
|
||||
FIXED_IP_ADDR,
|
||||
FIXED_NETMASK
|
||||
#if RTEMS_BSP_NETWORK_DRIVER_ATTACH == BSP_NE2000_NETWORK_DRIVER_ATTACH
|
||||
,
|
||||
ethernet_address,
|
||||
irno:9,
|
||||
port:0xc100
|
||||
#endif
|
||||
}};
|
||||
#else
|
||||
#warning "NO KNOWN NETWORK DRIVER FOR THIS BSP -- YOU MAY HAVE TO EDIT networkconfig.h"
|
||||
#endif
|
||||
|
||||
struct rtems_bsdnet_config rtems_bsdnet_config = {
|
||||
#ifdef NIC_NAME
|
||||
netdriver_config, /* link to next interface */
|
||||
RTEMS_DO_BOOTP, /* Use BOOTP to get network configuration */
|
||||
#else
|
||||
0,
|
||||
0,
|
||||
#endif
|
||||
NETWORK_TASK_PRIORITY, /* Network task priority */
|
||||
#if defined(MEMORY_CUSTOM)
|
||||
MEMORY_CUSTOM,
|
||||
#elif defined(MEMORY_SCARCE)
|
||||
100*1024, /* MBUF space */
|
||||
200*1024, /* MBUF cluster space */
|
||||
#elif defined(MEMORY_HUGE)
|
||||
2*1024*1024, /* MBUF space */
|
||||
5*1024*1024, /* MBUF cluster space */
|
||||
#else
|
||||
180*1024, /* MBUF space */
|
||||
350*1024, /* MBUF cluster space */
|
||||
#endif
|
||||
#if (!defined (RTEMS_USE_BOOTP)) && defined(ON_RTEMS_LAB_WINSYSTEMS)
|
||||
"rtems", /* Host name */
|
||||
"nodomain.com", /* Domain name */
|
||||
"192.168.1.14", /* Gateway */
|
||||
"192.168.1.1", /* Log host */
|
||||
{"89.212.75.6" }, /* Name server(s) */
|
||||
{"192.168.1.1" }, /* NTP server(s) */
|
||||
#else
|
||||
NULL, /* Host name */
|
||||
NULL, /* Domain name */
|
||||
NULL, /* Gateway */
|
||||
NULL, /* Log host */
|
||||
{ NULL }, /* Name server(s) */
|
||||
{ NULL }, /* NTP server(s) */
|
||||
#endif /* !RTEMS_USE_BOOTP */
|
||||
0, /* efficiency */
|
||||
0, /* udp TX buffer */
|
||||
0, /* udp RX buffer */
|
||||
0, /* tcp TX buffer */
|
||||
0, /* tcp RX buffer */
|
||||
};
|
||||
#endif /* _RTEMS_NETWORKCONFIG_H_ */
|
||||
@@ -1,38 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <rtems/error.h>
|
||||
|
||||
#include "rtemsNetworking.h"
|
||||
|
||||
#include <epicsExit.h>
|
||||
#include <osdTime.h>
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
extern void pvDatabaseAllTests(void);
|
||||
|
||||
rtems_task
|
||||
Init (rtems_task_argument ignored)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
rtems_bsdnet_initialize_network ();
|
||||
//rtems_bsdnet_show_if_stats ();
|
||||
|
||||
rtems_time_of_day timeOfDay;
|
||||
if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&timeOfDay) != RTEMS_SUCCESSFUL) {
|
||||
timeOfDay.year = 2014;
|
||||
timeOfDay.month = 1;
|
||||
timeOfDay.day = 1;
|
||||
timeOfDay.hour = 0;
|
||||
timeOfDay.minute = 0;
|
||||
timeOfDay.second = 0;
|
||||
timeOfDay.ticks = 0;
|
||||
|
||||
rtems_status_code ret = rtems_clock_set(&timeOfDay);
|
||||
if (ret != RTEMS_SUCCESSFUL) {
|
||||
printf("**** Can't set time %s\n", rtems_status_text(ret));
|
||||
}
|
||||
}
|
||||
osdTimeRegister();
|
||||
|
||||
pvDatabaseAllTests();
|
||||
epicsExit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
SRC_DIRS += $(PVDATABASE_TEST)/src
|
||||
|
||||
|
||||
TESTPROD_HOST += testPlugin
|
||||
testPlugin_SRCS += testPlugin.cpp
|
||||
testHarness_SRCS += testPlugin.cpp
|
||||
TESTS += testPlugin
|
||||
|
||||
TESTPROD_HOST += testPVCopy
|
||||
testPVCopy_SRCS += testPVCopy.cpp
|
||||
testHarness_SRCS += testPVCopy.cpp
|
||||
@@ -23,7 +29,6 @@ testLocalProvider_SRCS += testLocalProvider.cpp
|
||||
testHarness_SRCS += testLocalProvider.cpp
|
||||
TESTS += testLocalProvider
|
||||
|
||||
|
||||
TESTPROD_HOST += testPVAServer
|
||||
testPVAServer_SRCS += testPVAServer.cpp
|
||||
testHarness_SRCS += testPVAServer.cpp
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/pvAlarm.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/pvStructureCopy.h>
|
||||
|
||||
#ifdef listenerEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
@@ -87,7 +88,7 @@ public:
|
||||
private:
|
||||
Listener(PVRecordPtr const & pvRecord)
|
||||
: pvCopy(
|
||||
PVCopy::create(
|
||||
epics::pvCopy::PVCopy::create(
|
||||
getPVDataCreate()->createPVStructure(
|
||||
pvRecord->getPVRecordStructure()->getPVStructure()),
|
||||
CreateRequest::create()->createRequest(""),
|
||||
@@ -96,7 +97,7 @@ private:
|
||||
recordName(pvRecord->getRecordName())
|
||||
{
|
||||
}
|
||||
PVCopyPtr pvCopy;
|
||||
epics::pvCopy::PVCopyPtr pvCopy;
|
||||
PVStructurePtr pvStructure;
|
||||
string recordName;
|
||||
};
|
||||
|
||||
@@ -68,7 +68,6 @@ static void test()
|
||||
exampleRecord->unlock();
|
||||
}
|
||||
if(debug) {cout << "processed exampleDouble " << endl; }
|
||||
exampleRecord->destroy();
|
||||
recordName = "powerSupplyExample";
|
||||
PowerSupplyPtr psr;
|
||||
pvStructure = createPowerSupply();
|
||||
@@ -127,7 +126,6 @@ static void test()
|
||||
testOk1(psr->getVoltage()==1.0);
|
||||
testOk1(psr->getPower()==1.0);
|
||||
testOk1(psr->getCurrent()==1.0);
|
||||
psr->destroy();
|
||||
}
|
||||
|
||||
MAIN(testExampleRecord)
|
||||
|
||||
@@ -71,7 +71,6 @@ static void test()
|
||||
pvRecord->unlock();
|
||||
}
|
||||
if(debug) {cout << "processed exampleDouble " << endl; }
|
||||
channelProvider->destroy();
|
||||
}
|
||||
|
||||
MAIN(testLocalProvider)
|
||||
|
||||
@@ -67,7 +67,6 @@ static void test()
|
||||
ServerContext::shared_pointer ctx =
|
||||
startPVAServer("local",0,true,true);
|
||||
testOk1(ctx.get()!=0);
|
||||
ctx->destroy();
|
||||
}
|
||||
|
||||
MAIN(testPVAServer)
|
||||
|
||||
@@ -37,6 +37,7 @@ using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvCopy;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
static bool debug = false;
|
||||
@@ -281,7 +282,6 @@ static void scalarTest()
|
||||
string request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVCopyPtr pvCopy;
|
||||
string builder;
|
||||
string valueNameRecord;
|
||||
string valueNameCopy;
|
||||
|
||||
@@ -313,7 +313,6 @@ static void scalarTest()
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
@@ -324,7 +323,6 @@ static void arrayTest()
|
||||
string request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVCopyPtr pvCopy;
|
||||
string builder;
|
||||
string valueNameRecord;
|
||||
string valueNameCopy;
|
||||
|
||||
@@ -350,7 +348,6 @@ static void arrayTest()
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void powerSupplyTest()
|
||||
@@ -361,7 +358,6 @@ static void powerSupplyTest()
|
||||
string request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVCopyPtr pvCopy;
|
||||
string builder;
|
||||
string valueNameRecord;
|
||||
string valueNameCopy;
|
||||
|
||||
@@ -395,7 +391,6 @@ static void powerSupplyTest()
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "power.value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
MAIN(testPVCopy)
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvStructureCopy.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "powerSupply.h"
|
||||
|
||||
@@ -37,6 +37,7 @@ using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvDatabase;
|
||||
using namespace epics::pvCopy;
|
||||
using std::string;
|
||||
|
||||
static bool debug = false;
|
||||
@@ -69,7 +70,6 @@ static void scalarTest()
|
||||
if(pvRecord && debug) {
|
||||
cout << pvRecord << endl;
|
||||
}
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
@@ -81,7 +81,6 @@ static void arrayTest()
|
||||
if(pvRecord && debug) {
|
||||
cout << pvRecord << endl;
|
||||
}
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void powerSupplyTest()
|
||||
@@ -94,7 +93,6 @@ static void powerSupplyTest()
|
||||
if(pvRecord && debug) {
|
||||
cout << pvRecord << endl;
|
||||
}
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
MAIN(testPVRecord)
|
||||
|
||||
278
test/src/testPlugin.cpp
Normal file
278
test/src/testPlugin.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/*testPluginMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/pvStructureCopy.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "powerSupply.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvCopy;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
static bool debug = true;
|
||||
|
||||
static void deadbandTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****deadbandTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,""));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[deadband=abs:1.0]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
pvValue->put(.1);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==0);
|
||||
pvValue->put(1.0);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****arrayTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
size_t n = 10;
|
||||
shared_vector<double> values(n);
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalarArray(pvDouble,""));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleArrayRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoubleArrayPtr pvValue(pvRecordStructure->getSubField<PVDoubleArray>("value"));
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==0);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + .06;
|
||||
const shared_vector<const double> yyy(freeze(values));
|
||||
pvValue->putFrom(yyy);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
}
|
||||
|
||||
static void timeStampTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****timeStampTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,"timeStamp"));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value,timeStamp[timestamp=current]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after update"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==1);
|
||||
pvRecord->process();
|
||||
pvValue->put(1.0);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< " pvRecordStructure\n" << pvRecordStructure
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==2);
|
||||
}
|
||||
|
||||
static void ignoreTest()
|
||||
{
|
||||
if(debug) {cout << endl << endl << "****ignoreTest****" << endl;}
|
||||
bool result = false;
|
||||
uint32 nset = 0;
|
||||
|
||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,"alarm,timeStamp"));
|
||||
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
|
||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value,alarm[ignore=true],timeStamp[ignore=true]"));
|
||||
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
|
||||
PVStringPtr pvMessage(pvRecordStructure->getSubField<PVString>("alarm.message"));
|
||||
PVIntPtr pvUserTag(pvRecordStructure->getSubField<PVInt>("timeStamp.userTag"));
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "initial"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==0);
|
||||
pvMessage->put("test message");
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvMessage"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==1);
|
||||
pvUserTag->put(50);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvMessage"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==false);
|
||||
testOk1(nset==2);
|
||||
pvValue->put(1.0);
|
||||
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
nset = bitSet->cardinality();
|
||||
if(debug) {
|
||||
cout << "after pvValue"
|
||||
<< " result " << (result ? "true" : "false")
|
||||
<< " nset " << nset
|
||||
<< " bitSet " << *bitSet
|
||||
<< " pvStructureCopy\n" << pvStructureCopy
|
||||
<< "\n";
|
||||
}
|
||||
testOk1(result==true);
|
||||
testOk1(nset==3);
|
||||
}
|
||||
|
||||
MAIN(testPlugin)
|
||||
{
|
||||
testPlan(22);
|
||||
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
|
||||
deadbandTest();
|
||||
arrayTest();
|
||||
timeStampTest();
|
||||
ignoreTest();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user