Compare commits
162 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48e6c9f5ef | ||
|
|
073d2acafc | ||
|
|
8cf550ff57 | ||
|
|
c070a3485b | ||
|
|
b31d5079bf | ||
|
|
7c78b15a5c | ||
|
|
cd7d8735af | ||
|
|
94b48e4893 | ||
|
|
9d94e95521 | ||
|
|
e0d5925af3 | ||
|
|
f207e512d6 | ||
|
|
0a7d5b16aa | ||
|
|
aea8d9105e | ||
|
|
d18e0c913a | ||
|
|
e4cb8d2397 | ||
|
|
71b2a4bfe1 | ||
|
|
80703b6de1 | ||
|
|
203ee1b450 | ||
|
|
f43d50768e | ||
|
|
8ec8e47924 | ||
|
|
d374669f04 | ||
|
|
2f53d13021 | ||
|
|
00a8459944 | ||
|
|
91d0d2c315 | ||
|
|
c41f7cb3dc | ||
|
|
dbf83dd017 | ||
|
|
1b787c5149 | ||
|
|
ee3027f641 | ||
|
|
6cd0a1bdb0 | ||
|
|
0d85561481 | ||
|
|
05d54c61e1 | ||
|
|
182eee57e2 | ||
|
|
8daf322025 | ||
|
|
a68ef61a10 | ||
|
|
9dfebf1897 | ||
|
|
0cf706511e | ||
|
|
8cac3975cc | ||
|
|
219e5eaf94 | ||
|
|
f345651b67 | ||
|
|
4895107854 | ||
|
|
1c121b3f1e | ||
|
|
d493e52dda | ||
|
|
91d4d2a423 | ||
|
|
d54031a2fb | ||
|
|
1e1d5455a8 | ||
|
|
426af714a1 | ||
|
|
68bbb55370 | ||
|
|
716ec9857c | ||
|
|
e91b4b1b66 | ||
|
|
2c4e98db8c | ||
|
|
d4a13397d7 | ||
|
|
a622f66a94 | ||
|
|
81abd5f413 | ||
|
|
4df01038c3 | ||
|
|
e648cba659 | ||
|
|
42747b167c | ||
|
|
0a893a331b | ||
|
|
e95c959cfd | ||
|
|
e51c29d147 | ||
|
|
fec903fb06 | ||
|
|
ca066bc088 | ||
|
|
0481a7bf5b | ||
|
|
17f43b4452 | ||
|
|
a1514e5206 | ||
|
|
72c2489921 | ||
|
|
895698c3cd | ||
|
|
9d10b039fb | ||
|
|
bf82de407e | ||
|
|
58a603556b | ||
|
|
22e849c6f7 | ||
|
|
2a4d3a15f8 | ||
|
|
7143a8585f | ||
|
|
2d61b4c0f3 | ||
|
|
120fa22558 | ||
|
|
4ed8e6d625 | ||
|
|
4718021e39 | ||
|
|
b1822f5fbd | ||
|
|
333cd44da0 | ||
|
|
a514ab7b51 | ||
|
|
dafc37b585 | ||
|
|
2432f85784 | ||
|
|
bd1054f247 | ||
|
|
bc70b5f449 | ||
|
|
93a259cbde | ||
|
|
09423edeab | ||
|
|
ac1de6770e | ||
|
|
5427311390 | ||
|
|
b62b047f63 | ||
|
|
3bc89bfe0e | ||
|
|
cb5d9f976a | ||
|
|
3f5bfd067f | ||
|
|
85165e6579 | ||
|
|
476a8f1e32 | ||
| 31e883dbbc | |||
| 57cbf66833 | |||
| 7f31332a80 | |||
|
|
12015309d8 | ||
|
|
1e62844a22 | ||
|
|
ad479309b0 | ||
|
|
2f7c82757f | ||
|
|
634153a28d | ||
|
|
e664037063 | ||
|
|
75c16bd423 | ||
|
|
083dffac3c | ||
|
|
42ba054e5f | ||
|
|
3173e9aeae | ||
|
|
785d654129 | ||
|
|
22ce4440b7 | ||
|
|
80baccfd9c | ||
|
|
0c92f07749 | ||
|
|
73a9f1f84f | ||
|
|
3c3f0ab7f1 | ||
|
|
803098922a | ||
|
|
c028af8b6d | ||
|
|
d33d03189e | ||
|
|
d7bd5628d4 | ||
|
|
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 |
93
.appveyor.yml
Normal file
93
.appveyor.yml
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# .appveyor.yml for use with EPICS Base ci-scripts
|
||||||
|
# (see: https://github.com/epics-base/ci-scripts)
|
||||||
|
|
||||||
|
# This is YAML - indentation levels are crucial
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- C:\Users\appveyor\.tools
|
||||||
|
|
||||||
|
#---------------------------------#
|
||||||
|
# repository cloning #
|
||||||
|
#---------------------------------#
|
||||||
|
|
||||||
|
init:
|
||||||
|
# Set autocrlf to make batch files work
|
||||||
|
- git config --global core.autocrlf true
|
||||||
|
|
||||||
|
clone_depth: 5
|
||||||
|
|
||||||
|
# Build Configurations: dll/static, regular/debug
|
||||||
|
configuration:
|
||||||
|
- dynamic
|
||||||
|
- static
|
||||||
|
- dynamic-debug
|
||||||
|
- static-debug
|
||||||
|
|
||||||
|
# Default OS Image
|
||||||
|
image: Visual Studio 2019
|
||||||
|
|
||||||
|
# Environment variables: compiler toolchain, base version, setup file, ...
|
||||||
|
environment:
|
||||||
|
# common / default variables for all jobs
|
||||||
|
SETUP_PATH: .ci-local:.ci
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
- BASE: 3.15
|
||||||
|
CMP: vs2019
|
||||||
|
- BASE: 7.0
|
||||||
|
CMP: vs2019
|
||||||
|
- BASE: 7.0
|
||||||
|
CMP: gcc
|
||||||
|
- BASE: 7.0
|
||||||
|
CMP: vs2017
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
|
||||||
|
# Platform: processor architecture
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
|
||||||
|
#---------------------------------#
|
||||||
|
# building & testing #
|
||||||
|
#---------------------------------#
|
||||||
|
|
||||||
|
install:
|
||||||
|
- cmd: git submodule update --init --recursive
|
||||||
|
- cmd: pip install git+https://github.com/mdavidsaver/ci-core-dumper#egg=ci-core-dumper
|
||||||
|
- cmd: python .ci/cue.py prepare
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- cmd: python .ci/cue.py build
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- cmd: python -m ci_core_dumper install
|
||||||
|
- cmd: python .ci/cue.py -T 20M test
|
||||||
|
|
||||||
|
on_finish:
|
||||||
|
- ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||||
|
- cmd: python .ci/cue.py -T 5M test-results
|
||||||
|
|
||||||
|
on_failure:
|
||||||
|
- cmd: python -m ci_core_dumper report
|
||||||
|
|
||||||
|
#---------------------------------#
|
||||||
|
# debugging #
|
||||||
|
#---------------------------------#
|
||||||
|
|
||||||
|
## if you want to connect by remote desktop to a failed build, uncomment these lines
|
||||||
|
## note that you will need to connect within the usual build timeout limit (60 minutes)
|
||||||
|
## so you may want to adjust the build matrix above to just build the one of interest
|
||||||
|
|
||||||
|
#on_failure:
|
||||||
|
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||||
|
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||||
|
|
||||||
|
#---------------------------------#
|
||||||
|
# notifications #
|
||||||
|
#---------------------------------#
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
- provider: Email
|
||||||
|
to:
|
||||||
|
- core-talk@aps.anl.gov
|
||||||
|
on_build_success: false
|
||||||
|
- provider: GitHubPullRequest
|
||||||
1
.ci
Submodule
1
.ci
Submodule
Submodule .ci added at 130e88b709
14
.ci-local/defaults.set
Normal file
14
.ci-local/defaults.set
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# EPICS Base
|
||||||
|
BASE_DIRNAME=base
|
||||||
|
BASE_REPONAME=epics-base
|
||||||
|
BASE_REPOOWNER=epics-base
|
||||||
|
BASE_VARNAME=EPICS_BASE
|
||||||
|
BASE_RECURSIVE=NO
|
||||||
|
|
||||||
|
MODULES=PVDATA PVACCESS
|
||||||
|
|
||||||
|
PVDATA_REPONAME=pvDataCPP
|
||||||
|
PVDATA_REPOOWNER=epics-base
|
||||||
|
|
||||||
|
PVACCESS_REPONAME=pvAccessCPP
|
||||||
|
PVACCESS_REPOOWNER=epics-base
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e -x
|
|
||||||
|
|
||||||
make -j2 $EXTRA
|
|
||||||
|
|
||||||
if [ "$TEST" != "NO" ]
|
|
||||||
then
|
|
||||||
make -j2 tapfiles
|
|
||||||
make -j2 -s test-results
|
|
||||||
fi
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
#!/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
|
|
||||||
172
.github/workflows/ci-scripts-build.yml
vendored
Normal file
172
.github/workflows/ci-scripts-build.yml
vendored
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
|
||||||
|
# (see: https://github.com/epics-base/ci-scripts)
|
||||||
|
|
||||||
|
# This is YAML - indentation levels are crucial
|
||||||
|
|
||||||
|
# Workflow name
|
||||||
|
|
||||||
|
name: Base
|
||||||
|
|
||||||
|
# Trigger on pushes and PRs to any branch
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- 'documentation/*'
|
||||||
|
- '.appveyor.yml'
|
||||||
|
- '.readthedocs.yml'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'documentation/*'
|
||||||
|
- '.appveyor.yml'
|
||||||
|
- '.readthedocs.yml'
|
||||||
|
|
||||||
|
env:
|
||||||
|
SETUP_PATH: .ci-local:.ci
|
||||||
|
EPICS_TEST_IMPRECISE_TIMING: YES
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-base:
|
||||||
|
name: ${{ matrix.name }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
# Set environment variables from matrix parameters
|
||||||
|
env:
|
||||||
|
BASE: ${{ matrix.base }}
|
||||||
|
CMP: ${{ matrix.cmp }}
|
||||||
|
BCFG: ${{ matrix.configuration }}
|
||||||
|
CI_CROSS_TARGETS: ${{ matrix.cross }}
|
||||||
|
EXTRA: ${{ matrix.extra }}
|
||||||
|
TEST: ${{ matrix.test }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Job names also name artifacts, character limitations apply
|
||||||
|
include:
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
cross: "windows-x64-mingw"
|
||||||
|
name: "7.0 Ub-22 gcc + MinGW"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: static
|
||||||
|
base: "7.0"
|
||||||
|
cross: "windows-x64-mingw"
|
||||||
|
name: "7.0 Ub-22 gcc + MinGW, static"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: static
|
||||||
|
base: "7.0"
|
||||||
|
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||||
|
name: "7.0 Ub-22 gcc C++11, static"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: static
|
||||||
|
base: "7.0"
|
||||||
|
extra: "CMD_CFLAGS=-funsigned-char CMD_CXXFLAGS=-funsigned-char"
|
||||||
|
name: "7.0 Ub-22 gcc uchar"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: clang
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
name: "7.0 Ub-22 clang"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: clang
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||||
|
name: "7.0 Ub-22 clang C++11"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
cross: "RTEMS-pc686-qemu@5"
|
||||||
|
name: "7.0 Ub-22 gcc + RT-5.1 pc686"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
cross: "RTEMS-pc386-qemu@4.10"
|
||||||
|
test: NO
|
||||||
|
name: "7.0 Ub-22 gcc + RT-4.10"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
cross: "RTEMS-pc386-qemu@4.9"
|
||||||
|
name: "7.0 Ub-22 gcc + RT-4.9"
|
||||||
|
|
||||||
|
- os: macos-latest
|
||||||
|
cmp: clang
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
name: "7.0 MacOS clang"
|
||||||
|
|
||||||
|
- os: windows-2019
|
||||||
|
cmp: vs2019
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
name: "7.0 Win2019 MSC-19"
|
||||||
|
extra: "CMD_CXXFLAGS=-analysis"
|
||||||
|
|
||||||
|
- os: windows-2019
|
||||||
|
cmp: vs2019
|
||||||
|
configuration: static
|
||||||
|
base: "7.0"
|
||||||
|
name: "7.0 Win2019 MSC-19, static"
|
||||||
|
extra: "CMD_CXXFLAGS=-analysis"
|
||||||
|
|
||||||
|
- os: windows-2019
|
||||||
|
cmp: vs2019
|
||||||
|
configuration: debug
|
||||||
|
base: "7.0"
|
||||||
|
name: "7.0 Win2019 MSC-19, debug"
|
||||||
|
|
||||||
|
- os: windows-2019
|
||||||
|
cmp: gcc
|
||||||
|
configuration: default
|
||||||
|
base: "7.0"
|
||||||
|
name: "7.0 Win2019 mingw"
|
||||||
|
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
cmp: gcc
|
||||||
|
configuration: default
|
||||||
|
base: "3.15"
|
||||||
|
wine: "64"
|
||||||
|
name: "3.15 Ub-22 gcc + MinGW"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Automatic core dump analysis
|
||||||
|
uses: mdavidsaver/ci-core-dumper@master
|
||||||
|
- name: "apt-get install"
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
- name: Prepare and compile dependencies
|
||||||
|
run: python .ci/cue.py prepare
|
||||||
|
- name: Build main module
|
||||||
|
run: python .ci/cue.py build
|
||||||
|
- name: Run main module tests
|
||||||
|
run: python .ci/cue.py -T 20M test
|
||||||
|
- name: Upload tapfiles Artifact
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: tapfiles ${{ matrix.name }}
|
||||||
|
path: '**/O.*/*.tap'
|
||||||
|
if-no-files-found: ignore
|
||||||
|
- name: Collect and show test results
|
||||||
|
if: ${{ always() }}
|
||||||
|
run: python .ci/cue.py -T 5M test-results
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule ".ci"]
|
||||||
|
path = .ci
|
||||||
|
url = https://github.com/epics-base/ci-scripts
|
||||||
17
.readthedocs.yml
Normal file
17
.readthedocs.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# .readthedocs.yml
|
||||||
|
# Read the Docs configuration file
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Build documentation in the documentation/ directory with Sphinx
|
||||||
|
sphinx:
|
||||||
|
configuration: documentation/conf.py
|
||||||
|
|
||||||
|
# Build documentation with MkDocs
|
||||||
|
#mkdocs:
|
||||||
|
# configuration: mkdocs.yml
|
||||||
|
|
||||||
|
# Optionally build your docs in additional formats such as PDF and ePub
|
||||||
|
formats: all
|
||||||
31
.travis.yml
31
.travis.yml
@@ -1,31 +0,0 @@
|
|||||||
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
|
|
||||||
6
Doxyfile
6
Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = pvDatabaseCPP
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER =
|
PROJECT_NUMBER = 4.7.3-dev
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
@@ -765,7 +765,7 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = include
|
INPUT = src
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
@@ -1035,7 +1035,7 @@ GENERATE_HTML = YES
|
|||||||
# The default directory is: html.
|
# The default directory is: html.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_OUTPUT = documentation/html
|
HTML_OUTPUT = html/doxygen
|
||||||
|
|
||||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
||||||
# generated HTML page (for example: .htm, .php, .asp).
|
# generated HTML page (for example: .htm, .php, .asp).
|
||||||
|
|||||||
12
configure/CONFIG_PVDATABASE_VERSION
Normal file
12
configure/CONFIG_PVDATABASE_VERSION
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Version number for the PV Database API and shared library
|
||||||
|
|
||||||
|
EPICS_PVDATABASE_MAJOR_VERSION = 4
|
||||||
|
EPICS_PVDATABASE_MINOR_VERSION = 7
|
||||||
|
EPICS_PVDATABASE_MAINTENANCE_VERSION = 3
|
||||||
|
|
||||||
|
# Development flag, set to zero for release versions
|
||||||
|
|
||||||
|
EPICS_PVDATABASE_DEVELOPMENT_FLAG = 1
|
||||||
|
|
||||||
|
# Immediately after a release the MAINTENANCE_VERSION
|
||||||
|
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||||
@@ -2,6 +2,8 @@ TOP=..
|
|||||||
|
|
||||||
include $(TOP)/configure/CONFIG
|
include $(TOP)/configure/CONFIG
|
||||||
|
|
||||||
|
CFG += CONFIG_PVDATABASE_VERSION
|
||||||
|
|
||||||
TARGETS = $(CONFIG_TARGETS)
|
TARGETS = $(CONFIG_TARGETS)
|
||||||
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,79 @@
|
|||||||
|
|
||||||
This document summarizes the changes to the module between releases.
|
This document summarizes the changes to the module between releases.
|
||||||
|
|
||||||
|
## Release 4.7.2 (EPICS 7.0.9, Feb 2025)
|
||||||
|
|
||||||
|
* Resolved issue with changed field set in the case where the top level (master)
|
||||||
|
field ("_") is not requested by the client, but the master field callback causes
|
||||||
|
all fields to be marked as updated, rather than only those fields that have
|
||||||
|
actually been modified.
|
||||||
|
|
||||||
|
## Release 4.7.1 (EPICS 7.0.8, Dec 2023)
|
||||||
|
|
||||||
|
* Added data distributor plugin which can be used for distributing data between
|
||||||
|
a group of clients. The plugin is triggered by the request string of the
|
||||||
|
form:
|
||||||
|
|
||||||
|
`_[distributor=group:<group id>;set:<set_id>;trigger:<field_name>;updates:<n_updates>;mode:<update_mode>]`
|
||||||
|
|
||||||
|
The plugin parameters are optional and are described bellow:
|
||||||
|
|
||||||
|
- group: this parameter indicates a group that client application belongs to (default value: "default"); groups of clients are completely independent of each other
|
||||||
|
|
||||||
|
- set: this parameter designates a client set that application belongs to within its group (default value: "default")
|
||||||
|
|
||||||
|
- trigger: this is the PV structure field that distinguishes different channel updates (default value: "timeStamp"); for example, for area detector images one could use the "uniqueId" field of the NTND structure
|
||||||
|
|
||||||
|
- updates: this parameter configures how many sequential updates a client (or a set of clients) will receive before the data distributor starts updating the next one (default value: "1")
|
||||||
|
|
||||||
|
- mode: this parameter configures how channel updates are to be distributed between clients in a set:
|
||||||
|
- one: update goes to one client per set
|
||||||
|
- all: update goes to all clients in a set
|
||||||
|
- default is "one" if client set id is not specified, and "all" if set id is specified
|
||||||
|
|
||||||
|
For more information and examples of usage see the [plugin documentation](dataDistributorPlugin.md).
|
||||||
|
|
||||||
|
## Release 4.7.0 (EPICS 7.0.7, Sep 2022)
|
||||||
|
|
||||||
|
* Added support for the whole structure (master field) server side plugins.
|
||||||
|
The whole structure is identified as the `_` string, and a pvRequest string
|
||||||
|
that applies a plugin to it takes the form:
|
||||||
|
|
||||||
|
`field(_[XYZ=A:3;B:uniqueId])`
|
||||||
|
|
||||||
|
where `XYZ` is the name of a specific filter plugin that takes parameters
|
||||||
|
`A` and `B` with values `3` and `uniqueId` respectively.
|
||||||
|
|
||||||
|
## Release 4.6.0 (EPICS 7.0.6, Jul 2021)
|
||||||
|
|
||||||
|
* Access Security is now supported.
|
||||||
|
* <b>special</b> has been revised and extended.
|
||||||
|
* addRecord, removeRecord, processRecord, and traceRecord are replaced by pvdbcr versions.
|
||||||
|
* <b>support</b> is DEPRECATED
|
||||||
|
|
||||||
|
## Release 4.5.3 (EPICS 7.0.5, Feb 2021)
|
||||||
|
|
||||||
|
* The previously deprecated destroy methods have been removed.
|
||||||
|
Any application code that was previously calling these can just remove
|
||||||
|
those calls.
|
||||||
|
|
||||||
|
## Release 4.5.2 (EPICS 7.0.3.2, May 2020)
|
||||||
|
|
||||||
|
* plugin support is new
|
||||||
|
* fixed issues #53 and #52
|
||||||
|
|
||||||
|
## Release 4.5.1 (EPICS 7.0.3.1, Nov 2019)
|
||||||
|
|
||||||
|
* addRecord is new.
|
||||||
|
* Doxygen updates and read-the-docs integration.
|
||||||
|
|
||||||
|
|
||||||
|
## Release 4.5.0 (EPICS 7.0.3, Jul 2019)
|
||||||
|
|
||||||
|
* support is a new feature.
|
||||||
|
* processRecord is new.
|
||||||
|
|
||||||
|
|
||||||
## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019)
|
## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019)
|
||||||
|
|
||||||
Formerly if a client makes a request for a subfield of a non structure field
|
Formerly if a client makes a request for a subfield of a non structure field
|
||||||
@@ -15,6 +88,7 @@ Now if a request is made for a subfield of a non structure field
|
|||||||
b) if the subfield is the type for the current union the request succeeds
|
b) if the subfield is the type for the current union the request succeeds
|
||||||
c) if type is not the same an exception is thrown
|
c) if type is not the same an exception is thrown
|
||||||
|
|
||||||
|
|
||||||
## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019)
|
## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019)
|
||||||
|
|
||||||
* Cleaned up some build warnings.
|
* Cleaned up some build warnings.
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
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
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Currently only some simple tests exist. Most of the testing has been via the examples
|
|
||||||
7
documentation/_static/css/custom.css
Normal file
7
documentation/_static/css/custom.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.wy-side-nav-search {
|
||||||
|
background-color: #18334B;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search input[type="text"] {
|
||||||
|
border-color: #18334b;
|
||||||
|
}
|
||||||
80
documentation/conf.py
Normal file
80
documentation/conf.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# This file only contains a selection of the most common options. For a full
|
||||||
|
# list see the documentation:
|
||||||
|
# http://www.sphinx-doc.org/en/master/config
|
||||||
|
|
||||||
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = 'normativeTypes (C++)'
|
||||||
|
copyright = '2019, EPICS Controls.'
|
||||||
|
author = 'EPICS'
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = [
|
||||||
|
'sphinx.ext.intersphinx',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
# Intersphinx links to subprojects
|
||||||
|
intersphinx_mapping = {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
html_css_files = [
|
||||||
|
'css/custom.css',
|
||||||
|
]
|
||||||
|
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
html_theme_options = {
|
||||||
|
'logo_only': True,
|
||||||
|
}
|
||||||
|
html_logo = "images/EPICS_white_logo_v02.png"
|
||||||
|
|
||||||
|
html_extra_path = [
|
||||||
|
'../html',
|
||||||
|
'pvDatabaseCPP.html',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Run Doxygen ------------------------------------------------------------
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
subprocess.call('cd ..; mkdir -p html/doxygen; doxygen', shell=True)
|
||||||
233
documentation/dataDistributorPlugin.md
Normal file
233
documentation/dataDistributorPlugin.md
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
# Data Distributor Plugin
|
||||||
|
|
||||||
|
The data distributor plugin enables distribution of channel data between
|
||||||
|
multiple client applications. The plugin considers two basic use cases
|
||||||
|
for a group of clients:
|
||||||
|
|
||||||
|
- For simple parallel processing where client applications do not need
|
||||||
|
to share data all clients in a group receive n sequential updates
|
||||||
|
in a round-robin fashion: client \#1 sees the first n updates, client \#2 the
|
||||||
|
second n updates, and so on.
|
||||||
|
|
||||||
|
- For data analysis where several cooperating client applications must all
|
||||||
|
see the same data in order to process it the applications are grouped
|
||||||
|
into sets, and each set of clients receives the same number of sequential
|
||||||
|
updates. The first n updates are sent to all members of client set #1, the second n updates are sent to all members of client set #2, and so on.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
This plugin relies on the pvDatabase plugin framework and requires
|
||||||
|
epics base version > 7.0.7
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The PV request object which triggers plugin instantiation is defined below:
|
||||||
|
|
||||||
|
```
|
||||||
|
"_[distributor=group:<group id>;set:<set_id>;trigger:<field_name>;updates:<n_updates>;mode:<update_mode>]"
|
||||||
|
```
|
||||||
|
|
||||||
|
The underscore character at the begining of the PV request object
|
||||||
|
indicates that the data distributor will be targeting entire PV structure.
|
||||||
|
The same PV request object format should work regardless of the language
|
||||||
|
in which a particular client application is written.
|
||||||
|
|
||||||
|
The plugin parameters are the following:
|
||||||
|
|
||||||
|
- `group:<group_id>`: specifying a `group_id` names a group the client application belongs to (default value: `default`); clients with different group names are
|
||||||
|
completely independent of each other
|
||||||
|
|
||||||
|
- `set:<set_id>`: this parameter designates a client set that application belongs to within its group (default value: `default`)
|
||||||
|
|
||||||
|
- `trigger:<field_name>`: this is the PV structure field that distinguishes
|
||||||
|
different channel updates (default value: `timeStamp`); for example,
|
||||||
|
for area detector images one could use the `uniqueId` field of the NTND
|
||||||
|
structure
|
||||||
|
|
||||||
|
- `updates:<n_updates>`: this parameter must be an integer and configures how many sequential updates a client (or a set of clients) will receive before the data distributor starts updating the next one (default value: `1`)
|
||||||
|
|
||||||
|
- `mode:<update_mode>`: this parameter configures how channel updates are to be
|
||||||
|
distributed between clients in a set:
|
||||||
|
- `one`: update goes to one client per set
|
||||||
|
- `all`: update goes to all clients in a set
|
||||||
|
- default is `one` if client set id is not specified, and `all` if set
|
||||||
|
id is specified
|
||||||
|
|
||||||
|
The plugin obeys the following rules:
|
||||||
|
|
||||||
|
- Parameter names are case insensitive, but the string values
|
||||||
|
are not. For example, "group=abc" and "group=ABC" would indicate two
|
||||||
|
different groups of clients. String values allow alphanumeric characters,
|
||||||
|
as well as dashes and underscores.
|
||||||
|
|
||||||
|
- Updates for a set of clients are configured when the first client in
|
||||||
|
the set requests data. Configuration values (i.e., "trigger",
|
||||||
|
"updates", and "mode"), passed in the PV request by the subsequent
|
||||||
|
clients are ignored.
|
||||||
|
|
||||||
|
- A set is removed from the group once the last client in that
|
||||||
|
set disconnects.
|
||||||
|
|
||||||
|
- A group is removed from the distributor plugin once all of its
|
||||||
|
clients have disconnected.
|
||||||
|
|
||||||
|
- Different client groups are completely independent of each other.
|
||||||
|
In other words, channel updates sent to clients belonging to
|
||||||
|
group A do not interfere with updates sent to clients
|
||||||
|
belonging to group B.
|
||||||
|
|
||||||
|
- The order in which clients and groups receive data is on a
|
||||||
|
"first connected, first served basis".
|
||||||
|
|
||||||
|
- The current channel PV object is always distributed to a client on an
|
||||||
|
initial connect.
|
||||||
|
|
||||||
|
- Data distribution is dynamic with respect to the number of clients.
|
||||||
|
As clients connect and disconnect, the data distribution in a group adjusts
|
||||||
|
accordingly. For example, with a group of clients configured to
|
||||||
|
distribute one sequential update to each client, three clients would each be
|
||||||
|
receiving every third update; after client number four connects, all
|
||||||
|
clients would start receiving every fourth update; if one of those then
|
||||||
|
disconnects, remaining three clients would again be receiving every third
|
||||||
|
update.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
For all examples below we assume that PVDatabase server is serving
|
||||||
|
area detector images on the channel 'image'. All clients are started before
|
||||||
|
the server itself, and the initial (empty) object has unique id of 0.
|
||||||
|
|
||||||
|
### Example 1
|
||||||
|
|
||||||
|
This example show behavior of three clients that belong to the same (default)
|
||||||
|
group. Each client receives one sequential update in a round-robin fashion.
|
||||||
|
Note that all clients received current object on initial connection,
|
||||||
|
and every third object afterward:
|
||||||
|
|
||||||
|
Client 1:
|
||||||
|
```
|
||||||
|
$ pvget -m -r _[distributor=trigger:uniqueId] image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 1
|
||||||
|
int uniqueId 4
|
||||||
|
int uniqueId 7
|
||||||
|
int uniqueId 10
|
||||||
|
```
|
||||||
|
|
||||||
|
Client 2:
|
||||||
|
```
|
||||||
|
$ pvget -m -r _[distributor=trigger:uniqueId] image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 2
|
||||||
|
int uniqueId 5
|
||||||
|
int uniqueId 8
|
||||||
|
int uniqueId 11
|
||||||
|
```
|
||||||
|
|
||||||
|
Client 3:
|
||||||
|
```
|
||||||
|
$ pvget -m -r _[distributor=trigger:uniqueId] image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 3
|
||||||
|
int uniqueId 6
|
||||||
|
int uniqueId 9
|
||||||
|
int uniqueId 12
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2
|
||||||
|
|
||||||
|
In this example we have two sets of two clients, each client set receiving
|
||||||
|
three sequential updates. Both clients from client set \#1 receive updates
|
||||||
|
(1,2,3), both clients from client set \#2 receive updates (4,5,6),
|
||||||
|
client set \#1 receives updates (7,8,9), and so on.
|
||||||
|
|
||||||
|
Client 1 and Client 2/Set 1:
|
||||||
|
```
|
||||||
|
$ pvget -m -r "_[distributor=set:S1;trigger:uniqueId;updates:3]" image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 1
|
||||||
|
int uniqueId 2
|
||||||
|
int uniqueId 3
|
||||||
|
int uniqueId 7
|
||||||
|
int uniqueId 8
|
||||||
|
int uniqueId 9
|
||||||
|
int uniqueId 13
|
||||||
|
int uniqueId 14
|
||||||
|
int uniqueId 15
|
||||||
|
```
|
||||||
|
|
||||||
|
Client 3 and Client 4/Set 2:
|
||||||
|
```
|
||||||
|
$ pvget -m -r "_[distributor=set:S2;trigger:uniqueId;updates:3]" image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 4
|
||||||
|
int uniqueId 5
|
||||||
|
int uniqueId 6
|
||||||
|
int uniqueId 10
|
||||||
|
int uniqueId 11
|
||||||
|
int uniqueId 12
|
||||||
|
int uniqueId 16
|
||||||
|
int uniqueId 17
|
||||||
|
int uniqueId 18
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3
|
||||||
|
|
||||||
|
This example illustrates what happens when multiple independent groups of
|
||||||
|
clients connect to the same channel. Group G1 has two clients belonging
|
||||||
|
to the same default set, and requesting one sequential update per client, while
|
||||||
|
Group G2 has two clients in the default set requesting three
|
||||||
|
sequential updates per client.
|
||||||
|
|
||||||
|
In this case the first client in group G1 receives updates
|
||||||
|
(1,3,5,...), while the second one receives updates (2,4,6,...). On the
|
||||||
|
other hand, the first client in group G2 receives updates
|
||||||
|
(1,2,3,7,8,9,...), while the second one receives updates (4,5,6,10,11,12,...).
|
||||||
|
|
||||||
|
Client 1/Group G1:
|
||||||
|
```
|
||||||
|
$ pvget -m -r "_[distributor=group:G1;trigger:uniqueId]" image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 1
|
||||||
|
int uniqueId 3
|
||||||
|
int uniqueId 5
|
||||||
|
int uniqueId 7
|
||||||
|
int uniqueId 9
|
||||||
|
```
|
||||||
|
|
||||||
|
Client 2/Group G1:
|
||||||
|
```
|
||||||
|
pvget -m -r "_[distributor=group:G1;trigger:uniqueId]" image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 2
|
||||||
|
int uniqueId 4
|
||||||
|
int uniqueId 6
|
||||||
|
int uniqueId 8
|
||||||
|
```
|
||||||
|
|
||||||
|
Client 1/Group G2:
|
||||||
|
```
|
||||||
|
$ pvget -m -r "_[distributor=group:G2;trigger:uniqueId;updates:3]" image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 1
|
||||||
|
int uniqueId 2
|
||||||
|
int uniqueId 3
|
||||||
|
int uniqueId 7
|
||||||
|
int uniqueId 8
|
||||||
|
int uniqueId 9
|
||||||
|
```
|
||||||
|
|
||||||
|
Client 2/Group G2:
|
||||||
|
```
|
||||||
|
$ pvget -m -r "_[distributor=group:G2;trigger:uniqueId;updates:3]" image | grep uniqueId
|
||||||
|
int uniqueId 0
|
||||||
|
int uniqueId 4
|
||||||
|
int uniqueId 5
|
||||||
|
int uniqueId 6
|
||||||
|
int uniqueId 10
|
||||||
|
int uniqueId 11
|
||||||
|
int uniqueId 12
|
||||||
|
```
|
||||||
|
|
||||||
|
The above shows that the two client groups do not interfere with each other.
|
||||||
|
|
||||||
BIN
documentation/images/EPICS_white_logo_v02.png
Normal file
BIN
documentation/images/EPICS_white_logo_v02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
17
documentation/index.rst
Normal file
17
documentation/index.rst
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
pvDatabase (C++) Library
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
EPICS Website <https://epics-controls.org>
|
||||||
|
EPICS Documentation Home <https://docs.epics-controls.org>
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: pvDatabaseCPP
|
||||||
|
|
||||||
|
Reference Manual <https://docs.epics-controls.org/projects/pvdatabase-cpp/en/latest/pvDatabaseCPP.html>
|
||||||
|
API Documentation <https://docs.epics-controls.org/projects/pvdatabase-cpp/en/latest/doxygen>
|
||||||
|
Source Code Repository on GitHub <https://github.com/epics-base/pvDatabaseCPP>
|
||||||
@@ -4,69 +4,62 @@
|
|||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||||
<title>pvDatabaseCPP</title>
|
<title>EPICS pvDatabaseCPP</title>
|
||||||
<link rel="stylesheet" type="text/css"
|
<link rel="stylesheet" type="text/css"
|
||||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
href="https://mrkraimer.github.io/website/css/base.css" />
|
||||||
<link rel="stylesheet" type="text/css"
|
<link rel="stylesheet" type="text/css"
|
||||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
href="https://mrkraimer.github.io/website/css/epicsv4.css" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
/*<![CDATA[*/
|
/*<![CDATA[*/
|
||||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||||
table { margin-left: auto; margin-right: auto }
|
table { margin-left: auto; margin-right: auto }
|
||||||
.diagram { text-align: center; margin: 2.5em 0 }
|
.diagram { text-align: center; margin: 2.5em 0 }
|
||||||
span.opt { color: grey }
|
body { margin-right: 10% }
|
||||||
span.nterm { font-style:italic }
|
/*]]>*/</style>
|
||||||
span.term { font-family:courier }
|
|
||||||
span.user { font-family:courier }
|
<!-- Script that generates the Table of Contents -->
|
||||||
span.user:before { content:"<" }
|
<script type="text/javascript" src="https://mrkraimer.github.io/website/css/tocgen.js"></script>
|
||||||
span.user:after { content:">" }
|
|
||||||
.nonnorm { font-style:italic }
|
|
||||||
p.ed { color: #AA0000 }
|
|
||||||
span.ed { color: #AA0000 }
|
|
||||||
p.ed.priv { display: inline; }
|
|
||||||
span.ed.priv { display: inline; }
|
|
||||||
/*]]>*/</style>
|
|
||||||
<!-- Script that generates the Table of Contents -->
|
|
||||||
<script type="text/javascript"
|
|
||||||
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="head">
|
<div class="head">
|
||||||
<h1>pvDatabaseCPP</h1>
|
<h1>EPICS pvDatabaseCPP</h1>
|
||||||
<h2 class="nocount">Release 4.4 - December 2018</h2>
|
<h2 class="nocount">Release 4.6.0 - March 2021</h2>
|
||||||
|
|
||||||
|
|
||||||
<h2 class="nocount">Abstract</h2>
|
<h2 class="nocount">Abstract</h2>
|
||||||
|
|
||||||
<p>This document describes pvDatabaseCPP,
|
<p><b>pvDatabase</b> is a framework for implementing a network accessible database of smart memory resident
|
||||||
which is a framework for implementing a network accessible database of smart memory resident
|
|
||||||
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
|
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
|
||||||
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
|
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
|
||||||
The framework can be extended in order to create record instances that implements services.
|
The framework can be extended in order to create record instances that implements services.
|
||||||
The minimum that an extension must provide is a top level PVStructure and a process method.
|
The minimum that an extension must provide is a top level PVStructure and a process method.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- last para of Abstract is boilerplate reference to EPICS -->
|
<!-- last para of Abstract is boilerplate reference to EPICS -->
|
||||||
<p>For more information about EPICS generally, please refer to the home page of the <a
|
<p>For more information about EPICS generally, please refer to the home page of the <a
|
||||||
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
|
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
|
||||||
Control System</a>.</p>
|
Control System</a>.</p>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div> <!-- head -->
|
||||||
|
|
||||||
<div id="toc">
|
|
||||||
<h2 class="nocount">Table of Contents</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="contents" class="contents">
|
<div id="contents" class="contents">
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<h2>Overview</h2>
|
<h2>Overview</h2>
|
||||||
<p>
|
<p>
|
||||||
|
Documentation for pvDatabaseCPP is available at:
|
||||||
|
<a
|
||||||
|
href="https://mrkraimer.github.io/website/developerGuide/pvDatabase/pvDatabaseCPP.html">
|
||||||
|
pvDatabase
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
pvDatabaseCPP is one of the components of
|
pvDatabaseCPP is one of the components of
|
||||||
EPICS Version 7
|
<a href="https://epics-controls.org/resources-and-support/base/epics-7/">
|
||||||
|
EPICS-7
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP
|
<p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP
|
||||||
</p>
|
</p>
|
||||||
@@ -80,122 +73,28 @@ href="https://mrkraimer.github.io/website/developerGuide/developerGuide.html">
|
|||||||
developerGuide
|
developerGuide
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p>This guide discusses all the components that are part of an <b>EPICS V4</b> release.
|
<p>This guide provides an overview of the components that are part of an <b>EPICS V4</b> release.
|
||||||
Some understanding of the components and how they are related is necessary in order to
|
Some understanding of the components and how they are related is necessary in order to
|
||||||
develop code that uses pvDatabaseCPP.
|
develop code that uses pvDatabaseCPP.
|
||||||
In particular read everything related to pvDatabase.
|
In particular read everything related to pvaClient.
|
||||||
</p>
|
|
||||||
<p>pvDatabase has plugin support, which is implemented in <b>pvCopy</b>.
|
|
||||||
<b>pvCopy</b> was originally implemented in <b>pvDataCPP</b>,
|
|
||||||
but pvDatabaseCPP now implemnents its own version and adds plugin support.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
See
|
|
||||||
<a
|
|
||||||
href="https://mrkraimer.github.io/website/pvRequest/pvRequest.html">
|
|
||||||
pvRequest
|
|
||||||
</a>
|
|
||||||
for details.
|
|
||||||
</p>
|
|
||||||
<p>The developerGuide discusses code in a way that applies to both CPP and C++.
|
|
||||||
For the descriptions of the CPP specific code consult the next section.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>doxygen</h2>
|
<h2>doxygen</h2>
|
||||||
<p>doxygen documentation is available at
|
<p>doxygen documentation is available at
|
||||||
<a
|
<a
|
||||||
href="./html/index.html">doxgen</a>
|
href="./html/index.html">doxygen</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>pvDatabaseCPP</h2>
|
|
||||||
<p>pvDatabaseCPP itself has the following implementations of a <b>PVRecord</b></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>
|
|
||||||
</dl>
|
|
||||||
<h2>exampleCPP</h2>
|
<h2>exampleCPP</h2>
|
||||||
<p>Example code is available as part of this release.
|
<p>Example code is available at
|
||||||
<a
|
<a
|
||||||
href="http://epics-pvdata.sourceforge.net/docbuild/exampleCPP/tip/documentation/exampleCPP.html">
|
href="https://github.com/epics-base/exampleCPP">
|
||||||
exampleCPP
|
exampleCPP
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p>In particular look at the example code mentioned in the following sub-sections.
|
<p>In particular look at database, exampleLink, and helloPutGet.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>database</h3>
|
</div> <!-- class="contents" -->
|
||||||
<p>This has many examples of how to create both soft records and records that implement
|
|
||||||
other functionality.</p>
|
|
||||||
<dl>
|
|
||||||
<dt>exampleDatabase.cpp</dt>
|
|
||||||
<dd>
|
|
||||||
This shows how to create soft records of each pvData type.<br />
|
|
||||||
In addition shows how to create instances of the following two records.
|
|
||||||
</dd>
|
|
||||||
<dt>exampleHelloRecord.cpp</dt>
|
|
||||||
<dd>
|
|
||||||
This is a simple "hello world" that is intentended to be used via a channelPutGet request.
|
|
||||||
</dd>
|
|
||||||
<dt>exampleHelloRPC.cpp</dt>
|
|
||||||
<dd>
|
|
||||||
This is a simple "hello world" that is intentended to be used via a channelRPC request.
|
|
||||||
</dd>
|
|
||||||
<dt>exampleDatabaseMain.cpp</dt>
|
|
||||||
<dd>
|
|
||||||
This shows how to create a standalone IOC.
|
|
||||||
</dd>
|
|
||||||
<dt>ioc and iocBoot</dt>
|
|
||||||
<dd>
|
|
||||||
This has code and examples to create a V3 IOC which also has a PVDatabase.
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<h3>exampleLink</h3>
|
|
||||||
<p>This shows how to implement a record that has a link to another record</p>
|
|
||||||
<dl>
|
|
||||||
<dt>exampleMonitorLinkRecord</dt>
|
|
||||||
<dd>
|
|
||||||
This creates a monitor link to another record.
|
|
||||||
</dd>
|
|
||||||
<dt>exampleGetLinkRecord</dt>
|
|
||||||
<dd>
|
|
||||||
This creates a get link to another record.
|
|
||||||
</dd>
|
|
||||||
<dt>examplePutLinkRecord</dt>
|
|
||||||
<dd>
|
|
||||||
This creates a put link to another record.
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<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
|
|
||||||
qsrv
|
|
||||||
pvDatabaseCPP
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>pvDatabaseCPP provides the following iocshell command.</p>
|
|
||||||
<dl>
|
|
||||||
<dt>registerChannelProviderLocal</dt>
|
|
||||||
<dd>Including <b>registerChannelProviderLocal.dbd</b> as a dbd file automatically starts provider local
|
|
||||||
and also creates the pvdbl shell command.
|
|
||||||
</dd>
|
|
||||||
<dt>pvdbl</dt>
|
|
||||||
<dd>Provides a list of all the pvRecords in database <b>master</b>
|
|
||||||
</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>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
25
example/createdestroy/Makefile
Executable file
25
example/createdestroy/Makefile
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
TOP=../..
|
||||||
|
include $(TOP)/configure/CONFIG
|
||||||
|
#----------------------------------------
|
||||||
|
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||||
|
#=============================
|
||||||
|
|
||||||
|
#=============================
|
||||||
|
# Build the application
|
||||||
|
|
||||||
|
TESTPROD_HOST = createdestroy
|
||||||
|
|
||||||
|
createdestroy_SRCS += createdestroy.cpp
|
||||||
|
|
||||||
|
# Add all the support libraries needed by this application
|
||||||
|
#pvatest_LIBS += xxx
|
||||||
|
|
||||||
|
# Finally link to the EPICS Base libraries
|
||||||
|
createdestroy_LIBS += pvDatabase pvAccess pvData
|
||||||
|
createdestroy_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||||
|
|
||||||
|
#===========================
|
||||||
|
|
||||||
|
include $(TOP)/configure/RULES
|
||||||
|
#----------------------------------------
|
||||||
|
# ADD RULES AFTER THIS LINE
|
||||||
20
example/createdestroy/README.md
Normal file
20
example/createdestroy/README.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# pvDatabaseCPP/example/createdestroy
|
||||||
|
|
||||||
|
This is an example that:
|
||||||
|
|
||||||
|
1) Gets the master PVDatabase
|
||||||
|
2) Create ChannelProviderLocal
|
||||||
|
3) Creates a ServerContext
|
||||||
|
|
||||||
|
Then it executes a forever loop that:
|
||||||
|
|
||||||
|
1) creates a pvRecord and adds it to the pvDatabase.
|
||||||
|
2) creates a pvac::ClientProvider
|
||||||
|
3) creates a pvac::ClientChannel
|
||||||
|
4) creates a monitor on the channel
|
||||||
|
5) runs a loop 10 times that: does a put to the channel, and then gets the data for any outstanding monitors
|
||||||
|
6) removes the pvRecord from the pvDatabase
|
||||||
|
|
||||||
|
It also has options to set trace level for the pvRecord and to periodically pause by asking for input.
|
||||||
|
|
||||||
|
|
||||||
179
example/createdestroy/createdestroy.cpp
Normal file
179
example/createdestroy/createdestroy.cpp
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* This is modeled after a test program created by Bertrand Bauvir from the ITER Organization
|
||||||
|
******************************************************************************/
|
||||||
|
#include <iostream>
|
||||||
|
#include <epicsGetopt.h>
|
||||||
|
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/channelProviderLocal.h>
|
||||||
|
#include <pva/client.h>
|
||||||
|
#include <epicsEvent.h>
|
||||||
|
|
||||||
|
// Local header files
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
|
||||||
|
#define DEFAULT_RECORD_NAME "examplechannel"
|
||||||
|
|
||||||
|
using std::tr1::static_pointer_cast;
|
||||||
|
|
||||||
|
class Record : public ::epics::pvDatabase::PVRecord
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::shared_ptr<::epics::pvData::PVStructure> __pv;
|
||||||
|
static std::shared_ptr<Record> create (std::string const & name, std::shared_ptr<::epics::pvData::PVStructure> const & pvstruct);
|
||||||
|
Record (std::string const & name, std::shared_ptr<epics::pvData::PVStructure> const & pvstruct)
|
||||||
|
: epics::pvDatabase::PVRecord(name, pvstruct) { __pv = pvstruct; };
|
||||||
|
virtual void process (void);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<Record> Record::create (std::string const & name, std::shared_ptr<::epics::pvData::PVStructure> const & pvstruct)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Record> pvrecord (new Record (name, pvstruct));
|
||||||
|
// Need to be explicitly called .. not part of the base constructor
|
||||||
|
if(!pvrecord->init()) pvrecord.reset();
|
||||||
|
return pvrecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Record::process (void)
|
||||||
|
{
|
||||||
|
PVRecord::process();
|
||||||
|
std::string name = this->getRecordName();
|
||||||
|
std::cout << this->getRecordName()
|
||||||
|
<< " process\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyMonitor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::tr1::shared_ptr<::pvac::MonitorSync> monitor;
|
||||||
|
MyMonitor(std::tr1::shared_ptr<::pvac::ClientChannel> const &channel)
|
||||||
|
{
|
||||||
|
monitor = std::tr1::shared_ptr<::pvac::MonitorSync>(new ::pvac::MonitorSync(channel->monitor()));
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static std::tr1::shared_ptr<MyMonitor> create(std::tr1::shared_ptr<::pvac::ClientChannel> const &channel)
|
||||||
|
{
|
||||||
|
return std::tr1::shared_ptr<MyMonitor>(new MyMonitor(channel));
|
||||||
|
}
|
||||||
|
void getData();
|
||||||
|
};
|
||||||
|
|
||||||
|
void MyMonitor::getData()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
if(!monitor->wait(.001)) break;
|
||||||
|
switch(monitor->event.event) {
|
||||||
|
case pvac::MonitorEvent::Fail:
|
||||||
|
std::cerr<<monitor->name()<<" : Error : "<<monitor->event.message<<"\n";
|
||||||
|
return;
|
||||||
|
case pvac::MonitorEvent::Cancel:
|
||||||
|
std::cout<<monitor->name()<<" <Cancel>\n";
|
||||||
|
return;
|
||||||
|
case pvac::MonitorEvent::Disconnect:
|
||||||
|
std::cout<<monitor->name()<<" <Disconnect>\n";
|
||||||
|
return;
|
||||||
|
case pvac::MonitorEvent::Data:
|
||||||
|
while(monitor->poll()) {
|
||||||
|
std::cout<<monitor->name()<<" : "<<monitor->root;
|
||||||
|
}
|
||||||
|
if(monitor->complete()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char** argv)
|
||||||
|
{
|
||||||
|
int verbose = 0;
|
||||||
|
unsigned loopctr = 0;
|
||||||
|
unsigned pausectr = 0;
|
||||||
|
bool allowExit = false;
|
||||||
|
bool callRecord = false;
|
||||||
|
bool callDatabase = false;
|
||||||
|
int opt;
|
||||||
|
while((opt = getopt(argc, argv, "v:ardh")) != -1) {
|
||||||
|
switch(opt) {
|
||||||
|
case 'v':
|
||||||
|
verbose = std::stoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'a' :
|
||||||
|
allowExit = true;
|
||||||
|
break;
|
||||||
|
case 'r' :
|
||||||
|
callRecord = true;
|
||||||
|
break;
|
||||||
|
case 'd' :
|
||||||
|
callDatabase = true;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
std::cout << " -v level -a -r -d -h \n";
|
||||||
|
std::cout << "-r call pvRecord->remove -d call master->removeRecord\n";
|
||||||
|
std::cout << "default\n";
|
||||||
|
std::cout << "-v " << verbose
|
||||||
|
<< " -a false"
|
||||||
|
<< " -d"
|
||||||
|
<< "\n";
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
std::cerr<<"Unknown argument: "<<opt<<"\n";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!callRecord && !callDatabase) callDatabase = true;
|
||||||
|
::epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
|
||||||
|
::epics::pvDatabase::ChannelProviderLocalPtr channelProvider = epics::pvDatabase::getChannelProviderLocal();
|
||||||
|
epics::pvAccess::ServerContext::shared_pointer context
|
||||||
|
= epics::pvAccess::startPVAServer(epics::pvAccess::PVACCESS_ALL_PROVIDERS, 0, true, true);
|
||||||
|
std::string startset("starting set of puts valuectr = ");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
loopctr++;
|
||||||
|
std::string name = DEFAULT_RECORD_NAME + std::to_string(loopctr);
|
||||||
|
|
||||||
|
// Create record
|
||||||
|
// Create record structure
|
||||||
|
::epics::pvData::FieldBuilderPtr builder = epics::pvData::getFieldCreate()->createFieldBuilder();
|
||||||
|
builder->add("value", ::epics::pvData::pvULong);
|
||||||
|
std::shared_ptr<::epics::pvData::PVStructure> pvstruct
|
||||||
|
= ::epics::pvData::getPVDataCreate()->createPVStructure(builder->createStructure());
|
||||||
|
std::shared_ptr<Record> pvrecord = Record::create(std::string(name), pvstruct);
|
||||||
|
master->addRecord(pvrecord);
|
||||||
|
pvrecord->setTraceLevel(verbose);
|
||||||
|
// Start PVA (local) client
|
||||||
|
std::tr1::shared_ptr<::pvac::ClientProvider> provider
|
||||||
|
= std::tr1::shared_ptr<::pvac::ClientProvider>(new ::pvac::ClientProvider ("pva"));
|
||||||
|
std::tr1::shared_ptr<::pvac::ClientChannel> channel
|
||||||
|
= std::tr1::shared_ptr<::pvac::ClientChannel>(new ::pvac::ClientChannel (provider->connect(name)));
|
||||||
|
std::tr1::shared_ptr<MyMonitor> mymonitor = MyMonitor::create(channel);
|
||||||
|
unsigned valuectr = loopctr;
|
||||||
|
std::cout << startset << loopctr << "\n";
|
||||||
|
for (int ind=0; ind<100; ind++) {
|
||||||
|
channel->put().set("value",valuectr++).exec();
|
||||||
|
mymonitor->getData();
|
||||||
|
}
|
||||||
|
pausectr++;
|
||||||
|
if(allowExit && pausectr>10) {
|
||||||
|
pausectr = 0;
|
||||||
|
std::cout << "Type exit to stop: \n";
|
||||||
|
int c = std::cin.peek(); // peek character
|
||||||
|
if ( c == EOF ) continue;
|
||||||
|
std::string str;
|
||||||
|
std::getline(std::cin,str);
|
||||||
|
if(str.compare("exit")==0) break;
|
||||||
|
}
|
||||||
|
if(callRecord) {
|
||||||
|
std::cout << "callRecord\n";
|
||||||
|
pvrecord->remove();
|
||||||
|
}
|
||||||
|
if(callDatabase) {
|
||||||
|
std::cout << "callDatabase\n";
|
||||||
|
master->removeRecord(pvrecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
# pvDatabase C++ implementation
|
|
||||||
# Jenkins @ Cloudbees build script
|
|
||||||
#
|
|
||||||
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
|
|
||||||
# if any of the commands exits with a non-zero exit code.
|
|
||||||
#
|
|
||||||
# Author: Ralph Lange <ralph.lange@gmx.de>
|
|
||||||
# Copyright (C) 2014 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
|
|
||||||
# Copyright (C) 2014-2016 ITER Organization.
|
|
||||||
# All rights reserved. Use is subject to license terms.
|
|
||||||
|
|
||||||
installTool () {
|
|
||||||
local module=$1
|
|
||||||
local version=$2
|
|
||||||
|
|
||||||
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
|
|
||||||
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
|
|
||||||
}
|
|
||||||
|
|
||||||
installE4 () {
|
|
||||||
local module=$1
|
|
||||||
local branch=$2
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
DEFAULT_BASE=3.15.4
|
|
||||||
BASE=${BASE:-${DEFAULT_BASE}}
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Dependent module branches
|
|
||||||
|
|
||||||
PVDATA_BRANCH="master"
|
|
||||||
PVACCESS_BRANCH="master"
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Fetch and unpack dependencies
|
|
||||||
|
|
||||||
export STUFF=/tmp/stuff
|
|
||||||
|
|
||||||
rm -fr ${STUFF}
|
|
||||||
mkdir -p ${STUFF}
|
|
||||||
cd ${STUFF}
|
|
||||||
|
|
||||||
installTool Boost 1.61.0
|
|
||||||
installTool Base ${BASE}
|
|
||||||
|
|
||||||
installE4 pvData ${PVDATA_BRANCH}
|
|
||||||
installE4 pvAccess ${PVACCESS_BRANCH}
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Build
|
|
||||||
|
|
||||||
cd ${WORKSPACE}
|
|
||||||
|
|
||||||
export EPICS_BASE=${STUFF}
|
|
||||||
export EPICS_HOST_ARCH=$(${EPICS_BASE}/startup/EpicsHostArch)
|
|
||||||
export LD_LIBRARY_PATH=${EPICS_BASE}/lib/${EPICS_HOST_ARCH}
|
|
||||||
export PATH=${STUFF}/bin:${PATH}
|
|
||||||
|
|
||||||
cat > configure/RELEASE.local << EOF
|
|
||||||
EPICS_BASE=${EPICS_BASE}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
make distclean all
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Test
|
|
||||||
|
|
||||||
make runtests
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Create cache
|
|
||||||
|
|
||||||
tar -czf pvDatabase.CB-dist.tar.gz lib include dbd LICENSE
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# pvDatabase C++ implementation
|
|
||||||
# Jenkins @ Cloudbees documentation generation and deployment
|
|
||||||
#
|
|
||||||
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
|
|
||||||
# if any of the commands exits with a non-zero exit code.
|
|
||||||
#
|
|
||||||
# Author: Ralph Lange <ralph.lange@gmx.de>
|
|
||||||
# Copyright (C) 2014 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
|
|
||||||
# Copyright (C) 2014-2016 ITER Organization.
|
|
||||||
# All rights reserved. Use is subject to license terms.
|
|
||||||
|
|
||||||
installTool () {
|
|
||||||
local module=$1
|
|
||||||
local version=$2
|
|
||||||
|
|
||||||
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
|
|
||||||
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
|
|
||||||
}
|
|
||||||
|
|
||||||
installE4 () {
|
|
||||||
local module=$1
|
|
||||||
local branch=$2
|
|
||||||
|
|
||||||
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 parameters
|
|
||||||
|
|
||||||
BASE=3.15.4
|
|
||||||
PUBLISH=${PUBLISH:-NO}
|
|
||||||
BRANCH=${BRANCH:-master}
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Fetch and unpack dependencies
|
|
||||||
|
|
||||||
export STUFF=/tmp/stuff
|
|
||||||
|
|
||||||
rm -fr ${STUFF}
|
|
||||||
mkdir -p ${STUFF}
|
|
||||||
cd ${STUFF}
|
|
||||||
|
|
||||||
installTool Doxygen 1.8.11
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Generate
|
|
||||||
|
|
||||||
cd ${WORKSPACE}
|
|
||||||
|
|
||||||
installE4 pvDatabase ${BRANCH}
|
|
||||||
|
|
||||||
export PATH=${STUFF}/bin:${PATH}
|
|
||||||
|
|
||||||
doxygen
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
# Publish
|
|
||||||
|
|
||||||
if [ "${PUBLISH}" != "DONT" ]; then
|
|
||||||
# Upload explicit dummy to ensure target directory exists
|
|
||||||
echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY
|
|
||||||
rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDatabaseCPP/${PUBLISH}/
|
|
||||||
|
|
||||||
rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDatabaseCPP/${PUBLISH}/
|
|
||||||
fi
|
|
||||||
37
src/Makefile
37
src/Makefile
@@ -5,22 +5,43 @@ include $(TOP)/configure/CONFIG
|
|||||||
|
|
||||||
PVDATABASE_SRC = $(TOP)/src
|
PVDATABASE_SRC = $(TOP)/src
|
||||||
|
|
||||||
LIBRARY += pvDatabase
|
|
||||||
|
|
||||||
# shared library ABI version.
|
INC += pv/pvPlugin.h
|
||||||
SHRLIB_VERSION ?= 4.4.2
|
INC += pv/pvStructureCopy.h
|
||||||
|
INC += pv/pvArrayPlugin.h
|
||||||
|
INC += pv/pvDeadbandPlugin.h
|
||||||
|
INC += pv/pvTimestampPlugin.h
|
||||||
|
|
||||||
|
INC += pv/pvDatabase.h
|
||||||
|
|
||||||
INC += pv/channelProviderLocal.h
|
INC += pv/channelProviderLocal.h
|
||||||
INC += pv/pvDatabase.h
|
|
||||||
INC += pv/traceRecord.h
|
INC += pv/pvSupport.h
|
||||||
INC += pv/removeRecord.h
|
INC += pv/controlSupport.h
|
||||||
|
INC += pv/scalarAlarmSupport.h
|
||||||
|
|
||||||
|
INC += pv/pvdbcrScalarRecord.h
|
||||||
|
INC += pv/pvdbcrScalarArrayRecord.h
|
||||||
|
INC += pv/pvdbcrAddRecord.h
|
||||||
|
INC += pv/pvdbcrRemoveRecord.h
|
||||||
|
INC += pv/pvdbcrProcessRecord.h
|
||||||
|
INC += pv/pvdbcrTraceRecord.h
|
||||||
|
|
||||||
include $(PVDATABASE_SRC)/copy/Makefile
|
include $(PVDATABASE_SRC)/copy/Makefile
|
||||||
include $(PVDATABASE_SRC)/database/Makefile
|
include $(PVDATABASE_SRC)/database/Makefile
|
||||||
include $(PVDATABASE_SRC)/pvAccess/Makefile
|
include $(PVDATABASE_SRC)/pvAccess/Makefile
|
||||||
|
include $(PVDATABASE_SRC)/support/Makefile
|
||||||
include $(PVDATABASE_SRC)/special/Makefile
|
include $(PVDATABASE_SRC)/special/Makefile
|
||||||
|
|
||||||
pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
|
LIBRARY += pvDatabase
|
||||||
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
|
pvDatabase_LIBS += pvData
|
||||||
|
pvDatabase_LIBS += pvAccess
|
||||||
|
LIB_LIBS += Com
|
||||||
|
|
||||||
|
# shared library ABI version.
|
||||||
|
SHRLIB_VERSION ?= $(EPICS_PVDATABASE_MAJOR_VERSION).$(EPICS_PVDATABASE_MINOR_VERSION).$(EPICS_PVDATABASE_MAINTENANCE_VERSION)
|
||||||
|
|
||||||
|
# needed for Windows
|
||||||
|
LIB_SYS_LIBS_WIN32 += netapi32 ws2_32
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
|
|
||||||
# This is a Makefile fragment, see ../Makefile
|
# This is a Makefile fragment, see ../Makefile
|
||||||
|
|
||||||
SRC_DIRS += $(PVDATABASE_SRC)/copy
|
SRC_DIRS += $(PVDATABASE_SRC)/copy
|
||||||
|
|
||||||
INC += pv/pvStructureCopy.h
|
|
||||||
INC += pv/pvPlugin.h
|
|
||||||
INC += pv/pvArrayPlugin.h
|
|
||||||
INC += pv/pvDeadbandPlugin.h
|
|
||||||
INC += pv/pvTimestampPlugin.h
|
|
||||||
|
|
||||||
LIBSRCS += pvCopy.cpp
|
|
||||||
LIBSRCS += pvPlugin.cpp
|
LIBSRCS += pvPlugin.cpp
|
||||||
|
LIBSRCS += pvCopy.cpp
|
||||||
LIBSRCS += pvArrayPlugin.cpp
|
LIBSRCS += pvArrayPlugin.cpp
|
||||||
LIBSRCS += pvDeadbandPlugin.cpp
|
LIBSRCS += pvDeadbandPlugin.cpp
|
||||||
LIBSRCS += pvTimestampPlugin.cpp
|
LIBSRCS += pvTimestampPlugin.cpp
|
||||||
|
LIBSRCS += dataDistributorPlugin.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
428
src/copy/dataDistributorPlugin.cpp
Normal file
428
src/copy/dataDistributorPlugin.cpp
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
// Copyright information and license terms for this software can be
|
||||||
|
// found in the file LICENSE that is included with the distribution
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <pv/lock.h>
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/bitSet.h>
|
||||||
|
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/dataDistributorPlugin.h"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::size_t;
|
||||||
|
using std::endl;
|
||||||
|
using std::tr1::static_pointer_cast;
|
||||||
|
using std::vector;
|
||||||
|
using namespace epics::pvData;
|
||||||
|
namespace epvd = epics::pvData;
|
||||||
|
|
||||||
|
namespace epics { namespace pvCopy {
|
||||||
|
|
||||||
|
// Utilities for manipulating strings
|
||||||
|
static std::string leftTrim(const std::string& s)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int n = (unsigned int)s.length();
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (!isspace(s[i])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.substr(i,n-i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string rightTrim(const std::string& s)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int n = (unsigned int)s.length();
|
||||||
|
for (i = n; i > 0; i--) {
|
||||||
|
if (!isspace(s[i-1])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.substr(0,i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string trim(const std::string& s)
|
||||||
|
{
|
||||||
|
return rightTrim(leftTrim(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string>& split(const std::string& s, char delimiter, std::vector<std::string>& elements)
|
||||||
|
{
|
||||||
|
std::stringstream ss(s);
|
||||||
|
std::string item;
|
||||||
|
while (std::getline(ss, item, delimiter)) {
|
||||||
|
elements.push_back(trim(item));
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> split(const std::string& s, char delimiter)
|
||||||
|
{
|
||||||
|
std::vector<std::string> elements;
|
||||||
|
split(s, delimiter, elements);
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string toLowerCase(const std::string& input)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
for (unsigned int i = 0; i < input.size(); i++) {
|
||||||
|
char c = std::tolower(input.at(i));
|
||||||
|
ss << c;
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data distributor class
|
||||||
|
|
||||||
|
static std::string name("distributor");
|
||||||
|
bool DataDistributorPlugin::initialized(false);
|
||||||
|
|
||||||
|
std::map<std::string, DataDistributorPtr> DataDistributor::dataDistributorMap;
|
||||||
|
epics::pvData::Mutex DataDistributor::dataDistributorMapMutex;
|
||||||
|
|
||||||
|
DataDistributorPtr DataDistributor::getInstance(const std::string& groupId)
|
||||||
|
{
|
||||||
|
epvd::Lock lock(dataDistributorMapMutex);
|
||||||
|
std::map<std::string,DataDistributorPtr>::iterator ddit = dataDistributorMap.find(groupId);
|
||||||
|
if (ddit != dataDistributorMap.end()) {
|
||||||
|
DataDistributorPtr ddPtr = ddit->second;
|
||||||
|
return ddPtr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DataDistributorPtr ddPtr(new DataDistributor(groupId));
|
||||||
|
dataDistributorMap[groupId] = ddPtr;
|
||||||
|
return ddPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDistributor::removeUnusedInstance(DataDistributorPtr dataDistributorPtr)
|
||||||
|
{
|
||||||
|
epvd::Lock lock(dataDistributorMapMutex);
|
||||||
|
std::string groupId = dataDistributorPtr->getGroupId();
|
||||||
|
std::map<std::string,DataDistributorPtr>::iterator ddit = dataDistributorMap.find(groupId);
|
||||||
|
if (ddit != dataDistributorMap.end()) {
|
||||||
|
DataDistributorPtr ddPtr = ddit->second;
|
||||||
|
size_t nSets = ddPtr->clientSetMap.size();
|
||||||
|
if (nSets == 0) {
|
||||||
|
dataDistributorMap.erase(ddit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributor::DataDistributor(const std::string& groupId_)
|
||||||
|
: groupId(groupId_)
|
||||||
|
, mutex()
|
||||||
|
, clientSetMap()
|
||||||
|
, clientSetIdList()
|
||||||
|
, currentSetIdIter(clientSetIdList.end())
|
||||||
|
, lastUpdateValue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributor::~DataDistributor()
|
||||||
|
{
|
||||||
|
epvd::Lock lock(mutex);
|
||||||
|
clientSetMap.clear();
|
||||||
|
clientSetIdList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DataDistributor::addClient(int clientId, const std::string& setId, const std::string& triggerField, int nUpdatesPerClient, int updateMode)
|
||||||
|
{
|
||||||
|
epvd::Lock lock(mutex);
|
||||||
|
std::map<std::string,ClientSetPtr>::iterator git = clientSetMap.find(setId);
|
||||||
|
if (git != clientSetMap.end()) {
|
||||||
|
ClientSetPtr setPtr = git->second;
|
||||||
|
setPtr->clientIdList.push_back(clientId);
|
||||||
|
return setPtr->triggerField;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ClientSetPtr setPtr(new ClientSet(setId, triggerField, nUpdatesPerClient, updateMode));
|
||||||
|
setPtr->clientIdList.push_back(clientId);
|
||||||
|
clientSetMap[setId] = setPtr;
|
||||||
|
clientSetIdList.push_back(setId);
|
||||||
|
return triggerField;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDistributor::removeClient(int clientId, const std::string& setId)
|
||||||
|
{
|
||||||
|
epvd::Lock lock(mutex);
|
||||||
|
std::map<std::string,ClientSetPtr>::iterator git = clientSetMap.find(setId);
|
||||||
|
if (git != clientSetMap.end()) {
|
||||||
|
ClientSetPtr setPtr = git->second;
|
||||||
|
std::list<int>::iterator cit = std::find(setPtr->clientIdList.begin(), setPtr->clientIdList.end(), clientId);
|
||||||
|
if (cit != setPtr->clientIdList.end()) {
|
||||||
|
// If we are removing current client id, advance iterator
|
||||||
|
if (cit == setPtr->currentClientIdIter) {
|
||||||
|
setPtr->currentClientIdIter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find current client id
|
||||||
|
int currentClientId = -1;
|
||||||
|
if (setPtr->currentClientIdIter != setPtr->clientIdList.end()) {
|
||||||
|
currentClientId = *(setPtr->currentClientIdIter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove client id from the list
|
||||||
|
setPtr->clientIdList.erase(cit);
|
||||||
|
|
||||||
|
// Reset current client id iterator
|
||||||
|
setPtr->currentClientIdIter = setPtr->clientIdList.end();
|
||||||
|
if (currentClientId >= 0) {
|
||||||
|
std::list<int>::iterator cit2 = std::find(setPtr->clientIdList.begin(), setPtr->clientIdList.end(), currentClientId);
|
||||||
|
if (cit2 != setPtr->clientIdList.end()) {
|
||||||
|
setPtr->currentClientIdIter = cit2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setPtr->clientIdList.size() == 0) {
|
||||||
|
clientSetMap.erase(git);
|
||||||
|
std::list<std::string>::iterator git2 = std::find(clientSetIdList.begin(), clientSetIdList.end(), setId);
|
||||||
|
if (git2 == currentSetIdIter) {
|
||||||
|
currentSetIdIter++;
|
||||||
|
}
|
||||||
|
if (git2 != clientSetIdList.end()) {
|
||||||
|
clientSetIdList.erase(git2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataDistributor::updateClient(int clientId, const std::string& setId, const std::string& triggerFieldValue)
|
||||||
|
{
|
||||||
|
epvd::Lock lock(mutex);
|
||||||
|
bool proceedWithUpdate = false;
|
||||||
|
if (currentSetIdIter == clientSetIdList.end()) {
|
||||||
|
currentSetIdIter = clientSetIdList.begin();
|
||||||
|
}
|
||||||
|
std::string currentSetId = *currentSetIdIter;
|
||||||
|
if (setId != currentSetId) {
|
||||||
|
// We are not distributing data to this set at the moment
|
||||||
|
return proceedWithUpdate;
|
||||||
|
}
|
||||||
|
ClientSetPtr setPtr = clientSetMap[currentSetId];
|
||||||
|
if (setPtr->currentClientIdIter == setPtr->clientIdList.end()) {
|
||||||
|
// Move current client iterator to the beginning of the list
|
||||||
|
setPtr->currentClientIdIter = setPtr->clientIdList.begin();
|
||||||
|
}
|
||||||
|
if (lastUpdateValue == triggerFieldValue) {
|
||||||
|
// This update was already distributed.
|
||||||
|
return proceedWithUpdate;
|
||||||
|
}
|
||||||
|
switch (setPtr->updateMode) {
|
||||||
|
case(DD_UPDATE_ONE_PER_GROUP): {
|
||||||
|
if (clientId != *(setPtr->currentClientIdIter)) {
|
||||||
|
// Not this client's turn.
|
||||||
|
return proceedWithUpdate;
|
||||||
|
}
|
||||||
|
proceedWithUpdate = true;
|
||||||
|
lastUpdateValue = triggerFieldValue;
|
||||||
|
setPtr->lastUpdateValue = triggerFieldValue;
|
||||||
|
setPtr->updateCounter++;
|
||||||
|
if (setPtr->updateCounter >= setPtr->nUpdatesPerClient) {
|
||||||
|
// This client and set are done.
|
||||||
|
setPtr->currentClientIdIter++;
|
||||||
|
setPtr->updateCounter = 0;
|
||||||
|
currentSetIdIter++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(DD_UPDATE_ALL_IN_GROUP): {
|
||||||
|
proceedWithUpdate = true;
|
||||||
|
static unsigned int nClientsUpdated = 0;
|
||||||
|
if (setPtr->lastUpdateValue != triggerFieldValue) {
|
||||||
|
setPtr->lastUpdateValue = triggerFieldValue;
|
||||||
|
setPtr->updateCounter++;
|
||||||
|
nClientsUpdated = 0;
|
||||||
|
}
|
||||||
|
nClientsUpdated++;
|
||||||
|
if (nClientsUpdated == setPtr->clientIdList.size() && setPtr->updateCounter >= setPtr->nUpdatesPerClient) {
|
||||||
|
// This set is done.
|
||||||
|
lastUpdateValue = triggerFieldValue;
|
||||||
|
setPtr->updateCounter = 0;
|
||||||
|
currentSetIdIter++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
proceedWithUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proceedWithUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributorPlugin::DataDistributorPlugin()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributorPlugin::~DataDistributorPlugin()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDistributorPlugin::create()
|
||||||
|
{
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataDistributorPlugin::initialize()
|
||||||
|
{
|
||||||
|
if (!initialized) {
|
||||||
|
initialized = true;
|
||||||
|
DataDistributorPluginPtr pvPlugin = DataDistributorPluginPtr(new DataDistributorPlugin());
|
||||||
|
PVPluginRegistry::registerPlugin(name,pvPlugin);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PVFilterPtr DataDistributorPlugin::create(
|
||||||
|
const std::string& requestValue,
|
||||||
|
const PVCopyPtr& pvCopy,
|
||||||
|
const PVFieldPtr& master)
|
||||||
|
{
|
||||||
|
return DataDistributorFilter::create(requestValue,pvCopy,master);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributorFilter::~DataDistributorFilter()
|
||||||
|
{
|
||||||
|
dataDistributorPtr->removeClient(clientId, setId);
|
||||||
|
DataDistributor::removeUnusedInstance(dataDistributorPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributorFilterPtr DataDistributorFilter::create(
|
||||||
|
const std::string& requestValue,
|
||||||
|
const PVCopyPtr& pvCopy,
|
||||||
|
const PVFieldPtr& master)
|
||||||
|
{
|
||||||
|
static int clientId = 0;
|
||||||
|
clientId++;
|
||||||
|
|
||||||
|
std::vector<std::string> configItems = split(requestValue, ';');
|
||||||
|
// Use lowercase keys if possible.
|
||||||
|
std::string requestValue2 = toLowerCase(requestValue);
|
||||||
|
std::vector<std::string> configItems2 = split(requestValue2, ';');
|
||||||
|
int nUpdatesPerClient = 1;
|
||||||
|
int updateMode = DataDistributor::DD_UPDATE_ONE_PER_GROUP;
|
||||||
|
std::string groupId = "default";
|
||||||
|
std::string setId = "default";
|
||||||
|
std::string triggerField = "timeStamp";
|
||||||
|
bool hasUpdateMode = false;
|
||||||
|
bool hasSetId = false;
|
||||||
|
for(unsigned int i = 0; i < configItems2.size(); i++) {
|
||||||
|
std::string configItem2 = configItems2[i];
|
||||||
|
size_t ind = configItem2.find(':');
|
||||||
|
if (ind == string::npos) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(configItem2.find("updates") == 0) {
|
||||||
|
std::string svalue = configItem2.substr(ind+1);
|
||||||
|
nUpdatesPerClient = atoi(svalue.c_str());
|
||||||
|
}
|
||||||
|
else if(configItem2.find("group") == 0) {
|
||||||
|
std::string configItem = configItems[i];
|
||||||
|
groupId = configItem.substr(ind+1);
|
||||||
|
}
|
||||||
|
else if(configItem2.find("set") == 0) {
|
||||||
|
std::string configItem = configItems[i];
|
||||||
|
setId = configItem.substr(ind+1);
|
||||||
|
hasSetId = true;
|
||||||
|
}
|
||||||
|
else if(configItem2.find("mode") == 0) {
|
||||||
|
std::string svalue = toLowerCase(configItem2.substr(ind+1));
|
||||||
|
if (svalue == "one") {
|
||||||
|
updateMode = DataDistributor::DD_UPDATE_ONE_PER_GROUP;
|
||||||
|
hasUpdateMode = true;
|
||||||
|
}
|
||||||
|
else if (svalue == "all") {
|
||||||
|
updateMode = DataDistributor::DD_UPDATE_ALL_IN_GROUP;
|
||||||
|
hasUpdateMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(configItem2.find("trigger") == 0) {
|
||||||
|
std::string configItem = configItems[i];
|
||||||
|
triggerField = configItem.substr(ind+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If request does not have update mode specified, but has set id
|
||||||
|
// then use a different update mode
|
||||||
|
if(!hasUpdateMode && hasSetId) {
|
||||||
|
updateMode = DataDistributor::DD_UPDATE_ALL_IN_GROUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure request is valid
|
||||||
|
if(nUpdatesPerClient <= 0) {
|
||||||
|
return DataDistributorFilterPtr();
|
||||||
|
}
|
||||||
|
DataDistributorFilterPtr filter =
|
||||||
|
DataDistributorFilterPtr(new DataDistributorFilter(groupId, clientId, setId, triggerField, nUpdatesPerClient, updateMode, pvCopy, master));
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributorFilter::DataDistributorFilter(const std::string& groupId_, int clientId_, const std::string& setId_, const std::string& triggerField_, int nUpdatesPerClient, int updateMode, const PVCopyPtr& copyPtr_, const epvd::PVFieldPtr& masterFieldPtr_)
|
||||||
|
: dataDistributorPtr(DataDistributor::getInstance(groupId_))
|
||||||
|
, clientId(clientId_)
|
||||||
|
, setId(setId_)
|
||||||
|
, triggerField(triggerField_)
|
||||||
|
, masterFieldPtr(masterFieldPtr_)
|
||||||
|
, triggerFieldPtr()
|
||||||
|
, firstUpdate(true)
|
||||||
|
{
|
||||||
|
triggerField = dataDistributorPtr->addClient(clientId, setId, triggerField, nUpdatesPerClient, updateMode);
|
||||||
|
if(masterFieldPtr->getField()->getType() == epvd::structure) {
|
||||||
|
epvd::PVStructurePtr pvStructurePtr = static_pointer_cast<epvd::PVStructure>(masterFieldPtr);
|
||||||
|
if(pvStructurePtr) {
|
||||||
|
triggerFieldPtr = pvStructurePtr->getSubField(triggerField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!triggerFieldPtr) {
|
||||||
|
triggerFieldPtr = masterFieldPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DataDistributorFilter::filter(const PVFieldPtr& pvCopy, const BitSetPtr& bitSet, bool toCopy)
|
||||||
|
{
|
||||||
|
if(!toCopy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool proceedWithUpdate = false;
|
||||||
|
if(firstUpdate) {
|
||||||
|
// Always send first update
|
||||||
|
firstUpdate = false;
|
||||||
|
proceedWithUpdate = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << triggerFieldPtr;
|
||||||
|
std::string triggerFieldValue = ss.str();
|
||||||
|
proceedWithUpdate = dataDistributorPtr->updateClient(clientId, setId, triggerFieldValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proceedWithUpdate) {
|
||||||
|
pvCopy->copyUnchecked(*masterFieldPtr);
|
||||||
|
bitSet->set((unsigned int)pvCopy->getFieldOffset());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Clear all bits
|
||||||
|
//bitSet->clear(pvCopy->getFieldOffset());
|
||||||
|
bitSet->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string DataDistributorFilter::getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <pv/convert.h>
|
#include <pv/convert.h>
|
||||||
#include <pv/pvSubArrayCopy.h>
|
#include <pv/pvSubArrayCopy.h>
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/pvArrayPlugin.h>
|
#include "pv/pvArrayPlugin.h"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
@@ -76,9 +76,19 @@ static vector<string> split(string const & colonSeparatedList) {
|
|||||||
|
|
||||||
PVArrayFilterPtr PVArrayFilter::create(
|
PVArrayFilterPtr PVArrayFilter::create(
|
||||||
const std::string & requestValue,
|
const std::string & requestValue,
|
||||||
const PVFieldPtr & master)
|
const PVFieldPtr & masterField)
|
||||||
{
|
{
|
||||||
Type type = master->getField()->getType();
|
bool masterIsUnion = false;
|
||||||
|
PVUnionPtr pvUnion;
|
||||||
|
Type type = masterField->getField()->getType();
|
||||||
|
if(type==epics::pvData::union_) {
|
||||||
|
pvUnion = std::tr1::static_pointer_cast<PVUnion>(masterField);
|
||||||
|
PVFieldPtr pvField = pvUnion->get();
|
||||||
|
if(pvField) {
|
||||||
|
masterIsUnion = true;
|
||||||
|
type = pvField->getField()->getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
if(type!=scalarArray) {
|
if(type!=scalarArray) {
|
||||||
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
||||||
return filter;
|
return filter;
|
||||||
@@ -112,60 +122,82 @@ PVArrayFilterPtr PVArrayFilter::create(
|
|||||||
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
PVArrayFilterPtr filter = PVArrayFilterPtr();
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
PVScalarArrayPtr masterArray;
|
||||||
|
if(masterIsUnion) {
|
||||||
|
masterArray = static_pointer_cast<PVScalarArray>(pvUnion->get());
|
||||||
|
} else {
|
||||||
|
masterArray = static_pointer_cast<PVScalarArray>(masterField);
|
||||||
|
}
|
||||||
PVArrayFilterPtr filter =
|
PVArrayFilterPtr filter =
|
||||||
PVArrayFilterPtr(
|
PVArrayFilterPtr(
|
||||||
new PVArrayFilter(
|
new PVArrayFilter(start,increment,end,masterField,masterArray));
|
||||||
start,increment,end,static_pointer_cast<PVScalarArray>(master)));
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
PVArrayFilter::PVArrayFilter(long start,long increment,long end,const PVScalarArrayPtr & masterArray)
|
PVArrayFilter::PVArrayFilter(
|
||||||
|
long start,long increment,long end,
|
||||||
|
const PVFieldPtr & masterField,
|
||||||
|
const epics::pvData::PVScalarArrayPtr masterArray)
|
||||||
: start(start),
|
: start(start),
|
||||||
increment(increment),
|
increment(increment),
|
||||||
end(end),
|
end(end),
|
||||||
|
masterField(masterField),
|
||||||
masterArray(masterArray)
|
masterArray(masterArray)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PVArrayFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
bool PVArrayFilter::filter(const PVFieldPtr & pvField,const BitSetPtr & bitSet,bool toCopy)
|
||||||
{
|
{
|
||||||
PVScalarArrayPtr copyArray = static_pointer_cast<PVScalarArray>(pvCopy);
|
PVFieldPtr pvCopy = pvField;
|
||||||
|
PVScalarArrayPtr copyArray;
|
||||||
|
bool isUnion = false;
|
||||||
|
Type type = masterField->getField()->getType();
|
||||||
|
if(type==epics::pvData::union_) {
|
||||||
|
isUnion = true;
|
||||||
|
PVUnionPtr pvMasterUnion = std::tr1::static_pointer_cast<PVUnion>(masterField);
|
||||||
|
PVUnionPtr pvCopyUnion = std::tr1::static_pointer_cast<PVUnion>(pvCopy);
|
||||||
|
if(toCopy) pvCopyUnion->copy(*pvMasterUnion);
|
||||||
|
PVFieldPtr pvField = pvCopyUnion->get();
|
||||||
|
copyArray = static_pointer_cast<PVScalarArray>(pvField);
|
||||||
|
} else {
|
||||||
|
copyArray = static_pointer_cast<PVScalarArray>(pvCopy);
|
||||||
|
}
|
||||||
long len = 0;
|
long len = 0;
|
||||||
long start = this->start;
|
long start = this->start;
|
||||||
long end = this->end;
|
long end = this->end;
|
||||||
long no_elements = masterArray->getLength();
|
long no_elements = masterArray->getLength();
|
||||||
if(start<0) {
|
if(start<0) {
|
||||||
start = no_elements+start;
|
start = no_elements+start;
|
||||||
if(start<0) start = 0;
|
if(start<0) start = 0;
|
||||||
}
|
}
|
||||||
if (end < 0) {
|
if (end < 0) {
|
||||||
end = no_elements + end;
|
end = no_elements + end;
|
||||||
if (end < 0) end = 0;
|
if (end < 0) end = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
if(toCopy) {
|
if(toCopy) {
|
||||||
if (end >= no_elements) end = no_elements - 1;
|
if (end >= no_elements) end = no_elements - 1;
|
||||||
if (end - start >= 0) len = 1 + (end - start) / increment;
|
if (end - start >= 0) len = 1 + (end - start) / increment;
|
||||||
if(len<=0 || start>=no_elements) {
|
if(len<=0 || start>=no_elements) {
|
||||||
copyArray->setLength(0);
|
copyArray->setLength(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
long indfrom = start;
|
long indfrom = start;
|
||||||
long indto = 0;
|
long indto = 0;
|
||||||
copyArray->setCapacity(len);
|
copyArray->setCapacity(len);
|
||||||
if(increment==1) {
|
if(increment==1) {
|
||||||
copy(*masterArray,indfrom,1,*copyArray,indto,1,len);
|
copy(*masterArray,indfrom,1,*copyArray,indto,1,len);
|
||||||
} else {
|
} else {
|
||||||
for(long i=0; i<len; ++i) {
|
for(long i=0; i<len; ++i) {
|
||||||
copy(*masterArray,indfrom,1,*copyArray,indto,1,1);
|
copy(*masterArray,indfrom,1,*copyArray,indto,1,1);
|
||||||
indfrom += increment;
|
indfrom += increment;
|
||||||
indto += 1;
|
indto += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copyArray->setLength(len);
|
copyArray->setLength(len);
|
||||||
bitSet->set(pvCopy->getFieldOffset());
|
bitSet->set(pvField->getFieldOffset());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (end - start >= 0) len = 1 + (end - start) / increment;
|
if (end - start >= 0) len = 1 + (end - start) / increment;
|
||||||
if(len<=0) return true;
|
if(len<=0) return true;
|
||||||
@@ -173,21 +205,21 @@ bool PVArrayFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bo
|
|||||||
long indfrom = 0;
|
long indfrom = 0;
|
||||||
long indto = start;
|
long indto = start;
|
||||||
if(increment==1) {
|
if(increment==1) {
|
||||||
copy(*copyArray,indfrom,1,*masterArray,indto,1,len);
|
copy(*copyArray,indfrom,1,*masterArray,indto,1,len);
|
||||||
} else {
|
} else {
|
||||||
for(long i=0; i<len; ++i) {
|
for(long i=0; i<len; ++i) {
|
||||||
copy(*copyArray,indfrom,1,*masterArray,indto,1,1);
|
copy(*copyArray,indfrom,1,*masterArray,indto,1,1);
|
||||||
indfrom += increment;
|
indfrom += 1;
|
||||||
indto += 1;
|
indto += increment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(isUnion) masterField->postPut();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string PVArrayFilter::getName()
|
string PVArrayFilter::getName()
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
#include <pv/thread.h>
|
#include <pv/thread.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/pvPlugin.h>
|
#include "pv/pvPlugin.h"
|
||||||
#include <pv/pvStructureCopy.h>
|
#include "pv/pvStructureCopy.h"
|
||||||
|
|
||||||
using std::tr1::static_pointer_cast;
|
using std::tr1::static_pointer_cast;
|
||||||
using std::tr1::dynamic_pointer_cast;
|
using std::tr1::dynamic_pointer_cast;
|
||||||
@@ -29,7 +29,7 @@ using std::endl;
|
|||||||
using std::vector;
|
using std::vector;
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
|
|
||||||
namespace epics { namespace pvCopy {
|
namespace epics { namespace pvCopy {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method for implementing dump.
|
* Convenience method for implementing dump.
|
||||||
@@ -60,19 +60,19 @@ struct CopyNode {
|
|||||||
PVStructurePtr options;
|
PVStructurePtr options;
|
||||||
vector<PVFilterPtr> pvFilters;
|
vector<PVFilterPtr> pvFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
static CopyNodePtr NULLCopyNode;
|
static CopyNodePtr NULLCopyNode;
|
||||||
|
|
||||||
typedef std::vector<CopyNodePtr> CopyNodePtrArray;
|
typedef std::vector<CopyNodePtr> CopyNodePtrArray;
|
||||||
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
|
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
|
||||||
|
|
||||||
struct CopyStructureNode : public CopyNode {
|
struct CopyStructureNode : public CopyNode {
|
||||||
CopyNodePtrArrayPtr nodes;
|
CopyNodePtrArrayPtr nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
PVCopyPtr PVCopy::create(
|
PVCopyPtr PVCopy::create(
|
||||||
PVStructurePtr const &pvMaster,
|
PVStructurePtr const &pvMaster,
|
||||||
PVStructurePtr const &pvRequest,
|
PVStructurePtr const &pvRequest,
|
||||||
string const & structureName)
|
string const & structureName)
|
||||||
{
|
{
|
||||||
PVStructurePtr pvStructure(pvRequest);
|
PVStructurePtr pvStructure(pvRequest);
|
||||||
@@ -88,7 +88,6 @@ PVCopyPtr PVCopy::create(
|
|||||||
bool result = pvCopy->init(pvStructure);
|
bool result = pvCopy->init(pvStructure);
|
||||||
if(!result) return PVCopyPtr();
|
if(!result) return PVCopyPtr();
|
||||||
pvCopy->traverseMasterInitPlugin();
|
pvCopy->traverseMasterInitPlugin();
|
||||||
//cout << pvCopy->dump() << endl;
|
|
||||||
return pvCopy;
|
return pvCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +113,7 @@ PVStructurePtr PVCopy::createPVStructure()
|
|||||||
cacheInitStructure.reset();
|
cacheInitStructure.reset();
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
PVStructurePtr pvStructure =
|
PVStructurePtr pvStructure =
|
||||||
getPVDataCreate()->createPVStructure(structure);
|
getPVDataCreate()->createPVStructure(structure);
|
||||||
return pvStructure;
|
return pvStructure;
|
||||||
}
|
}
|
||||||
@@ -212,19 +211,91 @@ bool PVCopy::updateCopyFromBitSet(
|
|||||||
return checkIgnore(copyPVStructure,bitSet);
|
return checkIgnore(copyPVStructure,bitSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PVCopy::updateMasterField(
|
||||||
|
CopyNodePtr const & node,
|
||||||
|
PVFieldPtr const & pvCopy,
|
||||||
|
PVFieldPtr const &pvMaster,
|
||||||
|
BitSetPtr const &bitSet)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
||||||
|
PVFilterPtr pvFilter = node->pvFilters[i];
|
||||||
|
if(pvFilter->filter(pvCopy,bitSet,false)) result = true;
|
||||||
|
}
|
||||||
|
if(result) return;
|
||||||
|
pvMaster->copyUnchecked(*pvCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PVCopy::updateMasterCheckBitSet(
|
||||||
|
PVStructurePtr const ©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(
|
void PVCopy::updateMaster(
|
||||||
PVStructurePtr const ©PVStructure,
|
PVStructurePtr const ©PVStructure,
|
||||||
BitSetPtr const &bitSet)
|
BitSetPtr const &bitSet)
|
||||||
{
|
{
|
||||||
if(bitSet->get(0)) {
|
updateMasterCheckBitSet(copyPVStructure,bitSet,0);
|
||||||
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
|
size_t nextSet =0;
|
||||||
bitSet->set(i,true);
|
while(true) {
|
||||||
|
nextSet = bitSet->nextSetBit(nextSet);
|
||||||
|
if(nextSet==string::npos) return;
|
||||||
|
PVFieldPtr pvCopy = copyPVStructure->getSubField(nextSet);
|
||||||
|
PVFieldPtr pvMaster = headNode->masterPVField;
|
||||||
|
if(pvMaster->getField()->getType()==epics::pvData::structure) {
|
||||||
|
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvMaster);
|
||||||
|
pvMaster = pv->getSubField(pvCopy->getFullName());
|
||||||
}
|
}
|
||||||
|
updateMasterField(getCopyNode(nextSet),pvCopy,pvMaster,bitSet);
|
||||||
|
bitSet->clear(nextSet);
|
||||||
}
|
}
|
||||||
updateMaster(copyPVStructure,headNode,bitSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
|
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
|
||||||
{
|
{
|
||||||
if(fieldOffset==0) return headNode->options;
|
if(fieldOffset==0) return headNode->options;
|
||||||
@@ -248,7 +319,7 @@ PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(okToContinue) continue;
|
if(okToContinue) continue;
|
||||||
throw std::logic_error("PVCopy logic error: fieldOffset not valid");
|
throw std::logic_error("PVCopy::getOptions logic error: fieldOffset not valid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,43 +413,13 @@ void PVCopy::updateCopyFromBitSet(
|
|||||||
size_t offset = structureNode->structureOffset;
|
size_t offset = structureNode->structureOffset;
|
||||||
size_t nextSet = bitSet->nextSetBit(offset);
|
size_t nextSet = bitSet->nextSetBit(offset);
|
||||||
if(nextSet==string::npos) return;
|
if(nextSet==string::npos) return;
|
||||||
if(offset>=pvCopy->getNextFieldOffset()) return;
|
if(offset>=pvCopy->getNextFieldOffset()) return;
|
||||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
||||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
||||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
||||||
updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void PVCopy::updateMaster(
|
|
||||||
PVFieldPtr const & pvCopy,
|
|
||||||
CopyNodePtr const & node,
|
|
||||||
BitSetPtr const & bitSet)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
bool update = bitSet->get(pvCopy->getFieldOffset());
|
|
||||||
if(update) {
|
|
||||||
for(size_t i=0; i< node->pvFilters.size(); ++i) {
|
|
||||||
PVFilterPtr pvFilter = node->pvFilters[i];
|
|
||||||
if(pvFilter->filter(pvCopy,bitSet,false)) result = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!node->isStructure) {
|
|
||||||
if(result) return;
|
|
||||||
PVFieldPtr pvMaster = node->masterPVField;
|
|
||||||
pvMaster->copy(*pvCopy);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
|
||||||
size_t offset = structureNode->structureOffset;
|
|
||||||
size_t nextSet = bitSet->nextSetBit(offset);
|
|
||||||
if(nextSet==string::npos) return;
|
|
||||||
if(offset>=pvCopy->getNextFieldOffset()) return;
|
|
||||||
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
|
|
||||||
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
|
|
||||||
for(size_t i=0; i<pvCopyFields.size(); ++i) {
|
|
||||||
updateMaster(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PVCopy::PVCopy(
|
PVCopy::PVCopy(
|
||||||
PVStructurePtr const &pvMaster)
|
PVStructurePtr const &pvMaster)
|
||||||
@@ -386,20 +427,28 @@ PVCopy::PVCopy(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PVCopy::destroy()
|
|
||||||
{
|
|
||||||
headNode.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
|
bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
|
||||||
{
|
{
|
||||||
PVStructurePtr pvMasterStructure = pvMaster;
|
PVStructurePtr pvMasterStructure = pvMaster;
|
||||||
size_t len = pvRequest->getPVFields().size();
|
size_t len = pvRequest->getPVFields().size();
|
||||||
bool entireMaster = false;
|
bool entireMaster = false;
|
||||||
if(len==0) entireMaster = true;
|
requestHasMasterField = false;
|
||||||
PVStructurePtr pvOptions;
|
PVStructurePtr pvOptions;
|
||||||
if(len==1) {
|
if(len==0) {
|
||||||
pvOptions = pvRequest->getSubField<PVStructure>("_options");
|
entireMaster = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If "_" is in the request, but not in the master structure,
|
||||||
|
// then assume the top level PV structure is requested
|
||||||
|
PVStructurePtr masterFieldPtr = pvMaster->getSubField<PVStructure>("_");
|
||||||
|
PVStructurePtr requestFieldPtr = pvRequest->getSubField<PVStructure>("_");
|
||||||
|
if (requestFieldPtr) {
|
||||||
|
requestHasMasterField = true;
|
||||||
|
}
|
||||||
|
if (!masterFieldPtr && requestFieldPtr) {
|
||||||
|
entireMaster = true;
|
||||||
|
pvOptions = requestFieldPtr->getSubField<PVStructure>("_options");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(entireMaster) {
|
if(entireMaster) {
|
||||||
structure = pvMasterStructure->getStructure();
|
structure = pvMasterStructure->getStructure();
|
||||||
@@ -487,13 +536,13 @@ CopyNodePtr PVCopy::createStructureNodes(
|
|||||||
for(size_t i=0; i<number; i++) {
|
for(size_t i=0; i<number; i++) {
|
||||||
PVFieldPtr copyPVField = copyPVFields[i];
|
PVFieldPtr copyPVField = copyPVFields[i];
|
||||||
string fieldName = copyPVField->getFieldName();
|
string fieldName = copyPVField->getFieldName();
|
||||||
PVStructurePtr requestPVStructure =
|
PVStructurePtr requestPVStructure =
|
||||||
pvFromRequest->getSubField<PVStructure>(fieldName);
|
pvFromRequest->getSubField<PVStructure>(fieldName);
|
||||||
PVStructurePtr pvSubFieldOptions =
|
PVStructurePtr pvSubFieldOptions =
|
||||||
requestPVStructure->getSubField<PVStructure>("_options");
|
requestPVStructure->getSubField<PVStructure>("_options");
|
||||||
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
|
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
|
||||||
if(!pvMasterField) {
|
if(!pvMasterField) {
|
||||||
throw std::logic_error("PVCopy logic error: did not find field in master");
|
throw std::logic_error("PVCopy::createStructureNodes did not find field in master");
|
||||||
}
|
}
|
||||||
size_t numberRequest = requestPVStructure->getPVFields().size();
|
size_t numberRequest = requestPVStructure->getPVFields().size();
|
||||||
bool haveOptions = false;
|
bool haveOptions = false;
|
||||||
@@ -599,14 +648,14 @@ void PVCopy::initPlugin(
|
|||||||
|
|
||||||
void PVCopy::traverseMasterInitPlugin()
|
void PVCopy::traverseMasterInitPlugin()
|
||||||
{
|
{
|
||||||
traverseMasterInitPlugin(headNode);
|
traverseMasterInitPlugin(headNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PVCopy::traverseMasterInitPlugin(CopyNodePtr const & node)
|
void PVCopy::traverseMasterInitPlugin(CopyNodePtr const & node)
|
||||||
{
|
{
|
||||||
PVFieldPtr pvField = node->masterPVField;
|
PVFieldPtr pvField = node->masterPVField;
|
||||||
PVStructurePtr pvOptions = node->options;
|
PVStructurePtr pvOptions = node->options;
|
||||||
if(pvOptions) initPlugin(node,pvOptions,pvField);
|
if(pvOptions) initPlugin(node,pvOptions,pvField);
|
||||||
if(!node->isStructure) return;
|
if(!node->isStructure) return;
|
||||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||||
@@ -625,7 +674,7 @@ CopyNodePtr PVCopy::getCopyOffset(
|
|||||||
CopyNodePtr node = (*nodes)[i];
|
CopyNodePtr node = (*nodes)[i];
|
||||||
if(!node->isStructure) {
|
if(!node->isStructure) {
|
||||||
size_t off = node->masterPVField->getFieldOffset();
|
size_t off = node->masterPVField->getFieldOffset();
|
||||||
size_t nextOffset = node->masterPVField->getNextFieldOffset();
|
size_t nextOffset = node->masterPVField->getNextFieldOffset();
|
||||||
if(offset>= off && offset<nextOffset) return node;
|
if(offset>= off && offset<nextOffset) return node;
|
||||||
} else {
|
} else {
|
||||||
CopyStructureNodePtr subNode =
|
CopyStructureNodePtr subNode =
|
||||||
@@ -668,7 +717,7 @@ void PVCopy::setIgnore(CopyNodePtr const &node) {
|
|||||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||||
for(size_t i=0; i<nodes->size(); ++i) {
|
for(size_t i=0; i<nodes->size(); ++i) {
|
||||||
CopyNodePtr node = (*nodes)[i];
|
CopyNodePtr node = (*nodes)[i];
|
||||||
setIgnore(node); }
|
setIgnore(node); }
|
||||||
} else {
|
} else {
|
||||||
size_t num = node->masterPVField->getNumberFields();
|
size_t num = node->masterPVField->getNumberFields();
|
||||||
if(num>1) {
|
if(num>1) {
|
||||||
|
|||||||
@@ -4,12 +4,15 @@
|
|||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <pv/lock.h>
|
||||||
#include <pv/pvData.h>
|
#include <pv/pvData.h>
|
||||||
#include <pv/bitSet.h>
|
#include <pv/bitSet.h>
|
||||||
#include <pv/convert.h>
|
#include <pv/convert.h>
|
||||||
#include <pv/pvSubArrayCopy.h>
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/pvDeadbandPlugin.h>
|
#include "pv/pvDeadbandPlugin.h"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
@@ -64,9 +67,9 @@ PVDeadbandFilterPtr PVDeadbandFilter::create(
|
|||||||
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
|
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
|
||||||
if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr();
|
if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr();
|
||||||
bool absolute = false;
|
bool absolute = false;
|
||||||
if(requestValue.find("abs")>=0) {
|
if(requestValue.find("abs")==0) {
|
||||||
absolute = true;
|
absolute = true;
|
||||||
} else if(requestValue.find("rel")>=0) {
|
} else if(requestValue.find("rel")==0) {
|
||||||
absolute = false;
|
absolute = false;
|
||||||
} else {
|
} else {
|
||||||
return PVDeadbandFilterPtr();
|
return PVDeadbandFilterPtr();
|
||||||
@@ -79,7 +82,7 @@ PVDeadbandFilterPtr PVDeadbandFilter::create(
|
|||||||
PVDeadbandFilterPtr filter =
|
PVDeadbandFilterPtr filter =
|
||||||
PVDeadbandFilterPtr(
|
PVDeadbandFilterPtr(
|
||||||
new PVDeadbandFilter(
|
new PVDeadbandFilter(
|
||||||
absolute,deadband,static_pointer_cast<PVScalar>(master)));
|
absolute,deadband,static_pointer_cast<PVScalar>(master)));
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +91,7 @@ PVDeadbandFilter::PVDeadbandFilter(bool absolute,double deadband,PVScalarPtr con
|
|||||||
deadband(deadband),
|
deadband(deadband),
|
||||||
master(master),
|
master(master),
|
||||||
firstTime(true),
|
firstTime(true),
|
||||||
lastReportedValue(0.0)
|
lastReportedValue(0.0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,8 +128,7 @@ bool PVDeadbandFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet
|
|||||||
|
|
||||||
string PVDeadbandFilter::getName()
|
string PVDeadbandFilter::getName()
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pv/pvData.h>
|
#include <pv/pvData.h>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <pv/lock.h>
|
||||||
|
#include <pv/bitSet.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/pvStructureCopy.h>
|
#include "pv/pvPlugin.h"
|
||||||
#include <pv/pvPlugin.h>
|
|
||||||
|
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
|
|
||||||
namespace epics { namespace pvCopy{
|
namespace epics { namespace pvCopy{
|
||||||
|
|
||||||
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
||||||
|
|
||||||
@@ -34,4 +38,3 @@ PVPluginPtr PVPluginRegistry::find(const std::string & name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,17 @@
|
|||||||
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
* The License for this software can be found in the file LICENSE that is included with the distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <pv/lock.h>
|
||||||
#include <pv/pvData.h>
|
#include <pv/pvData.h>
|
||||||
#include <pv/bitSet.h>
|
#include <pv/bitSet.h>
|
||||||
#include <pv/convert.h>
|
#include <pv/convert.h>
|
||||||
#include <pv/pvTimeStamp.h>
|
#include <pv/pvTimeStamp.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/pvTimestampPlugin.h>
|
#include "pv/pvPlugin.h"
|
||||||
#include <pv/pvStructureCopy.h>
|
#include "pv/pvTimestampPlugin.h"
|
||||||
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
@@ -86,7 +89,7 @@ PVTimestampFilter::PVTimestampFilter(bool current,bool copy,PVFieldPtr const & m
|
|||||||
|
|
||||||
bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
|
||||||
{
|
{
|
||||||
if(current) {
|
if(current) {
|
||||||
timeStamp.getCurrent();
|
timeStamp.getCurrent();
|
||||||
if(toCopy) {
|
if(toCopy) {
|
||||||
if(!pvTimeStamp.attach(pvCopy)) return false;
|
if(!pvTimeStamp.attach(pvCopy)) return false;
|
||||||
@@ -97,7 +100,7 @@ bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSe
|
|||||||
bitSet->set(pvCopy->getFieldOffset());
|
bitSet->set(pvCopy->getFieldOffset());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(copy) {
|
if(copy) {
|
||||||
if(toCopy) {
|
if(toCopy) {
|
||||||
if(!pvTimeStamp.attach(master)) return false;
|
if(!pvTimeStamp.attach(master)) return false;
|
||||||
pvTimeStamp.get(timeStamp);
|
pvTimeStamp.get(timeStamp);
|
||||||
@@ -117,8 +120,7 @@ bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSe
|
|||||||
|
|
||||||
string PVTimestampFilter::getName()
|
string PVTimestampFilter::getName()
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <epicsGuard.h>
|
#include <epicsGuard.h>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/pvDatabase.h>
|
#include "pv/pvStructureCopy.h"
|
||||||
#include <pv/pvStructureCopy.h>
|
#include "pv/pvDatabase.h"
|
||||||
#include <pv/pvPlugin.h>
|
#include "pv/pvPlugin.h"
|
||||||
#include <pv/pvArrayPlugin.h>
|
#include "pv/pvArrayPlugin.h"
|
||||||
#include <pv/pvTimestampPlugin.h>
|
#include "pv/pvTimestampPlugin.h"
|
||||||
#include <pv/pvDeadbandPlugin.h>
|
#include "pv/pvDeadbandPlugin.h"
|
||||||
|
#include "pv/dataDistributorPlugin.h"
|
||||||
|
|
||||||
using std::tr1::static_pointer_cast;
|
using std::tr1::static_pointer_cast;
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
@@ -38,7 +45,8 @@ PVDatabasePtr PVDatabase::getMaster()
|
|||||||
PVArrayPlugin::create();
|
PVArrayPlugin::create();
|
||||||
PVTimestampPlugin::create();
|
PVTimestampPlugin::create();
|
||||||
PVDeadbandPlugin::create();
|
PVDeadbandPlugin::create();
|
||||||
}
|
DataDistributorPlugin::create();
|
||||||
|
}
|
||||||
return pvDatabaseMaster;
|
return pvDatabaseMaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,14 +58,6 @@ PVDatabase::PVDatabase()
|
|||||||
PVDatabase::~PVDatabase()
|
PVDatabase::~PVDatabase()
|
||||||
{
|
{
|
||||||
if(DEBUG_LEVEL>0) cout << "PVDatabase::~PVDatabase()\n";
|
if(DEBUG_LEVEL>0) cout << "PVDatabase::~PVDatabase()\n";
|
||||||
size_t len = recordMap.size();
|
|
||||||
shared_vector<string> names(len);
|
|
||||||
PVRecordMap::iterator iter;
|
|
||||||
size_t i = 0;
|
|
||||||
for(iter = recordMap.begin(); iter!=recordMap.end(); ++iter) {
|
|
||||||
names[i++] = (*iter).first;
|
|
||||||
}
|
|
||||||
for(size_t i=0; i<len; ++i) removeRecord(findRecord(names[i]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PVDatabase::lock() {
|
void PVDatabase::lock() {
|
||||||
@@ -94,17 +94,28 @@ bool PVDatabase::addRecord(PVRecordPtr const & record)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PVDatabase::removeRecord(PVRecordPtr const & record)
|
PVRecordWPtr PVDatabase::removeFromMap(PVRecordPtr const & record)
|
||||||
{
|
{
|
||||||
if(record->getTraceLevel()>0) {
|
|
||||||
cout << "PVDatabase::removeRecord " << record->getRecordName() << endl;
|
|
||||||
}
|
|
||||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||||
string recordName = record->getRecordName();
|
string recordName = record->getRecordName();
|
||||||
PVRecordMap::iterator iter = recordMap.find(recordName);
|
PVRecordMap::iterator iter = recordMap.find(recordName);
|
||||||
if(iter!=recordMap.end()) {
|
if(iter!=recordMap.end()) {
|
||||||
PVRecordPtr pvRecord = (*iter).second;
|
PVRecordPtr pvRecord = (*iter).second;
|
||||||
recordMap.erase(iter);
|
recordMap.erase(iter);
|
||||||
|
return pvRecord->shared_from_this();
|
||||||
|
}
|
||||||
|
return PVRecordWPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PVDatabase::removeRecord(PVRecordPtr const & record)
|
||||||
|
{
|
||||||
|
if(record->getTraceLevel()>0) {
|
||||||
|
cout << "PVDatabase::removeRecord " << record->getRecordName() << endl;
|
||||||
|
}
|
||||||
|
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||||
|
PVRecordWPtr pvRecord = removeFromMap(record);
|
||||||
|
if(pvRecord.use_count()!=0) {
|
||||||
|
pvRecord.lock()->unlistenClients();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -8,13 +8,25 @@
|
|||||||
* @author mrk
|
* @author mrk
|
||||||
* @date 2012.11.21
|
* @date 2012.11.21
|
||||||
*/
|
*/
|
||||||
|
#include <list>
|
||||||
#include <epicsGuard.h>
|
#include <epicsGuard.h>
|
||||||
#include <epicsThread.h>
|
#include <epicsThread.h>
|
||||||
|
#include <pv/status.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/createRequest.h>
|
||||||
|
#include <pv/pvaVersion.h>
|
||||||
|
#include <pv/pvaVersionNum.h>
|
||||||
|
#include <pv/monitor.h>
|
||||||
|
#include <pv/convert.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/pvDatabase.h>
|
#include "pv/pvStructureCopy.h"
|
||||||
#include <pv/pvStructureCopy.h>
|
#include "pv/pvDatabase.h"
|
||||||
|
|
||||||
|
|
||||||
using std::tr1::static_pointer_cast;
|
using std::tr1::static_pointer_cast;
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
@@ -25,9 +37,11 @@ namespace epics { namespace pvDatabase {
|
|||||||
|
|
||||||
PVRecordPtr PVRecord::create(
|
PVRecordPtr PVRecord::create(
|
||||||
string const &recordName,
|
string const &recordName,
|
||||||
PVStructurePtr const & pvStructure)
|
PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,
|
||||||
|
const std::string& asGroup)
|
||||||
{
|
{
|
||||||
PVRecordPtr pvRecord(new PVRecord(recordName,pvStructure));
|
PVRecordPtr pvRecord(new PVRecord(recordName,pvStructure,asLevel,asGroup));
|
||||||
if(!pvRecord->init()) {
|
if(!pvRecord->init()) {
|
||||||
pvRecord.reset();
|
pvRecord.reset();
|
||||||
}
|
}
|
||||||
@@ -37,25 +51,29 @@ PVRecordPtr PVRecord::create(
|
|||||||
|
|
||||||
PVRecord::PVRecord(
|
PVRecord::PVRecord(
|
||||||
string const & recordName,
|
string const & recordName,
|
||||||
PVStructurePtr const & pvStructure)
|
PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel_,
|
||||||
|
const std::string& asGroup_)
|
||||||
: recordName(recordName),
|
: recordName(recordName),
|
||||||
pvStructure(pvStructure),
|
pvStructure(pvStructure),
|
||||||
depthGroupPut(0),
|
depthGroupPut(0),
|
||||||
traceLevel(0),
|
traceLevel(0),
|
||||||
isAddListener(false)
|
isAddListener(false),
|
||||||
|
asLevel(asLevel_),
|
||||||
|
asGroup(asGroup_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PVRecord::notifyClients()
|
PVRecord::~PVRecord()
|
||||||
{
|
{
|
||||||
{
|
if(traceLevel>0) {
|
||||||
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
cout << "~PVRecord() " << recordName << endl;
|
||||||
if(traceLevel>0) {
|
|
||||||
cout << "PVRecord::notifyClients() " << recordName
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pvTimeStamp.detach();
|
}
|
||||||
|
|
||||||
|
void PVRecord::unlistenClients()
|
||||||
|
{
|
||||||
|
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||||
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
|
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
|
||||||
iter!=pvListenerList.end();
|
iter!=pvListenerList.end();
|
||||||
iter++ )
|
iter++ )
|
||||||
@@ -63,8 +81,7 @@ void PVRecord::notifyClients()
|
|||||||
PVListenerPtr listener = iter->lock();
|
PVListenerPtr listener = iter->lock();
|
||||||
if(!listener) continue;
|
if(!listener) continue;
|
||||||
if(traceLevel>0) {
|
if(traceLevel>0) {
|
||||||
cout << "PVRecord::notifyClients() calling listener->unlisten "
|
cout << "PVRecord::remove() calling listener->unlisten " << recordName << endl;
|
||||||
<< recordName << endl;
|
|
||||||
}
|
}
|
||||||
listener->unlisten(shared_from_this());
|
listener->unlisten(shared_from_this());
|
||||||
}
|
}
|
||||||
@@ -76,27 +93,24 @@ void PVRecord::notifyClients()
|
|||||||
PVRecordClientPtr client = iter->lock();
|
PVRecordClientPtr client = iter->lock();
|
||||||
if(!client) continue;
|
if(!client) continue;
|
||||||
if(traceLevel>0) {
|
if(traceLevel>0) {
|
||||||
cout << "PVRecord::notifyClients() calling client->detach "
|
cout << "PVRecord::remove() calling client->detach " << recordName << endl;
|
||||||
<< recordName << endl;
|
|
||||||
}
|
}
|
||||||
client->detach(shared_from_this());
|
client->detach(shared_from_this());
|
||||||
}
|
}
|
||||||
if(traceLevel>0) {
|
|
||||||
cout << "PVRecord::notifyClients() calling clientList.clear() "
|
|
||||||
<< recordName << endl;
|
|
||||||
}
|
|
||||||
clientList.clear();
|
clientList.clear();
|
||||||
if(traceLevel>0) {
|
|
||||||
cout << "PVRecord::notifyClients() returning " << recordName << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PVRecord::~PVRecord()
|
|
||||||
|
void PVRecord::remove()
|
||||||
{
|
{
|
||||||
if(traceLevel>0) {
|
if(traceLevel>0) {
|
||||||
cout << "~PVRecord() " << recordName << endl;
|
cout << "PVRecord::remove() " << recordName << endl;
|
||||||
}
|
}
|
||||||
notifyClients();
|
unlistenClients();
|
||||||
|
epicsGuard<epics::pvData::Mutex> guard(mutex);
|
||||||
|
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
|
||||||
|
if(pvDatabase) pvDatabase->removeFromMap(shared_from_this());
|
||||||
|
pvTimeStamp.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PVRecord::initPVRecord()
|
void PVRecord::initPVRecord()
|
||||||
@@ -240,7 +254,7 @@ void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
|
|||||||
PVRecordFieldPtr pvRecordField = findPVRecordField(pvField);
|
PVRecordFieldPtr pvRecordField = findPVRecordField(pvField);
|
||||||
PVListenerPtr listener = pvListener.lock();
|
PVListenerPtr listener = pvListener.lock();
|
||||||
if(!listener.get()) return;
|
if(!listener.get()) return;
|
||||||
if(isAddListener) {
|
if(isAddListener) {
|
||||||
pvRecordField->addListener(listener);
|
pvRecordField->addListener(listener);
|
||||||
} else {
|
} else {
|
||||||
pvRecordField->removeListener(listener);
|
pvRecordField->removeListener(listener);
|
||||||
@@ -318,6 +332,7 @@ PVRecordField::PVRecordField(
|
|||||||
PVRecordPtr const & pvRecord)
|
PVRecordPtr const & pvRecord)
|
||||||
: pvField(pvField),
|
: pvField(pvField),
|
||||||
isStructure(pvField->getField()->getType()==structure ? true : false),
|
isStructure(pvField->getField()->getType()==structure ? true : false),
|
||||||
|
master(),
|
||||||
parent(parent),
|
parent(parent),
|
||||||
pvRecord(pvRecord)
|
pvRecord(pvRecord)
|
||||||
{
|
{
|
||||||
@@ -369,7 +384,7 @@ bool PVRecordField::addListener(PVListenerPtr const & pvListener)
|
|||||||
|
|
||||||
void PVRecordField::removeListener(PVListenerPtr const & pvListener)
|
void PVRecordField::removeListener(PVListenerPtr const & pvListener)
|
||||||
{
|
{
|
||||||
PVRecordPtr pvRecord(this->pvRecord.lock());
|
PVRecordPtr pvRecord(this->pvRecord.lock());
|
||||||
if(pvRecord && pvRecord->getTraceLevel()>1) {
|
if(pvRecord && pvRecord->getTraceLevel()>1) {
|
||||||
cout << "PVRecordField::removeListener() " << getFullName() << endl;
|
cout << "PVRecordField::removeListener() " << getFullName() << endl;
|
||||||
}
|
}
|
||||||
@@ -404,14 +419,21 @@ void PVRecordField::postParent(PVRecordFieldPtr const & subField)
|
|||||||
listener->dataPut(pvrs,subField);
|
listener->dataPut(pvrs,subField);
|
||||||
}
|
}
|
||||||
PVRecordStructurePtr parent(this->parent.lock());
|
PVRecordStructurePtr parent(this->parent.lock());
|
||||||
if(parent) parent->postParent(subField);
|
if(parent) {
|
||||||
|
parent->postParent(subField);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PVRecordField::postSubField()
|
void PVRecordField::postSubField()
|
||||||
{
|
{
|
||||||
|
// Master field pointer will be set in only one subfield
|
||||||
|
PVRecordStructurePtr master(this->master.lock());
|
||||||
|
if(master) {
|
||||||
|
master->callListener();
|
||||||
|
}
|
||||||
callListener();
|
callListener();
|
||||||
if(isStructure) {
|
if(isStructure) {
|
||||||
PVRecordStructurePtr pvrs =
|
PVRecordStructurePtr pvrs =
|
||||||
static_pointer_cast<PVRecordStructure>(shared_from_this());
|
static_pointer_cast<PVRecordStructure>(shared_from_this());
|
||||||
PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields();
|
PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields();
|
||||||
PVRecordFieldPtrArray::iterator iter;
|
PVRecordFieldPtrArray::iterator iter;
|
||||||
@@ -451,19 +473,38 @@ void PVRecordStructure::init()
|
|||||||
PVRecordStructurePtr self =
|
PVRecordStructurePtr self =
|
||||||
static_pointer_cast<PVRecordStructure>(shared_from_this());
|
static_pointer_cast<PVRecordStructure>(shared_from_this());
|
||||||
PVRecordPtr pvRecord = getPVRecord();
|
PVRecordPtr pvRecord = getPVRecord();
|
||||||
for(size_t i=0; i<numFields; i++) {
|
static bool masterFieldCallbackSet = false;
|
||||||
|
bool isMasterField = (!getFullFieldName().size());
|
||||||
|
if (isMasterField) {
|
||||||
|
masterFieldCallbackSet = false;
|
||||||
|
}
|
||||||
|
for(size_t i=0; i<numFields; i++) {
|
||||||
PVFieldPtr pvField = pvFields[i];
|
PVFieldPtr pvField = pvFields[i];
|
||||||
if(pvField->getField()->getType()==structure) {
|
if(pvField->getField()->getType()==structure) {
|
||||||
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
|
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
|
||||||
PVRecordStructurePtr pvRecordStructure(
|
PVRecordStructurePtr pvRecordStructure(
|
||||||
new PVRecordStructure(xxx,self,pvRecord));
|
new PVRecordStructure(xxx,self,pvRecord));
|
||||||
pvRecordFields->push_back(pvRecordStructure);
|
pvRecordFields->push_back(pvRecordStructure);
|
||||||
pvRecordStructure->init();
|
pvRecordStructure->init();
|
||||||
} else {
|
} else {
|
||||||
PVRecordFieldPtr pvRecordField(
|
PVRecordFieldPtr pvRecordField(
|
||||||
new PVRecordField(pvField,self,pvRecord));
|
new PVRecordField(pvField,self,pvRecord));
|
||||||
pvRecordFields->push_back(pvRecordField);
|
pvRecordFields->push_back(pvRecordField);
|
||||||
pvRecordField->init();
|
pvRecordField->init();
|
||||||
|
// Master field listeners will be called before
|
||||||
|
// calling listeners for the first subfield
|
||||||
|
if (!masterFieldCallbackSet) {
|
||||||
|
masterFieldCallbackSet = true;
|
||||||
|
// Find master field
|
||||||
|
PVRecordStructurePtr p = pvRecordField->parent.lock();
|
||||||
|
while (p) {
|
||||||
|
PVRecordStructurePtr p2 = p->parent.lock();
|
||||||
|
if (!p2) {
|
||||||
|
pvRecordField->master = p;
|
||||||
|
}
|
||||||
|
p = p2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,6 @@
|
|||||||
#ifndef CHANNELPROVIDERLOCAL_H
|
#ifndef CHANNELPROVIDERLOCAL_H
|
||||||
#define CHANNELPROVIDERLOCAL_H
|
#define CHANNELPROVIDERLOCAL_H
|
||||||
|
|
||||||
#ifdef epicsExportSharedSymbols
|
|
||||||
# define channelProviderLocalEpicsExportSharedSymbols
|
|
||||||
# undef epicsExportSharedSymbols
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -28,18 +23,13 @@
|
|||||||
#include <pv/pvAccess.h>
|
#include <pv/pvAccess.h>
|
||||||
#include <pv/status.h>
|
#include <pv/status.h>
|
||||||
#include <pv/serverContext.h>
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
#ifdef channelProviderLocalEpicsExportSharedSymbols
|
|
||||||
# define epicsExportSharedSymbols
|
|
||||||
# undef channelProviderLocalEpicsExportSharedSymbols
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <shareLib.h>
|
#include <shareLib.h>
|
||||||
#include <pv/pvDatabase.h>
|
#include <asLib.h>
|
||||||
#include <pv/pvStructureCopy.h>
|
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
class ChannelProviderLocal;
|
class ChannelProviderLocal;
|
||||||
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
|
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
|
||||||
@@ -69,6 +59,19 @@ class epicsShareClass ChannelProviderLocal :
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ChannelProviderLocal);
|
POINTER_DEFINITIONS(ChannelProviderLocal);
|
||||||
|
/**
|
||||||
|
* @brief Initialize access security configuration
|
||||||
|
* @param filePath AS definition file path
|
||||||
|
* @param substitutions macro substitutions
|
||||||
|
* @throws std::runtime_error in case of configuration problem
|
||||||
|
*/
|
||||||
|
static void initAs(const std::string& filePath, const std::string& substitutions="");
|
||||||
|
/**
|
||||||
|
* @brief Is access security active?
|
||||||
|
* @return true is AS is active
|
||||||
|
*/
|
||||||
|
static bool isAsActive();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
*/
|
*/
|
||||||
@@ -77,11 +80,6 @@ public:
|
|||||||
* @brief Destructor
|
* @brief Destructor
|
||||||
*/
|
*/
|
||||||
virtual ~ChannelProviderLocal();
|
virtual ~ChannelProviderLocal();
|
||||||
/**
|
|
||||||
* @brief DEPRECATED
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
virtual void destroy(){};
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the channel provider name.
|
* @brief Returns the channel provider name.
|
||||||
*
|
*
|
||||||
@@ -104,7 +102,7 @@ public:
|
|||||||
virtual epics::pvAccess::ChannelFind::shared_pointer channelFind(
|
virtual epics::pvAccess::ChannelFind::shared_pointer channelFind(
|
||||||
std::string const &channelName,
|
std::string const &channelName,
|
||||||
epics::pvAccess::ChannelFindRequester::shared_pointer const & channelFindRequester);
|
epics::pvAccess::ChannelFindRequester::shared_pointer const & channelFindRequester);
|
||||||
/**
|
/**
|
||||||
* @brief Calls method channelListRequester::channelListResult.
|
* @brief Calls method channelListRequester::channelListResult.
|
||||||
*
|
*
|
||||||
* This provides the caller with a list of the record names on the PVDatabase.
|
* This provides the caller with a list of the record names on the PVDatabase.
|
||||||
@@ -112,7 +110,7 @@ public:
|
|||||||
* @param channelListRequester The client callback.
|
* @param channelListRequester The client callback.
|
||||||
* @return shared pointer to ChannelFind.
|
* @return shared pointer to ChannelFind.
|
||||||
* The interface for SyncChannelFind is defined by pvAccessCPP.
|
* The interface for SyncChannelFind is defined by pvAccessCPP.
|
||||||
*/
|
*/
|
||||||
virtual epics::pvAccess::ChannelFind::shared_pointer channelList(
|
virtual epics::pvAccess::ChannelFind::shared_pointer channelList(
|
||||||
epics::pvAccess::ChannelListRequester::shared_pointer const & channelListRequester);
|
epics::pvAccess::ChannelListRequester::shared_pointer const & channelListRequester);
|
||||||
/**
|
/**
|
||||||
@@ -174,6 +172,7 @@ private:
|
|||||||
friend class ChannelProviderLocalRun;
|
friend class ChannelProviderLocalRun;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Channel for accessing a PVRecord.
|
* @brief Channel for accessing a PVRecord.
|
||||||
*
|
*
|
||||||
@@ -197,28 +196,23 @@ public:
|
|||||||
epics::pvAccess::ChannelRequester::shared_pointer const & requester,
|
epics::pvAccess::ChannelRequester::shared_pointer const & requester,
|
||||||
PVRecordPtr const & pvRecord
|
PVRecordPtr const & pvRecord
|
||||||
);
|
);
|
||||||
/**
|
/**
|
||||||
* @brief Destructor
|
* @brief Destructor
|
||||||
*/
|
*/
|
||||||
virtual ~ChannelLocal();
|
virtual ~ChannelLocal();
|
||||||
/**
|
/**
|
||||||
* @brief DEPRECATED
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
virtual void destroy() {};
|
|
||||||
/**
|
|
||||||
* @brief Detach from the record.
|
* @brief Detach from the record.
|
||||||
*
|
*
|
||||||
* This is called when a record is being removed from the database.
|
* This is called when a record is being removed from the database.
|
||||||
* @param pvRecord The record being removed.
|
* @param pvRecord The record being removed.
|
||||||
*/
|
*/
|
||||||
virtual void detach(PVRecordPtr const &pvRecord);
|
virtual void detach(PVRecordPtr const &pvRecord);
|
||||||
/**
|
/**
|
||||||
* @brief Get the requester name.
|
* @brief Get the requester name.
|
||||||
* @return returns the name of the channel requester.
|
* @return returns the name of the channel requester.
|
||||||
*/
|
*/
|
||||||
virtual std::string getRequesterName();
|
virtual std::string getRequesterName();
|
||||||
/**
|
/**
|
||||||
* @brief Passes the message to the channel requester.
|
* @brief Passes the message to the channel requester.
|
||||||
* @param message The message.
|
* @param message The message.
|
||||||
* @param messageType The message type.
|
* @param messageType The message type.
|
||||||
@@ -226,37 +220,37 @@ public:
|
|||||||
virtual void message(
|
virtual void message(
|
||||||
std::string const & message,
|
std::string const & message,
|
||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
/**
|
/**
|
||||||
* @brief Get the channel provider
|
* @brief Get the channel provider
|
||||||
* @return The provider.
|
* @return The provider.
|
||||||
*/
|
*/
|
||||||
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider();
|
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider();
|
||||||
/**
|
/**
|
||||||
* @brief Get the remote address
|
* @brief Get the remote address
|
||||||
* @return <b>local</b>
|
* @return <b>local</b>
|
||||||
*/
|
*/
|
||||||
virtual std::string getRemoteAddress();
|
virtual std::string getRemoteAddress();
|
||||||
/**
|
/**
|
||||||
* Get the connection state.
|
* Get the connection state.
|
||||||
* @return Channel::CONNECTED.
|
* @return Channel::CONNECTED.
|
||||||
*/
|
*/
|
||||||
virtual epics::pvAccess::Channel::ConnectionState getConnectionState();
|
virtual epics::pvAccess::Channel::ConnectionState getConnectionState();
|
||||||
/**
|
/**
|
||||||
* @brief Get the channel name.
|
* @brief Get the channel name.
|
||||||
* @return the record name.
|
* @return the record name.
|
||||||
*/
|
*/
|
||||||
virtual std::string getChannelName();
|
virtual std::string getChannelName();
|
||||||
/**
|
/**
|
||||||
* @brief Get the channel requester
|
* @brief Get the channel requester
|
||||||
* @return The channel requester.
|
* @return The channel requester.
|
||||||
*/
|
*/
|
||||||
virtual epics::pvAccess::ChannelRequester::shared_pointer getChannelRequester();
|
virtual epics::pvAccess::ChannelRequester::shared_pointer getChannelRequester();
|
||||||
/**
|
/**
|
||||||
* @brief Is the channel connected?
|
* @brief Is the channel connected?
|
||||||
* @return true.
|
* @return true.
|
||||||
*/
|
*/
|
||||||
virtual bool isConnected();
|
virtual bool isConnected();
|
||||||
/**
|
/**
|
||||||
* @brief Get the introspection interface for subField.
|
* @brief Get the introspection interface for subField.
|
||||||
*
|
*
|
||||||
* The introspection interface is given via GetFieldRequester::getDone.
|
* The introspection interface is given via GetFieldRequester::getDone.
|
||||||
@@ -268,14 +262,14 @@ public:
|
|||||||
virtual void getField(
|
virtual void getField(
|
||||||
epics::pvAccess::GetFieldRequester::shared_pointer const &requester,
|
epics::pvAccess::GetFieldRequester::shared_pointer const &requester,
|
||||||
std::string const & subField);
|
std::string const & subField);
|
||||||
/**
|
/**
|
||||||
* Get the access rights for the record.
|
* Get the access rights for the record.
|
||||||
* This throws an exception because it is assumed that access rights are
|
* This throws an exception because it is assumed that access rights are
|
||||||
* handled by a higher level.
|
* handled by a higher level.
|
||||||
*/
|
*/
|
||||||
virtual epics::pvAccess::AccessRights getAccessRights(
|
virtual epics::pvAccess::AccessRights getAccessRights(
|
||||||
epics::pvData::PVField::shared_pointer const &pvField);
|
epics::pvData::PVField::shared_pointer const &pvField);
|
||||||
/**
|
/**
|
||||||
* @brief Create a channelProcess.
|
* @brief Create a channelProcess.
|
||||||
*
|
*
|
||||||
* @param requester The client callback.
|
* @param requester The client callback.
|
||||||
@@ -286,9 +280,9 @@ public:
|
|||||||
virtual epics::pvAccess::ChannelProcess::shared_pointer createChannelProcess(
|
virtual epics::pvAccess::ChannelProcess::shared_pointer createChannelProcess(
|
||||||
epics::pvAccess::ChannelProcessRequester::shared_pointer const &requester,
|
epics::pvAccess::ChannelProcessRequester::shared_pointer const &requester,
|
||||||
epics::pvData::PVStructurePtr const &pvRequest);
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
/**
|
/**
|
||||||
* @brief Create a channelGet.
|
* @brief Create a channelGet.
|
||||||
*
|
*
|
||||||
* @param requester The client callback.
|
* @param requester The client callback.
|
||||||
* @param pvRequest The options specified by the client.
|
* @param pvRequest The options specified by the client.
|
||||||
* @return A shared pointer to the newly created implementation.
|
* @return A shared pointer to the newly created implementation.
|
||||||
@@ -297,7 +291,7 @@ public:
|
|||||||
virtual epics::pvAccess::ChannelGet::shared_pointer createChannelGet(
|
virtual epics::pvAccess::ChannelGet::shared_pointer createChannelGet(
|
||||||
epics::pvAccess::ChannelGetRequester::shared_pointer const &requester,
|
epics::pvAccess::ChannelGetRequester::shared_pointer const &requester,
|
||||||
epics::pvData::PVStructurePtr const &pvRequest);
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
/**
|
/**
|
||||||
* @brief Create a channelPut.
|
* @brief Create a channelPut.
|
||||||
*
|
*
|
||||||
* @param requester The client callback.
|
* @param requester The client callback.
|
||||||
@@ -308,9 +302,9 @@ public:
|
|||||||
virtual epics::pvAccess::ChannelPut::shared_pointer createChannelPut(
|
virtual epics::pvAccess::ChannelPut::shared_pointer createChannelPut(
|
||||||
epics::pvAccess::ChannelPutRequester::shared_pointer const &requester,
|
epics::pvAccess::ChannelPutRequester::shared_pointer const &requester,
|
||||||
epics::pvData::PVStructurePtr const &pvRequest);
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
/**
|
/**
|
||||||
* @brief Create a channelPutGet.
|
* @brief Create a channelPutGet.
|
||||||
*
|
*
|
||||||
* @param requester The client callback.
|
* @param requester The client callback.
|
||||||
* @param pvRequest The options specified by the client.
|
* @param pvRequest The options specified by the client.
|
||||||
* @return A shared pointer to the newly created implementation.
|
* @return A shared pointer to the newly created implementation.
|
||||||
@@ -319,7 +313,7 @@ public:
|
|||||||
virtual epics::pvAccess::ChannelPutGet::shared_pointer createChannelPutGet(
|
virtual epics::pvAccess::ChannelPutGet::shared_pointer createChannelPutGet(
|
||||||
epics::pvAccess::ChannelPutGetRequester::shared_pointer const &requester,
|
epics::pvAccess::ChannelPutGetRequester::shared_pointer const &requester,
|
||||||
epics::pvData::PVStructurePtr const &pvRequest);
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
/**
|
/**
|
||||||
* @brief Create a channelRPC.
|
* @brief Create a channelRPC.
|
||||||
*
|
*
|
||||||
* The PVRecord must implement <b>getService</b> or an empty shared pointer is returned.
|
* The PVRecord must implement <b>getService</b> or an empty shared pointer is returned.
|
||||||
@@ -330,9 +324,9 @@ public:
|
|||||||
virtual epics::pvAccess::ChannelRPC::shared_pointer createChannelRPC(
|
virtual epics::pvAccess::ChannelRPC::shared_pointer createChannelRPC(
|
||||||
epics::pvAccess::ChannelRPCRequester::shared_pointer const &requester,
|
epics::pvAccess::ChannelRPCRequester::shared_pointer const &requester,
|
||||||
epics::pvData::PVStructurePtr const &pvRequest);
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
/**
|
/**
|
||||||
* @brief Create a monitor.
|
* @brief Create a monitor.
|
||||||
*
|
*
|
||||||
* @param requester The client callback.
|
* @param requester The client callback.
|
||||||
* @param pvRequest The options specified by the client.
|
* @param pvRequest The options specified by the client.
|
||||||
* @return A shared pointer to the newly created implementation.
|
* @return A shared pointer to the newly created implementation.
|
||||||
@@ -341,9 +335,9 @@ public:
|
|||||||
virtual epics::pvData::Monitor::shared_pointer createMonitor(
|
virtual epics::pvData::Monitor::shared_pointer createMonitor(
|
||||||
epics::pvData::MonitorRequester::shared_pointer const &requester,
|
epics::pvData::MonitorRequester::shared_pointer const &requester,
|
||||||
epics::pvData::PVStructurePtr const &pvRequest);
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
/**
|
/**
|
||||||
* @brief Create a channelArray.
|
* @brief Create a channelArray.
|
||||||
*
|
*
|
||||||
* @param requester The client callback.
|
* @param requester The client callback.
|
||||||
* @param pvRequest The options specified by the client.
|
* @param pvRequest The options specified by the client.
|
||||||
* @return A shared pointer to the newly created implementation.
|
* @return A shared pointer to the newly created implementation.
|
||||||
@@ -352,16 +346,28 @@ public:
|
|||||||
virtual epics::pvAccess::ChannelArray::shared_pointer createChannelArray(
|
virtual epics::pvAccess::ChannelArray::shared_pointer createChannelArray(
|
||||||
epics::pvAccess::ChannelArrayRequester::shared_pointer const &requester,
|
epics::pvAccess::ChannelArrayRequester::shared_pointer const &requester,
|
||||||
epics::pvData::PVStructurePtr const &pvRequest);
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
/**
|
/**
|
||||||
* @brief calls printInfo(std::cout);
|
* @brief calls printInfo(std::cout);
|
||||||
*/
|
*/
|
||||||
virtual void printInfo();
|
virtual void printInfo();
|
||||||
/**
|
/**
|
||||||
* @brief displays a message
|
* @brief displays a message
|
||||||
*
|
*
|
||||||
* @param out the stream on which the message is displayed.
|
* @param out the stream on which the message is displayed.
|
||||||
*/
|
*/
|
||||||
virtual void printInfo(std::ostream& out);
|
virtual void printInfo(std::ostream& out);
|
||||||
|
/**
|
||||||
|
* @brief determines if client can write
|
||||||
|
*
|
||||||
|
* @return true if client can write
|
||||||
|
*/
|
||||||
|
virtual bool canWrite();
|
||||||
|
/**
|
||||||
|
* @brief determines if client can read
|
||||||
|
*
|
||||||
|
* @return true if client can read
|
||||||
|
*/
|
||||||
|
virtual bool canRead();
|
||||||
protected:
|
protected:
|
||||||
shared_pointer getPtrSelf()
|
shared_pointer getPtrSelf()
|
||||||
{
|
{
|
||||||
@@ -372,6 +378,19 @@ private:
|
|||||||
ChannelProviderLocalWPtr provider;
|
ChannelProviderLocalWPtr provider;
|
||||||
PVRecordWPtr pvRecord;
|
PVRecordWPtr pvRecord;
|
||||||
epics::pvData::Mutex mutex;
|
epics::pvData::Mutex mutex;
|
||||||
|
|
||||||
|
// AS-specific variables/methods
|
||||||
|
std::vector<char> toCharArray(const std::string& s);
|
||||||
|
std::vector<char> getAsGroup(const PVRecordPtr& pvRecord);
|
||||||
|
std::vector<char> getAsUser(const epics::pvAccess::ChannelRequester::shared_pointer& requester);
|
||||||
|
std::vector<char> getAsHost(const epics::pvAccess::ChannelRequester::shared_pointer& requester);
|
||||||
|
|
||||||
|
int asLevel;
|
||||||
|
std::vector<char> asGroup;
|
||||||
|
std::vector<char> asUser;
|
||||||
|
std::vector<char> asHost;
|
||||||
|
ASMEMBERPVT asMemberPvt;
|
||||||
|
ASCLIENTPVT asClientPvt;
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|||||||
89
src/pv/controlSupport.h
Normal file
89
src/pv/controlSupport.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2019.06.01
|
||||||
|
*/
|
||||||
|
#ifndef CONTROLSUPPORT_H
|
||||||
|
#define CONTROLSUPPORT_H
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class ControlSupport;
|
||||||
|
typedef std::tr1::shared_ptr<ControlSupport> ControlSupportPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base interface for a ControlSupport.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass ControlSupport :
|
||||||
|
PVSupport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ControlSupport);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~ControlSupport();
|
||||||
|
/**
|
||||||
|
* @brief Connects to contol fields.
|
||||||
|
*
|
||||||
|
* @param pvValue The field to support.
|
||||||
|
* @param pvSupport Support specific fields.
|
||||||
|
* @return <b>true</b> for success and <b>false</b> for failure.
|
||||||
|
*/
|
||||||
|
virtual bool init(
|
||||||
|
epics::pvData::PVFieldPtr const & pvValue,
|
||||||
|
epics::pvData::PVFieldPtr const & pvSupport);
|
||||||
|
/**
|
||||||
|
* @brief Honors control fields.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return Returns true is any fields were modified; otherwise false.
|
||||||
|
*/
|
||||||
|
virtual bool process();
|
||||||
|
/**
|
||||||
|
* @brief If implementing minSteps it sets isMinStep to false.
|
||||||
|
*
|
||||||
|
* @return Returns true is any fields were modified; otherwise false.
|
||||||
|
*/
|
||||||
|
virtual void reset();
|
||||||
|
/**
|
||||||
|
* @brief create a ControlSupport
|
||||||
|
*
|
||||||
|
* @param pvRecord - The pvRecord to which the support is attached.
|
||||||
|
* @return The new ControlSupport
|
||||||
|
*/
|
||||||
|
static ControlSupportPtr create(PVRecordPtr const & pvRecord);
|
||||||
|
/**
|
||||||
|
* @brief create a controlSupport required by ControlSupport
|
||||||
|
*
|
||||||
|
* @param scalarType The type for outputValue.
|
||||||
|
* @return The controlField introspection structure.
|
||||||
|
*/
|
||||||
|
static epics::pvData::StructureConstPtr controlField(epics::pvData::ScalarType scalarType);
|
||||||
|
private:
|
||||||
|
ControlSupport(PVRecordPtr const & pvRecord);
|
||||||
|
PVRecordPtr pvRecord;
|
||||||
|
epics::pvData::PVScalarPtr pvValue;
|
||||||
|
epics::pvData::PVStructurePtr pvControl;
|
||||||
|
epics::pvData::PVDoublePtr pvLimitLow;
|
||||||
|
epics::pvData::PVDoublePtr pvLimitHigh;
|
||||||
|
epics::pvData::PVDoublePtr pvMinStep;
|
||||||
|
epics::pvData::PVScalarPtr pvOutputValue;
|
||||||
|
double currentValue;
|
||||||
|
bool isMinStep;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* CONTROLSUPPORT_H */
|
||||||
167
src/pv/dataDistributorPlugin.h
Normal file
167
src/pv/dataDistributorPlugin.h
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
// Copyright information and license terms for this software can be
|
||||||
|
// found in the file LICENSE that is included with the distribution
|
||||||
|
|
||||||
|
#ifndef DATA_DISTRIBUTOR_PLUGIN_H
|
||||||
|
#define DATA_DISTRIBUTOR_PLUGIN_H
|
||||||
|
|
||||||
|
// The data distributor plugin enables distribution of channel data between
|
||||||
|
// multiple client applications.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <pv/lock.h>
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/pvPlugin.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvCopy {
|
||||||
|
|
||||||
|
class DataDistributorPlugin;
|
||||||
|
class DataDistributorFilter;
|
||||||
|
class DataDistributor;
|
||||||
|
|
||||||
|
typedef std::tr1::shared_ptr<DataDistributorPlugin> DataDistributorPluginPtr;
|
||||||
|
typedef std::tr1::shared_ptr<DataDistributorFilter> DataDistributorFilterPtr;
|
||||||
|
typedef std::tr1::shared_ptr<DataDistributor> DataDistributorPtr;
|
||||||
|
|
||||||
|
struct ClientSet;
|
||||||
|
typedef std::tr1::shared_ptr<ClientSet> ClientSetPtr;
|
||||||
|
typedef std::tr1::shared_ptr<const ClientSet> ClientSetConstPtr;
|
||||||
|
|
||||||
|
struct ClientSet
|
||||||
|
{
|
||||||
|
POINTER_DEFINITIONS(ClientSet);
|
||||||
|
|
||||||
|
ClientSet(const std::string& setId_, const std::string triggerField_, int nUpdatesPerClient_, int updateMode_)
|
||||||
|
: setId(setId_)
|
||||||
|
, triggerField(triggerField_)
|
||||||
|
, nUpdatesPerClient(nUpdatesPerClient_)
|
||||||
|
, updateMode(updateMode_)
|
||||||
|
, clientIdList()
|
||||||
|
, lastUpdateValue()
|
||||||
|
, updateCounter(0)
|
||||||
|
, currentClientIdIter(clientIdList.end())
|
||||||
|
{}
|
||||||
|
~ClientSet() {}
|
||||||
|
std::string setId;
|
||||||
|
std::string triggerField;
|
||||||
|
int nUpdatesPerClient;
|
||||||
|
int updateMode;
|
||||||
|
std::list<int> clientIdList;
|
||||||
|
std::string lastUpdateValue;
|
||||||
|
int updateCounter;
|
||||||
|
std::list<int>::iterator currentClientIdIter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DataDistributor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ClientUpdateMode {
|
||||||
|
DD_UPDATE_ONE_PER_GROUP = 0, // Update goes to one client per set
|
||||||
|
DD_UPDATE_ALL_IN_GROUP = 1, // Update goes to all clients in set
|
||||||
|
DD_N_UPDATE_MODES = 2 // Number of valid update modes
|
||||||
|
};
|
||||||
|
|
||||||
|
static DataDistributorPtr getInstance(const std::string& groupId);
|
||||||
|
static void removeUnusedInstance(DataDistributorPtr dataDistributorPtr);
|
||||||
|
|
||||||
|
virtual ~DataDistributor();
|
||||||
|
std::string getGroupId() const { return groupId; }
|
||||||
|
std::string addClient(int clientId, const std::string& setId, const std::string& triggerField, int nUpdatesPerClient, int updateMode);
|
||||||
|
void removeClient(int clientId, const std::string& setId);
|
||||||
|
bool updateClient(int clientId, const std::string& setId, const std::string& triggerFieldValue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DataDistributor(const std::string& id);
|
||||||
|
DataDistributor(const DataDistributor& distributor);
|
||||||
|
DataDistributor& operator=(const DataDistributor& distributor);
|
||||||
|
|
||||||
|
static std::map<std::string, DataDistributorPtr> dataDistributorMap;
|
||||||
|
static epics::pvData::Mutex dataDistributorMapMutex;
|
||||||
|
|
||||||
|
std::string groupId;
|
||||||
|
epics::pvData::Mutex mutex;
|
||||||
|
std::map<std::string, ClientSetPtr> clientSetMap;
|
||||||
|
std::list<std::string> clientSetIdList;
|
||||||
|
std::list<std::string>::iterator currentSetIdIter;
|
||||||
|
std::string lastUpdateValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class epicsShareClass DataDistributorPlugin : public PVPlugin
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
DataDistributorPlugin();
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(DataDistributorPlugin);
|
||||||
|
virtual ~DataDistributorPlugin();
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
private:
|
||||||
|
static bool initialize();
|
||||||
|
static bool initialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A Plugin for a filter that gets a sub array from a PVScalarDeadband.
|
||||||
|
*/
|
||||||
|
class epicsShareClass DataDistributorFilter : public PVFilter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
DataDistributorPtr dataDistributorPtr;
|
||||||
|
int clientId;
|
||||||
|
std::string setId;
|
||||||
|
std::string triggerField;
|
||||||
|
epics::pvData::PVFieldPtr masterFieldPtr;
|
||||||
|
epics::pvData::PVFieldPtr triggerFieldPtr;
|
||||||
|
bool firstUpdate;
|
||||||
|
|
||||||
|
DataDistributorFilter(const std::string& groupId, int clientId, const std::string& setId, const std::string& triggerField, int nUpdatesPerClient, int updateMode, const epics::pvCopy::PVCopyPtr& copyPtr, const epics::pvData::PVFieldPtr& masterFieldPtr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(DataDistributorFilter);
|
||||||
|
virtual ~DataDistributorFilter();
|
||||||
|
/**
|
||||||
|
* Create a DataDistributorFilter.
|
||||||
|
* @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 DataDistributorFilterPtr create(
|
||||||
|
const std::string& requestValue,
|
||||||
|
const PVCopyPtr& pvCopy,
|
||||||
|
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
|
||||||
@@ -6,10 +6,6 @@
|
|||||||
#ifndef PVARRAYPLUGIN_H
|
#ifndef PVARRAYPLUGIN_H
|
||||||
#define PVARRAYPLUGIN_H
|
#define PVARRAYPLUGIN_H
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <pv/lock.h>
|
#include <pv/lock.h>
|
||||||
@@ -67,9 +63,13 @@ private:
|
|||||||
long start;
|
long start;
|
||||||
long increment;
|
long increment;
|
||||||
long end;
|
long end;
|
||||||
|
epics::pvData::PVFieldPtr masterField;
|
||||||
epics::pvData::PVScalarArrayPtr masterArray;
|
epics::pvData::PVScalarArrayPtr masterArray;
|
||||||
|
|
||||||
PVArrayFilter(long start,long increment,long end,const epics::pvData::PVScalarArrayPtr & masterArray);
|
PVArrayFilter(
|
||||||
|
long start,long increment,long end,
|
||||||
|
const epics::pvData::PVFieldPtr & masterField,
|
||||||
|
const epics::pvData::PVScalarArrayPtr masterArray);
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVArrayFilter);
|
POINTER_DEFINITIONS(PVArrayFilter);
|
||||||
virtual ~PVArrayFilter();
|
virtual ~PVArrayFilter();
|
||||||
@@ -99,4 +99,3 @@ public:
|
|||||||
|
|
||||||
}}
|
}}
|
||||||
#endif /* PVARRAYPLUGIN_H */
|
#endif /* PVARRAYPLUGIN_H */
|
||||||
|
|
||||||
@@ -6,28 +6,17 @@
|
|||||||
#ifndef PVDATABASE_H
|
#ifndef PVDATABASE_H
|
||||||
#define PVDATABASE_H
|
#define PVDATABASE_H
|
||||||
|
|
||||||
#ifdef epicsExportSharedSymbols
|
|
||||||
# define pvdatabaseEpicsExportSharedSymbols
|
|
||||||
# undef epicsExportSharedSymbols
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <pv/pvData.h>
|
#include <pv/pvData.h>
|
||||||
#include <pv/pvTimeStamp.h>
|
#include <pv/pvTimeStamp.h>
|
||||||
#include <pv/rpcService.h>
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef pvdatabaseEpicsExportSharedSymbols
|
|
||||||
# define epicsExportSharedSymbols
|
|
||||||
# undef pvdatabaseEpicsExportSharedSymbols
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <shareLib.h>
|
|
||||||
#include <pv/pvStructureCopy.h>
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
class PVRecord;
|
class PVRecord;
|
||||||
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
||||||
@@ -70,6 +59,7 @@ class epicsShareClass PVRecord :
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVRecord);
|
POINTER_DEFINITIONS(PVRecord);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Destructor.
|
* The Destructor.
|
||||||
*/
|
*/
|
||||||
@@ -98,14 +88,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void process();
|
virtual void process();
|
||||||
/**
|
/**
|
||||||
* @brief DEPRECATED
|
* @brief remove record from database.
|
||||||
|
*
|
||||||
|
* Remove the PVRecord. Release any resources used and
|
||||||
|
* get rid of listeners and requesters.
|
||||||
|
* If derived class overrides this then it must call PVRecord::remove()
|
||||||
|
* after it has destroyed any resorces it uses.
|
||||||
*/
|
*/
|
||||||
virtual void destroy() {}
|
virtual void remove();
|
||||||
/**
|
/**
|
||||||
* @brief Optional method for derived class.
|
* @brief Optional method for derived class.
|
||||||
*
|
*
|
||||||
* Return a service corresponding to the specified request PVStructure.
|
* Return a service corresponding to the specified request PVStructure.
|
||||||
* @param pvRequest The request PVStructure
|
* @param pvRequest The request PVStructure
|
||||||
* @return The corresponding service
|
* @return The corresponding service
|
||||||
*/
|
*/
|
||||||
virtual epics::pvAccess::RPCServiceAsync::shared_pointer getService(
|
virtual epics::pvAccess::RPCServiceAsync::shared_pointer getService(
|
||||||
@@ -114,15 +109,18 @@ public:
|
|||||||
return epics::pvAccess::RPCServiceAsync::shared_pointer();
|
return epics::pvAccess::RPCServiceAsync::shared_pointer();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Creates a <b>soft</b> record.
|
* @brief Creates a <b>soft</b> record.
|
||||||
*
|
*
|
||||||
* @param recordName The name of the record, which is also the channelName.
|
* @param recordName The name of the record, which is also the channelName.
|
||||||
* @param pvStructure The top level structure.
|
* @param pvStructure The top level structure.
|
||||||
|
* @param asLevel AS level (default: ASL0)
|
||||||
|
* @param asGroup AS group (default: DEFAULT)
|
||||||
* @return A shared pointer to the newly created record.
|
* @return A shared pointer to the newly created record.
|
||||||
*/
|
*/
|
||||||
static PVRecordPtr create(
|
static PVRecordPtr create(
|
||||||
std::string const & recordName,
|
std::string const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel = 0, const std::string& asGroup = "DEFAULT");
|
||||||
/**
|
/**
|
||||||
* @brief Get the name of the record.
|
* @brief Get the name of the record.
|
||||||
*
|
*
|
||||||
@@ -238,26 +236,53 @@ public:
|
|||||||
* @param level The level
|
* @param level The level
|
||||||
*/
|
*/
|
||||||
void setTraceLevel(int level) {traceLevel = level;}
|
void setTraceLevel(int level) {traceLevel = level;}
|
||||||
|
/**
|
||||||
|
* @brief Get the ASlevel
|
||||||
|
*
|
||||||
|
* @return The level.
|
||||||
|
*/
|
||||||
|
int getAsLevel() const {return asLevel;}
|
||||||
|
/**
|
||||||
|
* @brief Get the AS group name
|
||||||
|
*
|
||||||
|
* @return The name.
|
||||||
|
*/
|
||||||
|
std::string getAsGroup() const {return asGroup;}
|
||||||
|
/**
|
||||||
|
* @brief set access security level.
|
||||||
|
* @param level The level
|
||||||
|
*/
|
||||||
|
void setAsLevel(int level) {asLevel=level;}
|
||||||
|
/**
|
||||||
|
* @brief set access security group
|
||||||
|
* @param group The group name
|
||||||
|
*/
|
||||||
|
void setAsGroup(const std::string& group) {asGroup = group;}
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
* @param recordName The name of the record
|
* @param recordName The name of the record
|
||||||
* @param pvStructure The top level PVStructutre
|
* @param pvStructure The top level PVStructutre
|
||||||
|
* @param asLevel AS level (default: ASL0)
|
||||||
|
* @param asGroup AS group (default: DEFAULT)
|
||||||
*/
|
*/
|
||||||
PVRecord(
|
PVRecord(
|
||||||
std::string const & recordName,
|
std::string const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel = 0, const std::string& asGroup = "DEFAULT");
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the base class.
|
* @brief Initializes the base class.
|
||||||
*
|
*
|
||||||
* Must be called by derived classes.
|
* Must be called by derived classes.
|
||||||
*/
|
*/
|
||||||
void initPVRecord();
|
void initPVRecord();
|
||||||
private:
|
private:
|
||||||
|
friend class PVDatabase;
|
||||||
|
void unlistenClients();
|
||||||
|
|
||||||
PVRecordFieldPtr findPVRecordField(
|
PVRecordFieldPtr findPVRecordField(
|
||||||
PVRecordStructurePtr const & pvrs,
|
PVRecordStructurePtr const & pvrs,
|
||||||
epics::pvData::PVFieldPtr const & pvField);
|
epics::pvData::PVFieldPtr const & pvField);
|
||||||
void notifyClients();
|
|
||||||
|
|
||||||
std::string recordName;
|
std::string recordName;
|
||||||
epics::pvData::PVStructurePtr pvStructure;
|
epics::pvData::PVStructurePtr pvStructure;
|
||||||
@@ -273,6 +298,9 @@ private:
|
|||||||
|
|
||||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||||
epics::pvData::TimeStamp timeStamp;
|
epics::pvData::TimeStamp timeStamp;
|
||||||
|
|
||||||
|
int asLevel;
|
||||||
|
std::string asGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
epicsShareFunc std::ostream& operator<<(std::ostream& o, const PVRecord& record);
|
epicsShareFunc std::ostream& operator<<(std::ostream& o, const PVRecord& record);
|
||||||
@@ -348,6 +376,7 @@ private:
|
|||||||
std::list<PVListenerWPtr> pvListenerList;
|
std::list<PVListenerWPtr> pvListenerList;
|
||||||
epics::pvData::PVField::weak_pointer pvField;
|
epics::pvData::PVField::weak_pointer pvField;
|
||||||
bool isStructure;
|
bool isStructure;
|
||||||
|
PVRecordStructureWPtr master;
|
||||||
PVRecordStructureWPtr parent;
|
PVRecordStructureWPtr parent;
|
||||||
PVRecordWPtr pvRecord;
|
PVRecordWPtr pvRecord;
|
||||||
std::string fullName;
|
std::string fullName;
|
||||||
@@ -501,6 +530,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Remove a record.
|
* @brief Remove a record.
|
||||||
* @param record The record to remove.
|
* @param record The record to remove.
|
||||||
|
*
|
||||||
* @return <b>true</b> if record was removed.
|
* @return <b>true</b> if record was removed.
|
||||||
*/
|
*/
|
||||||
bool removeRecord(PVRecordPtr const & record);
|
bool removeRecord(PVRecordPtr const & record);
|
||||||
@@ -510,6 +540,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
epics::pvData::PVStringArrayPtr getRecordNames();
|
epics::pvData::PVStringArrayPtr getRecordNames();
|
||||||
private:
|
private:
|
||||||
|
friend class PVRecord;
|
||||||
|
|
||||||
|
PVRecordWPtr removeFromMap(PVRecordPtr const & record);
|
||||||
PVDatabase();
|
PVDatabase();
|
||||||
void lock();
|
void lock();
|
||||||
void unlock();
|
void unlock();
|
||||||
@@ -521,4 +554,3 @@ private:
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
#endif /* PVDATABASE_H */
|
#endif /* PVDATABASE_H */
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
#ifndef PVDEADBANDPLUGIN_H
|
#ifndef PVDEADBANDPLUGIN_H
|
||||||
#define PVDEADBANDPLUGIN_H
|
#define PVDEADBANDPLUGIN_H
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -69,7 +66,7 @@ private:
|
|||||||
epics::pvData::PVScalarPtr master;
|
epics::pvData::PVScalarPtr master;
|
||||||
bool firstTime;
|
bool firstTime;
|
||||||
double lastReportedValue;
|
double lastReportedValue;
|
||||||
|
|
||||||
|
|
||||||
PVDeadbandFilter(bool absolute,double deadband,epics::pvData::PVScalarPtr const & master);
|
PVDeadbandFilter(bool absolute,double deadband,epics::pvData::PVScalarPtr const & master);
|
||||||
public:
|
public:
|
||||||
@@ -103,4 +100,3 @@ public:
|
|||||||
|
|
||||||
}}
|
}}
|
||||||
#endif /* PVDEADBANDPLUGIN_H */
|
#endif /* PVDEADBANDPLUGIN_H */
|
||||||
|
|
||||||
@@ -9,23 +9,22 @@
|
|||||||
#ifndef PVPLUGIN_H
|
#ifndef PVPLUGIN_H
|
||||||
#define PVPLUGIN_H
|
#define PVPLUGIN_H
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <pv/lock.h>
|
#include <pv/lock.h>
|
||||||
#include <pv/pvStructureCopy.h>
|
#include <pv/bitSet.h>
|
||||||
|
|
||||||
#include <shareLib.h>
|
#include <shareLib.h>
|
||||||
|
|
||||||
namespace epics { namespace pvCopy{
|
namespace epics { namespace pvCopy{
|
||||||
|
|
||||||
class PVPlugin;
|
class PVPlugin;
|
||||||
class PVFilter;
|
class PVFilter;
|
||||||
class PVPluginRegistry;
|
class PVPluginRegistry;
|
||||||
|
|
||||||
|
class PVCopy;
|
||||||
|
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
|
||||||
|
|
||||||
typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr;
|
typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr;
|
||||||
typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr;
|
typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr;
|
||||||
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
||||||
@@ -37,7 +36,7 @@ typedef std::map<std::string,PVPluginPtr> PVPluginMap;
|
|||||||
* PVCopy looks for plugins defined in pvRequest and calls the filter when a pvCopy is updated.
|
* PVCopy looks for plugins defined in pvRequest and calls the filter when a pvCopy is updated.
|
||||||
* @author mrk
|
* @author mrk
|
||||||
* @since 2017.03.17
|
* @since 2017.03.17
|
||||||
*
|
*
|
||||||
* Interface for a filter plugin for PVCopy.
|
* Interface for a filter plugin for PVCopy.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -10,10 +10,6 @@
|
|||||||
#ifndef PVSTRUCTURECOPY_H
|
#ifndef PVSTRUCTURECOPY_H
|
||||||
#define PVSTRUCTURECOPY_H
|
#define PVSTRUCTURECOPY_H
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -22,7 +18,7 @@
|
|||||||
|
|
||||||
#include <shareLib.h>
|
#include <shareLib.h>
|
||||||
|
|
||||||
namespace epics { namespace pvCopy{
|
namespace epics { namespace pvCopy{
|
||||||
|
|
||||||
class PVCopyTraverseMasterCallback;
|
class PVCopyTraverseMasterCallback;
|
||||||
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr;
|
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr;
|
||||||
@@ -66,7 +62,7 @@ typedef std::tr1::shared_ptr<CopyStructureNode> CopyStructureNodePtr;
|
|||||||
* Class that manages one or more PVStructures that holds an arbitrary subset of the fields
|
* Class that manages one or more PVStructures that holds an arbitrary subset of the fields
|
||||||
* in another PVStructure called master.
|
* in another PVStructure called master.
|
||||||
*/
|
*/
|
||||||
class epicsShareClass PVCopy :
|
class epicsShareClass PVCopy :
|
||||||
public std::tr1::enable_shared_from_this<PVCopy>
|
public std::tr1::enable_shared_from_this<PVCopy>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -83,7 +79,6 @@ public:
|
|||||||
epics::pvData::PVStructurePtr const &pvRequest,
|
epics::pvData::PVStructurePtr const &pvRequest,
|
||||||
std::string const & structureName);
|
std::string const & structureName);
|
||||||
virtual ~PVCopy(){}
|
virtual ~PVCopy(){}
|
||||||
virtual void destroy();
|
|
||||||
/**
|
/**
|
||||||
* Get the top-level structure of master
|
* Get the top-level structure of master
|
||||||
* @returns The master top-level structure.
|
* @returns The master top-level structure.
|
||||||
@@ -172,22 +167,27 @@ public:
|
|||||||
* name is the subField name and value is the subField value.
|
* name is the subField name and value is the subField value.
|
||||||
*/
|
*/
|
||||||
epics::pvData::PVStructurePtr getOptions(std::size_t fieldOffset);
|
epics::pvData::PVStructurePtr getOptions(std::size_t fieldOffset);
|
||||||
|
/**
|
||||||
|
* Is master field requested?
|
||||||
|
*/
|
||||||
|
bool isMasterFieldRequested() const {return requestHasMasterField;}
|
||||||
/**
|
/**
|
||||||
* For debugging.
|
* For debugging.
|
||||||
*/
|
*/
|
||||||
std::string dump();
|
std::string dump();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
PVCopyPtr getPtrSelf()
|
PVCopyPtr getPtrSelf()
|
||||||
{
|
{
|
||||||
return shared_from_this();
|
return shared_from_this();
|
||||||
}
|
}
|
||||||
|
|
||||||
epics::pvData::PVStructurePtr pvMaster;
|
epics::pvData::PVStructurePtr pvMaster;
|
||||||
epics::pvData::StructureConstPtr structure;
|
epics::pvData::StructureConstPtr structure;
|
||||||
CopyNodePtr headNode;
|
CopyNodePtr headNode;
|
||||||
epics::pvData::PVStructurePtr cacheInitStructure;
|
epics::pvData::PVStructurePtr cacheInitStructure;
|
||||||
epics::pvData::BitSetPtr ignorechangeBitSet;
|
epics::pvData::BitSetPtr ignorechangeBitSet;
|
||||||
|
bool requestHasMasterField;
|
||||||
|
|
||||||
void traverseMaster(
|
void traverseMaster(
|
||||||
CopyNodePtr const &node,
|
CopyNodePtr const &node,
|
||||||
@@ -204,10 +204,16 @@ private:
|
|||||||
epics::pvData::PVFieldPtr const &pvCopy,
|
epics::pvData::PVFieldPtr const &pvCopy,
|
||||||
CopyNodePtr const &node,
|
CopyNodePtr const &node,
|
||||||
epics::pvData::BitSetPtr const &bitSet);
|
epics::pvData::BitSetPtr const &bitSet);
|
||||||
void updateMaster(
|
void updateMasterField(
|
||||||
epics::pvData::PVFieldPtr const &pvCopy,
|
CopyNodePtr const & node,
|
||||||
CopyNodePtr const &node,
|
epics::pvData::PVFieldPtr const & pvCopy,
|
||||||
|
epics::pvData::PVFieldPtr const &pvMaster,
|
||||||
epics::pvData::BitSetPtr const &bitSet);
|
epics::pvData::BitSetPtr const &bitSet);
|
||||||
|
void updateMasterCheckBitSet(
|
||||||
|
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||||
|
epics::pvData::BitSetPtr const &bitSet,
|
||||||
|
size_t nextSet);
|
||||||
|
CopyNodePtr getCopyNode(std::size_t fieldOffset);
|
||||||
|
|
||||||
PVCopy(epics::pvData::PVStructurePtr const &pvMaster);
|
PVCopy(epics::pvData::PVStructurePtr const &pvMaster);
|
||||||
bool init(epics::pvData::PVStructurePtr const &pvRequest);
|
bool init(epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
@@ -239,7 +245,6 @@ private:
|
|||||||
std::string *builder,
|
std::string *builder,
|
||||||
CopyNodePtr const &node,
|
CopyNodePtr const &node,
|
||||||
int indentLevel);
|
int indentLevel);
|
||||||
friend class PVCopyMonitor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
77
src/pv/pvSupport.h
Normal file
77
src/pv/pvSupport.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2019.06.01
|
||||||
|
*/
|
||||||
|
#ifndef PVSUPPORT_H
|
||||||
|
#define PVSUPPORT_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class PVSupport;
|
||||||
|
typedef std::tr1::shared_ptr<PVSupport> PVSupportPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base interface for a PVSupport.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass PVSupport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(PVSupport);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~PVSupport(){}
|
||||||
|
/**
|
||||||
|
* @brief Optional initialization method.
|
||||||
|
*
|
||||||
|
* Called after PVRecord is created but before record is installed into PVDatabase.
|
||||||
|
*
|
||||||
|
* @param pvValue The field to support.
|
||||||
|
* @param pvSupport Support specific fields.
|
||||||
|
* @return <b>true</b> for success and <b>false</b> for failure.
|
||||||
|
*/
|
||||||
|
virtual bool init(
|
||||||
|
epics::pvData::PVFieldPtr const & pvValue,
|
||||||
|
epics::pvData::PVFieldPtr const & pvSupport) {return true;}
|
||||||
|
/**
|
||||||
|
* @brief Optional method for derived class.
|
||||||
|
*
|
||||||
|
* It is called before record is added to database.
|
||||||
|
*/
|
||||||
|
virtual void start() {}
|
||||||
|
/**
|
||||||
|
* @brief Virtual method for derived class.
|
||||||
|
*
|
||||||
|
* Called when record is processed.
|
||||||
|
* It is the method that implements support.
|
||||||
|
* It is called each time the record is processed.
|
||||||
|
*
|
||||||
|
* @return Returns true is any fields were modified; otherwise false.
|
||||||
|
*/
|
||||||
|
virtual bool process() = 0;
|
||||||
|
/**
|
||||||
|
* @brief Optional method for derived class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual void reset() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* PVSUPPORT_H */
|
||||||
@@ -6,10 +6,6 @@
|
|||||||
#ifndef PVTIMESTAMPPLUGIN_H
|
#ifndef PVTIMESTAMPPLUGIN_H
|
||||||
#define PVTIMESTAMPPLUGIN_H
|
#define PVTIMESTAMPPLUGIN_H
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <pv/lock.h>
|
#include <pv/lock.h>
|
||||||
@@ -60,7 +56,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A filter that sets a timeStamp to the current time.
|
* @brief A filter that sets a timeStamp to/from the current field or pvCopy.
|
||||||
*/
|
*/
|
||||||
class epicsShareClass PVTimestampFilter : public PVFilter
|
class epicsShareClass PVTimestampFilter : public PVFilter
|
||||||
{
|
{
|
||||||
@@ -70,7 +66,7 @@ private:
|
|||||||
bool current;
|
bool current;
|
||||||
bool copy;
|
bool copy;
|
||||||
epics::pvData::PVFieldPtr master;
|
epics::pvData::PVFieldPtr master;
|
||||||
|
|
||||||
|
|
||||||
PVTimestampFilter(bool current,bool copy,epics::pvData::PVFieldPtr const & pvField);
|
PVTimestampFilter(bool current,bool copy,epics::pvData::PVFieldPtr const & pvField);
|
||||||
public:
|
public:
|
||||||
@@ -102,4 +98,3 @@ public:
|
|||||||
|
|
||||||
}}
|
}}
|
||||||
#endif /* PVTIMESTAMPPLUGIN_H */
|
#endif /* PVTIMESTAMPPLUGIN_H */
|
||||||
|
|
||||||
67
src/pv/pvdbcrAddRecord.h
Normal file
67
src/pv/pvdbcrAddRecord.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* 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 2021.04.11
|
||||||
|
*/
|
||||||
|
#ifndef PVDBCRADDARRAY_H
|
||||||
|
#define PVDBCRADDARRAY_H
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class PvdbcrAddRecord;
|
||||||
|
typedef std::tr1::shared_ptr<PvdbcrAddRecord> PvdbcrAddRecordPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PvdbcrAddRecord A record that adds a record to the master database.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass PvdbcrAddRecord :
|
||||||
|
public PVRecord
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PvdbcrAddRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup);
|
||||||
|
epics::pvData::PVStringPtr pvRecordName;
|
||||||
|
epics::pvData::PVStringPtr pvResult;
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(PvdbcrAddRecord);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~PvdbcrAddRecord() {}
|
||||||
|
/**
|
||||||
|
* @brief Create a record.
|
||||||
|
*
|
||||||
|
* @param recordName The record name.
|
||||||
|
* @param asLevel The access security level.
|
||||||
|
* @param asGroup The access security group.
|
||||||
|
* @return The PVRecord
|
||||||
|
*/
|
||||||
|
static PvdbcrAddRecordPtr create(
|
||||||
|
std::string const & recordName,
|
||||||
|
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
|
||||||
|
/**
|
||||||
|
* @brief a PVRecord method
|
||||||
|
* @return success or failure
|
||||||
|
*/
|
||||||
|
virtual bool init();
|
||||||
|
/**
|
||||||
|
* @brief process method that adds a record to the master database.
|
||||||
|
*/
|
||||||
|
virtual void process();
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* PVDBCRADDARRAY_H */
|
||||||
105
src/pv/pvdbcrProcessRecord.h
Normal file
105
src/pv/pvdbcrProcessRecord.h
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* 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 2021.04.11
|
||||||
|
*/
|
||||||
|
#ifndef PVDBCRPROCESSARRAY_H
|
||||||
|
#define PVDBCRPROCESSARRAY_H
|
||||||
|
#include <epicsThread.h>
|
||||||
|
#include <epicsGuard.h>
|
||||||
|
#include <pv/event.h>
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
|
||||||
|
class PvdbcrProcessRecord;
|
||||||
|
typedef std::tr1::shared_ptr<PvdbcrProcessRecord> PvdbcrProcessRecordPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PvdbcrProcessRecord A record that processes other records in the master database.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass PvdbcrProcessRecord :
|
||||||
|
public PVRecord,
|
||||||
|
public epicsThreadRunable
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PvdbcrProcessRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
double delay,
|
||||||
|
int asLevel,std::string const & asGroup);
|
||||||
|
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;
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(PvdbcrProcessRecord);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~PvdbcrProcessRecord() {}
|
||||||
|
/**
|
||||||
|
* @brief Create a record.
|
||||||
|
*
|
||||||
|
* @param recordName The record name.
|
||||||
|
* @param asLevel The access security level.
|
||||||
|
* @param asGroup The access security group.
|
||||||
|
* @return The PVRecord
|
||||||
|
*/
|
||||||
|
static PvdbcrProcessRecordPtr create(
|
||||||
|
std::string const & recordName,
|
||||||
|
double delay= 1.0,
|
||||||
|
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
|
||||||
|
/**
|
||||||
|
* @brief set the delay between prcocessing.
|
||||||
|
*
|
||||||
|
* @param delay in seconds
|
||||||
|
*/
|
||||||
|
void setDelay(double delay);
|
||||||
|
/**
|
||||||
|
* @brief get the delay between prcocessing.
|
||||||
|
*
|
||||||
|
* @return delay in seconds
|
||||||
|
*/
|
||||||
|
double getDelay();
|
||||||
|
/**
|
||||||
|
* @brief a PVRecord method
|
||||||
|
* @return success or failure
|
||||||
|
*/
|
||||||
|
virtual bool init();
|
||||||
|
/**
|
||||||
|
* @brief method that processes other records in the master database.
|
||||||
|
*/
|
||||||
|
virtual void process();
|
||||||
|
/**
|
||||||
|
* @brief thread method
|
||||||
|
*/
|
||||||
|
virtual void run();
|
||||||
|
/**
|
||||||
|
* @brief thread method
|
||||||
|
*/
|
||||||
|
void startThread();
|
||||||
|
/**
|
||||||
|
* @brief thread method
|
||||||
|
*/
|
||||||
|
void stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* PVDBCRPROCESSARRAY_H */
|
||||||
67
src/pv/pvdbcrRemoveRecord.h
Normal file
67
src/pv/pvdbcrRemoveRecord.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* 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 2021.04.11
|
||||||
|
*/
|
||||||
|
#ifndef PVDBCRREMOVEARRAY_H
|
||||||
|
#define PVDBCRREMOVEARRAY_H
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class PvdbcrRemoveRecord;
|
||||||
|
typedef std::tr1::shared_ptr<PvdbcrRemoveRecord> PvdbcrRemoveRecordPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PvdbcrRemoveRecord A record that removes a record from the master database.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass PvdbcrRemoveRecord :
|
||||||
|
public PVRecord
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PvdbcrRemoveRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup);
|
||||||
|
epics::pvData::PVStringPtr pvRecordName;
|
||||||
|
epics::pvData::PVStringPtr pvResult;
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(PvdbcrRemoveRecord);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~PvdbcrRemoveRecord() {}
|
||||||
|
/**
|
||||||
|
* @brief Create a record.
|
||||||
|
*
|
||||||
|
* @param recordName The record name.
|
||||||
|
* @param asLevel The access security level.
|
||||||
|
* @param asGroup The access security group.
|
||||||
|
* @return The PVRecord
|
||||||
|
*/
|
||||||
|
static PvdbcrRemoveRecordPtr create(
|
||||||
|
std::string const & recordName,
|
||||||
|
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
|
||||||
|
/**
|
||||||
|
* @brief a PVRecord method
|
||||||
|
* @return success or failure
|
||||||
|
*/
|
||||||
|
virtual bool init();
|
||||||
|
/**
|
||||||
|
* @brief process method that removes a record from the master database.
|
||||||
|
*/
|
||||||
|
virtual void process();
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* PVDBCRREMOVEARRAY_H */
|
||||||
57
src/pv/pvdbcrScalarArrayRecord.h
Normal file
57
src/pv/pvdbcrScalarArrayRecord.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* 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 2021.04.11
|
||||||
|
*/
|
||||||
|
#ifndef PVDBCRSCALARARRAYRECORD_H
|
||||||
|
#define PVDBCRSCALARARRAYRECORD_H
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class PvdbcrScalarArrayRecord;
|
||||||
|
typedef std::tr1::shared_ptr<PvdbcrScalarArrayRecord> PvdbcrScalarArrayRecordPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PvdbcrScalarArrayRecord creates a record with a scalar array value, alarm, and timeStamp.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass PvdbcrScalarArrayRecord :
|
||||||
|
public PVRecord
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PvdbcrScalarArrayRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup);
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(PvdbcrScalarArrayRecord);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~PvdbcrScalarArrayRecord() {}
|
||||||
|
/**
|
||||||
|
* @brief Create a record.
|
||||||
|
*
|
||||||
|
* @param recordName The record name.
|
||||||
|
* @param scalarType The type for the value field
|
||||||
|
* @param asLevel The access security level.
|
||||||
|
* @param asGroup The access security group.
|
||||||
|
* @return The PVRecord
|
||||||
|
*/
|
||||||
|
static PvdbcrScalarArrayRecordPtr create(
|
||||||
|
std::string const & recordName,std::string const & scalarType,
|
||||||
|
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* PVDBCRSCALARARRAYRECORD_H */
|
||||||
57
src/pv/pvdbcrScalarRecord.h
Normal file
57
src/pv/pvdbcrScalarRecord.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* 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 2021.04.11
|
||||||
|
*/
|
||||||
|
#ifndef PVDBCRSCALARRECORD_H
|
||||||
|
#define PVDBCRSCALARRECORD_H
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class PvdbcrScalarRecord;
|
||||||
|
typedef std::tr1::shared_ptr<PvdbcrScalarRecord> PvdbcrScalarRecordPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PvdbcrScalarRecord creates a record with a scalar value, alarm, and timeStamp.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass PvdbcrScalarRecord :
|
||||||
|
public PVRecord
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PvdbcrScalarRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup);
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(PvdbcrScalarRecord);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~PvdbcrScalarRecord() {}
|
||||||
|
/**
|
||||||
|
* @brief Create a record.
|
||||||
|
*
|
||||||
|
* @param recordName The record name.
|
||||||
|
* @param scalarType The type for the value field
|
||||||
|
* @param asLevel The access security level.
|
||||||
|
* @param asGroup The access security group.
|
||||||
|
* @return The PVRecord
|
||||||
|
*/
|
||||||
|
static PvdbcrScalarRecordPtr create(
|
||||||
|
std::string const & recordName,std::string const & scalarType,
|
||||||
|
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* PVDBCRSCALARRECORD_H */
|
||||||
68
src/pv/pvdbcrTraceRecord.h
Normal file
68
src/pv/pvdbcrTraceRecord.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* 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 2021.04.11
|
||||||
|
*/
|
||||||
|
#ifndef PVDBCRTRACEARRAY_H
|
||||||
|
#define PVDBCRTRACEARRAY_H
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class PvdbcrTraceRecord;
|
||||||
|
typedef std::tr1::shared_ptr<PvdbcrTraceRecord> PvdbcrTraceRecordPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PvdbcrTraceRecord A record sets trace level for a record in the master database.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass PvdbcrTraceRecord :
|
||||||
|
public PVRecord
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PvdbcrTraceRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup);
|
||||||
|
epics::pvData::PVStringPtr pvRecordName;
|
||||||
|
epics::pvData::PVIntPtr pvLevel;
|
||||||
|
epics::pvData::PVStringPtr pvResult;
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(PvdbcrTraceRecord);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~PvdbcrTraceRecord() {}
|
||||||
|
/**
|
||||||
|
* @brief Create a record.
|
||||||
|
*
|
||||||
|
* @param recordName The record name.
|
||||||
|
* @param asLevel The access security level.
|
||||||
|
* @param asGroup The access security group.
|
||||||
|
* @return The PVRecord
|
||||||
|
*/
|
||||||
|
static PvdbcrTraceRecordPtr create(
|
||||||
|
std::string const & recordName,
|
||||||
|
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
|
||||||
|
/**
|
||||||
|
* @brief a PVRecord method
|
||||||
|
* @return success or failure
|
||||||
|
*/
|
||||||
|
virtual bool init();
|
||||||
|
/**
|
||||||
|
* @brief process method that sets trace level for a record in the master database.
|
||||||
|
*/
|
||||||
|
virtual void process();
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* PVDBCRTRACEARRAY_H */
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/* removeRecord.h */
|
|
||||||
/**
|
|
||||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
|
||||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
|
||||||
* in file LICENSE that is included with this distribution.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @author mrk
|
|
||||||
* @date 2013.04.18
|
|
||||||
*/
|
|
||||||
#ifndef REMOVERECORD_H
|
|
||||||
#define REMOVERECORD_H
|
|
||||||
|
|
||||||
#include <shareLib.h>
|
|
||||||
|
|
||||||
#include <pv/channelProviderLocal.h>
|
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveRecord;
|
|
||||||
typedef std::tr1::shared_ptr<RemoveRecord> RemoveRecordPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Remove another record in the same database.
|
|
||||||
*
|
|
||||||
* A record to remove 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 RemoveRecord :
|
|
||||||
public PVRecord
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
POINTER_DEFINITIONS(RemoveRecord);
|
|
||||||
/**
|
|
||||||
* Factory methods to create RemoveRecord.
|
|
||||||
* @param recordName The name for the RemoveRecord.
|
|
||||||
* @return A shared pointer to RemoveRecord..
|
|
||||||
*/
|
|
||||||
static RemoveRecordPtr create(
|
|
||||||
std::string const & recordName);
|
|
||||||
/**
|
|
||||||
* standard init method required by PVRecord
|
|
||||||
* @return true unless record name already exists.
|
|
||||||
*/
|
|
||||||
virtual bool init();
|
|
||||||
/**
|
|
||||||
* @brief Remove the record specified by recordName.
|
|
||||||
*/
|
|
||||||
virtual void process();
|
|
||||||
private:
|
|
||||||
RemoveRecord(
|
|
||||||
std::string const & recordName,
|
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
|
||||||
epics::pvData::PVStringPtr pvRecordName;
|
|
||||||
epics::pvData::PVStringPtr pvResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
}}
|
|
||||||
|
|
||||||
#endif /* REMOVERECORD_H */
|
|
||||||
110
src/pv/scalarAlarmSupport.h
Normal file
110
src/pv/scalarAlarmSupport.h
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2019.06.01
|
||||||
|
*/
|
||||||
|
#ifndef SCALARALARMSUPPORT_H
|
||||||
|
#define SCALARALARMSUPPORT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/pvSupport.h>
|
||||||
|
#include <pv/alarm.h>
|
||||||
|
#include <pv/pvAlarm.h>
|
||||||
|
#include <pv/pvStructureCopy.h>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
class ScalarAlarmSupport;
|
||||||
|
typedef std::tr1::shared_ptr<ScalarAlarmSupport> ScalarAlarmSupportPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base interface for a ScalarAlarmSupport.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class epicsShareClass ScalarAlarmSupport :
|
||||||
|
PVSupport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ScalarAlarmSupport);
|
||||||
|
/**
|
||||||
|
* The Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~ScalarAlarmSupport();
|
||||||
|
/**
|
||||||
|
* @brief Connects to contol fields.
|
||||||
|
*
|
||||||
|
* @param pvValue The field to support.
|
||||||
|
* @param pvAlarm The alarm field.
|
||||||
|
* @param pvSupport Support specific fields.
|
||||||
|
* @return <b>true</b> for success and <b>false</b> for failure.
|
||||||
|
*/
|
||||||
|
virtual bool init(
|
||||||
|
epics::pvData::PVFieldPtr const & pvValue,
|
||||||
|
epics::pvData::PVStructurePtr const & pvAlarm,
|
||||||
|
epics::pvData::PVFieldPtr const & pvSupport);
|
||||||
|
/**
|
||||||
|
* @brief Honors scalarAlarm fields.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return Returns true is any fields were modified; otherwise false.
|
||||||
|
*/
|
||||||
|
virtual bool process();
|
||||||
|
/**
|
||||||
|
* @brief If implementing minSteps it sets isMinStep to false.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual void reset();
|
||||||
|
/**
|
||||||
|
* @brief create a ScalarAlarm
|
||||||
|
*
|
||||||
|
* @param pvRecord - The pvRecord to which the support is attached.
|
||||||
|
* @return The new ScalarAlarm
|
||||||
|
*/
|
||||||
|
static ScalarAlarmSupportPtr create(PVRecordPtr const & pvRecord);
|
||||||
|
/**
|
||||||
|
* @brief create a scalarAlarm required by ScalarAlarm
|
||||||
|
*
|
||||||
|
* @return The scalarAlarmField introspection structure.
|
||||||
|
*/
|
||||||
|
static epics::pvData::StructureConstPtr scalarAlarmField();
|
||||||
|
private:
|
||||||
|
|
||||||
|
ScalarAlarmSupport(PVRecordPtr const & pvRecord);
|
||||||
|
enum {
|
||||||
|
range_Lolo = 0,
|
||||||
|
range_Low,
|
||||||
|
range_Normal,
|
||||||
|
range_High,
|
||||||
|
range_Hihi,
|
||||||
|
range_Invalid,
|
||||||
|
range_Undefined
|
||||||
|
} AlarmRange;
|
||||||
|
void setAlarm(
|
||||||
|
epics::pvData::PVStructurePtr const & pvAlarm,
|
||||||
|
int alarmRange);
|
||||||
|
PVRecordPtr pvRecord;
|
||||||
|
int prevAlarmRange;
|
||||||
|
epics::pvData::PVScalarPtr pvValue;
|
||||||
|
epics::pvData::PVStructurePtr pvAlarm;
|
||||||
|
epics::pvData::PVStructurePtr pvScalarAlarm;
|
||||||
|
epics::pvData::PVBooleanPtr pvActive;
|
||||||
|
epics::pvData::PVDoublePtr pvLowAlarmLimit;
|
||||||
|
epics::pvData::PVDoublePtr pvLowWarningLimit;
|
||||||
|
epics::pvData::PVDoublePtr pvHighWarningLimit;
|
||||||
|
epics::pvData::PVDoublePtr pvHighAlarmLimit;
|
||||||
|
epics::pvData::PVDoublePtr pvHysteresis;
|
||||||
|
double requestedValue;
|
||||||
|
double currentValue;
|
||||||
|
bool isHystersis;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* SCALARALARMSUPPORT_H */
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/* traceRecord.h */
|
|
||||||
/**
|
|
||||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
|
||||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
|
||||||
* in file LICENSE that is included with this distribution.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @author mrk
|
|
||||||
* @date 2013.04.18
|
|
||||||
*/
|
|
||||||
#ifndef TRACERECORD_H
|
|
||||||
#define TRACERECORD_H
|
|
||||||
|
|
||||||
#include <shareLib.h>
|
|
||||||
|
|
||||||
#include <pv/channelProviderLocal.h>
|
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
|
||||||
|
|
||||||
|
|
||||||
class TraceRecord;
|
|
||||||
typedef std::tr1::shared_ptr<TraceRecord> TraceRecordPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Trace activity of PVRecord.
|
|
||||||
*
|
|
||||||
* A record to set the trace value for another record
|
|
||||||
* It is meant to be used via a channelPutGet request.
|
|
||||||
* The argument has two fields: recordName and level.
|
|
||||||
* The result has a field named status.
|
|
||||||
*/
|
|
||||||
class epicsShareClass TraceRecord :
|
|
||||||
public PVRecord
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
POINTER_DEFINITIONS(TraceRecord);
|
|
||||||
/**
|
|
||||||
* @brief Factory method to create TraceRecord.
|
|
||||||
*
|
|
||||||
* @param recordName The name for the TraceRecord.
|
|
||||||
* @return A shared pointer to TraceRecord..
|
|
||||||
*/
|
|
||||||
static TraceRecordPtr create(
|
|
||||||
std::string const & recordName);
|
|
||||||
/**
|
|
||||||
* standard init method required by PVRecord
|
|
||||||
* @return true unless record name already exists.
|
|
||||||
*/
|
|
||||||
virtual bool init();
|
|
||||||
/**
|
|
||||||
* @brief Set the trace level for record specified by recordName.
|
|
||||||
*/
|
|
||||||
virtual void process();
|
|
||||||
private:
|
|
||||||
TraceRecord(
|
|
||||||
std::string const & recordName,
|
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
|
||||||
epics::pvData::PVStringPtr pvRecordName;
|
|
||||||
epics::pvData::PVIntPtr pvLevel;
|
|
||||||
epics::pvData::PVStringPtr pvResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
}}
|
|
||||||
|
|
||||||
#endif /* TRACERECORD_H */
|
|
||||||
@@ -10,15 +10,27 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <asLib.h>
|
||||||
#include <epicsGuard.h>
|
#include <epicsGuard.h>
|
||||||
#include <epicsThread.h>
|
#include <epicsThread.h>
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
#include <pv/timeStamp.h>
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/createRequest.h>
|
||||||
|
#include <pv/pvaVersion.h>
|
||||||
|
#include <pv/pvaVersionNum.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
#include <pv/pvSubArrayCopy.h>
|
#include <pv/pvSubArrayCopy.h>
|
||||||
|
#include <pv/security.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvStructureCopy.h"
|
||||||
#include <pv/channelProviderLocal.h>
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/channelProviderLocal.h"
|
||||||
|
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
using namespace epics::pvAccess;
|
using namespace epics::pvAccess;
|
||||||
@@ -29,7 +41,7 @@ using std::cout;
|
|||||||
using std::endl;
|
using std::endl;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
static StructureConstPtr nullStructure;
|
static StructureConstPtr nullStructure;
|
||||||
|
|
||||||
@@ -59,19 +71,18 @@ static bool getProcess(PVStructurePtr pvRequest,bool processDefault)
|
|||||||
return pvString->get().compare("true")==0 ? true : false;
|
return pvString->get().compare("true")==0 ? true : false;
|
||||||
} else if(scalar->getScalarType()==pvBoolean) {
|
} else if(scalar->getScalarType()==pvBoolean) {
|
||||||
PVBooleanPtr pvBoolean = static_pointer_cast<PVBoolean>(pvField);
|
PVBooleanPtr pvBoolean = static_pointer_cast<PVBoolean>(pvField);
|
||||||
return pvBoolean->get();
|
return pvBoolean->get();
|
||||||
}
|
}
|
||||||
return processDefault;
|
return processDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelProcessLocal :
|
class ChannelProcessLocal :
|
||||||
public ChannelProcess,
|
public epics::pvAccess::ChannelProcess,
|
||||||
public std::tr1::enable_shared_from_this<ChannelProcessLocal>
|
public std::tr1::enable_shared_from_this<ChannelProcessLocal>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ChannelProcessLocal);
|
POINTER_DEFINITIONS(ChannelProcessLocal);
|
||||||
virtual ~ChannelProcessLocal();
|
virtual ~ChannelProcessLocal();
|
||||||
virtual void destroy() {} // DEPRECATED
|
|
||||||
static ChannelProcessLocalPtr create(
|
static ChannelProcessLocalPtr create(
|
||||||
ChannelLocalPtr const &channelLocal,
|
ChannelLocalPtr const &channelLocal,
|
||||||
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
||||||
@@ -93,7 +104,7 @@ private:
|
|||||||
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
||||||
PVRecordPtr const &pvRecord,
|
PVRecordPtr const &pvRecord,
|
||||||
int nProcess)
|
int nProcess)
|
||||||
:
|
:
|
||||||
channelLocal(channelLocal),
|
channelLocal(channelLocal),
|
||||||
channelProcessRequester(channelProcessRequester),
|
channelProcessRequester(channelProcessRequester),
|
||||||
pvRecord(pvRecord),
|
pvRecord(pvRecord),
|
||||||
@@ -123,7 +134,7 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
|
|||||||
if(pvField) {
|
if(pvField) {
|
||||||
PVStringPtr pvString = pvOptions->getSubField<PVString>("nProcess");
|
PVStringPtr pvString = pvOptions->getSubField<PVString>("nProcess");
|
||||||
if(pvString) {
|
if(pvString) {
|
||||||
int size;
|
int size=0;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << pvString->get();
|
ss << pvString->get();
|
||||||
ss >> size;
|
ss >> size;
|
||||||
@@ -147,10 +158,7 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
|
|||||||
|
|
||||||
ChannelProcessLocal::~ChannelProcessLocal()
|
ChannelProcessLocal::~ChannelProcessLocal()
|
||||||
{
|
{
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
//cout << "~ChannelProcessLocal()\n";
|
||||||
if(pvr && pvr->getTraceLevel()>0) {
|
|
||||||
cout << "~ChannelProcessLocal() " << pvr->getRecordName() << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tr1::shared_ptr<Channel> ChannelProcessLocal::getChannel()
|
std::tr1::shared_ptr<Channel> ChannelProcessLocal::getChannel()
|
||||||
@@ -198,13 +206,12 @@ void ChannelProcessLocal::process()
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ChannelGetLocal :
|
class ChannelGetLocal :
|
||||||
public ChannelGet,
|
public epics::pvAccess::ChannelGet,
|
||||||
public std::tr1::enable_shared_from_this<ChannelGetLocal>
|
public std::tr1::enable_shared_from_this<ChannelGetLocal>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ChannelGetLocal);
|
POINTER_DEFINITIONS(ChannelGetLocal);
|
||||||
virtual ~ChannelGetLocal();
|
virtual ~ChannelGetLocal();
|
||||||
virtual void destroy() {} // DEPRECATED
|
|
||||||
static ChannelGetLocalPtr create(
|
static ChannelGetLocalPtr create(
|
||||||
ChannelLocalPtr const &channelLocal,
|
ChannelLocalPtr const &channelLocal,
|
||||||
ChannelGetRequester::shared_pointer const & channelGetRequester,
|
ChannelGetRequester::shared_pointer const & channelGetRequester,
|
||||||
@@ -229,7 +236,7 @@ private:
|
|||||||
PVStructurePtr const&pvStructure,
|
PVStructurePtr const&pvStructure,
|
||||||
BitSetPtr const & bitSet,
|
BitSetPtr const & bitSet,
|
||||||
PVRecordPtr const &pvRecord)
|
PVRecordPtr const &pvRecord)
|
||||||
:
|
:
|
||||||
firstTime(true),
|
firstTime(true),
|
||||||
callProcess(callProcess),
|
callProcess(callProcess),
|
||||||
channelLocal(channelLocal),
|
channelLocal(channelLocal),
|
||||||
@@ -295,10 +302,7 @@ ChannelGetLocalPtr ChannelGetLocal::create(
|
|||||||
|
|
||||||
ChannelGetLocal::~ChannelGetLocal()
|
ChannelGetLocal::~ChannelGetLocal()
|
||||||
{
|
{
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
//cout << "~ChannelGetLocal()\n";
|
||||||
if(pvr && pvr->getTraceLevel()>0) {
|
|
||||||
cout << "~ChannelGetLocal() " << pvr->getRecordName() << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tr1::shared_ptr<Channel> ChannelGetLocal::getChannel()
|
std::tr1::shared_ptr<Channel> ChannelGetLocal::getChannel()
|
||||||
@@ -325,6 +329,13 @@ void ChannelGetLocal::get()
|
|||||||
{
|
{
|
||||||
ChannelGetRequester::shared_pointer requester = channelGetRequester.lock();
|
ChannelGetRequester::shared_pointer requester = channelGetRequester.lock();
|
||||||
if(!requester) return;
|
if(!requester) return;
|
||||||
|
ChannelLocalPtr channel(channelLocal.lock());
|
||||||
|
if(!channel) throw std::logic_error("channel is deleted");
|
||||||
|
if(!channel->canRead()) {
|
||||||
|
Status status = Status::error("ChannelGet::get is not allowed");
|
||||||
|
requester->getDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
PVRecordPtr pvr(pvRecord.lock());
|
||||||
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
||||||
try {
|
try {
|
||||||
@@ -372,13 +383,12 @@ void ChannelGetLocal::get()
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ChannelPutLocal :
|
class ChannelPutLocal :
|
||||||
public ChannelPut,
|
public epics::pvAccess::ChannelPut,
|
||||||
public std::tr1::enable_shared_from_this<ChannelPutLocal>
|
public std::tr1::enable_shared_from_this<ChannelPutLocal>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ChannelPutLocal);
|
POINTER_DEFINITIONS(ChannelPutLocal);
|
||||||
virtual ~ChannelPutLocal();
|
virtual ~ChannelPutLocal();
|
||||||
virtual void destroy() {} // DEPRECATED
|
|
||||||
static ChannelPutLocalPtr create(
|
static ChannelPutLocalPtr create(
|
||||||
ChannelLocalPtr const &channelLocal,
|
ChannelLocalPtr const &channelLocal,
|
||||||
ChannelPutRequester::shared_pointer const & channelPutRequester,
|
ChannelPutRequester::shared_pointer const & channelPutRequester,
|
||||||
@@ -460,10 +470,7 @@ ChannelPutLocalPtr ChannelPutLocal::create(
|
|||||||
|
|
||||||
ChannelPutLocal::~ChannelPutLocal()
|
ChannelPutLocal::~ChannelPutLocal()
|
||||||
{
|
{
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
//cout << "~ChannelPutLocal()\n";
|
||||||
if(pvr && pvr->getTraceLevel()>0) {
|
|
||||||
cout << "~ChannelPutLocal() " << pvr->getRecordName() << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tr1::shared_ptr<Channel> ChannelPutLocal::getChannel()
|
std::tr1::shared_ptr<Channel> ChannelPutLocal::getChannel()
|
||||||
@@ -490,6 +497,13 @@ void ChannelPutLocal::get()
|
|||||||
{
|
{
|
||||||
ChannelPutRequester::shared_pointer requester = channelPutRequester.lock();
|
ChannelPutRequester::shared_pointer requester = channelPutRequester.lock();
|
||||||
if(!requester) return;
|
if(!requester) return;
|
||||||
|
ChannelLocalPtr channel(channelLocal.lock());
|
||||||
|
if(!channel) throw std::logic_error("channel is deleted");
|
||||||
|
if(!channel->canRead()) {
|
||||||
|
Status status = Status::error("ChannelPut::get is not allowed");
|
||||||
|
requester->getDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
PVRecordPtr pvr(pvRecord.lock());
|
||||||
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
||||||
try {
|
try {
|
||||||
@@ -520,10 +534,18 @@ void ChannelPutLocal::put(
|
|||||||
{
|
{
|
||||||
ChannelPutRequester::shared_pointer requester = channelPutRequester.lock();
|
ChannelPutRequester::shared_pointer requester = channelPutRequester.lock();
|
||||||
if(!requester) return;
|
if(!requester) return;
|
||||||
|
ChannelLocalPtr channel(channelLocal.lock());
|
||||||
|
if(!channel) throw std::logic_error("channel is deleted");
|
||||||
|
if(!channel->canWrite()) {
|
||||||
|
Status status = Status::error("ChannelPut::put is not allowed");
|
||||||
|
requester->putDone(status,getPtrSelf());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
PVRecordPtr pvr(pvRecord.lock());
|
||||||
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
||||||
try {
|
try {
|
||||||
{
|
{
|
||||||
epicsGuard <PVRecord> guard(*pvr);
|
epicsGuard <PVRecord> guard(*pvr);
|
||||||
pvr->beginGroupPut();
|
pvr->beginGroupPut();
|
||||||
pvCopy->updateMaster(pvStructure, bitSet);
|
pvCopy->updateMaster(pvStructure, bitSet);
|
||||||
@@ -534,7 +556,7 @@ void ChannelPutLocal::put(
|
|||||||
}
|
}
|
||||||
requester->putDone(Status::Ok,getPtrSelf());
|
requester->putDone(Status::Ok,getPtrSelf());
|
||||||
if(pvr->getTraceLevel()>1)
|
if(pvr->getTraceLevel()>1)
|
||||||
{
|
{
|
||||||
cout << "ChannelPutLocal::put" << endl;
|
cout << "ChannelPutLocal::put" << endl;
|
||||||
}
|
}
|
||||||
} catch(std::exception& ex) {
|
} catch(std::exception& ex) {
|
||||||
@@ -545,13 +567,12 @@ void ChannelPutLocal::put(
|
|||||||
|
|
||||||
|
|
||||||
class ChannelPutGetLocal :
|
class ChannelPutGetLocal :
|
||||||
public ChannelPutGet,
|
public epics::pvAccess::ChannelPutGet,
|
||||||
public std::tr1::enable_shared_from_this<ChannelPutGetLocal>
|
public std::tr1::enable_shared_from_this<ChannelPutGetLocal>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ChannelPutGetLocal);
|
POINTER_DEFINITIONS(ChannelPutGetLocal);
|
||||||
virtual ~ChannelPutGetLocal();
|
virtual ~ChannelPutGetLocal();
|
||||||
virtual void destroy() {} // DEPRECATED
|
|
||||||
static ChannelPutGetLocalPtr create(
|
static ChannelPutGetLocalPtr create(
|
||||||
ChannelLocalPtr const &channelLocal,
|
ChannelLocalPtr const &channelLocal,
|
||||||
ChannelPutGetRequester::shared_pointer const & channelPutGetRequester,
|
ChannelPutGetRequester::shared_pointer const & channelPutGetRequester,
|
||||||
@@ -581,7 +602,7 @@ private:
|
|||||||
PVStructurePtr const&pvGetStructure,
|
PVStructurePtr const&pvGetStructure,
|
||||||
BitSetPtr const & getBitSet,
|
BitSetPtr const & getBitSet,
|
||||||
PVRecordPtr const &pvRecord)
|
PVRecordPtr const &pvRecord)
|
||||||
:
|
:
|
||||||
callProcess(callProcess),
|
callProcess(callProcess),
|
||||||
channelLocal(channelLocal),
|
channelLocal(channelLocal),
|
||||||
channelPutGetRequester(channelPutGetRequester),
|
channelPutGetRequester(channelPutGetRequester),
|
||||||
@@ -653,10 +674,7 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create(
|
|||||||
|
|
||||||
ChannelPutGetLocal::~ChannelPutGetLocal()
|
ChannelPutGetLocal::~ChannelPutGetLocal()
|
||||||
{
|
{
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
//cout << "~ChannelPutGetLocal()\n";
|
||||||
if(pvr && pvr->getTraceLevel()>0) {
|
|
||||||
cout << "~ChannelPutGetLocal() " << pvr->getRecordName() << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tr1::shared_ptr<Channel> ChannelPutGetLocal::getChannel()
|
std::tr1::shared_ptr<Channel> ChannelPutGetLocal::getChannel()
|
||||||
@@ -684,6 +702,13 @@ void ChannelPutGetLocal::putGet(
|
|||||||
{
|
{
|
||||||
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
|
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
|
||||||
if(!requester) return;
|
if(!requester) return;
|
||||||
|
ChannelLocalPtr channel(channelLocal.lock());
|
||||||
|
if(!channel) throw std::logic_error("channel is deleted");
|
||||||
|
if(!channel->canWrite()||!channel->canRead() ) {
|
||||||
|
Status status = Status::error("ChannelPutGet::putGet is not allowed");
|
||||||
|
requester->putGetDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
PVRecordPtr pvr(pvRecord.lock());
|
||||||
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
||||||
try {
|
try {
|
||||||
@@ -712,6 +737,13 @@ void ChannelPutGetLocal::getPut()
|
|||||||
{
|
{
|
||||||
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
|
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
|
||||||
if(!requester) return;
|
if(!requester) return;
|
||||||
|
ChannelLocalPtr channel(channelLocal.lock());
|
||||||
|
if(!channel) throw std::logic_error("channel is deleted");
|
||||||
|
if(!channel->canRead()) {
|
||||||
|
Status status = Status::error("ChannelPutGet::getPut is not allowed");
|
||||||
|
requester->getPutDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
PVRecordPtr pvr(pvRecord.lock());
|
||||||
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
||||||
try {
|
try {
|
||||||
@@ -739,6 +771,13 @@ void ChannelPutGetLocal::getGet()
|
|||||||
{
|
{
|
||||||
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
|
ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
|
||||||
if(!requester) return;
|
if(!requester) return;
|
||||||
|
ChannelLocalPtr channel(channelLocal.lock());
|
||||||
|
if(!channel) throw std::logic_error("channel is deleted");
|
||||||
|
if(!channel->canRead()) {
|
||||||
|
Status status = Status::error("ChannelPutGet::getGet is not allowed");
|
||||||
|
requester->getPutDone(status,getPtrSelf(),PVStructurePtr(),BitSetPtr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
PVRecordPtr pvr(pvRecord.lock());
|
||||||
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
if(!pvr) throw std::logic_error("pvRecord is deleted");
|
||||||
try {
|
try {
|
||||||
@@ -763,13 +802,12 @@ void ChannelPutGetLocal::getGet()
|
|||||||
|
|
||||||
|
|
||||||
class ChannelRPCLocal :
|
class ChannelRPCLocal :
|
||||||
public ChannelRPC,
|
public epics::pvAccess::ChannelRPC,
|
||||||
public RPCResponseCallback,
|
public epics::pvAccess::RPCResponseCallback,
|
||||||
public std::tr1::enable_shared_from_this<ChannelRPCLocal>
|
public std::tr1::enable_shared_from_this<ChannelRPCLocal>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ChannelRPCLocal);
|
POINTER_DEFINITIONS(ChannelRPCLocal);
|
||||||
virtual void destroy() {} // DEPRECATED
|
|
||||||
static ChannelRPCLocalPtr create(
|
static ChannelRPCLocalPtr create(
|
||||||
ChannelLocalPtr const & channelLocal,
|
ChannelLocalPtr const & channelLocal,
|
||||||
ChannelRPCRequester::shared_pointer const & channelRPCRequester,
|
ChannelRPCRequester::shared_pointer const & channelRPCRequester,
|
||||||
@@ -853,10 +891,7 @@ ChannelRPCLocalPtr ChannelRPCLocal::create(
|
|||||||
|
|
||||||
ChannelRPCLocal::~ChannelRPCLocal()
|
ChannelRPCLocal::~ChannelRPCLocal()
|
||||||
{
|
{
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
//cout << "~ChannelRPCLocal()\n";
|
||||||
if(pvr && pvr->getTraceLevel()>0) {
|
|
||||||
cout << "~ChannelRPCLocal() " << pvr->getRecordName() << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tr1::shared_ptr<Channel> ChannelRPCLocal::getChannel()
|
std::tr1::shared_ptr<Channel> ChannelRPCLocal::getChannel()
|
||||||
@@ -877,7 +912,7 @@ void ChannelRPCLocal::processRequest(
|
|||||||
{
|
{
|
||||||
result = service->request(pvArgument);
|
result = service->request(pvArgument);
|
||||||
}
|
}
|
||||||
catch (RPCRequestException& rre)
|
catch (epics::pvAccess::RPCRequestException& rre)
|
||||||
{
|
{
|
||||||
status = Status(rre.getStatus(), rre.what());
|
status = Status(rre.getStatus(), rre.what());
|
||||||
ok = false;
|
ok = false;
|
||||||
@@ -893,7 +928,7 @@ void ChannelRPCLocal::processRequest(
|
|||||||
status = Status(Status::STATUSTYPE_FATAL, "Unexpected exception caught while calling RPCService.request(PVStructure).");
|
status = Status(Status::STATUSTYPE_FATAL, "Unexpected exception caught while calling RPCService.request(PVStructure).");
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check null result
|
// check null result
|
||||||
if (ok && !result)
|
if (ok && !result)
|
||||||
{
|
{
|
||||||
@@ -958,13 +993,12 @@ void ChannelRPCLocal::request(PVStructurePtr const & pvArgument)
|
|||||||
typedef std::tr1::shared_ptr<PVArray> PVArrayPtr;
|
typedef std::tr1::shared_ptr<PVArray> PVArrayPtr;
|
||||||
|
|
||||||
class ChannelArrayLocal :
|
class ChannelArrayLocal :
|
||||||
public ChannelArray,
|
public epics::pvAccess::ChannelArray,
|
||||||
public std::tr1::enable_shared_from_this<ChannelArrayLocal>
|
public std::tr1::enable_shared_from_this<ChannelArrayLocal>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ChannelArrayLocal);
|
POINTER_DEFINITIONS(ChannelArrayLocal);
|
||||||
virtual ~ChannelArrayLocal();
|
virtual ~ChannelArrayLocal();
|
||||||
virtual void destroy() {} // DEPRECATED
|
|
||||||
static ChannelArrayLocalPtr create(
|
static ChannelArrayLocalPtr create(
|
||||||
ChannelLocalPtr const &channelLocal,
|
ChannelLocalPtr const &channelLocal,
|
||||||
ChannelArrayRequester::shared_pointer const & channelArrayRequester,
|
ChannelArrayRequester::shared_pointer const & channelArrayRequester,
|
||||||
@@ -992,7 +1026,7 @@ private:
|
|||||||
PVArrayPtr const &pvArray,
|
PVArrayPtr const &pvArray,
|
||||||
PVArrayPtr const &pvCopy,
|
PVArrayPtr const &pvCopy,
|
||||||
PVRecordPtr const &pvRecord)
|
PVRecordPtr const &pvRecord)
|
||||||
:
|
:
|
||||||
channelLocal(channelLocal),
|
channelLocal(channelLocal),
|
||||||
channelArrayRequester(channelArrayRequester),
|
channelArrayRequester(channelArrayRequester),
|
||||||
pvArray(pvArray),
|
pvArray(pvArray),
|
||||||
@@ -1095,10 +1129,7 @@ ChannelArrayLocalPtr ChannelArrayLocal::create(
|
|||||||
|
|
||||||
ChannelArrayLocal::~ChannelArrayLocal()
|
ChannelArrayLocal::~ChannelArrayLocal()
|
||||||
{
|
{
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
//cout << "~ChannelArrayLocal()\n";
|
||||||
if(pvr && pvr->getTraceLevel()>0) {
|
|
||||||
cout << "~ChannelArrayLocal() " << pvr->getRecordName() << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tr1::shared_ptr<Channel> ChannelArrayLocal::getChannel()
|
std::tr1::shared_ptr<Channel> ChannelArrayLocal::getChannel()
|
||||||
@@ -1237,10 +1268,16 @@ ChannelLocal::ChannelLocal(
|
|||||||
ChannelProviderLocalPtr const & provider,
|
ChannelProviderLocalPtr const & provider,
|
||||||
ChannelRequester::shared_pointer const & requester,
|
ChannelRequester::shared_pointer const & requester,
|
||||||
PVRecordPtr const & pvRecord)
|
PVRecordPtr const & pvRecord)
|
||||||
:
|
:
|
||||||
requester(requester),
|
requester(requester),
|
||||||
provider(provider),
|
provider(provider),
|
||||||
pvRecord(pvRecord)
|
pvRecord(pvRecord),
|
||||||
|
asLevel(pvRecord->getAsLevel()),
|
||||||
|
asGroup(getAsGroup(pvRecord)),
|
||||||
|
asUser(getAsUser(requester)),
|
||||||
|
asHost(getAsHost(requester)),
|
||||||
|
asMemberPvt(0),
|
||||||
|
asClientPvt(0)
|
||||||
{
|
{
|
||||||
if(pvRecord->getTraceLevel()>0) {
|
if(pvRecord->getTraceLevel()>0) {
|
||||||
cout << "ChannelLocal::ChannelLocal()"
|
cout << "ChannelLocal::ChannelLocal()"
|
||||||
@@ -1248,15 +1285,91 @@ ChannelLocal::ChannelLocal(
|
|||||||
<< " requester exists " << (requester ? "true" : "false")
|
<< " requester exists " << (requester ? "true" : "false")
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
if (pvRecord->getAsGroup().empty() || asAddMember(&asMemberPvt, &asGroup[0]) != 0) {
|
||||||
|
asMemberPvt = 0;
|
||||||
|
}
|
||||||
|
if (asMemberPvt) {
|
||||||
|
asAddClient(&asClientPvt, asMemberPvt, asLevel, &asUser[0], &asHost[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<char> ChannelLocal::toCharArray(const std::string& s)
|
||||||
|
{
|
||||||
|
std::vector<char> v(s.begin(), s.end());
|
||||||
|
v.push_back('\0');
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> ChannelLocal::getAsGroup(const PVRecordPtr& pvRecord)
|
||||||
|
{
|
||||||
|
return toCharArray(pvRecord->getAsGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> ChannelLocal::getAsUser(const ChannelRequester::shared_pointer& requester)
|
||||||
|
{
|
||||||
|
PeerInfo::const_shared_pointer info(requester->getPeerInfo());
|
||||||
|
std::string user;
|
||||||
|
if(info && info->identified) {
|
||||||
|
if(info->authority=="ca") {
|
||||||
|
user = info->account;
|
||||||
|
size_t first = user.find_last_of('/');
|
||||||
|
if(first != std::string::npos) {
|
||||||
|
// prevent CA accounts like "<authority>/<user>"
|
||||||
|
user = user.substr(first+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
user = info->authority + "/" + info->account;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toCharArray(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> ChannelLocal::getAsHost(const epics::pvAccess::ChannelRequester::shared_pointer& requester)
|
||||||
|
{
|
||||||
|
PeerInfo::const_shared_pointer info(requester->getPeerInfo());
|
||||||
|
std::string host;
|
||||||
|
if(info && info->identified) {
|
||||||
|
host= info->peer;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// anonymous
|
||||||
|
host = requester->getRequesterName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle form "ip:port"
|
||||||
|
size_t last = host.find_first_of(':');
|
||||||
|
if(last == std::string::npos) {
|
||||||
|
last = host.size();
|
||||||
|
}
|
||||||
|
host.resize(last);
|
||||||
|
return toCharArray(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelLocal::canWrite()
|
||||||
|
{
|
||||||
|
if(!asActive || (asClientPvt && asCheckPut(asClientPvt))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelLocal::canRead()
|
||||||
|
{
|
||||||
|
if(!asActive || (asClientPvt && asCheckGet(asClientPvt))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ChannelLocal::~ChannelLocal()
|
ChannelLocal::~ChannelLocal()
|
||||||
{
|
{
|
||||||
PVRecordPtr pvr(pvRecord.lock());
|
if(asMemberPvt) {
|
||||||
if(!pvr) return;
|
asRemoveMember(&asMemberPvt);
|
||||||
if(pvr->getTraceLevel()>0)
|
asMemberPvt = 0;
|
||||||
{
|
}
|
||||||
cout << "~ChannelLocal()" << endl;
|
if(asClientPvt) {
|
||||||
|
asRemoveClient(&asClientPvt);
|
||||||
|
asClientPvt = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1287,7 +1400,7 @@ string ChannelLocal::getRequesterName()
|
|||||||
<< " requester exists " << (requester ? "true" : "false")
|
<< " requester exists " << (requester ? "true" : "false")
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!requester) return string();
|
if(!requester) return string();
|
||||||
return requester->getRequesterName();
|
return requester->getRequesterName();
|
||||||
}
|
}
|
||||||
@@ -1310,7 +1423,7 @@ void ChannelLocal::message(
|
|||||||
string recordName("record deleted");
|
string recordName("record deleted");
|
||||||
if(pvr) recordName = pvr->getRecordName();
|
if(pvr) recordName = pvr->getRecordName();
|
||||||
cout << recordName
|
cout << recordName
|
||||||
<< " message " << message
|
<< " message " << message
|
||||||
<< " messageType " << getMessageTypeName(messageType)
|
<< " messageType " << getMessageTypeName(messageType)
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
@@ -1353,8 +1466,8 @@ void ChannelLocal::getField(GetFieldRequester::shared_pointer const &requester,
|
|||||||
pvr->getPVRecordStructure()->getPVStructure()->getStructure();
|
pvr->getPVRecordStructure()->getPVStructure()->getStructure();
|
||||||
requester->getDone(Status::Ok,structure);
|
requester->getDone(Status::Ok,structure);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PVFieldPtr pvField =
|
PVFieldPtr pvField =
|
||||||
pvr->getPVRecordStructure()->getPVStructure()->getSubField(subField);
|
pvr->getPVRecordStructure()->getPVStructure()->getSubField(subField);
|
||||||
if(pvField) {
|
if(pvField) {
|
||||||
requester->getDone(Status::Ok,pvField->getField());
|
requester->getDone(Status::Ok,pvField->getField());
|
||||||
@@ -1470,7 +1583,7 @@ ChannelRPC::shared_pointer ChannelLocal::createChannelRPC(
|
|||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelRPCLocalPtr channelRPC =
|
ChannelRPCLocalPtr channelRPC =
|
||||||
ChannelRPCLocal::create(
|
ChannelRPCLocal::create(
|
||||||
getPtrSelf(),
|
getPtrSelf(),
|
||||||
channelRPCRequester,
|
channelRPCRequester,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* channelChannelProviderLocal.cpp */
|
/* channelProviderLocal.cpp */
|
||||||
/**
|
/**
|
||||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
@@ -10,13 +10,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <epicsThread.h>
|
#include <epicsThread.h>
|
||||||
|
#include <asLib.h>
|
||||||
#include <pv/serverContext.h>
|
#include <pv/serverContext.h>
|
||||||
#include <pv/syncChannelFind.h>
|
#include <pv/syncChannelFind.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvStructureCopy.h"
|
||||||
#include <pv/channelProviderLocal.h>
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/channelProviderLocal.h"
|
||||||
|
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
using namespace epics::pvAccess;
|
using namespace epics::pvAccess;
|
||||||
@@ -27,13 +31,13 @@ using std::cout;
|
|||||||
using std::endl;
|
using std::endl;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
static string providerName("local");
|
static string providerName("local");
|
||||||
static ChannelProviderLocalPtr channelProvider;
|
static ChannelProviderLocalPtr channelProvider;
|
||||||
|
|
||||||
class LocalChannelProviderFactory : public ChannelProviderFactory
|
class LocalChannelProviderFactory : public ChannelProviderFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(LocalChannelProviderFactory);
|
POINTER_DEFINITIONS(LocalChannelProviderFactory);
|
||||||
virtual string getFactoryName() { return providerName;}
|
virtual string getFactoryName() { return providerName;}
|
||||||
@@ -111,7 +115,7 @@ ChannelFind::shared_pointer ChannelProviderLocal::channelFind(
|
|||||||
Status::Ok,
|
Status::Ok,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found");
|
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found");
|
||||||
channelFindRequester->channelFindResult(
|
channelFindRequester->channelFindResult(
|
||||||
@@ -173,4 +177,18 @@ Channel::shared_pointer ChannelProviderLocal::createChannel(
|
|||||||
return createChannel(channelName, channelRequester, priority);
|
return createChannel(channelName, channelRequester, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChannelProviderLocal::initAs(const std::string& filePath, const std::string& substitutions)
|
||||||
|
{
|
||||||
|
int status = asInitFile(filePath.c_str(), substitutions.c_str());
|
||||||
|
if(status) {
|
||||||
|
throw std::runtime_error("Invalid AS configuration.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelProviderLocal::isAsActive()
|
||||||
|
{
|
||||||
|
return asActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -14,11 +14,17 @@
|
|||||||
#include <epicsGuard.h>
|
#include <epicsGuard.h>
|
||||||
#include <pv/thread.h>
|
#include <pv/thread.h>
|
||||||
#include <pv/bitSetUtil.h>
|
#include <pv/bitSetUtil.h>
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
#include <pv/timeStamp.h>
|
#include <pv/timeStamp.h>
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvStructureCopy.h"
|
||||||
#include <pv/channelProviderLocal.h>
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/channelProviderLocal.h"
|
||||||
|
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
using namespace epics::pvAccess;
|
using namespace epics::pvAccess;
|
||||||
@@ -28,7 +34,7 @@ using std::cout;
|
|||||||
using std::endl;
|
using std::endl;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
class MonitorLocal;
|
class MonitorLocal;
|
||||||
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
||||||
@@ -82,7 +88,7 @@ public:
|
|||||||
nextGetUsed = 0;
|
nextGetUsed = 0;
|
||||||
nextReleaseUsed = 0;
|
nextReleaseUsed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonitorElementPtr getFree()
|
MonitorElementPtr getFree()
|
||||||
{
|
{
|
||||||
if(numberFree==0) return MonitorElementPtr();
|
if(numberFree==0) return MonitorElementPtr();
|
||||||
@@ -92,7 +98,7 @@ public:
|
|||||||
if(nextGetFree>=size) nextGetFree = 0;
|
if(nextGetFree>=size) nextGetFree = 0;
|
||||||
return elements[ind];
|
return elements[ind];
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUsed(MonitorElementPtr const &element)
|
void setUsed(MonitorElementPtr const &element)
|
||||||
{
|
{
|
||||||
if(element!=elements[nextSetUsed++]) {
|
if(element!=elements[nextSetUsed++]) {
|
||||||
@@ -101,7 +107,7 @@ public:
|
|||||||
numberUsed++;
|
numberUsed++;
|
||||||
if(nextSetUsed>=size) nextSetUsed = 0;
|
if(nextSetUsed>=size) nextSetUsed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonitorElementPtr getUsed()
|
MonitorElementPtr getUsed()
|
||||||
{
|
{
|
||||||
if(numberUsed==0) return MonitorElementPtr();
|
if(numberUsed==0) return MonitorElementPtr();
|
||||||
@@ -125,7 +131,7 @@ public:
|
|||||||
|
|
||||||
typedef std::tr1::shared_ptr<MonitorRequester> MonitorRequesterPtr;
|
typedef std::tr1::shared_ptr<MonitorRequester> MonitorRequesterPtr;
|
||||||
|
|
||||||
|
|
||||||
class MonitorLocal :
|
class MonitorLocal :
|
||||||
public Monitor,
|
public Monitor,
|
||||||
public PVListener,
|
public PVListener,
|
||||||
@@ -135,7 +141,6 @@ class MonitorLocal :
|
|||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(MonitorLocal);
|
POINTER_DEFINITIONS(MonitorLocal);
|
||||||
virtual ~MonitorLocal();
|
virtual ~MonitorLocal();
|
||||||
virtual void destroy() {} // DEPRECATED
|
|
||||||
virtual Status start();
|
virtual Status start();
|
||||||
virtual Status stop();
|
virtual Status stop();
|
||||||
virtual MonitorElementPtr poll();
|
virtual MonitorElementPtr poll();
|
||||||
@@ -185,10 +190,7 @@ MonitorLocal::MonitorLocal(
|
|||||||
|
|
||||||
MonitorLocal::~MonitorLocal()
|
MonitorLocal::~MonitorLocal()
|
||||||
{
|
{
|
||||||
if(pvRecord->getTraceLevel()>0)
|
//cout << "MonitorLocal::~MonitorLocal()" << endl;
|
||||||
{
|
|
||||||
cout << "MonitorLocal::~MonitorLocal()" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -288,7 +290,13 @@ void MonitorLocal::dataPut(PVRecordFieldPtr const & pvRecordField)
|
|||||||
{
|
{
|
||||||
if(pvRecord->getTraceLevel()>1)
|
if(pvRecord->getTraceLevel()>1)
|
||||||
{
|
{
|
||||||
cout << "PVCopyMonitor::dataPut(pvRecordField)" << endl;
|
cout << "MonitorLocal::dataPut(pvRecordField)" << endl;
|
||||||
|
}
|
||||||
|
// If this record field is the master field, and the master field was not
|
||||||
|
// requested, we do not proceed with copy
|
||||||
|
bool isMasterField = pvRecordField->getPVRecord()->getPVStructure()->getFieldOffset()==0;
|
||||||
|
if (isMasterField && !pvCopy->isMasterFieldRequested()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(state!=active) return;
|
if(state!=active) return;
|
||||||
{
|
{
|
||||||
@@ -313,7 +321,7 @@ void MonitorLocal::dataPut(
|
|||||||
{
|
{
|
||||||
if(pvRecord->getTraceLevel()>1)
|
if(pvRecord->getTraceLevel()>1)
|
||||||
{
|
{
|
||||||
cout << "PVCopyMonitor::dataPut(requested,pvRecordField)" << endl;
|
cout << "MonitorLocal::dataPut(requested,pvRecordField)" << endl;
|
||||||
}
|
}
|
||||||
if(state!=active) return;
|
if(state!=active) return;
|
||||||
{
|
{
|
||||||
@@ -340,7 +348,7 @@ void MonitorLocal::beginGroupPut(PVRecordPtr const & pvRecord)
|
|||||||
{
|
{
|
||||||
if(pvRecord->getTraceLevel()>1)
|
if(pvRecord->getTraceLevel()>1)
|
||||||
{
|
{
|
||||||
cout << "PVCopyMonitor::beginGroupPut()" << endl;
|
cout << "MonitorLocal::beginGroupPut()" << endl;
|
||||||
}
|
}
|
||||||
if(state!=active) return;
|
if(state!=active) return;
|
||||||
{
|
{
|
||||||
@@ -354,7 +362,7 @@ void MonitorLocal::endGroupPut(PVRecordPtr const & pvRecord)
|
|||||||
{
|
{
|
||||||
if(pvRecord->getTraceLevel()>1)
|
if(pvRecord->getTraceLevel()>1)
|
||||||
{
|
{
|
||||||
cout << "PVCopyMonitor::endGroupPut dataChanged " << dataChanged << endl;
|
cout << "MonitorLocal::endGroupPut dataChanged " << dataChanged << endl;
|
||||||
}
|
}
|
||||||
if(state!=active) return;
|
if(state!=active) return;
|
||||||
{
|
{
|
||||||
@@ -371,7 +379,7 @@ void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
|
|||||||
{
|
{
|
||||||
if(pvRecord->getTraceLevel()>1)
|
if(pvRecord->getTraceLevel()>1)
|
||||||
{
|
{
|
||||||
cout << "PVCopyMonitor::unlisten\n";
|
cout << "MonitorLocal::unlisten\n";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Lock xx(mutex);
|
Lock xx(mutex);
|
||||||
@@ -381,7 +389,7 @@ void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
|
|||||||
if(requester) {
|
if(requester) {
|
||||||
if(pvRecord->getTraceLevel()>1)
|
if(pvRecord->getTraceLevel()>1)
|
||||||
{
|
{
|
||||||
cout << "PVCopyMonitor::unlisten calling requester->unlisten\n";
|
cout << "MonitorLocal::unlisten calling requester->unlisten\n";
|
||||||
}
|
}
|
||||||
requester->unlisten(getPtrSelf());
|
requester->unlisten(getPtrSelf());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,30 +11,19 @@
|
|||||||
|
|
||||||
/* Author: Marty Kraimer */
|
/* Author: Marty Kraimer */
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <string>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <memory>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <cantProceed.h>
|
|
||||||
#include <epicsStdio.h>
|
|
||||||
#include <epicsMutex.h>
|
|
||||||
#include <epicsEvent.h>
|
|
||||||
#include <epicsThread.h>
|
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
#include <shareLib.h>
|
|
||||||
#include <epicsExit.h>
|
|
||||||
|
|
||||||
#include <pv/pvAccess.h>
|
#include <pv/pvAccess.h>
|
||||||
#include <pv/serverContext.h>
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/syncChannelFind.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
|
||||||
// this declared epicsExportSharedSymbols
|
// The following must be the last include for code pvDatabase uses
|
||||||
#include <epicsExport.h>
|
#include <epicsExport.h>
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
#include <pv/channelProviderLocal.h>
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/channelProviderLocal.h"
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
@@ -57,7 +46,6 @@ extern "C" void pvdbl(const iocshArgBuf *args)
|
|||||||
static void registerChannelProviderLocal(void)
|
static void registerChannelProviderLocal(void)
|
||||||
{
|
{
|
||||||
static int firstTime = 1;
|
static int firstTime = 1;
|
||||||
cout << "registerChannelProviderLocal firstTime " << (firstTime ? "true" : "false") << endl;
|
|
||||||
if (firstTime) {
|
if (firstTime) {
|
||||||
firstTime = 0;
|
firstTime = 0;
|
||||||
iocshRegister(&pvdblFuncDef, pvdbl);
|
iocshRegister(&pvdblFuncDef, pvdbl);
|
||||||
|
|||||||
@@ -2,5 +2,17 @@
|
|||||||
|
|
||||||
SRC_DIRS += $(PVDATABASE_SRC)/special
|
SRC_DIRS += $(PVDATABASE_SRC)/special
|
||||||
|
|
||||||
LIBSRCS += traceRecord.cpp
|
DBD += pvdbcrScalarRecord.dbd
|
||||||
LIBSRCS += removeRecord.cpp
|
DBD += pvdbcrScalarArrayRecord.dbd
|
||||||
|
DBD += pvdbcrAddRecord.dbd
|
||||||
|
DBD += pvdbcrRemoveRecord.dbd
|
||||||
|
DBD += pvdbcrProcessRecord.dbd
|
||||||
|
DBD += pvdbcrTraceRecord.dbd
|
||||||
|
DBD += pvdbcrAllRecords.dbd
|
||||||
|
|
||||||
|
LIBSRCS += pvdbcrScalarRecord.cpp
|
||||||
|
LIBSRCS += pvdbcrScalarArrayRecord.cpp
|
||||||
|
LIBSRCS += pvdbcrAddRecord.cpp
|
||||||
|
LIBSRCS += pvdbcrRemoveRecord.cpp
|
||||||
|
LIBSRCS += pvdbcrProcessRecord.cpp
|
||||||
|
LIBSRCS += pvdbcrTraceRecord.cpp
|
||||||
|
|||||||
147
src/special/pvdbcrAddRecord.cpp
Normal file
147
src/special/pvdbcrAddRecord.cpp
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2021.04.07
|
||||||
|
*/
|
||||||
|
#include <iocsh.h>
|
||||||
|
#include <pv/standardField.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/alarm.h>
|
||||||
|
#include <pv/pvAlarm.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
|
// The following must be the last include for code exampleLink uses
|
||||||
|
#include <epicsExport.h>
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/pvdbcrAddRecord.h"
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
PvdbcrAddRecordPtr PvdbcrAddRecord::create(
|
||||||
|
std::string const & recordName,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
{
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||||
|
addNestedStructure("argument")->
|
||||||
|
add("recordName",pvString)->
|
||||||
|
addNestedUnion("union") ->
|
||||||
|
endNested()->
|
||||||
|
endNested()->
|
||||||
|
addNestedStructure("result") ->
|
||||||
|
add("status",pvString) ->
|
||||||
|
endNested()->
|
||||||
|
createStructure();
|
||||||
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||||
|
PvdbcrAddRecordPtr pvRecord(
|
||||||
|
new PvdbcrAddRecord(recordName,pvStructure,asLevel,asGroup));
|
||||||
|
if(!pvRecord->init()) pvRecord.reset();
|
||||||
|
return pvRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
PvdbcrAddRecord::PvdbcrAddRecord(
|
||||||
|
std::string const & recordName,
|
||||||
|
PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
: PVRecord(recordName,pvStructure,asLevel,asGroup)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PvdbcrAddRecord::init()
|
||||||
|
{
|
||||||
|
initPVRecord();
|
||||||
|
PVStructurePtr pvStructure = getPVStructure();
|
||||||
|
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
|
||||||
|
if(!pvRecordName) return false;
|
||||||
|
pvResult = pvStructure->getSubField<PVString>("result.status");
|
||||||
|
if(!pvResult) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PvdbcrAddRecord::process()
|
||||||
|
{
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
string name = pvRecordName->get();
|
||||||
|
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
|
||||||
|
if(pvRecord) {
|
||||||
|
pvResult->put(name + " already exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PVUnionPtr pvUnion = getPVStructure()->getSubField<PVUnion>("argument.union");
|
||||||
|
if(!pvUnion) {
|
||||||
|
pvResult->put(name + " argument.union is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PVFieldPtr pvField(pvUnion->get());
|
||||||
|
if(!pvField) {
|
||||||
|
pvResult->put(name + " union has no value");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(pvField->getField()->getType()!=epics::pvData::structure) {
|
||||||
|
pvResult->put(name + " union most be a structure");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StructureConstPtr st = std::tr1::static_pointer_cast<const Structure>(pvField->getField());
|
||||||
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(st);
|
||||||
|
PVRecordPtr pvRec = PVRecord::create(name,pvStructure);
|
||||||
|
bool result = PVDatabase::getMaster()->addRecord(pvRec);
|
||||||
|
if(result) {
|
||||||
|
pvResult->put("success");
|
||||||
|
} else {
|
||||||
|
pvResult->put("failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
static const iocshArg arg0 = { "recordName", iocshArgString };
|
||||||
|
static const iocshArg arg1 = { "asLevel", iocshArgInt };
|
||||||
|
static const iocshArg arg2 = { "asGroup", iocshArgString };
|
||||||
|
static const iocshArg *args[] = {&arg0,&arg1,&arg2};
|
||||||
|
|
||||||
|
static const iocshFuncDef pvdbcrAddRecordFuncDef = {"pvdbcrAddRecord", 3,args};
|
||||||
|
|
||||||
|
static void pvdbcrAddRecordCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
char *sval = args[0].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrAddRecord recordName not specified");
|
||||||
|
}
|
||||||
|
string recordName = string(sval);
|
||||||
|
int asLevel = args[1].ival;
|
||||||
|
string asGroup("DEFAULT");
|
||||||
|
sval = args[2].sval;
|
||||||
|
if(sval) {
|
||||||
|
asGroup = string(sval);
|
||||||
|
}
|
||||||
|
epics::pvDatabase::PvdbcrAddRecordPtr record = epics::pvDatabase::PvdbcrAddRecord::create(recordName);
|
||||||
|
record->setAsLevel(asLevel);
|
||||||
|
record->setAsGroup(asGroup);
|
||||||
|
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
|
||||||
|
bool result = master->addRecord(record);
|
||||||
|
if(!result) cout << "recordname " << recordName << " not added" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pvdbcrAddRecord(void)
|
||||||
|
{
|
||||||
|
static int firstTime = 1;
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = 0;
|
||||||
|
iocshRegister(&pvdbcrAddRecordFuncDef, pvdbcrAddRecordCallFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
epicsExportRegistrar(pvdbcrAddRecord);
|
||||||
|
}
|
||||||
1
src/special/pvdbcrAddRecord.dbd
Normal file
1
src/special/pvdbcrAddRecord.dbd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
registrar("pvdbcrAddRecord")
|
||||||
6
src/special/pvdbcrAllRecords.dbd
Normal file
6
src/special/pvdbcrAllRecords.dbd
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
include "pvdbcrAddRecord.dbd"
|
||||||
|
include "pvdbcrRemoveRecord.dbd"
|
||||||
|
include "pvdbcrProcessRecord.dbd"
|
||||||
|
include "pvdbcrTraceRecord.dbd"
|
||||||
|
include "pvdbcrScalarRecord.dbd"
|
||||||
|
include "pvdbcrScalarArrayRecord.dbd"
|
||||||
206
src/special/pvdbcrProcessRecord.cpp
Normal file
206
src/special/pvdbcrProcessRecord.cpp
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2021.04.07
|
||||||
|
*/
|
||||||
|
#include <epicsThread.h>
|
||||||
|
#include <epicsGuard.h>
|
||||||
|
#include <pv/event.h>
|
||||||
|
#include <pv/lock.h>
|
||||||
|
#include <iocsh.h>
|
||||||
|
#include <pv/standardField.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/alarm.h>
|
||||||
|
#include <pv/pvAlarm.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
|
#include <epicsExport.h>
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/pvdbcrProcessRecord.h"
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
PvdbcrProcessRecordPtr PvdbcrProcessRecord::create(
|
||||||
|
std::string const & recordName,double delay,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
PvdbcrProcessRecordPtr pvRecord(
|
||||||
|
new PvdbcrProcessRecord(recordName,pvStructure,delay,asLevel,asGroup));
|
||||||
|
if(!pvRecord->init()) pvRecord.reset();
|
||||||
|
return pvRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PvdbcrProcessRecord::PvdbcrProcessRecord(
|
||||||
|
std::string const & recordName,
|
||||||
|
epics::pvData::PVStructurePtr const & pvStructure,double delay,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
: PVRecord(recordName,pvStructure,asLevel,asGroup),
|
||||||
|
delay(delay),
|
||||||
|
pvDatabase(PVDatabase::getMaster())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PvdbcrProcessRecord::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 PvdbcrProcessRecord::setDelay(double delay) {this->delay = delay;}
|
||||||
|
|
||||||
|
double PvdbcrProcessRecord::getDelay() {return delay;}
|
||||||
|
|
||||||
|
void PvdbcrProcessRecord::startThread()
|
||||||
|
{
|
||||||
|
thread = EpicsThreadPtr(new epicsThread(
|
||||||
|
*this,
|
||||||
|
"processRecord",
|
||||||
|
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||||
|
epicsThreadPriorityLow));
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PvdbcrProcessRecord::stop()
|
||||||
|
{
|
||||||
|
runStop.signal();
|
||||||
|
runReturn.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PvdbcrProcessRecord::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 PvdbcrProcessRecord::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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
static const iocshArg arg0 = { "recordName", iocshArgString };
|
||||||
|
static const iocshArg arg1 = { "delay", iocshArgDouble };
|
||||||
|
static const iocshArg arg2 = { "asLevel", iocshArgInt };
|
||||||
|
static const iocshArg arg3 = { "asGroup", iocshArgString };
|
||||||
|
static const iocshArg *args[] = {&arg0,&arg1,&arg2,&arg3};
|
||||||
|
|
||||||
|
static const iocshFuncDef pvdbcrProcessRecordFuncDef = {"pvdbcrProcessRecord", 4,args};
|
||||||
|
|
||||||
|
static void pvdbcrProcessRecordCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
char *sval = args[0].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrProcessRecord recordName not specified");
|
||||||
|
}
|
||||||
|
string recordName = string(sval);
|
||||||
|
double delay = args[1].dval;
|
||||||
|
if(delay<0.0) delay = 1.0;
|
||||||
|
int asLevel = args[2].ival;
|
||||||
|
string asGroup("DEFAULT");
|
||||||
|
sval = args[3].sval;
|
||||||
|
if(sval) {
|
||||||
|
asGroup = string(sval);
|
||||||
|
}
|
||||||
|
epics::pvDatabase::PvdbcrProcessRecordPtr record
|
||||||
|
= epics::pvDatabase::PvdbcrProcessRecord::create(recordName,delay);
|
||||||
|
record->setAsLevel(asLevel);
|
||||||
|
record->setAsGroup(asGroup);
|
||||||
|
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
|
||||||
|
bool result = master->addRecord(record);
|
||||||
|
if(!result) cout << "recordname " << recordName << " not added" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pvdbcrProcessRecord(void)
|
||||||
|
{
|
||||||
|
static int firstTime = 1;
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = 0;
|
||||||
|
iocshRegister(&pvdbcrProcessRecordFuncDef, pvdbcrProcessRecordCallFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
epicsExportRegistrar(pvdbcrProcessRecord);
|
||||||
|
}
|
||||||
1
src/special/pvdbcrProcessRecord.dbd
Normal file
1
src/special/pvdbcrProcessRecord.dbd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
registrar("pvdbcrProcessRecord")
|
||||||
123
src/special/pvdbcrRemoveRecord.cpp
Normal file
123
src/special/pvdbcrRemoveRecord.cpp
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2021.04.07
|
||||||
|
*/
|
||||||
|
#include <iocsh.h>
|
||||||
|
#include <pv/standardField.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/alarm.h>
|
||||||
|
#include <pv/pvAlarm.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
|
#include <epicsExport.h>
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/pvdbcrRemoveRecord.h"
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
PvdbcrRemoveRecordPtr PvdbcrRemoveRecord::create(
|
||||||
|
std::string const & recordName,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
{
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||||
|
addNestedStructure("argument")->
|
||||||
|
add("recordName",pvString)->
|
||||||
|
endNested()->
|
||||||
|
addNestedStructure("result") ->
|
||||||
|
add("status",pvString) ->
|
||||||
|
endNested()->
|
||||||
|
createStructure();
|
||||||
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||||
|
PvdbcrRemoveRecordPtr pvRecord(
|
||||||
|
new PvdbcrRemoveRecord(recordName,pvStructure,
|
||||||
|
asLevel,asGroup));
|
||||||
|
if(!pvRecord->init()) pvRecord.reset();
|
||||||
|
return pvRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
PvdbcrRemoveRecord::PvdbcrRemoveRecord(
|
||||||
|
std::string const & recordName,
|
||||||
|
epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
: PVRecord(recordName,pvStructure,asLevel,asGroup)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PvdbcrRemoveRecord::init()
|
||||||
|
{
|
||||||
|
initPVRecord();
|
||||||
|
PVStructurePtr pvStructure = getPVStructure();
|
||||||
|
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
|
||||||
|
if(!pvRecordName) return false;
|
||||||
|
pvResult = pvStructure->getSubField<PVString>("result.status");
|
||||||
|
if(!pvResult) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PvdbcrRemoveRecord::process()
|
||||||
|
{
|
||||||
|
string name = pvRecordName->get();
|
||||||
|
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
|
||||||
|
if(!pvRecord) {
|
||||||
|
pvResult->put(name + " not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pvRecord->remove();
|
||||||
|
pvResult->put("success");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
static const iocshArg arg0 = { "recordName", iocshArgString };
|
||||||
|
static const iocshArg arg1 = { "asLevel", iocshArgInt };
|
||||||
|
static const iocshArg arg2 = { "asGroup", iocshArgString };
|
||||||
|
static const iocshArg *args[] = {&arg0,&arg1,&arg2};
|
||||||
|
|
||||||
|
static const iocshFuncDef pvdbcrRemoveRecordFuncDef = {"pvdbcrRemoveRecord", 3,args};
|
||||||
|
|
||||||
|
static void pvdbcrRemoveRecordCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
char *sval = args[0].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrRemoveRecord recordName not specified");
|
||||||
|
}
|
||||||
|
string recordName = string(sval);
|
||||||
|
int asLevel = args[1].ival;
|
||||||
|
string asGroup("DEFAULT");
|
||||||
|
sval = args[2].sval;
|
||||||
|
if(sval) {
|
||||||
|
asGroup = string(sval);
|
||||||
|
}
|
||||||
|
epics::pvDatabase::PvdbcrRemoveRecordPtr record = epics::pvDatabase::PvdbcrRemoveRecord::create(recordName);
|
||||||
|
record->setAsLevel(asLevel);
|
||||||
|
record->setAsGroup(asGroup);
|
||||||
|
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
|
||||||
|
bool result = master->addRecord(record);
|
||||||
|
if(!result) cout << "recordname " << recordName << " not added" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pvdbcrRemoveRecord(void)
|
||||||
|
{
|
||||||
|
static int firstTime = 1;
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = 0;
|
||||||
|
iocshRegister(&pvdbcrRemoveRecordFuncDef, pvdbcrRemoveRecordCallFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
epicsExportRegistrar(pvdbcrRemoveRecord);
|
||||||
|
}
|
||||||
1
src/special/pvdbcrRemoveRecord.dbd
Normal file
1
src/special/pvdbcrRemoveRecord.dbd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
registrar("pvdbcrRemoveRecord")
|
||||||
103
src/special/pvdbcrScalarArrayRecord.cpp
Normal file
103
src/special/pvdbcrScalarArrayRecord.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2021.04.07
|
||||||
|
*/
|
||||||
|
#include <iocsh.h>
|
||||||
|
#include <pv/standardField.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/alarm.h>
|
||||||
|
#include <pv/pvAlarm.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
|
// The following must be the last include for code pvDatabase implements
|
||||||
|
#include <epicsExport.h>
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/pvdbcrScalarArrayRecord.h"
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
PvdbcrScalarArrayRecord::PvdbcrScalarArrayRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
: PVRecord(recordName,pvStructure,asLevel,asGroup)
|
||||||
|
{}
|
||||||
|
|
||||||
|
PvdbcrScalarArrayRecordPtr PvdbcrScalarArrayRecord::create(
|
||||||
|
std::string const & recordName,std::string const & scalarType,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
{
|
||||||
|
ScalarType st = epics::pvData::ScalarTypeFunc::getScalarType(scalarType);
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
StandardFieldPtr standardField = getStandardField();
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
StructureConstPtr top = fieldCreate->createFieldBuilder()->
|
||||||
|
addArray("value",st) ->
|
||||||
|
add("timeStamp",standardField->timeStamp()) ->
|
||||||
|
add("alarm",standardField->alarm()) ->
|
||||||
|
createStructure();
|
||||||
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
|
||||||
|
PvdbcrScalarArrayRecordPtr pvRecord(new PvdbcrScalarArrayRecord(recordName,pvStructure,asLevel,asGroup));
|
||||||
|
pvRecord->initPVRecord();
|
||||||
|
return pvRecord;
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
|
||||||
|
static const iocshArg arg0 = { "recordName", iocshArgString };
|
||||||
|
static const iocshArg arg1 = { "scalarType", iocshArgString };
|
||||||
|
static const iocshArg arg2 = { "asLevel", iocshArgInt };
|
||||||
|
static const iocshArg arg3 = { "asGroup", iocshArgString };
|
||||||
|
static const iocshArg *args[] = {&arg0,&arg1,&arg2,&arg3};
|
||||||
|
|
||||||
|
static const iocshFuncDef pvdbcrScalarArrayFuncDef = {"pvdbcrScalarArrayRecord", 4,args};
|
||||||
|
|
||||||
|
static void pvdbcrScalarArrayCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
char *sval = args[0].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrScalarArrayRecord recordName not specified");
|
||||||
|
}
|
||||||
|
string recordName = string(sval);
|
||||||
|
sval = args[1].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrScalarArrayRecord scalarType not specified");
|
||||||
|
}
|
||||||
|
string scalarType = string(sval);
|
||||||
|
int asLevel = args[2].ival;
|
||||||
|
string asGroup("DEFAULT");
|
||||||
|
sval = args[3].sval;
|
||||||
|
if(sval) {
|
||||||
|
asGroup = string(sval);
|
||||||
|
}
|
||||||
|
epics::pvDatabase::PvdbcrScalarArrayRecordPtr record
|
||||||
|
= epics::pvDatabase::PvdbcrScalarArrayRecord::create(recordName,scalarType);
|
||||||
|
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
|
||||||
|
record->setAsLevel(asLevel);
|
||||||
|
record->setAsGroup(asGroup);
|
||||||
|
bool result = master->addRecord(record);
|
||||||
|
if(!result) cout << "recordname " << recordName << " not added" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pvdbcrScalarArrayRecord(void)
|
||||||
|
{
|
||||||
|
static int firstTime = 1;
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = 0;
|
||||||
|
iocshRegister(&pvdbcrScalarArrayFuncDef, pvdbcrScalarArrayCallFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
epicsExportRegistrar(pvdbcrScalarArrayRecord);
|
||||||
|
}
|
||||||
1
src/special/pvdbcrScalarArrayRecord.dbd
Normal file
1
src/special/pvdbcrScalarArrayRecord.dbd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
registrar("pvdbcrScalarArrayRecord")
|
||||||
103
src/special/pvdbcrScalarRecord.cpp
Normal file
103
src/special/pvdbcrScalarRecord.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2021.04.07
|
||||||
|
*/
|
||||||
|
#include <iocsh.h>
|
||||||
|
#include <pv/standardField.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/alarm.h>
|
||||||
|
#include <pv/pvAlarm.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
|
// The following must be the last include for code pvDatabase implements
|
||||||
|
#include <epicsExport.h>
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/pvdbcrScalarRecord.h"
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
PvdbcrScalarRecord::PvdbcrScalarRecord(
|
||||||
|
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
: PVRecord(recordName,pvStructure,asLevel,asGroup)
|
||||||
|
{}
|
||||||
|
|
||||||
|
PvdbcrScalarRecordPtr PvdbcrScalarRecord::create(
|
||||||
|
std::string const & recordName,std::string const & scalarType,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
{
|
||||||
|
ScalarType st = epics::pvData::ScalarTypeFunc::getScalarType(scalarType);
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
StandardFieldPtr standardField = getStandardField();
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
StructureConstPtr top = fieldCreate->createFieldBuilder()->
|
||||||
|
add("value",st) ->
|
||||||
|
add("timeStamp",standardField->timeStamp()) ->
|
||||||
|
add("alarm",standardField->alarm()) ->
|
||||||
|
createStructure();
|
||||||
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
|
||||||
|
PvdbcrScalarRecordPtr pvRecord(new PvdbcrScalarRecord(recordName,pvStructure,asLevel,asGroup));
|
||||||
|
pvRecord->initPVRecord();
|
||||||
|
return pvRecord;
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
|
||||||
|
static const iocshArg arg0 = { "recordName", iocshArgString };
|
||||||
|
static const iocshArg arg1 = { "scalarType", iocshArgString };
|
||||||
|
static const iocshArg arg2 = { "asLevel", iocshArgInt };
|
||||||
|
static const iocshArg arg3 = { "asGroup", iocshArgString };
|
||||||
|
static const iocshArg *args[] = {&arg0,&arg1,&arg2,&arg3};
|
||||||
|
|
||||||
|
static const iocshFuncDef pvdbcrScalarFuncDef = {"pvdbcrScalarRecord", 4,args};
|
||||||
|
|
||||||
|
static void pvdbcrScalarCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
char *sval = args[0].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrScalarRecord recordName not specified");
|
||||||
|
}
|
||||||
|
string recordName = string(sval);
|
||||||
|
sval = args[1].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrScalarRecord scalarType not specified");
|
||||||
|
}
|
||||||
|
string scalarType = string(sval);
|
||||||
|
int asLevel = args[2].ival;
|
||||||
|
string asGroup("DEFAULT");
|
||||||
|
sval = args[3].sval;
|
||||||
|
if(sval) {
|
||||||
|
asGroup = string(sval);
|
||||||
|
}
|
||||||
|
epics::pvDatabase::PvdbcrScalarRecordPtr record
|
||||||
|
= epics::pvDatabase::PvdbcrScalarRecord::create(recordName,scalarType);
|
||||||
|
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
|
||||||
|
record->setAsLevel(asLevel);
|
||||||
|
record->setAsGroup(asGroup);
|
||||||
|
bool result = master->addRecord(record);
|
||||||
|
if(!result) cout << "recordname " << recordName << " not added" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pvdbcrScalarRecord(void)
|
||||||
|
{
|
||||||
|
static int firstTime = 1;
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = 0;
|
||||||
|
iocshRegister(&pvdbcrScalarFuncDef, pvdbcrScalarCallFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
epicsExportRegistrar(pvdbcrScalarRecord);
|
||||||
|
}
|
||||||
1
src/special/pvdbcrScalarRecord.dbd
Normal file
1
src/special/pvdbcrScalarRecord.dbd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
registrar("pvdbcrScalarRecord")
|
||||||
128
src/special/pvdbcrTraceRecord.cpp
Normal file
128
src/special/pvdbcrTraceRecord.cpp
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2021.04.07
|
||||||
|
*/
|
||||||
|
#include <iocsh.h>
|
||||||
|
#include <pv/standardField.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
#include <pv/timeStamp.h>
|
||||||
|
#include <pv/pvTimeStamp.h>
|
||||||
|
#include <pv/alarm.h>
|
||||||
|
#include <pv/pvAlarm.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/rpcService.h>
|
||||||
|
|
||||||
|
// The following must be the last include
|
||||||
|
#include <epicsExport.h>
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pv/pvDatabase.h"
|
||||||
|
#include "pv/pvdbcrTraceRecord.h"
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
PvdbcrTraceRecordPtr PvdbcrTraceRecord::create(
|
||||||
|
std::string const & recordName,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
{
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||||
|
addNestedStructure("argument")->
|
||||||
|
add("recordName",pvString)->
|
||||||
|
add("level",pvInt)->
|
||||||
|
endNested()->
|
||||||
|
addNestedStructure("result") ->
|
||||||
|
add("status",pvString) ->
|
||||||
|
endNested()->
|
||||||
|
createStructure();
|
||||||
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||||
|
PvdbcrTraceRecordPtr pvRecord(
|
||||||
|
new PvdbcrTraceRecord(recordName,pvStructure,asLevel,asGroup));
|
||||||
|
if(!pvRecord->init()) pvRecord.reset();
|
||||||
|
return pvRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
PvdbcrTraceRecord::PvdbcrTraceRecord(
|
||||||
|
std::string const & recordName,
|
||||||
|
epics::pvData::PVStructurePtr const & pvStructure,
|
||||||
|
int asLevel,std::string const & asGroup)
|
||||||
|
: PVRecord(recordName,pvStructure,asLevel,asGroup)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PvdbcrTraceRecord::init()
|
||||||
|
{
|
||||||
|
initPVRecord();
|
||||||
|
PVStructurePtr pvStructure = getPVStructure();
|
||||||
|
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
|
||||||
|
if(!pvRecordName) return false;
|
||||||
|
pvLevel = pvStructure->getSubField<PVInt>("argument.level");
|
||||||
|
if(!pvLevel) return false;
|
||||||
|
pvResult = pvStructure->getSubField<PVString>("result.status");
|
||||||
|
if(!pvResult) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PvdbcrTraceRecord::process()
|
||||||
|
{
|
||||||
|
string name = pvRecordName->get();
|
||||||
|
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
|
||||||
|
if(!pvRecord) {
|
||||||
|
pvResult->put(name + " not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pvRecord->setTraceLevel(pvLevel->get());
|
||||||
|
pvResult->put("success");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
static const iocshArg arg0 = { "recordName", iocshArgString };
|
||||||
|
static const iocshArg arg1 = { "asLevel", iocshArgInt };
|
||||||
|
static const iocshArg arg2 = { "asGroup", iocshArgString };
|
||||||
|
static const iocshArg *args[] = {&arg0,&arg1,&arg2};
|
||||||
|
|
||||||
|
static const iocshFuncDef pvdbcrTraceRecordFuncDef = {"pvdbcrTraceRecord", 3,args};
|
||||||
|
|
||||||
|
static void pvdbcrTraceRecordCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
char *sval = args[0].sval;
|
||||||
|
if(!sval) {
|
||||||
|
throw std::runtime_error("pvdbcrTraceRecord recordName not specified");
|
||||||
|
}
|
||||||
|
string recordName = string(sval);
|
||||||
|
int asLevel = args[1].ival;
|
||||||
|
string asGroup("DEFAULT");
|
||||||
|
sval = args[2].sval;
|
||||||
|
if(sval) {
|
||||||
|
asGroup = string(sval);
|
||||||
|
}
|
||||||
|
epics::pvDatabase::PvdbcrTraceRecordPtr record
|
||||||
|
= epics::pvDatabase::PvdbcrTraceRecord::create(recordName);
|
||||||
|
record->setAsLevel(asLevel);
|
||||||
|
record->setAsGroup(asGroup);
|
||||||
|
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
|
||||||
|
bool result = master->addRecord(record);
|
||||||
|
if(!result) cout << "recordname " << recordName << " not added" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pvdbcrTraceRecord(void)
|
||||||
|
{
|
||||||
|
static int firstTime = 1;
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = 0;
|
||||||
|
iocshRegister(&pvdbcrTraceRecordFuncDef, pvdbcrTraceRecordCallFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
epicsExportRegistrar(pvdbcrTraceRecord);
|
||||||
|
}
|
||||||
1
src/special/pvdbcrTraceRecord.dbd
Normal file
1
src/special/pvdbcrTraceRecord.dbd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
registrar("pvdbcrTraceRecord")
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/* removeRecord.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
|
|
||||||
*/
|
|
||||||
#define epicsExportSharedSymbols
|
|
||||||
|
|
||||||
#include <pv/removeRecord.h>
|
|
||||||
|
|
||||||
using std::tr1::static_pointer_cast;
|
|
||||||
using namespace epics::pvData;
|
|
||||||
using namespace epics::pvAccess;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
|
||||||
|
|
||||||
RemoveRecordPtr RemoveRecord::create(
|
|
||||||
std::string const & recordName)
|
|
||||||
{
|
|
||||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
|
||||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
|
||||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
|
||||||
addNestedStructure("argument")->
|
|
||||||
add("recordName",pvString)->
|
|
||||||
endNested()->
|
|
||||||
addNestedStructure("result") ->
|
|
||||||
add("status",pvString) ->
|
|
||||||
endNested()->
|
|
||||||
createStructure();
|
|
||||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
|
||||||
RemoveRecordPtr pvRecord(
|
|
||||||
new RemoveRecord(recordName,pvStructure));
|
|
||||||
if(!pvRecord->init()) pvRecord.reset();
|
|
||||||
return pvRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveRecord::RemoveRecord(
|
|
||||||
std::string const & recordName,
|
|
||||||
epics::pvData::PVStructurePtr const & pvStructure)
|
|
||||||
: PVRecord(recordName,pvStructure)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RemoveRecord::init()
|
|
||||||
{
|
|
||||||
initPVRecord();
|
|
||||||
PVStructurePtr pvStructure = getPVStructure();
|
|
||||||
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
|
|
||||||
if(!pvRecordName) return false;
|
|
||||||
pvResult = pvStructure->getSubField<PVString>("result.status");
|
|
||||||
if(!pvResult) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveRecord::process()
|
|
||||||
{
|
|
||||||
string name = pvRecordName->get();
|
|
||||||
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
|
|
||||||
if(!pvRecord) {
|
|
||||||
pvResult->put(name + " not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pvRecord->destroy();
|
|
||||||
pvResult->put("success");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}}
|
|
||||||
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
/* traceRecord.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
|
|
||||||
*/
|
|
||||||
#define epicsExportSharedSymbols
|
|
||||||
|
|
||||||
#include <pv/traceRecord.h>
|
|
||||||
|
|
||||||
using std::tr1::static_pointer_cast;
|
|
||||||
using namespace epics::pvData;
|
|
||||||
using namespace epics::pvAccess;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
|
||||||
|
|
||||||
TraceRecordPtr TraceRecord::create(
|
|
||||||
std::string const & recordName)
|
|
||||||
{
|
|
||||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
|
||||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
|
||||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
|
||||||
addNestedStructure("argument")->
|
|
||||||
add("recordName",pvString)->
|
|
||||||
add("level",pvInt)->
|
|
||||||
endNested()->
|
|
||||||
addNestedStructure("result") ->
|
|
||||||
add("status",pvString) ->
|
|
||||||
endNested()->
|
|
||||||
createStructure();
|
|
||||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
|
||||||
TraceRecordPtr pvRecord(
|
|
||||||
new TraceRecord(recordName,pvStructure));
|
|
||||||
if(!pvRecord->init()) pvRecord.reset();
|
|
||||||
return pvRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
TraceRecord::TraceRecord(
|
|
||||||
std::string const & recordName,
|
|
||||||
epics::pvData::PVStructurePtr const & pvStructure)
|
|
||||||
: PVRecord(recordName,pvStructure)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool TraceRecord::init()
|
|
||||||
{
|
|
||||||
initPVRecord();
|
|
||||||
PVStructurePtr pvStructure = getPVStructure();
|
|
||||||
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
|
|
||||||
if(!pvRecordName) return false;
|
|
||||||
pvLevel = pvStructure->getSubField<PVInt>("argument.level");
|
|
||||||
if(!pvLevel) return false;
|
|
||||||
pvResult = pvStructure->getSubField<PVString>("result.status");
|
|
||||||
if(!pvResult) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TraceRecord::process()
|
|
||||||
{
|
|
||||||
string name = pvRecordName->get();
|
|
||||||
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
|
|
||||||
if(!pvRecord) {
|
|
||||||
pvResult->put(name + " not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pvRecord->setTraceLevel(pvLevel->get());
|
|
||||||
pvResult->put("success");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}}
|
|
||||||
|
|
||||||
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)
|
||||||
|
{
|
||||||
|
cerr << "ControlSupport IS DEPRECATED\n";
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
cerr << "ScalarAlarmSupport IS DEPRECATED\n";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
@@ -33,3 +33,8 @@ TESTPROD_HOST += testPVAServer
|
|||||||
testPVAServer_SRCS += testPVAServer.cpp
|
testPVAServer_SRCS += testPVAServer.cpp
|
||||||
testHarness_SRCS += testPVAServer.cpp
|
testHarness_SRCS += testPVAServer.cpp
|
||||||
TESTS += testPVAServer
|
TESTS += testPVAServer
|
||||||
|
|
||||||
|
TESTPROD_HOST += testChannelMonitor
|
||||||
|
testChannelMonitor_SRCS += testChannelMonitor.cpp
|
||||||
|
testHarness_SRCS += testChannelMonitor.cpp
|
||||||
|
TESTS += testChannelMonitor
|
||||||
|
|||||||
@@ -26,14 +26,14 @@
|
|||||||
|
|
||||||
#ifdef listenerEpicsExportSharedSymbols
|
#ifdef listenerEpicsExportSharedSymbols
|
||||||
# define epicsExportSharedSymbols
|
# define epicsExportSharedSymbols
|
||||||
# undef listenerEpicsExportSharedSymbols
|
# undef listenerEpicsExportSharedSymbols
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <shareLib.h>
|
#include <shareLib.h>
|
||||||
|
|
||||||
//epicsShareFunc epics::pvData::PVStructurePtr createListener();
|
//epicsShareFunc epics::pvData::PVStructurePtr createListener();
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField)
|
virtual void dataPut(PVRecordFieldPtr const & pvRecordField)
|
||||||
{
|
{
|
||||||
cout << "Listener::dataPut record " << recordName
|
cout << "Listener::dataPut record " << recordName
|
||||||
<< " pvRecordField " << pvRecordField->getPVField()->getFullName()
|
<< " pvRecordField " << pvRecordField->getPVField()->getFullName()
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
PVRecordStructurePtr const & requested,
|
PVRecordStructurePtr const & requested,
|
||||||
PVRecordFieldPtr const & pvRecordField)
|
PVRecordFieldPtr const & pvRecordField)
|
||||||
{
|
{
|
||||||
cout << "Listener::dataPut record " << recordName
|
cout << "Listener::dataPut record " << recordName
|
||||||
<< " requested " << requested->getPVStructure()->getFullName()
|
<< " requested " << requested->getPVStructure()->getFullName()
|
||||||
<< " pvRecordField " << pvRecordField->getPVField()->getFullName()
|
<< " pvRecordField " << pvRecordField->getPVField()->getFullName()
|
||||||
<< endl;
|
<< endl;
|
||||||
@@ -84,7 +84,7 @@ public:
|
|||||||
{
|
{
|
||||||
cout << "Listener::unlisten record " << recordName << endl;
|
cout << "Listener::unlisten record " << recordName << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Listener(PVRecordPtr const & pvRecord)
|
Listener(PVRecordPtr const & pvRecord)
|
||||||
: pvCopy(
|
: pvCopy(
|
||||||
|
|||||||
@@ -25,14 +25,14 @@
|
|||||||
|
|
||||||
#ifdef powerSupplyEpicsExportSharedSymbols
|
#ifdef powerSupplyEpicsExportSharedSymbols
|
||||||
# define epicsExportSharedSymbols
|
# define epicsExportSharedSymbols
|
||||||
# undef powerSupplyEpicsExportSharedSymbols
|
# undef powerSupplyEpicsExportSharedSymbols
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <shareLib.h>
|
#include <shareLib.h>
|
||||||
|
|
||||||
//epicsShareFunc epics::pvData::PVStructurePtr createPowerSupply();
|
//epicsShareFunc epics::pvData::PVStructurePtr createPowerSupply();
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
class PowerSupply;
|
class PowerSupply;
|
||||||
typedef std::tr1::shared_ptr<PowerSupply> PowerSupplyPtr;
|
typedef std::tr1::shared_ptr<PowerSupply> PowerSupplyPtr;
|
||||||
@@ -46,7 +46,6 @@ public:
|
|||||||
std::string const & recordName,
|
std::string const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
epics::pvData::PVStructurePtr const & pvStructure);
|
||||||
virtual ~PowerSupply();
|
virtual ~PowerSupply();
|
||||||
virtual void destroy();
|
|
||||||
virtual bool init();
|
virtual bool init();
|
||||||
virtual void process();
|
virtual void process();
|
||||||
void put(double power,double voltage);
|
void put(double power,double voltage);
|
||||||
@@ -111,11 +110,6 @@ inline PowerSupply::~PowerSupply()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PowerSupply::destroy()
|
|
||||||
{
|
|
||||||
PVRecord::destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool PowerSupply::init()
|
inline bool PowerSupply::init()
|
||||||
{
|
{
|
||||||
initPVRecord();
|
initPVRecord();
|
||||||
|
|||||||
@@ -25,12 +25,12 @@
|
|||||||
|
|
||||||
#ifdef pvRecordClientEpicsExportSharedSymbols
|
#ifdef pvRecordClientEpicsExportSharedSymbols
|
||||||
# define epicsExportSharedSymbols
|
# define epicsExportSharedSymbols
|
||||||
# undef pvRecordClientEpicsExportSharedSymbols
|
# undef pvRecordClientEpicsExportSharedSymbols
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <shareLib.h>
|
#include <shareLib.h>
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
class RecordClient;
|
class RecordClient;
|
||||||
typedef std::tr1::shared_ptr<RecordClient> RecordClientPtr;
|
typedef std::tr1::shared_ptr<RecordClient> RecordClientPtr;
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
std::cout << "RecordClient::detach record " << pvRecord->getRecordName() << std::endl;
|
std::cout << "RecordClient::detach record " << pvRecord->getRecordName() << std::endl;
|
||||||
this->pvRecord.reset();
|
this->pvRecord.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RecordClient(PVRecordPtr const & pvRecord)
|
RecordClient(PVRecordPtr const & pvRecord)
|
||||||
: pvRecord(pvRecord)
|
: pvRecord(pvRecord)
|
||||||
|
|||||||
312
test/src/testChannelMonitor.cpp
Normal file
312
test/src/testChannelMonitor.cpp
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
/* testChannelMonitor.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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/pvData.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/channelProviderLocal.h>
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/event.h>
|
||||||
|
#include <pv/clientFactory.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using std::tr1::static_pointer_cast;
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace epics::pvAccess;
|
||||||
|
using namespace epics::pvDatabase;
|
||||||
|
namespace TR1 = std::tr1;
|
||||||
|
|
||||||
|
static bool debug = true;
|
||||||
|
|
||||||
|
PVStructurePtr createTestPvStructure()
|
||||||
|
{
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
StandardFieldPtr standardField = getStandardField()
|
||||||
|
;
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
|
||||||
|
return pvDataCreate->createPVStructure(
|
||||||
|
fieldCreate->createFieldBuilder()->
|
||||||
|
add("id",pvInt) ->
|
||||||
|
add("x",pvInt) ->
|
||||||
|
add("y",pvInt) ->
|
||||||
|
add("z",pvInt) ->
|
||||||
|
add("alarm",standardField->alarm()) ->
|
||||||
|
add("timeStamp",standardField->timeStamp()) ->
|
||||||
|
createStructure());
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChannelMonitorRequesterImpl : public MonitorRequester
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ChannelMonitorRequesterImpl(const std::string& channelName_)
|
||||||
|
: channelName(channelName_)
|
||||||
|
, lastReceivedPvStructure(createTestPvStructure())
|
||||||
|
, lastReceivedBitSet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual string getRequesterName()
|
||||||
|
{
|
||||||
|
return "ChannelMonitorRequesterImpl";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void message(const std::string& message, MessageType messageType)
|
||||||
|
{
|
||||||
|
cout << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void monitorConnect(const epics::pvData::Status& status, const Monitor::shared_pointer& /*monitor*/, const Structure::const_shared_pointer& /*structure*/)
|
||||||
|
{
|
||||||
|
if (status.isSuccess()) {
|
||||||
|
// show warning
|
||||||
|
if (!status.isOK()) {
|
||||||
|
cout << "[" << channelName << "] channel monitor create: " << status << endl;
|
||||||
|
}
|
||||||
|
connectionEvent.signal();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cout << "[" << channelName << "] failed to create channel monitor: " << status << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void monitorEvent(const Monitor::shared_pointer& monitor)
|
||||||
|
{
|
||||||
|
MonitorElement::shared_pointer element;
|
||||||
|
while ((element = monitor->poll())) {
|
||||||
|
cout << "changed/overrun " << *element->changedBitSet << '/' << *element->overrunBitSet << endl;
|
||||||
|
if (!lastReceivedBitSet) {
|
||||||
|
lastReceivedBitSet = BitSet::create(element->changedBitSet->size());
|
||||||
|
}
|
||||||
|
lastReceivedBitSet->clear();
|
||||||
|
*lastReceivedBitSet |= *element->changedBitSet;
|
||||||
|
lastReceivedPvStructure->copyUnchecked(*element->pvStructurePtr);
|
||||||
|
monitor->release(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void unlisten(const Monitor::shared_pointer& /*monitor*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitUntilConnected(double timeOut)
|
||||||
|
{
|
||||||
|
return connectionEvent.wait(timeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
PVStructurePtr getLastReceivedPvStructure()
|
||||||
|
{
|
||||||
|
return lastReceivedPvStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetPtr getLastReceivedBitSet()
|
||||||
|
{
|
||||||
|
return lastReceivedBitSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Event event;
|
||||||
|
Event connectionEvent;
|
||||||
|
string channelName;
|
||||||
|
PVStructurePtr lastReceivedPvStructure;
|
||||||
|
BitSetPtr lastReceivedBitSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChannelRequesterImpl : public ChannelRequester
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Event event;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual string getRequesterName()
|
||||||
|
{
|
||||||
|
return "ChannelRequesterImpl";
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void message(const std::string& message, MessageType messageType)
|
||||||
|
{
|
||||||
|
cout << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void channelCreated(const Status& status, const Channel::shared_pointer& channel)
|
||||||
|
{
|
||||||
|
if (status.isSuccess()) {
|
||||||
|
// show warning
|
||||||
|
if (!status.isOK()) {
|
||||||
|
cout << "[" << channel->getChannelName() << "] channel create: " << status << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cout << "[" << channel->getChannelName() << "] failed to create a channel: " << status << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void channelStateChange(const Channel::shared_pointer& /*channel*/, Channel::ConnectionState connectionState)
|
||||||
|
{
|
||||||
|
if (connectionState == Channel::CONNECTED) {
|
||||||
|
event.signal();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cout << Channel::ConnectionStateNames[connectionState] << endl;
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitUntilConnected(double timeOut)
|
||||||
|
{
|
||||||
|
return event.wait(timeOut);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void test()
|
||||||
|
{
|
||||||
|
PVDatabasePtr master = PVDatabase::getMaster();
|
||||||
|
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||||
|
string recordName = "positions";
|
||||||
|
PVStructurePtr pvStructure = createTestPvStructure();
|
||||||
|
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
|
||||||
|
master->addRecord(pvRecord);
|
||||||
|
pvRecord = master->findRecord(recordName);
|
||||||
|
{
|
||||||
|
pvRecord->lock();
|
||||||
|
pvRecord->process();
|
||||||
|
pvRecord->unlock();
|
||||||
|
}
|
||||||
|
if(debug) {cout << "processed positions" << endl; }
|
||||||
|
ServerContext::shared_pointer ctx = startPVAServer("local",0,true,true);
|
||||||
|
testOk1(ctx.get() != 0);
|
||||||
|
|
||||||
|
ClientFactory::start();
|
||||||
|
ChannelProvider::shared_pointer provider = ChannelProviderRegistry::clients()->getProvider("pva");
|
||||||
|
|
||||||
|
cout << "creating channel: " << recordName << endl;
|
||||||
|
TR1::shared_ptr<ChannelRequesterImpl> channelRequesterImpl(new ChannelRequesterImpl());
|
||||||
|
|
||||||
|
Channel::shared_pointer channel = provider->createChannel(recordName, channelRequesterImpl);
|
||||||
|
bool channelConnected = channelRequesterImpl->waitUntilConnected(1.0);
|
||||||
|
testOk1(channelConnected);
|
||||||
|
if (channelConnected) {
|
||||||
|
string remoteAddress = channel->getRemoteAddress();
|
||||||
|
cout << "remote address: " << remoteAddress << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
string request = "";
|
||||||
|
PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(request);
|
||||||
|
TR1::shared_ptr<ChannelMonitorRequesterImpl> cmRequesterImpl(new ChannelMonitorRequesterImpl(channel->getChannelName()));
|
||||||
|
Monitor::shared_pointer monitor = channel->createMonitor(cmRequesterImpl, pvRequest);
|
||||||
|
bool monitorConnected = cmRequesterImpl->waitUntilConnected(1.0);
|
||||||
|
testOk1(monitorConnected);
|
||||||
|
Status status = monitor->start();
|
||||||
|
testOk1(status.isOK());
|
||||||
|
epicsThreadSleep(1);
|
||||||
|
|
||||||
|
// Set id, x
|
||||||
|
{
|
||||||
|
pvRecord->beginGroupPut();
|
||||||
|
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||||
|
id->put(1);
|
||||||
|
PVIntPtr x = pvStructure->getSubField<PVInt>("x");
|
||||||
|
x->put(1);
|
||||||
|
pvRecord->endGroupPut();
|
||||||
|
}
|
||||||
|
epicsThreadSleep(1);
|
||||||
|
|
||||||
|
// Changed set for (id,x): 0 unset, 1 set, 2 set, 3 unset, 4 unset
|
||||||
|
BitSetPtr changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||||
|
testOk1(!changedSet->get(0) && changedSet->get(1) && changedSet->get(2) && !changedSet->get(3) && !changedSet->get(4));
|
||||||
|
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||||
|
|
||||||
|
// Set id, y
|
||||||
|
{
|
||||||
|
pvRecord->beginGroupPut();
|
||||||
|
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||||
|
id->put(2);
|
||||||
|
PVIntPtr y = pvStructure->getSubField<PVInt>("y");
|
||||||
|
y->put(2);
|
||||||
|
pvRecord->endGroupPut();
|
||||||
|
}
|
||||||
|
epicsThreadSleep(1);
|
||||||
|
|
||||||
|
// Changed set for (id,y): 0 unset, 1 set, 2 unset, 3 set, 4 unset
|
||||||
|
changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||||
|
testOk1(!changedSet->get(0) && changedSet->get(1) && !changedSet->get(2) && changedSet->get(3) && !changedSet->get(4));
|
||||||
|
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||||
|
|
||||||
|
// Set id, z
|
||||||
|
{
|
||||||
|
pvRecord->beginGroupPut();
|
||||||
|
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||||
|
id->put(3);
|
||||||
|
PVIntPtr z = pvStructure->getSubField<PVInt>("z");
|
||||||
|
z->put(3);
|
||||||
|
pvRecord->endGroupPut();
|
||||||
|
}
|
||||||
|
epicsThreadSleep(1);
|
||||||
|
|
||||||
|
// Changed set for (id,z): 0 unset, 1 set, 2 unset, 3 unset, 4 set
|
||||||
|
changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||||
|
testOk1(!changedSet->get(0) && changedSet->get(1) && !changedSet->get(2) && !changedSet->get(3) && changedSet->get(4));
|
||||||
|
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||||
|
|
||||||
|
status = monitor->stop();
|
||||||
|
testOk1(status.isOK());
|
||||||
|
|
||||||
|
// Test master field
|
||||||
|
request = "field(_)";
|
||||||
|
pvRequest = CreateRequest::create()->createRequest(request);
|
||||||
|
cmRequesterImpl = TR1::shared_ptr<ChannelMonitorRequesterImpl>(new ChannelMonitorRequesterImpl(channel->getChannelName()));
|
||||||
|
monitor = channel->createMonitor(cmRequesterImpl, pvRequest);
|
||||||
|
monitorConnected = cmRequesterImpl->waitUntilConnected(1.0);
|
||||||
|
testOk1(monitorConnected);
|
||||||
|
status = monitor->start();
|
||||||
|
testOk1(status.isOK());
|
||||||
|
epicsThreadSleep(1);
|
||||||
|
{
|
||||||
|
pvRecord->beginGroupPut();
|
||||||
|
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||||
|
id->put(4);
|
||||||
|
PVIntPtr x = pvStructure->getSubField<PVInt>("x");
|
||||||
|
x->put(4);
|
||||||
|
pvRecord->endGroupPut();
|
||||||
|
}
|
||||||
|
epicsThreadSleep(1);
|
||||||
|
// Changed set with master field requested: 0 set
|
||||||
|
changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||||
|
testOk1(changedSet->get(0));
|
||||||
|
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||||
|
|
||||||
|
status = monitor->stop();
|
||||||
|
testOk1(status.isOK());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MAIN(testChannelMonitor)
|
||||||
|
{
|
||||||
|
testPlan(16);
|
||||||
|
test();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -134,4 +134,3 @@ MAIN(testExampleRecord)
|
|||||||
test();
|
test();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,4 +79,3 @@ MAIN(testLocalProvider)
|
|||||||
test();
|
test();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,4 +75,3 @@ MAIN(testPVAServer)
|
|||||||
test();
|
test();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -273,7 +273,35 @@ static void testPVScalarArray(
|
|||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testMasterField(PVRecordPtr const& pvRecord)
|
||||||
|
{
|
||||||
|
CreateRequest::shared_pointer createRequest = CreateRequest::create();
|
||||||
|
PVStructurePtr pvRequest = createRequest->createRequest("field(_)");
|
||||||
|
if(debug) {
|
||||||
|
cout << "pvRequest" << *pvRequest << endl ;
|
||||||
|
}
|
||||||
|
PVStructurePtr pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
|
||||||
|
PVCopyPtr pvCopy = PVCopy::create(pvStructureRecord,pvRequest,"");
|
||||||
|
PVStructurePtr pvMasterField = pvCopy->getPVMaster();
|
||||||
|
if(debug) {
|
||||||
|
cout << "PV structure from record" << endl << *pvStructureRecord << endl;
|
||||||
|
cout << "Master PV structure from copy" << endl << *pvMasterField << endl;
|
||||||
|
cout << "Master PV structure from copy offset " << pvMasterField->getFieldOffset() << endl;
|
||||||
|
}
|
||||||
|
testOk1(pvCopy->isMasterFieldRequested());
|
||||||
|
testOk1(pvMasterField->getNumberFields() == pvStructureRecord->getNumberFields());
|
||||||
|
testOk1(pvMasterField->getFieldOffset() == 0);
|
||||||
|
PVStructurePtr pvStructureCopy = pvCopy->createPVStructure();
|
||||||
|
BitSetPtr bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
|
||||||
|
pvCopy->initCopy(pvStructureCopy, bitSet);
|
||||||
|
if(debug) {
|
||||||
|
cout << "PV structure from copy" << endl << *pvStructureCopy << endl;
|
||||||
|
cout << "PV structure from copy offset " << pvStructureCopy->getFieldOffset() << endl;
|
||||||
|
}
|
||||||
|
testOk1(pvMasterField->getNumberFields() == pvStructureCopy->getNumberFields());
|
||||||
|
}
|
||||||
|
|
||||||
static void scalarTest()
|
static void scalarTest()
|
||||||
{
|
{
|
||||||
if(debug) {cout << endl << endl << "****scalarTest****" << endl;}
|
if(debug) {cout << endl << endl << "****scalarTest****" << endl;}
|
||||||
@@ -393,12 +421,21 @@ static void powerSupplyTest()
|
|||||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void masterFieldTest()
|
||||||
|
{
|
||||||
|
if(debug) {
|
||||||
|
cout << endl << endl << "****masterFieldTest****" << endl;
|
||||||
|
}
|
||||||
|
PVRecordPtr pvRecord = createScalar("doubleRecord",pvDouble,"alarm,timeStamp,display");
|
||||||
|
testMasterField(pvRecord);
|
||||||
|
}
|
||||||
|
|
||||||
MAIN(testPVCopy)
|
MAIN(testPVCopy)
|
||||||
{
|
{
|
||||||
testPlan(67);
|
testPlan(71);
|
||||||
scalarTest();
|
scalarTest();
|
||||||
arrayTest();
|
arrayTest();
|
||||||
powerSupplyTest();
|
powerSupplyTest();
|
||||||
|
masterFieldTest();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,4 +103,3 @@ MAIN(testPVRecord)
|
|||||||
powerSupplyTest();
|
powerSupplyTest();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ static void arrayTest()
|
|||||||
uint32 nset = 0;
|
uint32 nset = 0;
|
||||||
size_t n = 10;
|
size_t n = 10;
|
||||||
shared_vector<double> values(n);
|
shared_vector<double> values(n);
|
||||||
|
|
||||||
PVStructurePtr pvRecordStructure(getStandardPVField()->scalarArray(pvDouble,""));
|
PVStructurePtr pvRecordStructure(getStandardPVField()->scalarArray(pvDouble,""));
|
||||||
PVRecordPtr pvRecord(PVRecord::create("doubleArrayRecord",pvRecordStructure));
|
PVRecordPtr pvRecord(PVRecord::create("doubleArrayRecord",pvRecordStructure));
|
||||||
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
|
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
|
||||||
@@ -145,6 +145,73 @@ static void arrayTest()
|
|||||||
testOk1(nset==1);
|
testOk1(nset==1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unionArrayTest()
|
||||||
|
{
|
||||||
|
if(debug) {cout << endl << endl << "****unionArrayTest****" << endl;}
|
||||||
|
bool result = false;
|
||||||
|
uint32 nset = 0;
|
||||||
|
size_t n = 10;
|
||||||
|
shared_vector<double> values(n);
|
||||||
|
for(size_t i=0; i<n; i++) values[i] = i + .06;
|
||||||
|
PVDoubleArrayPtr pvDoubleArray =
|
||||||
|
static_pointer_cast<PVDoubleArray>(PVDataCreate::getPVDataCreate()->createPVScalarArray(pvDouble));
|
||||||
|
const shared_vector<const double> yyy(freeze(values));
|
||||||
|
pvDoubleArray->putFrom(yyy);
|
||||||
|
|
||||||
|
StandardFieldPtr standardField = getStandardField();
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
StructureConstPtr top = fieldCreate->createFieldBuilder()->
|
||||||
|
add("value",fieldCreate->createVariantUnion()) ->
|
||||||
|
add("timeStamp", standardField->timeStamp()) ->
|
||||||
|
addNestedStructure("subfield") ->
|
||||||
|
add("value",fieldCreate->createVariantUnion()) ->
|
||||||
|
endNested()->
|
||||||
|
createStructure();
|
||||||
|
PVStructurePtr pvRecordStructure(PVDataCreate::getPVDataCreate()->createPVStructure(top));
|
||||||
|
PVRecordPtr pvRecord(PVRecord::create("unionArrayRecord",pvRecordStructure));
|
||||||
|
PVUnionPtr pvUnion = pvRecord->getPVStructure()->getSubField<PVUnion>("value");
|
||||||
|
pvUnion->set(pvDoubleArray);
|
||||||
|
pvUnion = pvRecord->getPVStructure()->getSubField<PVUnion>("subfield.value");
|
||||||
|
pvUnion->set(pvDoubleArray);
|
||||||
|
if(debug) { cout << "initial\n" << pvRecordStructure << "\n";}
|
||||||
|
|
||||||
|
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
|
||||||
|
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||||
|
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
|
||||||
|
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
|
||||||
|
PVDoubleArrayPtr pvValue(pvRecordStructure->getSubField<PVDoubleArray>("value"));
|
||||||
|
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||||
|
nset = bitSet->cardinality();
|
||||||
|
if(debug) {
|
||||||
|
cout << "after get value"
|
||||||
|
<< " result " << (result ? "true" : "false")
|
||||||
|
<< " nset " << nset
|
||||||
|
<< " bitSet " << *bitSet
|
||||||
|
<< " pvStructureCopy\n" << pvStructureCopy
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nset==1);
|
||||||
|
|
||||||
|
pvRequest = CreateRequest::create()->createRequest("subfield.value[array=1:3]");
|
||||||
|
pvCopy = PVCopy::create(pvRecordStructure,pvRequest,"");
|
||||||
|
pvStructureCopy = pvCopy->createPVStructure();
|
||||||
|
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
|
||||||
|
pvValue = pvRecordStructure->getSubField<PVDoubleArray>("subfield.value");
|
||||||
|
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||||
|
nset = bitSet->cardinality();
|
||||||
|
if(debug) {
|
||||||
|
cout << "after get subfield.value"
|
||||||
|
<< " result " << (result ? "true" : "false")
|
||||||
|
<< " nset " << nset
|
||||||
|
<< " bitSet " << *bitSet
|
||||||
|
<< " pvStructureCopy\n" << pvStructureCopy
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nset==1);
|
||||||
|
}
|
||||||
|
|
||||||
static void timeStampTest()
|
static void timeStampTest()
|
||||||
{
|
{
|
||||||
if(debug) {cout << endl << endl << "****timeStampTest****" << endl;}
|
if(debug) {cout << endl << endl << "****timeStampTest****" << endl;}
|
||||||
@@ -265,14 +332,128 @@ static void ignoreTest()
|
|||||||
testOk1(nset==3);
|
testOk1(nset==3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void debugOutput(const string& what, bool result, uint32 nSet, BitSetPtr bitSet, PVStructurePtr pvStructureCopy)
|
||||||
|
{
|
||||||
|
if(debug) {
|
||||||
|
cout << what
|
||||||
|
<< " result " << (result ? "true" : "false")
|
||||||
|
<< " nSet " << nSet
|
||||||
|
<< " bitSet " << *bitSet
|
||||||
|
<< "\n pvStructureCopy\n" << pvStructureCopy
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dataDistributorTest()
|
||||||
|
{
|
||||||
|
if(debug) {cout << endl << endl << "****dataDistributorTest****" << endl;}
|
||||||
|
bool result = false;
|
||||||
|
uint32 nSet = 0;
|
||||||
|
|
||||||
|
// Create test structure
|
||||||
|
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvInt,""));
|
||||||
|
PVIntPtr pvValue(pvRecordStructure->getSubField<PVInt>("value"));
|
||||||
|
PVRecordPtr pvRecord(PVRecord::create("intRecord",pvRecordStructure));
|
||||||
|
if(debug) {
|
||||||
|
cout << " pvRecordStructure\n" << pvRecordStructure
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request distributor plugin with trigger field value
|
||||||
|
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("_[distributor=trigger:value]"));
|
||||||
|
|
||||||
|
// Create clients
|
||||||
|
PVCopyPtr pvCopy1(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||||
|
PVStructurePtr pvStructureCopy1(pvCopy1->createPVStructure());
|
||||||
|
BitSetPtr bitSet1(new BitSet(pvStructureCopy1->getNumberFields()));
|
||||||
|
|
||||||
|
PVCopyPtr pvCopy2(PVCopy::create(pvRecordStructure,pvRequest,""));
|
||||||
|
PVStructurePtr pvStructureCopy2(pvCopy2->createPVStructure());
|
||||||
|
BitSetPtr bitSet2(new BitSet(pvStructureCopy2->getNumberFields()));
|
||||||
|
|
||||||
|
// Update 0: both clients get it
|
||||||
|
result = pvCopy1->updateCopySetBitSet(pvStructureCopy1,bitSet1);
|
||||||
|
nSet = bitSet1->cardinality();
|
||||||
|
debugOutput("client 1: update 0", result, nSet, bitSet1, pvStructureCopy1);
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nSet==1);
|
||||||
|
|
||||||
|
result = pvCopy2->updateCopySetBitSet(pvStructureCopy2,bitSet2);
|
||||||
|
nSet = bitSet2->cardinality();
|
||||||
|
debugOutput("client 2: update 0", result, nSet, bitSet2, pvStructureCopy2);
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nSet==1);
|
||||||
|
|
||||||
|
// Update 1: only client 1 gets it
|
||||||
|
pvValue->put(1);
|
||||||
|
|
||||||
|
result = pvCopy1->updateCopySetBitSet(pvStructureCopy1,bitSet1);
|
||||||
|
nSet = bitSet1->cardinality();
|
||||||
|
debugOutput("client 1: update 1", result, nSet, bitSet1, pvStructureCopy1);
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nSet==1);
|
||||||
|
|
||||||
|
result = pvCopy2->updateCopySetBitSet(pvStructureCopy2,bitSet2);
|
||||||
|
nSet = bitSet2->cardinality();
|
||||||
|
debugOutput("client 2: update 1", result, nSet, bitSet2, pvStructureCopy2);
|
||||||
|
testOk1(result==false);
|
||||||
|
testOk1(nSet==0);
|
||||||
|
|
||||||
|
// Update 2: only client 2 gets it
|
||||||
|
pvValue->put(2);
|
||||||
|
|
||||||
|
result = pvCopy1->updateCopySetBitSet(pvStructureCopy1,bitSet1);
|
||||||
|
nSet = bitSet1->cardinality();
|
||||||
|
debugOutput("client 1: update 2", result, nSet, bitSet1, pvStructureCopy1);
|
||||||
|
testOk1(result==false);
|
||||||
|
testOk1(nSet==0);
|
||||||
|
|
||||||
|
result = pvCopy2->updateCopySetBitSet(pvStructureCopy2,bitSet2);
|
||||||
|
nSet = bitSet2->cardinality();
|
||||||
|
debugOutput("client 2: update 2", result, nSet, bitSet2, pvStructureCopy2);
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nSet==1);
|
||||||
|
|
||||||
|
// Update 3: only client 1 gets it
|
||||||
|
pvValue->put(3);
|
||||||
|
|
||||||
|
result = pvCopy1->updateCopySetBitSet(pvStructureCopy1,bitSet1);
|
||||||
|
nSet = bitSet1->cardinality();
|
||||||
|
debugOutput("client 1: update 3", result, nSet, bitSet1, pvStructureCopy1);
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nSet==1);
|
||||||
|
|
||||||
|
result = pvCopy2->updateCopySetBitSet(pvStructureCopy2,bitSet2);
|
||||||
|
nSet = bitSet2->cardinality();
|
||||||
|
debugOutput("client 2: update 3", result, nSet, bitSet2, pvStructureCopy2);
|
||||||
|
testOk1(result==false);
|
||||||
|
testOk1(nSet==0);
|
||||||
|
|
||||||
|
// Update 4: only client 2 gets it
|
||||||
|
pvValue->put(4);
|
||||||
|
|
||||||
|
result = pvCopy1->updateCopySetBitSet(pvStructureCopy1,bitSet1);
|
||||||
|
nSet = bitSet1->cardinality();
|
||||||
|
debugOutput("client 1: update 4", result, nSet, bitSet1, pvStructureCopy1);
|
||||||
|
testOk1(result==false);
|
||||||
|
testOk1(nSet==0);
|
||||||
|
|
||||||
|
result = pvCopy2->updateCopySetBitSet(pvStructureCopy2,bitSet2);
|
||||||
|
nSet = bitSet2->cardinality();
|
||||||
|
debugOutput("client 2: update 4", result, nSet, bitSet2, pvStructureCopy2);
|
||||||
|
testOk1(result==true);
|
||||||
|
testOk1(nSet==1);
|
||||||
|
}
|
||||||
|
|
||||||
MAIN(testPlugin)
|
MAIN(testPlugin)
|
||||||
{
|
{
|
||||||
testPlan(22);
|
testPlan(46);
|
||||||
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
|
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
|
||||||
deadbandTest();
|
deadbandTest();
|
||||||
arrayTest();
|
arrayTest();
|
||||||
|
unionArrayTest();
|
||||||
timeStampTest();
|
timeStampTest();
|
||||||
ignoreTest();
|
ignoreTest();
|
||||||
|
dataDistributorTest();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user