Compare commits
418 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
2715f585e0 | ||
|
|
c2e3315f54 | ||
|
|
d0ddcead24 | ||
|
|
5f42eec15a | ||
|
|
20e55d5bca | ||
|
|
6d2d63621e | ||
|
|
b3f96f730f | ||
|
|
02930b78a0 | ||
|
|
68cc5e3b28 | ||
|
|
0c0a77def5 | ||
|
|
79b05db5e2 | ||
|
|
cd653a809f | ||
|
|
07a951c3a2 | ||
|
|
9cfbc7983c | ||
|
|
761c62050d | ||
|
|
d508792f2a | ||
|
|
4b98e70ce0 | ||
|
|
2450e356f5 | ||
|
|
14442774ab | ||
|
|
3f320fac32 | ||
|
|
4ad470d3f4 | ||
|
|
fd97c9ac8e | ||
|
|
93c6305952 | ||
|
|
7e0bc0c45a | ||
|
|
ebd4e3827c | ||
|
|
11393ce6b1 | ||
|
|
4a13cab5a4 | ||
|
|
7529f58b63 | ||
|
|
7491f3b531 | ||
|
|
595163a1fa | ||
|
|
6fe27251f1 | ||
|
|
a2a07a1d33 | ||
|
|
3e0282d956 | ||
|
|
e667e39573 | ||
|
|
6239ef0c0c | ||
|
|
87ccf78a9b | ||
|
|
bbb5fa2c64 | ||
|
|
8e04875a45 | ||
|
|
83101e210a | ||
|
|
e31aae5f5d | ||
|
|
2469fc04b5 | ||
|
|
e0cb7d7f93 | ||
|
|
2904e00b3d | ||
|
|
b26c0ecd71 | ||
|
|
e06b2b7076 | ||
|
|
63214b98f6 | ||
|
|
a1714c9aab | ||
|
|
64c5fd1e67 | ||
|
|
955947fd0f | ||
|
|
c6339f4f1b | ||
|
|
ae97789beb | ||
|
|
35d4b5c70e | ||
|
|
977f078246 | ||
|
|
063313f246 | ||
|
|
cec282f77f | ||
|
|
24cf1d277e | ||
|
|
1d5e9e7b25 | ||
|
|
f131f0631c | ||
|
|
aa44396a43 | ||
|
|
547df7a2cd | ||
|
|
be6527b01e | ||
|
|
d7486622bf | ||
|
|
974bf061a2 | ||
|
|
d99087d2f6 | ||
|
|
8c2926ad92 | ||
|
|
5b60025b76 | ||
|
|
d080a073b1 | ||
|
|
ff172cc495 | ||
|
|
da00928e7e | ||
|
|
9dcb68669c | ||
|
|
33852c6375 | ||
|
|
ce9322eb9c | ||
|
|
a634d53a00 | ||
|
|
515e7926b8 | ||
|
|
6877ec8397 | ||
|
|
03fc6f4a63 | ||
|
|
1d80fbf512 | ||
|
|
04688b1e1a | ||
|
|
08751c619b | ||
|
|
0c96300e99 | ||
|
|
e17d8bbd76 | ||
|
|
0784cc15d0 | ||
|
|
81220c87f8 | ||
|
|
75849c6676 | ||
|
|
5f98b5230a | ||
|
|
d3bbbdd083 | ||
|
|
4197eb9422 | ||
|
|
349f7d0a58 | ||
|
|
355cb68363 | ||
|
|
b5e1341736 | ||
|
|
570fbf80ae | ||
|
|
fde7953de0 | ||
|
|
e025e542ea | ||
|
|
f7a3ca2c3c | ||
|
|
1eea87efc7 | ||
|
|
15c6d32b61 | ||
|
|
db2f528c0a | ||
|
|
351840b490 | ||
|
|
c36b969da4 | ||
|
|
f4c0b54c17 | ||
|
|
0611db9a18 | ||
|
|
80ff17cfbc | ||
|
|
1ea3d46baf | ||
|
|
3babe530ca | ||
|
|
6647ab3142 | ||
|
|
0595b5a9d5 | ||
|
|
9c93cef34e | ||
|
|
3fc5aad6f5 | ||
|
|
4934e5a8c7 | ||
|
|
bb3aca734c | ||
|
|
ce41acd373 | ||
|
|
264100df7c | ||
|
|
64909f2152 | ||
|
|
f0320e7173 | ||
|
|
7f15b136b1 | ||
|
|
6c08a05b81 | ||
|
|
326dc6ca69 | ||
|
|
751cc8965d | ||
|
|
102174913c | ||
|
|
61c41ceb7e | ||
|
|
4ac867ec0f | ||
|
|
ca3573291a | ||
|
|
3764c3ad36 | ||
|
|
0aadb3b0a7 | ||
|
|
bc3335d4f9 | ||
|
|
a99b08fd02 | ||
|
|
c717138c7d | ||
|
|
e6e7902831 | ||
|
|
d71d3f1862 | ||
|
|
77ff6ad6c1 | ||
|
|
b3b01959e5 | ||
|
|
9db7ed360b | ||
|
|
1f7881010e | ||
|
|
90a96f4ee4 | ||
|
|
34ff6077c7 | ||
|
|
1050b980ec | ||
|
|
2bdb012709 | ||
|
|
8a1690f35a | ||
|
|
b20fd4c5c5 | ||
|
|
d578dfbb99 | ||
|
|
e9d14d061e | ||
|
|
409b045779 | ||
|
|
fda81767a5 | ||
|
|
fe1b167e23 | ||
|
|
dc0f20cc5f | ||
|
|
6e7d887e6e | ||
|
|
699a6cd8b4 | ||
|
|
70454a6006 | ||
|
|
deebe46378 | ||
|
|
18dc4279ad | ||
|
|
61e9dc0368 | ||
|
|
6b0d1ce49b | ||
|
|
81b160d7b6 | ||
|
|
4e22a056d2 | ||
|
|
4af5ba92d9 | ||
|
|
e79c70c74c | ||
|
|
c0694e2d69 | ||
|
|
36dac883f4 | ||
|
|
35dcbf35b3 | ||
|
|
30dd2ed046 | ||
|
|
e30e4f3638 | ||
|
|
15578d1647 | ||
|
|
e3e270e242 | ||
|
|
ec44251df0 | ||
|
|
3344165f19 | ||
|
|
c2ea402be0 | ||
|
|
0535ff990d | ||
|
|
18ff90e641 | ||
|
|
a781195458 | ||
|
|
1a641f0d1b | ||
|
|
0e6639c149 | ||
|
|
93ba23aeb8 | ||
|
|
7743f3e3fd | ||
|
|
e9ce6a2f0b | ||
|
|
1ed48c15f1 | ||
|
|
d27f929595 | ||
|
|
b4e17f271b | ||
|
|
79f407486a | ||
|
|
3c359728f7 | ||
|
|
7b9693562a | ||
|
|
f1c39ca5d2 | ||
|
|
16b1775b98 | ||
|
|
f6ee7333bb | ||
|
|
9f45bdfa75 | ||
|
|
03aa15b5f7 | ||
|
|
8093952ca2 | ||
|
|
2bea54e218 | ||
|
|
e81230dba5 | ||
|
|
50b8f306c3 | ||
|
|
65be8e5678 | ||
|
|
dbb9310adc | ||
|
|
50fbb396e8 | ||
|
|
ff19fe1cd8 | ||
|
|
230938220e | ||
|
|
334ed3b70a | ||
|
|
4c7e51d8ad | ||
|
|
4973a6297e | ||
|
|
f0d1481a28 | ||
|
|
d5235db54c | ||
|
|
b125035a11 | ||
|
|
9551b0e4c6 | ||
|
|
d6aa03815e | ||
|
|
ce0d62fbbc | ||
|
|
2fe3e66047 | ||
|
|
fa53d72258 | ||
|
|
b010cf0849 | ||
|
|
7fd707cb4b | ||
|
|
5d823307f0 | ||
|
|
d41d5726d2 | ||
|
|
723f98bc44 | ||
|
|
1544147bdd | ||
|
|
0447441cfa | ||
|
|
8ce42ebb9a | ||
|
|
c39b966121 | ||
|
|
61edf17cdf | ||
|
|
39f537d7da | ||
|
|
ba496de2d3 | ||
|
|
38574ed76f | ||
|
|
92be294bbf | ||
|
|
35429bf4df | ||
|
|
552925dfe6 | ||
|
|
d1791393ad | ||
|
|
3dbad700f7 | ||
|
|
c06e33e197 | ||
|
|
1d8f01517a | ||
|
|
8c1b142e48 | ||
|
|
ca27cb5e3c | ||
|
|
8fb02d5602 | ||
|
|
38f8f1de51 | ||
|
|
a5fa17aca7 | ||
|
|
fe62a7181f | ||
|
|
69fe610c5d | ||
|
|
83f2fa9d9a | ||
|
|
5faa9902ea | ||
|
|
f10a5f8279 | ||
|
|
fcb82fd31f | ||
|
|
16fbd0f205 | ||
|
|
597bca1ca5 | ||
|
|
3e790e34e3 | ||
|
|
144da546ea | ||
|
|
2d450bdd5b | ||
|
|
333bbca2f2 | ||
|
|
d17192804e | ||
|
|
63e7401ff1 | ||
|
|
42e2e72474 | ||
|
|
342ab45dc8 | ||
|
|
c91f2e7263 | ||
|
|
f3dc67e620 | ||
|
|
127830e3c7 | ||
|
|
9d3873c3fe | ||
|
|
3ce6df5b0d | ||
|
|
0f1c0c28d0 | ||
|
|
e740687635 | ||
|
|
d1df670c83 | ||
|
|
6b47485810 | ||
|
|
228b46a622 | ||
|
|
e932c01cf1 | ||
|
|
c6f6465457 | ||
|
|
068d3070e2 | ||
|
|
4ad2e56a08 | ||
|
|
d63610c7f5 | ||
|
|
92509abde8 | ||
|
|
c445368537 | ||
|
|
2269a5bd66 | ||
|
|
876ec8062f | ||
|
|
53c3901099 | ||
|
|
51f4820c24 | ||
|
|
a21189cfda | ||
|
|
61d884334a | ||
|
|
9a798bc05a | ||
|
|
94bd84211b | ||
|
|
5d0718ab3a | ||
|
|
e8a9771d1e | ||
|
|
ac971042de | ||
|
|
ce116eefb8 | ||
|
|
3e1a405d01 | ||
|
|
3039e1cdb0 | ||
|
|
006859120e | ||
|
|
14b3640e9a | ||
|
|
ed5bf2d79b | ||
|
|
313ba68a06 | ||
|
|
22786bb07e | ||
|
|
534671dbe8 |
10
.ci/travis-build.sh
Executable file
10
.ci/travis-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
make -j2 $EXTRA
|
||||
|
||||
if [ "$TEST" != "NO" ]
|
||||
then
|
||||
make -j2 tapfiles
|
||||
make -j2 -s test-results
|
||||
fi
|
||||
109
.ci/travis-prepare.sh
Executable file
109
.ci/travis-prepare.sh
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
CURDIR="$PWD"
|
||||
|
||||
cat << EOF > $CURDIR/configure/RELEASE.local
|
||||
EPICS_BASE=$HOME/.source/epics-base
|
||||
EOF
|
||||
|
||||
install -d "$HOME/.source"
|
||||
cd "$HOME/.source"
|
||||
|
||||
add_gh_flat() {
|
||||
MODULE=$1
|
||||
REPOOWNER=$2
|
||||
REPONAME=$3
|
||||
BRANCH=$4
|
||||
MODULE_UC=$(echo $MODULE | tr 'a-z' 'A-Z')
|
||||
( git clone --quiet --depth 5 --branch $BRANCH https://github.com/$REPOOWNER/$REPONAME.git $MODULE && \
|
||||
cd $MODULE && git log -n1 )
|
||||
cat < $CURDIR/configure/RELEASE.local > $MODULE/configure/RELEASE.local
|
||||
cat << EOF >> $CURDIR/configure/RELEASE.local
|
||||
${MODULE_UC}=$HOME/.source/$MODULE
|
||||
EOF
|
||||
}
|
||||
|
||||
# not recursive
|
||||
git clone --quiet --depth 5 --branch "$BRBASE" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
|
||||
(cd epics-base && git log -n1 )
|
||||
add_gh_flat pvData ${REPOPVD:-epics-base} pvDataCPP ${BRPVD:-master}
|
||||
add_gh_flat pvAccess ${REPOPVA:-epics-base} pvAccessCPP ${BRPVA:-master}
|
||||
|
||||
if [ -e $CURDIR/configure/RELEASE.local ]
|
||||
then
|
||||
cat $CURDIR/configure/RELEASE.local
|
||||
fi
|
||||
|
||||
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
|
||||
|
||||
# requires wine and g++-mingw-w64-i686
|
||||
if [ "$WINE" = "32" ]
|
||||
then
|
||||
echo "Cross mingw32"
|
||||
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
CMPLR_PREFIX=i686-w64-mingw32-
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$STATIC" = "YES" ]
|
||||
then
|
||||
echo "Build static libraries/executables"
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
SHARED_LIBRARIES=NO
|
||||
STATIC_BUILD=YES
|
||||
EOF
|
||||
fi
|
||||
|
||||
case "$CMPLR" in
|
||||
clang)
|
||||
echo "Host compiler is clang"
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
|
||||
GNU = NO
|
||||
CMPLR_CLASS = clang
|
||||
CC = clang
|
||||
CCC = clang++
|
||||
EOF
|
||||
|
||||
# hack
|
||||
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
|
||||
|
||||
clang --version
|
||||
;;
|
||||
*)
|
||||
echo "Host compiler is default"
|
||||
gcc --version
|
||||
;;
|
||||
esac
|
||||
|
||||
cat <<EOF >> epics-base/configure/CONFIG_SITE
|
||||
USR_CPPFLAGS += $USR_CPPFLAGS
|
||||
USR_CFLAGS += $USR_CFLAGS
|
||||
USR_CXXFLAGS += $USR_CXXFLAGS
|
||||
EOF
|
||||
|
||||
# set RTEMS to eg. "4.9" or "4.10"
|
||||
# requires qemu, bison, flex, texinfo, install-info
|
||||
if [ -n "$RTEMS" ]
|
||||
then
|
||||
echo "Cross RTEMS${RTEMS} for pc386"
|
||||
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
|
||||
| tar -C / -xmj
|
||||
|
||||
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
RTEMS_VERSION=$RTEMS
|
||||
RTEMS_BASE=$HOME/.rtems
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
|
||||
EOF
|
||||
fi
|
||||
|
||||
make -j2 -C epics-base $EXTRA
|
||||
make -j2 -C pvData $EXTRA
|
||||
make -j2 -C pvAccess $EXTRA
|
||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/cfg/
|
||||
/bin/
|
||||
/lib/
|
||||
/db/
|
||||
/dbd/
|
||||
/html/
|
||||
/include/
|
||||
/templates/
|
||||
/configure/*.local
|
||||
/documentation/html
|
||||
/documentation/*.tag
|
||||
O.*/
|
||||
/QtC-*
|
||||
envPaths
|
||||
*.orig
|
||||
*.log
|
||||
.*.swp
|
||||
11
.hgignore
11
.hgignore
@@ -1,11 +0,0 @@
|
||||
^QtC-
|
||||
^bin/
|
||||
^lib/
|
||||
^doc/
|
||||
^include/
|
||||
^db/
|
||||
^dbd/
|
||||
^documentation/html
|
||||
envPaths
|
||||
configure/.*\.local
|
||||
/O\..*
|
||||
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
Normal file
31
.travis.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
sudo: false
|
||||
dist: trusty
|
||||
language: c++
|
||||
compiler:
|
||||
- gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libreadline6-dev
|
||||
- libncurses5-dev
|
||||
- perl
|
||||
- clang
|
||||
- g++-mingw-w64-i686
|
||||
- qemu-system-x86
|
||||
install:
|
||||
- ./.ci/travis-prepare.sh
|
||||
script:
|
||||
- ./.ci/travis-build.sh
|
||||
env:
|
||||
- BRBASE=7.0
|
||||
- BRBASE=7.0 CMPLR=clang
|
||||
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++98"
|
||||
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
- BRBASE=7.0 CMPLR=clang EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
- BRBASE=7.0 WINE=32 TEST=NO STATIC=YES
|
||||
- BRBASE=7.0 WINE=32 TEST=NO STATIC=NO
|
||||
- BRBASE=7.0 RTEMS=4.10 TEST=NO
|
||||
- BRBASE=7.0 RTEMS=4.9 TEST=NO
|
||||
- BRBASE=3.16
|
||||
- BRBASE=3.15
|
||||
|
||||
77
LICENSE
77
LICENSE
@@ -1,12 +1,17 @@
|
||||
Copyright and License Terms
|
||||
---------------------------
|
||||
|
||||
Copyright (c) 2008 Martin R. Kraimer
|
||||
Copyright (c) 2006 The University of Chicago, as Operator of Argonne
|
||||
Copyright (c) 2006-2016 Martin R. Kraimer
|
||||
Copyright (c) 2006-2016 UChicago Argonne LLC, as Operator of Argonne
|
||||
National Laboratory.
|
||||
Copyright (c) 2006 Deutsches Elektronen-Synchroton,
|
||||
Copyright (c) 2006 Deutsches Elektronen-Synchrotron,
|
||||
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
|
||||
Copyright (c) 2007 Control System Laboratory,
|
||||
Copyright (c) 2007-2016 Control System Laboratory,
|
||||
(COSYLAB) Ljubljana Slovenia
|
||||
|
||||
Copyright (c) 2010-2016 Brookhaven Science Associates, as Operator
|
||||
of Brookhaven National Laboratory
|
||||
Copyright (c) 2011-2016 Diamond Light Source Limited,
|
||||
(DLS) Didcot, United Kingdom
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
@@ -31,48 +36,30 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
________________________________________________________________________
|
||||
|
||||
This software is in part copyrighted by the University of Chicago (UofC)
|
||||
Additional Disclaimers
|
||||
----------------------
|
||||
|
||||
In no event shall UofC be liable to any party for direct, indirect,
|
||||
special, incidental, or consequential damages arising out of the use of
|
||||
this software, its documentation, or any derivatives thereof, even if
|
||||
UofC has been advised of the possibility of such damage.
|
||||
This software is copyright in part by these institutions:
|
||||
|
||||
UofC specifically disclaims any warranties, including, but not limited
|
||||
to, the implied warranties of merchantability, fitness for a particular
|
||||
purpose, and non-infringement. This software is provided on an "as is"
|
||||
basis, and UofC has no obligation to provide maintenance, support,
|
||||
updates, enhancements, or modifications.
|
||||
* Brookhaven Science Associates, as Operator of Brookhaven
|
||||
National Laboratory, New York, USA
|
||||
* Control System Laboratory, Ljubljana, Slovenia
|
||||
* Deutsches Elektronen-Synchroton, Member of the Helmholtz
|
||||
Association, Hamburg, Germany
|
||||
* Diamond Light Source Limited, Didcot, United Kingdom
|
||||
* Helmholtz-Zentrum Berlin fuer Materialien und Energie m.b.H.,
|
||||
Berlin, Germany.
|
||||
* UChicage Argonne LLC, as Operator of Argonne National Laboratory,
|
||||
Illinois, USA
|
||||
|
||||
________________________________________________________________________
|
||||
In no event shall these institutions be liable to any party for direct,
|
||||
indirect, special, incidental, or consequential damages arising out of
|
||||
the use of this software, its documentation, or any derivatives thereof,
|
||||
even if advised of the possibility of such damage.
|
||||
|
||||
This software is in part copyrighted by the BERLINER SPEICHERRING
|
||||
GESELLSCHAFT FUER SYNCHROTRONSTRAHLUNG M.B.H. (BESSY), BERLIN, GERMANY.
|
||||
These institutions specifically disclaim any warranties, including, but
|
||||
not limited to, the implied warranties of merchantability, fitness for a
|
||||
particular purpose, and non-infringement. This software is provided on
|
||||
an "as is" basis, and these institutions have no obligation to provide
|
||||
maintenance, support, updates, enhancements, or modifications.
|
||||
|
||||
In no event shall BESSY be liable to any party for direct, indirect,
|
||||
special, incidental, or consequential damages arising out of the use of
|
||||
this software, its documentation, or any derivatives thereof, even if
|
||||
BESSY has been advised of the possibility of such damage.
|
||||
|
||||
BESSY specifically disclaims any warranties, including, but not limited
|
||||
to, the implied warranties of merchantability, fitness for a particular
|
||||
purpose, and non-infringement. This software is provided on an "as is"
|
||||
basis, and BESSY has no obligation to provide maintenance, support,
|
||||
updates, enhancements, or modifications.
|
||||
|
||||
________________________________________________________________________
|
||||
|
||||
This software is in part copyrighted by the Deutsches Elektronen-Synchroton,
|
||||
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
|
||||
|
||||
In no event shall DESY be liable to any party for direct, indirect,
|
||||
special, incidental, or consequential damages arising out of the use of
|
||||
this software, its documentation, or any derivatives thereof, even if
|
||||
DESY has been advised of the possibility of such damage.
|
||||
|
||||
DESY specifically disclaims any warranties, including, but not limited
|
||||
to, the implied warranties of merchantability, fitness for a particular
|
||||
purpose, and non-infringement. This software is provided on an "as is"
|
||||
basis, and DESY has no obligation to provide maintenance, support,
|
||||
updates, enhancements, or modifications.
|
||||
________________________________________________________________________
|
||||
|
||||
6
Makefile
6
Makefile
@@ -6,11 +6,7 @@ DIRS += configure
|
||||
DIRS += src
|
||||
src_DEPEND_DIRS = configure
|
||||
|
||||
DIRS += example
|
||||
DIRS += test
|
||||
test_DEPEND_DIRS = src
|
||||
|
||||
DIRS += iocBoot
|
||||
|
||||
include $(TOP)/configure/RULES_TOP
|
||||
|
||||
|
||||
|
||||
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# pvDatabaseCPP
|
||||
|
||||
The EPICS **pvDatabase** module provides a set of network accessible, smart, memory resident records with a C++ API. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider gives access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.
|
||||
|
||||
The pvDatabase module implements a synchronous C++ server interface to pvAccessCPP that was designed to be easier to use than the basic pvAccess server API.
|
||||
|
||||
## Links
|
||||
|
||||
- General information about EPICS can be found at the
|
||||
[EPICS Controls website](https://epics-controls.org).
|
||||
- API documentation for this module can be found in its
|
||||
documentation directory, in particular the file
|
||||
pvDatabaseCPP.html
|
||||
|
||||
## Building
|
||||
|
||||
This module is included as a submodule of a full EPICS 7 release and will be compiled during builds of that software.
|
||||
|
||||
## Examples
|
||||
|
||||
Some examples are available in the separate exampleCPP module.
|
||||
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 = 0
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_PVDATABASE_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
@@ -14,26 +14,11 @@
|
||||
# Set CHECK_RELEASE to NO to disable checking completely.
|
||||
# Set CHECK_RELEASE to WARN to perform consistency checking but
|
||||
# continue building anyway if conflicts are found.
|
||||
#CHECK_RELEASE = YES
|
||||
|
||||
# Set this when you only want to compile this application
|
||||
# for a subset of the cross-compiled target architectures
|
||||
# that Base is built for.
|
||||
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040
|
||||
CHECK_RELEASE = WARN
|
||||
|
||||
# To install files into a location other than $(TOP) define
|
||||
# INSTALL_LOCATION here.
|
||||
#INSTALL_LOCATION=</path/name/to/install/top>
|
||||
|
||||
# Set this when your IOC and the host use different paths
|
||||
# to access the application. This will be needed to boot
|
||||
# from a Microsoft FTP server or with some NFS mounts.
|
||||
# You must rebuild in the iocBoot directory for this to
|
||||
# take effect.
|
||||
#IOCS_APPL_TOP = </IOC/path/to/application/top>
|
||||
|
||||
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
|
||||
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
|
||||
|
||||
-include $(TOP)/../CONFIG_SITE.local
|
||||
-include $(TOP)/configure/CONFIG_SITE.local
|
||||
-include $(TOP)/../CONFIG.local
|
||||
|
||||
@@ -2,7 +2,10 @@ TOP=..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
CFG += CONFIG_PVDATABASE_VERSION
|
||||
|
||||
TARGETS = $(CONFIG_TARGETS)
|
||||
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
# RELEASE - Location of external support modules
|
||||
#
|
||||
# IF YOU MAKE ANY CHANGES to this file you must subsequently
|
||||
# do a "gnumake rebuild" in this application's top level
|
||||
# directory.
|
||||
# IF YOU CHANGE ANY PATHS in this file or make API changes to
|
||||
# any modules it refers to, you should do a "make rebuild" in
|
||||
# this application's top level directory.
|
||||
#
|
||||
# The build process does not check dependencies against files
|
||||
# that are outside this application, thus you should do a
|
||||
# "gnumake rebuild" in the top level directory after EPICS_BASE
|
||||
# or any other external module pointed to below is rebuilt.
|
||||
# The EPICS build process does not check dependencies against
|
||||
# any files from outside the application, so it is safest to
|
||||
# rebuild it completely if any modules it depends on change.
|
||||
#
|
||||
# Host- or target-specific settings can be given in files named
|
||||
# RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
# RELEASE.Common.$(T_A)
|
||||
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
#
|
||||
# This file should ONLY define paths to other support modules,
|
||||
# or include statements that pull in similar RELEASE files.
|
||||
# Build settings that are NOT module paths should appear in a
|
||||
# CONFIG_SITE file.
|
||||
# This file is parsed by both GNUmake and an EPICS Perl script,
|
||||
# so it may ONLY contain definititions of paths to other support
|
||||
# modules, variable definitions that are used in module paths,
|
||||
# and include statements that pull in other RELEASE files.
|
||||
# Variables may be used before their values have been set.
|
||||
# Build variables that are NOT used in paths should be set in
|
||||
# the CONFIG_SITE file.
|
||||
|
||||
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
||||
# Variables and paths to dependent modules:
|
||||
#MODULES = /path/to/modules
|
||||
#MYMODULE = $(MODULES)/my-module
|
||||
|
||||
# If using the sequencer, point SNCSEQ at its top directory:
|
||||
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
|
||||
# If building the EPICS modules individually, set these:
|
||||
#EPICS_PVACCESS = $(MODULES)/pvAccess
|
||||
#EPICS_PVDATA = $(MODULES)/pvData
|
||||
#EPICS_DATABASE = $(MODULES)/database
|
||||
#EPICS_CA = $(MODULES)/ca
|
||||
#EPICS_LIBCOM = $(MODULES)/libcom
|
||||
#EPICS_BASE = $(MODULES)/core
|
||||
|
||||
# EPICS_BASE usually appears last so other apps can override stuff:
|
||||
# Set RULES here if you want to use build rules from elsewhere:
|
||||
#RULES = $(MODULES)/build-rules
|
||||
|
||||
# do not edit the locations in this file
|
||||
# create RELEASE.local with the paths to your EPICS_BASE, PVDATA, and PVACCESS
|
||||
# these default locations are needed for the BNL Jenkins server to work
|
||||
|
||||
# Set RULES here if you want to take build rules from somewhere
|
||||
# other than EPICS_BASE:
|
||||
#RULES=/path/to/epics/support/module/rules/x-y
|
||||
|
||||
# Leave these in for the Jenkins build at BNL to work
|
||||
EPICS_BASE=/home/install/epics/base
|
||||
PVDATA=/home/mrk/hg/pvDataCPP
|
||||
PVACCESS=/home/mrk/hg/pvAccessCPP
|
||||
|
||||
# set your EPICS_BASE, PVDATA and PVACCESS paths in here
|
||||
-include $(TOP)/configure/RELEASE.local
|
||||
# These allow developers to override the RELEASE variable settings
|
||||
# without having to modify the configure/RELEASE file itself.
|
||||
-include $(TOP)/../RELEASE.local
|
||||
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
|
||||
-include $(TOP)/configure/RELEASE.local
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
#RULES_TOP
|
||||
include $(CONFIG)/RULES_TOP
|
||||
|
||||
EMTOPACTIONS += cvsclean realuninstall
|
||||
|
||||
distclean: emtop_distclean
|
||||
|
||||
emtopDistcleanTargets += $(foreach dir, $(EMBEDDED_TOPS), \
|
||||
$(dir)$(DIVIDER)emtop_dummy_action)
|
||||
|
||||
$(emtopDistcleanTargets) :
|
||||
$(MAKE) -C $(dirPart) $(EMTOPACTIONS)
|
||||
|
||||
emtop_distclean : $(emtopDistcleanTargets)
|
||||
|
||||
.PHONY : $(emtopDistcleanTargets)
|
||||
|
||||
92
documentation/RELEASE_NOTES.md
Normal file
92
documentation/RELEASE_NOTES.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# pvDatabaseCPP Module
|
||||
|
||||
This document summarizes the changes to the module between releases.
|
||||
|
||||
## 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)
|
||||
|
||||
Formerly if a client makes a request for a subfield of a non structure field
|
||||
it resulted in a crash.
|
||||
|
||||
Now if a request is made for a subfield of a non structure field
|
||||
|
||||
1) if the field is not a union an exception is thrown which is passed to the client.
|
||||
2) if the field is a union
|
||||
a) if more than one subfield is requested an exception is thrown
|
||||
b) if the subfield is the type for the current union the request succeeds
|
||||
c) if type is not the same an exception is thrown
|
||||
|
||||
|
||||
## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019)
|
||||
|
||||
* Cleaned up some build warnings.
|
||||
* RTEMS test harness simplified.
|
||||
|
||||
|
||||
## Release 4.4 (EPICS 7.0.2, Dec 2018)
|
||||
|
||||
* pvCopy is now implemented in pvDatabaseCPP. The version in pvDatacPP can be deprecated.
|
||||
* plugin support is implemented.
|
||||
|
||||
|
||||
## Release 4.3 (EPICS 7.0.1, Dec 2017)
|
||||
|
||||
* Updates for pvAccess API and build system changes.
|
||||
|
||||
|
||||
## Release 4.2 (EPICS V4.6, Aug 2016)
|
||||
|
||||
* The examples are moved to exampleCPP
|
||||
* Support for channelRPC is now available.
|
||||
* removeRecord and traceRecord are now available.
|
||||
|
||||
The test is now a regression test which can be run using:
|
||||
|
||||
make runtests
|
||||
|
||||
|
||||
## Release 4.1 (EPICS V4.5, Oct 2015)
|
||||
|
||||
This is the first release of pvDatabaseCPP.
|
||||
|
||||
It provides functionality equivalent to pvDatabaseJava.
|
||||
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)
|
||||
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>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,733 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>pvDatabaseCPP</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
||||
<style type="text/css">
|
||||
/*<![CDATA[*/
|
||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||
table { margin-left: auto; margin-right: auto }
|
||||
.diagram { text-align: center; margin: 2.5em 0 }
|
||||
span.opt { color: grey }
|
||||
span.nterm { font-style:italic }
|
||||
span.term { font-family:courier }
|
||||
span.user { font-family:courier }
|
||||
span.user:before { content:"<" }
|
||||
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>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 27-Nov-2012</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd>None</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
</dl>
|
||||
|
||||
<p class="copyright">This product is made available subject to acceptance of the <a
|
||||
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
|
||||
<p>This document describes pvDatabaseCPP,
|
||||
which is a framework for implementing a network accessable database of smart memory resident
|
||||
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.
|
||||
The framework must be extended in order to create record instances.
|
||||
The minimum that an extenson must provide is a top level PVStructure and a process method
|
||||
but the framework provides for complex extensions.</p>
|
||||
|
||||
<p>EPICS version 4 is a set of related products in the EPICS
|
||||
V4 control system programming environment:</p>
|
||||
<dl>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvDataJava/tip/documentation/pvDataJava.html">pvData</a></dt>
|
||||
<dd>pvData (Process Variable Data) defines and implements an efficent way
|
||||
to store, access, and communicate memory resident structured data</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvAccessJava/tip/documentation/pvAccessJava.html">pvAccess</a></dt>
|
||||
<dd>pvAccess is a software library for high speed controls network communications,
|
||||
optimized for pvData</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvIOCJava/tip/documentation/pvIOCJava.html">pvIOC</a></dt>
|
||||
<dd>pvIOC is a software framework for building network accessable "smart" real time
|
||||
databases, suitable for interfacing devices in a distributed control system,
|
||||
that can exchange pvData over pvAccess.
|
||||
</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvServiceJava/tip/documentation/pvAccessJava.html">pvService</a></dt>
|
||||
<dd>A middle layer for implementing data services.</dd>
|
||||
</dl>
|
||||
|
||||
<p>Each of these products has a Java and a C++ implementation.</p>
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 27-Nov-2012 version of the definition of pvDatabaseCPP.
|
||||
This is the original version.
|
||||
</p>
|
||||
<p>This is the beginning of the implementation of pvDataBaseCPP.
|
||||
It describes the features that will be provided.
|
||||
The class definitions for PVRecord and PVDatabase are defined but not implemented.</p>
|
||||
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
</div>
|
||||
<div id="contents" class="contents">
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava.
|
||||
It extracts the core components required to create a network accessible database of smart
|
||||
memory resident records.
|
||||
pvDatabaseCPP does not and will not implement any of the specialized support that pvIOCJava
|
||||
provides. Instead other projects will implement the specialized support.
|
||||
It is expected that many services will be created that do not require the full features provided
|
||||
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
|
||||
them named pvDatabaseJava.
|
||||
</p>
|
||||
|
||||
<p>A brief description of a pvDatase is that it is a network accessible set of smart memory resident
|
||||
records. Each record has data composed of a top level PVStructure. Each record has a name which is
|
||||
the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and
|
||||
Channel interfaces as defined by pvAccess.
|
||||
This local provider is accessed by the remote pvAccess server.
|
||||
A record is smart because code can be attached to a record.</p>
|
||||
<p>This document describes components that provides the following features:
|
||||
<dl>
|
||||
<dt>database<dt>
|
||||
<dd>This encapsulates the concept of a database of memory resident smart records.
|
||||
The two main components are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>This encapsulates the concept of a smart record. It can be processed.
|
||||
Changes to field values can be trapped. A record can be locked.</dd>
|
||||
<dt>pvDatabase<dt>
|
||||
<dd>This is a database of pvRecords.
|
||||
Records can be added and removed from a database.</dd>
|
||||
</dl>
|
||||
<dt>localChannelProvider</dt>
|
||||
<dd>This is a complete implementation of ChannelProvider and Channel as defined by pvAccess.
|
||||
It is used by the server side of pvAccess to attach to pvRecords.
|
||||
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||
</dl>
|
||||
<p><b>database</b> does not itself implement pvRecord instances.
|
||||
Instead it provides a base classes that make it easy to create record instances.
|
||||
What does have to be implemented is a top
|
||||
level PVStructure and the following two methods:</p>
|
||||
<dl>
|
||||
<dt>process</dt>
|
||||
<dd>This is what makes a record <b>smart</b>.
|
||||
What process does is up to the implementation except that it must decide if
|
||||
it's execution model is synchronous or asynchronous.
|
||||
Synchronous means that when process returns the processing is complete.
|
||||
Asynchronous means that when process returns the processing is <b>not</b> complete.
|
||||
Instead process invokes other threads that will complete the processing at a later time.</dd>
|
||||
<dt>isSynchronous</dt>
|
||||
<dd>Which execution model is being implemented.</dd>
|
||||
</dl>
|
||||
<h3>Example PVRecord Extension</h3>
|
||||
<p>Directory <b>example/record</b> has an example PVRecord implementation.
|
||||
It implements a counter.
|
||||
The top level structure is:</p>
|
||||
<pre>
|
||||
structure
|
||||
long value
|
||||
</pre>
|
||||
<p><b>NOTE:</b> The example compiles but does not build because nothing
|
||||
is implemented.</p>
|
||||
|
||||
<h4>exampleRecord.h</h4>
|
||||
<p>This is the class description.
|
||||
The example extends PVRecord.</p>
|
||||
<pre>
|
||||
class ExampleRecord :
|
||||
public virtual PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleRecord);
|
||||
static PVRecordPtr create(epics::pvData::String const & recordName);
|
||||
virtual ~ExampleRecord();
|
||||
virtual bool isSynchronous();
|
||||
virtual void process(
|
||||
epics::pvDatabase::RecordProcessRequesterPtr const &processRequester);
|
||||
private:
|
||||
ExampleRecord(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
epics::pvData::PVLongPtr const &pvValue);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>This is example specific. See the implemention for details.</dd>
|
||||
<dt>~ExampleRecord<dt>
|
||||
<dd>The destructor must be declared virtual.</dd>
|
||||
<dt>isSynchronous<dt>
|
||||
<dd>The implementation must say if process is synchronous or asynchronous.</dd>
|
||||
<dt>process<dt>
|
||||
<dd><b>The</b> implementation.</dd>
|
||||
<dt>ExampleRecord<dt>
|
||||
<dd>For the example this is private.</dd>
|
||||
<dl>
|
||||
|
||||
<h4>exampleRecord.cpp</h4>
|
||||
<p>This is the class implementation.</p>
|
||||
<pre>
|
||||
ExampleRecord::~ExampleRecord(){}
|
||||
|
||||
PVRecordPtr ExampleRecord::create(String const & recordName)
|
||||
{
|
||||
String properties;
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties);
|
||||
PVLongPtr pvValue = pvStructure->getLongField("value");
|
||||
PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ExampleRecord::ExampleRecord(
|
||||
String const & recordName,
|
||||
PVStructurePtr const & pvStructure,
|
||||
PVLongPtr const &pvValue)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
pvValue(pvValue)
|
||||
{}
|
||||
|
||||
bool ExampleRecord::isSynchronous() {return true;}
|
||||
|
||||
void ExampleRecord::process(
|
||||
RecordProcessRequesterPtr const &processRequester)
|
||||
{
|
||||
pvValue->put(pvValue->get() + 1);
|
||||
processRequester->recordProcessResult(Status::Ok);
|
||||
processRequester->recordProcessComplete();
|
||||
}
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>Creates a PVStructure with a single subfield named value.
|
||||
It gets the interface to the value field.
|
||||
It then creates an ExampleRecord and returns it.
|
||||
</dd>
|
||||
<dt>~ExampleRecord<dt>
|
||||
<dd>Does not have to do anything because of shared pointers.</dd>
|
||||
<dt>ExampleRecord<dt>
|
||||
<dd>Calls the base class constructor and sets pvValue.</dd>
|
||||
<dt>isSynchronous<dt>
|
||||
<dd>The example is synchronous.</dd>
|
||||
<dt>process<dt>
|
||||
<dd>Gets the curent value, increments it, and puts the new value.
|
||||
It than calls two processRequester callbacks.</dd>
|
||||
<dl>
|
||||
|
||||
<h4>exampleRecordMain.cpp</h4>
|
||||
<p>This is a main for creating and running the example.</p>
|
||||
<pre>
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
String recordName("exampleRecord");
|
||||
PVRecordPtr pvRecord = ExampleRecord::create(recordName);
|
||||
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
|
||||
pvDatabase->addRecord(pvRecord);
|
||||
cout << recordName << "\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
<p>The main program creates an example record and adds it to the database.
|
||||
It then runs until the process is stopped by typing <b>exit</b>.
|
||||
<p>Until the process is stopped,
|
||||
pvAccess clients can put and get the value field.
|
||||
For example</p>
|
||||
<pre>
|
||||
pvget exampleRecord
|
||||
pvput exampleRecord 5
|
||||
</pre>
|
||||
<p>Will both work.</p>
|
||||
<h3>Phased Development</h3>
|
||||
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
||||
<dl>
|
||||
<dt>pvRecord</d>
|
||||
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
|
||||
<dt>pvDatabase</d>
|
||||
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
||||
<dt>Local Channel Provider</dt>
|
||||
<dd>These two features will be the first phase.
|
||||
But only synchronous record processing will be supported.</dd>
|
||||
</dl>
|
||||
<p>Future phases of pvDatabaseCPP should include:</p>
|
||||
<dl>
|
||||
<dt>Install</dt>
|
||||
<dd>This provides on-line add and delete.</dd>
|
||||
<dt>Field support</dt>
|
||||
<dd>Add ability to optionally add support to fields.
|
||||
In addition some of the basic support defined in pvIOCJava will also be implemented.</dd>
|
||||
<dt>XML parser</dt>
|
||||
<dd>This provides the ability to create record instances without writing any code.</dd>
|
||||
</dl>
|
||||
<p>The completion of each phase provides useful features that can be used without waiting for the
|
||||
completion of later phases.
|
||||
The rest of this document discusses only the first phase.</p>
|
||||
<h3>Features Required for localChannelProvider</h3>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>Creates a PVStructure that contains a copy of an arbitary
|
||||
subset of the fields of another top level PVStructure.
|
||||
It can copy data between the two and maintains a bitSet that show
|
||||
which fields are changed.<dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||
<dt>PVRecord and PVDatabase</dt>
|
||||
<dd>Defined below.</dd>
|
||||
<dt>local ChannelProvider</dt>
|
||||
<dd>This is the pvAccess package in pvIOCJava.
|
||||
The localChannelProvider will access data from PVRecords.
|
||||
It will implement all channel methods except channelRPC.</dd>
|
||||
</dl>
|
||||
<h3>Minumum Features Required for pvRecord</h3>
|
||||
<p>The first phase will only implement record processing, i. e.
|
||||
the process method has to do everything itself without any generic field support.
|
||||
This will be sufficient for starting to implement services.
|
||||
The following are the minimium features required</p>
|
||||
<dl>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This, and a set of related interfaces, provide the following:
|
||||
<dl>
|
||||
<dt>PVStructure</dt>
|
||||
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
||||
<dt>Record locking</dt>
|
||||
<dd>A record can be locked and unlocked.
|
||||
A record must be locked whenever data in the pvStructure is accessed.</dd>
|
||||
<dt>Trapping data changes</dt>
|
||||
<dd>A client can request to be notified when data in the pvStructure is modified.
|
||||
It can do this on a field by field basis.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The following sections provide a first attempt to describe the classes required for the first
|
||||
phase.</p>
|
||||
<p>The last section gives a brief overview of the features provided by pvIOCJava.</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<p>The classes in <b>pvDatabase.h</b> implement a database of memory resident
|
||||
smart records. The next subsection has the definitions for all the classes
|
||||
defined in this header file.
|
||||
It describes the following classes:</p>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
|
||||
<dt>PVRecordField</dt>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>These <b>wrap</b> PVField and PVStructure so that pvCopy and monitor can be implemented.</dd>
|
||||
<dt>PVListener</dt>
|
||||
<dd>This is implemented by anything that wants to trap calls to the PVRecord::message.</dd>
|
||||
<dt>RecordProcessRequester</dt>
|
||||
<dd>This is implemented by anything that calls PVRecord::queueProcessRequest.</dd>
|
||||
<dt>PVRecordClient</dt>
|
||||
<dd>This is called by anything that acceses PVRecord.</dd>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This is a database of PVRecords.</dd>
|
||||
</dl>
|
||||
<p>Each class is described in a separate subsection.</p>
|
||||
|
||||
<h3>class PVRecord</h3>
|
||||
<pre>
|
||||
class PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
PVRecord(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PVRecord();
|
||||
virtual void process(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester) = 0;
|
||||
virtual bool isSynchronous() = 0;
|
||||
epics::pvData::String getRecordName();
|
||||
PVRecordStructurePtr getPVRecordStructure();
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
void lock();
|
||||
void unlock();
|
||||
void registerClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void unregisterClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void detachClients();
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
void registerListener(PVListenerPtr const & pvListener);
|
||||
void unregisterListener(PVListenerPtr const & pvListener);
|
||||
void removeEveryListener();
|
||||
epics::pvData::Status processRequest();
|
||||
void queueProcessRequest(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester);
|
||||
void addRequester(epics::pvData::RequesterPtr const & requester);
|
||||
void removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||
void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
epics::pvData::String toString();
|
||||
epics::pvData::String toString(int indentLevel);
|
||||
};
|
||||
</pre>
|
||||
<p>The methods are:</h3>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The desctructor which must be virtual. A derived class must also have
|
||||
a virtual destructor.</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Pure virtual method. Derived classes must implement this method.</dd>
|
||||
<dt>isSynchronous</dt>
|
||||
<dd>Pure virtual method. Derived classes must implement this method.</dd>
|
||||
<dt>getRecordName</dt>
|
||||
<dd>Return the recordName.</dd>
|
||||
<dt>getPVRecordStructure</dt>
|
||||
<dd>Get the top level PVStructure.</dd>
|
||||
<dt>findPVRecordField</dt>
|
||||
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
|
||||
<dt>lock</dt>
|
||||
<dt>unlock</dt>
|
||||
<dd>Lock and Unlock the record.
|
||||
Any code accessing the data in the record or calling other PVRecord methods
|
||||
must have the record locked.</dd>
|
||||
<dt>registerClient</dt>
|
||||
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
|
||||
<dt>unregisterClient</dt>
|
||||
<dd>Client is no longer accessing the record.</dd>
|
||||
<dt>detachClients</dt>
|
||||
<dd>Ask all clients to detach from the record</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>Begin a group of puts. This results in all registered PVListeners being called</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>End a group of puts. This results in all registered PVListeners being called.</dd>
|
||||
<dt>registerListener</dt>
|
||||
<dd>Register a PVListener. This must be called before calling pvRecordField.addListener.</dd>
|
||||
<dt>unregisterListener</dt>
|
||||
<dd>Unregister a listener. The listener will also be removed from all fields to which it is attached.</dd>
|
||||
<dt>removeEveryListener</dt>
|
||||
<dd>This must be called by any code that is deleting or changing the structure of a record.</dd>
|
||||
<dt>processRequest</dt>
|
||||
<dd>This is a convenience method for clients that are willing to block if
|
||||
process is asynchronous. It implements RecordProcessRequester.
|
||||
If process is synchronous it just calls process and returns the result
|
||||
to the caller. If process is asynchronous it calls queueProcessRequest,
|
||||
and process and waits for completion and then returns the result to the caller.</dd>
|
||||
<dt>queueProcessRequest</dt>
|
||||
<dd>Queue a process request.</dd>
|
||||
<dt>addRequester</dt>
|
||||
<dd>Add a requester to receive messages.</dd>
|
||||
<dt>removeRequester</dt>
|
||||
<dd>Remove a message requester.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordField</h3>
|
||||
<pre>
|
||||
class PVRecordField {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordField);
|
||||
PVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField,
|
||||
PVRecordPtr const & pvRecord);
|
||||
virtual ~PVRecordField();
|
||||
PVRecordStructurePtr getParent();
|
||||
epics::pvData::PVFieldPtr getPVField();
|
||||
epics::pvData::String getFullFieldName();
|
||||
epics::pvData::String getFullName();
|
||||
PVRecordPtr getPVRecord();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
void removeListener(PVListenerPtr const & pvListener);
|
||||
void postPut();
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>PVRecordField</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordField</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getParent</dt>
|
||||
<dd>Get the parent PVRecordStructure for this field.</dd>
|
||||
<dt>getPVField</dt>
|
||||
<dd>Get the PVField associated with this PVRecordField.</dd>
|
||||
<dt>getFullFieldName</dt>
|
||||
<dd>This gets the full name of the field, i.e. field,field,..</dd>
|
||||
<dt>getFullName</dt>
|
||||
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
|
||||
<dt>getPVRecord</dt>
|
||||
<dd>Returns the PVRecord to which this field belongs.</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add A PVListener to this field.
|
||||
Whenever this field or any subfield if this field is modified the listener will be notified.
|
||||
PVListener is described below.
|
||||
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordStructure</h3>
|
||||
<pre>
|
||||
class PVRecordStructure : public PVRecordField {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordStructure);
|
||||
PVRecordStructure(
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
PVRecordFieldPtrArrayPtr const & pvRecordField);
|
||||
virtual ~PVRecordStructure();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
<dl>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordStructure</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getPVRecordFields</dt>
|
||||
<dd>Get the PVRecordField array for the subfields</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Get the PVStructure for this field.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVListener</h3>
|
||||
<pre>
|
||||
class PVListener {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVListener);
|
||||
virtual ~PVListener();
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void unlisten(PVRecordPtr const & pvRecord) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVListener</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>dataPut(PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
|
||||
<dt>dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
Requested is the field to which the requester issued a pvField-&addListener.
|
||||
This is called if the listener has called PVRecordField-&addListener for requested.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>A related set of changes is being started.</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>A related set of changes is done.</dd>
|
||||
<dt>unlisten</dt>
|
||||
<dd>The PVLister is being removed from the record.
|
||||
This is called when the record is being destroyed or when the record structure
|
||||
(not the data values) is being changed.</dd>
|
||||
</dl>
|
||||
<h3>class RecordProcessRequester</h3>
|
||||
<pre>
|
||||
class RecordProcessRequester :
|
||||
virtual public epics::pvData::Requester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(RecordProcessRequester);
|
||||
virtual ~RecordProcessRequester();
|
||||
virtual void becomeProcessor() = 0;
|
||||
virtual void recordProcessResult(epics::pvData::Status status) = 0;
|
||||
virtual void recordProcessComplete() = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~RecordProcessRequester</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>becomeProcessor</dt>
|
||||
<dd>Called as a result of queueRequeProcessst. The requester can the call process.</dd>
|
||||
<dt>recordProcessResult</dt>
|
||||
<dd>The results of record processing.
|
||||
This is called with the record locked so that the process requester
|
||||
can access data from the record.</dd>
|
||||
<dt>recordProcessComplete</dt>
|
||||
<dd>Processing is complete.
|
||||
This is called with the record unlocked.
|
||||
If the process requester called process with leaveActive true then the requester
|
||||
must call setInactive.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordClient</h3>
|
||||
<pre>
|
||||
class PVRecordClient {
|
||||
POINTER_DEFINITIONS(PVRecordClient);
|
||||
virtual ~PVRecordClient();
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVRecordClient</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>detach</dt>
|
||||
<dd>The record is being removed from the master database,</dd>
|
||||
</dl>
|
||||
<h3>class PVDatabase</h3>
|
||||
<pre>
|
||||
class PVDatabase : virtual public epics::pvData::Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDatabase);
|
||||
static PVDatabasePtr getMaster();
|
||||
virtual ~PVDatabase();
|
||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
private:
|
||||
PVDatabase();
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>getMaster</dt>
|
||||
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
|
||||
<dt>~PVDatabase</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>findRecord</dt>
|
||||
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
|
||||
<dt>addRecord</dt>
|
||||
<dd>Add a record to the database.
|
||||
If the record already exists it is not modified and false is returned.</dd>
|
||||
<dt>removeRecord</dt>
|
||||
<dd>Remove a record from the database.
|
||||
If the record was not in the database false is returned.</dd>
|
||||
</dl>
|
||||
<h2>Local Channel Provider</h2>
|
||||
<p>Not yet described.</p>
|
||||
<p>A brief description is that it must implement the following components of pvIOCJava:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dt>monitor</dt>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>See the next section for a description</dd>
|
||||
</dl>
|
||||
<h2>Summary of Packages in pvIOCJAVA</h2>
|
||||
<p>The following are the direct sub packages of <b>pvIOCJava/src/org/epics/pvioc</b>:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>This provides a copy of an arbitrary subset of the fields in a PVRecord.
|
||||
It also provides the ability to detect and report changes to fields.
|
||||
It is required for pvAccess.</dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to a PVRecord. It is required for pvAccess monitors.</dd>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>The local implementation of Channel Provider and Channel.
|
||||
It is accessed by the remote pvAccess server and can also be accessed by code in the same IOC.</dd>
|
||||
<dt>database</dt>
|
||||
<dd>This defines and implements PVRecord, PVDatabase , and PVListener.
|
||||
It supports the basic feature required the implement a local Channel Provider.</dd>
|
||||
<dt>support</dt>
|
||||
<dd>This provides the ability to optionally attach code to any field of a pvRecord.
|
||||
It and several sub packages provide a set of standard support modules.</dd>
|
||||
<dt>install</dt>
|
||||
<dd>This provides the ability to dynamically initialize and add new PVRecords. It also provides
|
||||
the ability to dynamicall delete PVRecords.</d>
|
||||
<dt>xml</dt>
|
||||
<dd>This provides the ability to configure record instances without writing code.</dd>
|
||||
<dt>util</dt>
|
||||
<dd>This is misnamed since it is code related to scanning.</dd>
|
||||
<dt>pdrv</dt>
|
||||
<dd>This is portDriver, which is a proposed sucessor to the asynManager component of asynDriver.</dd>
|
||||
<dt>swtshell</dt>
|
||||
<dd>This is shell that is can either run under the same process as a JavaIOC or as a remote shell.
|
||||
It is like a version of probe but for pvData/pvAccess.
|
||||
Almost all of it's features work in either local or remote mode.
|
||||
With a little more work all or it's features could work remotely.
|
||||
This should be done and then only remote mode should be supported.
|
||||
It can then be rewritten in a completely different language and using a complely different GUI
|
||||
framework.
|
||||
</dd>
|
||||
<dt>caV3</dt>
|
||||
<dd>This has two components:
|
||||
<dl>
|
||||
<dt>ClientFactory</dt>
|
||||
<dd>This is a small wrapper on top of the caV3 client support implemented by pvAccess.
|
||||
It allows code in the pvIOC to access V3Records via pvAccess.</dd>
|
||||
<dt>ServerFactory</dt>
|
||||
<dd>This is a caV3 server that allows a caV3 client to access a PVRecord.
|
||||
The Java implementation uses CAJ, which does most of the work.
|
||||
For now it will not be discussed in this document.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>v3a</dt>
|
||||
<dd>I do not know what this is.</dd>
|
||||
</dl>
|
||||
<p>In addition there is one class file <b>JavaIOC.java</b>.
|
||||
This is starting a IOC instance.
|
||||
This is not required for pvIOCCPP which is either a main or runs as part of a V3 IOC.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,892 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>pvDatabaseCPP</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
||||
<style type="text/css">
|
||||
/*<![CDATA[*/
|
||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||
table { margin-left: auto; margin-right: auto }
|
||||
.diagram { text-align: center; margin: 2.5em 0 }
|
||||
span.opt { color: grey }
|
||||
span.nterm { font-style:italic }
|
||||
span.term { font-family:courier }
|
||||
span.user { font-family:courier }
|
||||
span.user:before { content:"<" }
|
||||
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>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 11-Dec-2012</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20121127.html">pvDatabaseCPP_20121127.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
</dl>
|
||||
|
||||
<p class="copyright">This product is made available subject to acceptance of the <a
|
||||
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
|
||||
<p>This document describes pvDatabaseCPP,
|
||||
which is a framework for implementing a network accessable database of smart memory resident
|
||||
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.
|
||||
The framework must be extended in order to create record instances.
|
||||
The minimum that an extenson must provide is a top level PVStructure and a process method
|
||||
but the framework provides for complex extensions.</p>
|
||||
|
||||
<p>EPICS version 4 is a set of related products in the EPICS
|
||||
V4 control system programming environment:</p>
|
||||
<dl>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvDataJava/tip/documentation/pvDataJava.html">pvData</a></dt>
|
||||
<dd>pvData (Process Variable Data) defines and implements an efficent way
|
||||
to store, access, and communicate memory resident structured data</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvAccessJava/tip/documentation/pvAccessJava.html">pvAccess</a></dt>
|
||||
<dd>pvAccess is a software library for high speed controls network communications,
|
||||
optimized for pvData</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvIOCJava/tip/documentation/pvIOCJava.html">pvIOC</a></dt>
|
||||
<dd>pvIOC is a software framework for building network accessable "smart" real time
|
||||
databases, suitable for interfacing devices in a distributed control system,
|
||||
that can exchange pvData over pvAccess.
|
||||
</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/pvServiceJava/tip/documentation/pvAccessJava.html">pvService</a></dt>
|
||||
<dd>A middle layer for implementing data services.</dd>
|
||||
</dl>
|
||||
|
||||
<p>Each of these products has a Java and a C++ implementation.</p>
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 11-Dec-2012 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>This is the beginning of the implementation of pvDataBaseCPP.
|
||||
It describes the features that will be provided.
|
||||
The class definitions for PVRecord are implemented.
|
||||
The class definition for PVDatabase are defined but not implemented.</p>
|
||||
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
</div>
|
||||
<div id="contents" class="contents">
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava.
|
||||
It extracts the core components required to create a network accessible database of smart
|
||||
memory resident records.
|
||||
pvDatabaseCPP does not and will not implement any of the specialized support that pvIOCJava
|
||||
provides. Instead other projects will implement the specialized support.
|
||||
It is expected that many services will be created that do not require the full features provided
|
||||
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
|
||||
them named pvDatabaseJava.
|
||||
</p>
|
||||
|
||||
<p>A brief description of a pvDatase is that it is a network accessible set of smart memory resident
|
||||
records. Each record has data composed of a top level PVStructure. Each record has a name which is
|
||||
the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and
|
||||
Channel interfaces as defined by pvAccess.
|
||||
This local provider is accessed by the remote pvAccess server.
|
||||
A record is smart because code can be attached to a record.</p>
|
||||
<p>This document describes components that provides the following features:
|
||||
<dl>
|
||||
<dt>database<dt>
|
||||
<dd>This encapsulates the concept of a database of memory resident smart records.
|
||||
The two main components are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>This encapsulates the concept of a smart record. It can be processed.
|
||||
Changes to field values can be trapped. A record can be locked.</dd>
|
||||
<dt>pvDatabase<dt>
|
||||
<dd>This is a database of pvRecords.
|
||||
Records can be added and removed from a database.</dd>
|
||||
</dl>
|
||||
<dt>localChannelProvider</dt>
|
||||
<dd>This is a complete implementation of ChannelProvider and Channel as defined by pvAccess.
|
||||
It is used by the server side of pvAccess to attach to pvRecords.
|
||||
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||
</dl>
|
||||
<p><b>database</b> does not itself implement pvRecord instances.
|
||||
Instead it provides a base classes that make it easy to create record instances.
|
||||
What does have to be implemented is a top
|
||||
level PVStructure and the following two methods:</p>
|
||||
<dl>
|
||||
<dt>process</dt>
|
||||
<dd>This is what makes a record <b>smart</b>.
|
||||
What process does is up to the implementation except that it must decide if
|
||||
it's execution model is synchronous or asynchronous.
|
||||
Synchronous means that when process returns the processing is complete.
|
||||
Asynchronous means that when process returns the processing is <b>not</b> complete.
|
||||
Instead process invokes other threads that will complete the processing at a later time.</dd>
|
||||
<dt>isSynchronous</dt>
|
||||
<dd>Which execution model is being implemented.</dd>
|
||||
</dl>
|
||||
<h3>Example PVRecord Extension</h3>
|
||||
<p>Directory <b>example/record</b> has an example PVRecord implementation.
|
||||
It implements a counter.
|
||||
The top level structure is:</p>
|
||||
<pre>
|
||||
structure
|
||||
long value
|
||||
</pre>
|
||||
<p><b>NOTE:</b> The example compiles but does not build because nothing
|
||||
is implemented.</p>
|
||||
|
||||
<h4>exampleRecord.h</h4>
|
||||
<p>This is the class description.
|
||||
The example extends PVRecord.</p>
|
||||
<pre>
|
||||
class ExampleRecord :
|
||||
public virtual PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleRecord);
|
||||
static PVRecordPtr create(epics::pvData::String const & recordName);
|
||||
virtual ~ExampleRecord();
|
||||
virtual bool isSynchronous();
|
||||
virtual void process(
|
||||
epics::pvDatabase::RecordProcessRequesterPtr const &processRequester);
|
||||
private:
|
||||
ExampleRecord(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
epics::pvData::PVLongPtr const &pvValue);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>This is example specific. See the implemention for details.</dd>
|
||||
<dt>~ExampleRecord<dt>
|
||||
<dd>The destructor must be declared virtual.</dd>
|
||||
<dt>isSynchronous<dt>
|
||||
<dd>The implementation must say if process is synchronous or asynchronous.</dd>
|
||||
<dt>process<dt>
|
||||
<dd><b>The</b> implementation.</dd>
|
||||
<dt>ExampleRecord<dt>
|
||||
<dd>For the example this is private.</dd>
|
||||
<dl>
|
||||
|
||||
<h4>exampleRecord.cpp</h4>
|
||||
<p>This is the class implementation.</p>
|
||||
<pre>
|
||||
ExampleRecord::~ExampleRecord(){}
|
||||
|
||||
PVRecordPtr ExampleRecord::create(String const & recordName)
|
||||
{
|
||||
String properties;
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties);
|
||||
PVLongPtr pvValue = pvStructure->getLongField("value");
|
||||
PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ExampleRecord::ExampleRecord(
|
||||
String const & recordName,
|
||||
PVStructurePtr const & pvStructure,
|
||||
PVLongPtr const &pvValue)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
pvValue(pvValue)
|
||||
{}
|
||||
|
||||
bool ExampleRecord::isSynchronous() {return true;}
|
||||
|
||||
void ExampleRecord::process(
|
||||
RecordProcessRequesterPtr const &processRequester,bool alreadyLocked)
|
||||
{
|
||||
if(!alreadyLocked) lock();
|
||||
pvValue->put(pvValue->get() + 1);
|
||||
processRequester->recordProcessResult(Status::Ok);
|
||||
unlock();
|
||||
processRequester->recordProcessComplete();
|
||||
dequeueProcessRequest(processRequester);
|
||||
}
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>Creates a PVStructure with a single subfield named value.
|
||||
It gets the interface to the value field.
|
||||
It then creates an ExampleRecord and returns it.
|
||||
</dd>
|
||||
<dt>~ExampleRecord<dt>
|
||||
<dd>Does not have to do anything because of shared pointers.</dd>
|
||||
<dt>ExampleRecord<dt>
|
||||
<dd>Calls the base class constructor and sets pvValue.</dd>
|
||||
<dt>isSynchronous<dt>
|
||||
<dd>The example is synchronous.</dd>
|
||||
<dt>process<dt>
|
||||
<dd>Gets the curent value, increments it, and puts the new value.
|
||||
It than calls two processRequester callbacks.</dd>
|
||||
<dl>
|
||||
|
||||
<h4>exampleRecordMain.cpp</h4>
|
||||
<p>This is a main for creating and running the example.</p>
|
||||
<pre>
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
String recordName("exampleRecord");
|
||||
PVRecordPtr pvRecord = ExampleRecord::create(recordName);
|
||||
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
|
||||
pvDatabase->addRecord(pvRecord);
|
||||
cout << recordName << "\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
<p>The main program creates an example record and adds it to the database.
|
||||
It then runs until the process is stopped by typing <b>exit</b>.
|
||||
<p>Until the process is stopped,
|
||||
pvAccess clients can put and get the value field.
|
||||
For example</p>
|
||||
<pre>
|
||||
pvget exampleRecord
|
||||
pvput exampleRecord 5
|
||||
</pre>
|
||||
<p>Will both work.</p>
|
||||
<h3>Phased Development</h3>
|
||||
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
||||
<dl>
|
||||
<dt>pvRecord</d>
|
||||
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
|
||||
<dt>pvDatabase</d>
|
||||
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
||||
<dt>Local Channel Provider</dt>
|
||||
<dd>These two features will be the first phase.
|
||||
But only synchronous record processing will be supported.</dd>
|
||||
</dl>
|
||||
<p>Future phases of pvDatabaseCPP should include:</p>
|
||||
<dl>
|
||||
<dt>Install</dt>
|
||||
<dd>This provides on-line add and delete.</dd>
|
||||
<dt>Field support</dt>
|
||||
<dd>Add ability to optionally add support to fields.
|
||||
In addition some of the basic support defined in pvIOCJava will also be implemented.</dd>
|
||||
<dt>XML parser</dt>
|
||||
<dd>This provides the ability to create record instances without writing any code.</dd>
|
||||
</dl>
|
||||
<p>The completion of each phase provides useful features that can be used without waiting for the
|
||||
completion of later phases.
|
||||
The rest of this document discusses only the first phase.</p>
|
||||
<h3>Features Required for localChannelProvider</h3>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>Creates a PVStructure that contains a copy of an arbitary
|
||||
subset of the fields of another top level PVStructure.
|
||||
It can copy data between the two and maintains a bitSet that show
|
||||
which fields are changed.<dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||
<dt>PVRecord and PVDatabase</dt>
|
||||
<dd>Defined below.</dd>
|
||||
<dt>local ChannelProvider</dt>
|
||||
<dd>This is the pvAccess package in pvIOCJava.
|
||||
The localChannelProvider will access data from PVRecords.
|
||||
It will implement all channel methods except channelRPC.</dd>
|
||||
</dl>
|
||||
<h3>Minumum Features Required for pvRecord</h3>
|
||||
<p>The first phase will only implement record processing, i. e.
|
||||
the process method has to do everything itself without any generic field support.
|
||||
This will be sufficient for starting to implement services.
|
||||
The following are the minimium features required</p>
|
||||
<dl>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This, and a set of related interfaces, provide the following:
|
||||
<dl>
|
||||
<dt>PVStructure</dt>
|
||||
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
||||
<dt>Record locking</dt>
|
||||
<dd>A record can be locked and unlocked.
|
||||
A record must be locked whenever data in the pvStructure is accessed.</dd>
|
||||
<dt>Trapping data changes</dt>
|
||||
<dd>A client can request to be notified when data in the pvStructure is modified.
|
||||
It can do this on a field by field basis.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The following sections provide a first attempt to describe the classes required for the first
|
||||
phase.</p>
|
||||
<p>The last section gives a brief overview of the features provided by pvIOCJava.</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<p>The classes in <b>pvDatabase.h</b> implement a database of memory resident
|
||||
smart records.
|
||||
It describes the following classes:</p>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
|
||||
<dt>PVRecordField</dt>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>These <b>wrap</b> PVField and PVStructure so that pvCopy and monitor
|
||||
can be implemented.</dd>
|
||||
<dt>PVRecordClient</dt>
|
||||
<dd>This is called by anything that acceses PVRecord.</dd>
|
||||
<dt>PVListener</dt>
|
||||
<dd>This is implemented by anything that wants to trap calls to the PVRecord::message.</dd>
|
||||
<dt>RecordProcessRequester</dt>
|
||||
<dd>This is implemented by anything that calls PVRecord::queueProcessRequest.</dd>
|
||||
<dt>RecordPutRequester</dt>
|
||||
<dd>This is implemented by anything that calls PVRecord::queuePutRequest.</dd>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This is a database of PVRecords.</dd>
|
||||
</dl>
|
||||
<p>Each class is described in a separate subsection.</p>
|
||||
<h3>C++ namespace and typedefs</h3>
|
||||
<pre>
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVRecord;
|
||||
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
||||
|
||||
class PVRecordField;
|
||||
typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
|
||||
typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray;
|
||||
typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr;
|
||||
|
||||
class PVRecordStructure;
|
||||
typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr;
|
||||
|
||||
class PVRecordClient;
|
||||
typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
|
||||
|
||||
class PVListener;
|
||||
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
||||
|
||||
class RecordProcessRequester;
|
||||
typedef std::tr1::shared_ptr<RecordProcessRequester> RecordProcessRequesterPtr;
|
||||
|
||||
class RecordPutRequester;
|
||||
typedef std::tr1::shared_ptr<RecordPutRequester> RecordPutRequesterPtr;
|
||||
|
||||
class PVDatabase;
|
||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
</pre>
|
||||
|
||||
<h3>class PVRecord</h3>
|
||||
<p><b>NOTES:</b>
|
||||
<ul>
|
||||
<li>This section uses the name record instead of "an instance of PVRecord".</li>
|
||||
<li>Most clients will access a record via the local channel provider,
|
||||
i. e. via pvAccess.
|
||||
Thus this section is mainly of interest to
|
||||
the local channel provider and record implementers.</li>
|
||||
</ul>
|
||||
<hr>PVRecord Methods</h4>
|
||||
<pre>
|
||||
class PVRecord
|
||||
public epics::pvData::Requester,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
PVRecord(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PVRecord();
|
||||
virtual void process(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester,
|
||||
bool alreadyLocked) = 0;
|
||||
virtual bool isSynchronous() = 0;
|
||||
virtual bool requestImmediatePut(epics::pvData::PVFieldPtr const &pvField);
|
||||
virtual void immediatePutDone();
|
||||
virtual void destroy();
|
||||
epics::pvData::String getRecordName();
|
||||
PVRecordStructurePtr getPVRecordStructure();
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||
void addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void detachClients();
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
void queueProcessRequest(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester);
|
||||
void dequeueProcessRequest(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester);
|
||||
void queuePutRequest(
|
||||
RecordPutRequesterPtr const &recordPutRequester);
|
||||
void putDone(
|
||||
RecordPutRequesterPtr const &recordPutRequester);
|
||||
virtual epics::pvData::String getRequesterName();
|
||||
void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void message(
|
||||
PVRecordFieldPtr const & pvRecordField,
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void toString(epics::pvData::StringBuilder buf);
|
||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||
//init MUST be called after derived class is constructed
|
||||
void init();
|
||||
|
||||
};
|
||||
</pre>
|
||||
<p>The methods are:</h3>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The destructor which must be virtual. A derived class must also have
|
||||
a virtual destructor.</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Pure virtual method.
|
||||
<p>Derived classes must implement this method.</p>
|
||||
<p>A client <b>must</b> only call this method when
|
||||
<b>RecordProcessRequester::becomeProcessor</b> is called as a result
|
||||
of a <b>queueProcessRequest</b>.
|
||||
A client can either call lock before calling processs
|
||||
or let process lock the record.
|
||||
If a client wants to put data into the record it should lock, put, and then call
|
||||
process.</p>
|
||||
<p>If the record is synchronous, process will return only when all processing
|
||||
is complete. If the record is asynchronous then process arranges for some
|
||||
other thread to do the processing and returns.</p>
|
||||
<p>When processing is done the record calls two client callbacks:</p>
|
||||
<dl>
|
||||
<dt>RecordProcessRequester::recordProcessResult</dt>
|
||||
<dd>This is called with the record still locked.
|
||||
The clients can get data from the record.</dd>
|
||||
<dt>RecordProcessRequester::recordProcessComplete</dt>
|
||||
<dd>This is called with the record unlocked.
|
||||
The client can no longer access the record.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>isSynchronous</dt>
|
||||
<dd>Pure virtual method. Derived classes must implement this method.</dd>
|
||||
<dt>requestImmediatePut</dt>
|
||||
<dd>This is a virtual method.
|
||||
<p> The purpose is to allow the implementation to provide fields
|
||||
that allow a client to abort process.
|
||||
For example a motor record might provide a field <b>stop</b></p>
|
||||
<p>The default always returns <b>false</b>.</p>
|
||||
<p>A record implementation can override the default and return <b>true</b>.
|
||||
In it does requestImmediatePut it returns with the record locked.</p>
|
||||
<p>The client can change the value of the associated field and then call
|
||||
<b>immediatePutDone</b></p>
|
||||
</dd>
|
||||
<dt>immediatePutDone</dt>
|
||||
<dd>This is a virtual method.
|
||||
<p>The default does nothing.</p>
|
||||
<p>Must be called by client as a result of a call to <b>requestImmediatePut</b>
|
||||
that returns <b>true</b>.</p>
|
||||
</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is a virtual method.
|
||||
<p>The default does nothing.</p>
|
||||
</dd>
|
||||
<dt>getRecordName</dt>
|
||||
<dd>Return the recordName.</dd>
|
||||
<dt>getPVRecordStructure</dt>
|
||||
<dd>Get the top level PVStructure.</dd>
|
||||
<dt>findPVRecordField</dt>
|
||||
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
|
||||
<dt>addRequester</dt>
|
||||
<dd>Add a requester to receive messages.</dd>
|
||||
<dt>removeRequester</dt>
|
||||
<dd>Remove a message requester.</dd>
|
||||
<dt>lock</dt>
|
||||
<dt>unlock</dt>
|
||||
<dd>Lock and Unlock the record.
|
||||
Any code accessing the data in the record or calling other PVRecord methods
|
||||
must have the record locked.</dd>
|
||||
<dt>tryLock</dt>
|
||||
<dd>If <b>true</b> then just like <b>lock</b>.
|
||||
If <b>false</b>client can not access record.
|
||||
A client can try to simultaneously hold the lock for more than two records
|
||||
by calling this method. But must be willing to accept failure.
|
||||
</dd>
|
||||
<dt>lockOtherRecord</dt>
|
||||
<dd>A client that holds the lock for one record can lock one other record.
|
||||
A client <b>must</b> not call this if the client already has the lock for
|
||||
more then one record.
|
||||
</dd>
|
||||
<dt>addPVRecordClient</dt>
|
||||
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
|
||||
<dt>removePVRecordClient</dt>
|
||||
<dd>Client is no longer accessing the record.</dd>
|
||||
<dt>detachClients</dt>
|
||||
<dd>Ask all clients to detach from the record</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>Begin a group of puts.
|
||||
This results in all registered PVListeners being called</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>End a group of puts.
|
||||
This results in all registered PVListeners being called.</dd>
|
||||
<dt>queueProcessRequest</dt>
|
||||
<dd>Queue a process request.</dd>
|
||||
<dt>dequeueProcessRequest</dt>
|
||||
<dd>This <b>must</b> be called by record implementation after it has
|
||||
completed a process request.
|
||||
</dd>
|
||||
<dt>queuePutRequest</dt>
|
||||
<dd>Queue a put request.
|
||||
<p>This is for code that wants to change data in a record without processing.
|
||||
If <b>RecordPutRequester::requestResult</b> is called with result <b>true</b>
|
||||
then the record is locked and the client can make changes.
|
||||
When done the client <b>must</b> call <b>putDone</b></p>
|
||||
</dd>
|
||||
<dt>putDone</dt>
|
||||
<dd>Called by <b>RecordPutRequester</b> after changing values in record.
|
||||
This method unlocks the record</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>virtual method of <b>Requester</b>
|
||||
</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
<dt>init</dt>
|
||||
<dd>This method <b>must</b> be called by derived class
|
||||
<b>after</b> class is completely constructed.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordField</h3>
|
||||
<pre>
|
||||
class PVRecordField {
|
||||
public virtual epics::pvData::PostHandler,
|
||||
public std::tr1::enable_shared_from_this<PVRecordField>
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordField);
|
||||
PVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField,
|
||||
PVRecordStructurePtr const &parent,
|
||||
PVRecordPtr const & pvRecord);
|
||||
virtual ~PVRecordField();
|
||||
PVRecordStructurePtr getParent();
|
||||
epics::pvData::PVFieldPtr getPVField();
|
||||
epics::pvData::String getFullFieldName();
|
||||
epics::pvData::String getFullName();
|
||||
PVRecordPtr getPVRecord();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>PVRecordField</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordField</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getParent</dt>
|
||||
<dd>Get the parent PVRecordStructure for this field.</dd>
|
||||
<dt>getPVField</dt>
|
||||
<dd>Get the PVField associated with this PVRecordField.</dd>
|
||||
<dt>getFullFieldName</dt>
|
||||
<dd>This gets the full name of the field, i.e. field,field,..</dd>
|
||||
<dt>getFullName</dt>
|
||||
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
|
||||
<dt>getPVRecord</dt>
|
||||
<dd>Returns the PVRecord to which this field belongs.</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add A PVListener to this field.
|
||||
Whenever this field or any subfield if this field is modified the listener will be notified.
|
||||
PVListener is described below.
|
||||
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordStructure</h3>
|
||||
<pre>
|
||||
class PVRecordStructure : public PVRecordField {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordStructure);
|
||||
PVRecordStructure(
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
PVRecordFieldPtrArrayPtr const & pvRecordField);
|
||||
virtual ~PVRecordStructure();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
<dl>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordStructure</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getPVRecordFields</dt>
|
||||
<dd>Get the PVRecordField array for the subfields</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Get the PVStructure for this field.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<h3>class PVRecordClient</h3>
|
||||
<pre>
|
||||
class PVRecordClient {
|
||||
POINTER_DEFINITIONS(PVRecordClient);
|
||||
virtual ~PVRecordClient();
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVRecordClient</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>detach</dt>
|
||||
<dd>The record is being removed from the master database,</dd>
|
||||
</dl>
|
||||
</dl>
|
||||
<h3>class PVListener</h3>
|
||||
<pre>
|
||||
class PVListener {
|
||||
virtual public PVRecordClient
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVListener);
|
||||
virtual ~PVListener();
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVListener</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>dataPut(PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
|
||||
<dt>dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
Requested is the field to which the requester issued a pvField-&addListener.
|
||||
This is called if the listener has called PVRecordField-&addListener for requested.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>A related set of changes is being started.</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>A related set of changes is done.</dd>
|
||||
</dl>
|
||||
<h3>class RecordProcessRequester</h3>
|
||||
<pre>
|
||||
class RecordProcessRequester :
|
||||
virtual public PVRecordClient,
|
||||
virtual public epics::pvData::Requester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(RecordProcessRequester);
|
||||
virtual ~RecordProcessRequester();
|
||||
virtual void recordDestroyed() = 0;
|
||||
virtual void becomeProcessor() = 0;
|
||||
virtual void recordProcessResult(epics::pvData::Status status) = 0;
|
||||
virtual void recordProcessComplete() = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~RecordProcessRequester</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>recordDestroyed</dt>
|
||||
<dd>Record is being destroyed.</dd>
|
||||
<dt>becomeProcessor</dt>
|
||||
<dd>Called as a result of queueRequeProcessst. The requester can the call process.</dd>
|
||||
<dt>recordProcessResult</dt>
|
||||
<dd>The results of record processing.
|
||||
This is called with the record locked so that the process requester
|
||||
can access data from the record.</dd>
|
||||
<dt>recordProcessComplete</dt>
|
||||
<dd>Processing is complete.
|
||||
This is called with the record unlocked.
|
||||
If the process requester called process with leaveActive true then the requester
|
||||
must call setInactive.</dd>
|
||||
</dl>
|
||||
<h3>class RecordPutRequester</h3>
|
||||
<pre>
|
||||
class RecordPutRequester :
|
||||
virtual public PVRecordClient
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(RecordPutRequester);
|
||||
virtual ~RecordPutRequester();
|
||||
virtual void requestResult(bool result) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~RecordPutRequester</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>requestResult</dt>
|
||||
<dd>Result of a call to queuePutRequest. If <b>requestResult</b> is <b>false</b>
|
||||
then the caller can not access the record.
|
||||
If <b>requestResult</b> is <b>true</b>
|
||||
then the record is locked and the caller can get and put data in the record.
|
||||
When done the caller must call <b>PVRecord::putDone</b>, which will unlock the
|
||||
record.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>class PVDatabase</h3>
|
||||
<pre>
|
||||
class PVDatabase : virtual public epics::pvData::Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDatabase);
|
||||
static PVDatabasePtr getMaster();
|
||||
virtual ~PVDatabase();
|
||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
private:
|
||||
PVDatabase();
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>getMaster</dt>
|
||||
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
|
||||
<dt>~PVDatabase</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>findRecord</dt>
|
||||
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
|
||||
<dt>addRecord</dt>
|
||||
<dd>Add a record to the database.
|
||||
If the record already exists it is not modified and false is returned.</dd>
|
||||
<dt>removeRecord</dt>
|
||||
<dd>Remove a record from the database.
|
||||
If the record was not in the database false is returned.</dd>
|
||||
</dl>
|
||||
<h2>Local Channel Provider</h2>
|
||||
<p>Not yet described.</p>
|
||||
<p>A brief description is that it must implement the following components of pvIOCJava:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dt>monitor</dt>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>See the next section for a description</dd>
|
||||
</dl>
|
||||
<h2>Summary of Packages in pvIOCJAVA</h2>
|
||||
<p>The following are the direct sub packages of <b>pvIOCJava/src/org/epics/pvioc</b>:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>This provides a copy of an arbitrary subset of the fields in a PVRecord.
|
||||
It also provides the ability to detect and report changes to fields.
|
||||
It is required for pvAccess.</dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to a PVRecord. It is required for pvAccess monitors.</dd>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>The local implementation of Channel Provider and Channel.
|
||||
It is accessed by the remote pvAccess server and can also be accessed by code in the same IOC.</dd>
|
||||
<dt>database</dt>
|
||||
<dd>This defines and implements PVRecord, PVDatabase , and PVListener.
|
||||
It supports the basic feature required the implement a local Channel Provider.</dd>
|
||||
<dt>support</dt>
|
||||
<dd>This provides the ability to optionally attach code to any field of a pvRecord.
|
||||
It and several sub packages provide a set of standard support modules.</dd>
|
||||
<dt>install</dt>
|
||||
<dd>This provides the ability to dynamically initialize and add new PVRecords. It also provides
|
||||
the ability to dynamicall delete PVRecords.</d>
|
||||
<dt>xml</dt>
|
||||
<dd>This provides the ability to configure record instances without writing code.</dd>
|
||||
<dt>util</dt>
|
||||
<dd>This is misnamed since it is code related to scanning.</dd>
|
||||
<dt>pdrv</dt>
|
||||
<dd>This is portDriver, which is a proposed sucessor to the asynManager component of asynDriver.</dd>
|
||||
<dt>swtshell</dt>
|
||||
<dd>This is shell that is can either run under the same process as a JavaIOC or as a remote shell.
|
||||
It is like a version of probe but for pvData/pvAccess.
|
||||
Almost all of it's features work in either local or remote mode.
|
||||
With a little more work all or it's features could work remotely.
|
||||
This should be done and then only remote mode should be supported.
|
||||
It can then be rewritten in a completely different language and using a complely different GUI
|
||||
framework.
|
||||
</dd>
|
||||
<dt>caV3</dt>
|
||||
<dd>This has two components:
|
||||
<dl>
|
||||
<dt>ClientFactory</dt>
|
||||
<dd>This is a small wrapper on top of the caV3 client support implemented by pvAccess.
|
||||
It allows code in the pvIOC to access V3Records via pvAccess.</dd>
|
||||
<dt>ServerFactory</dt>
|
||||
<dd>This is a caV3 server that allows a caV3 client to access a PVRecord.
|
||||
The Java implementation uses CAJ, which does most of the work.
|
||||
For now it will not be discussed in this document.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>v3a</dt>
|
||||
<dd>I do not know what this is.</dd>
|
||||
</dl>
|
||||
<p>In addition there is one class file <b>JavaIOC.java</b>.
|
||||
This is starting a IOC instance.
|
||||
This is not required for pvIOCCPP which is either a main or runs as part of a V3 IOC.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,865 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>pvDatabaseCPP</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
||||
<style type="text/css">
|
||||
/*<![CDATA[*/
|
||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||
table { margin-left: auto; margin-right: auto }
|
||||
.diagram { text-align: center; margin: 2.5em 0 }
|
||||
span.opt { color: grey }
|
||||
span.nterm { font-style:italic }
|
||||
span.term { font-family:courier }
|
||||
span.user { font-family:courier }
|
||||
span.user:before { content:"<" }
|
||||
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>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 17-Apr-2013</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
</dl>
|
||||
|
||||
<p class="copyright">This product is made available subject to acceptance of the <a
|
||||
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
|
||||
<p>This document describes pvDatabaseCPP,
|
||||
which is a framework for implementing a network accessable database of smart memory resident
|
||||
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.
|
||||
The framework can be extended in order to create record instances that implements services.
|
||||
The minimum that an extenson must provide is a top level PVStructure and a process method.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 17-Apr-2013 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>The following Channel methods are implemented and working: getField,i
|
||||
channelProcess, channelGet, channelPut, and channelPutGet.
|
||||
But lots of work remains:</p>
|
||||
<dl>
|
||||
<dt>Other Channel Methods</dt>
|
||||
<dd>Monitor is next.</dd>
|
||||
<dt>Memory leaks at exit</dt>
|
||||
<dd>May need help from Matej.</dd>
|
||||
<dt>Scalar Arrays</dt>
|
||||
<dd>Have not been tested. Share has not been implemented.</dd>
|
||||
<dt>Structure Arrays</dt>
|
||||
<dd>Has not been implemented</dd>
|
||||
<dt>Testing</dt>
|
||||
<dd>Needs lots more testing</dd>
|
||||
</dl>
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
</div>
|
||||
<div id="contents" class="contents">
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>A brief description of a pvDatabase is that it is a set of network accessible, smart,
|
||||
memory resident records.
|
||||
Each record has data composed of a top level PVStructure.
|
||||
Each record has a name which is the channelName for pvAccess.
|
||||
A local Channel Provider implements the complete ChannelProvider and
|
||||
Channel interfaces as defined by pvAccess.
|
||||
The local provider provides access to the records in the pvDatabase.
|
||||
This local provider is accessed by the remote pvAccess server.
|
||||
A record is smart because code can be attached to a record, which is accessed via a method named process.</p>
|
||||
|
||||
<p>This document describes components that provides the following features:
|
||||
<dl>
|
||||
<dt>database<dt>
|
||||
<dd>This encapsulates the concept of a database of memory resident smart records.
|
||||
The two main components are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>This encapsulates the concept of a smart record. It can be processed.
|
||||
Changes to field values can be trapped. A record can be locked.</dd>
|
||||
<dt>pvDatabase<dt>
|
||||
<dd>This is a database of pvRecords.
|
||||
Records can be added and removed from a database.</dd>
|
||||
</dl>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>This is a complete implementation of ChannelProvider and Channel
|
||||
as defined by pvAccess.
|
||||
It is used by the server side of pvAccess to attach to pvRecords.
|
||||
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||
</dl>
|
||||
<p>database provides base classes that make it easy to create record instances.
|
||||
The code attached to each record must create the top
|
||||
level PVStructure and the following two methods:</p>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>This is a method for initializing the support.
|
||||
It returns true if successful and false otherwise.
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>This is what makes a record smart.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Relationship with pvIOCJava.</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
|
||||
which also implements a pvDatabase.
|
||||
PVDatabaseCPP extracts the core components required to create a network accessible database of smart
|
||||
memory resident records.
|
||||
pvDatabaseCPP does not implement any of the specialized support that pvIOCJava
|
||||
provides.
|
||||
It is expected that many services will be created that do not require the full features provided
|
||||
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
|
||||
them named pvDatabaseJava.</p>
|
||||
<p>Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing.
|
||||
For pvDatabaseCPP the process method is allowed to block.
|
||||
Until a need is demonstrated this will remain true.
|
||||
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
|
||||
The server side of remote pvAccess creates two threads for each client and always accesses
|
||||
a record via these threads.
|
||||
It is expected that these threads will be sufficient to efficently handle all channel methods except
|
||||
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
|
||||
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
|
||||
then the scanning facility will have to provide some way of handling process requests that block.</p>
|
||||
</p>
|
||||
<h3>Example PVRecord Extension</h3>
|
||||
<p>The example implements a simple counter.
|
||||
The example can be run on linux as follows:</p>
|
||||
<pre>
|
||||
mrk> pwd
|
||||
/home/hg/pvDatabaseCPP
|
||||
mrk> bin/linux-x86_64/exampleCounter
|
||||
|
||||
</pre>
|
||||
<p>The example consists of two components:</p>
|
||||
<dl>
|
||||
<dt>ExampleCounter.h</dt>
|
||||
<dd>The source code for the counter.</dd>
|
||||
<dt>exampleCounterMain.cpp</dt>
|
||||
<dd>A main program that runs the example so that it can be accessed
|
||||
by a pvAccess client.</dd>
|
||||
</dl>
|
||||
<h4>ExampleCounter.h</h4>
|
||||
<p>The example resides in src/database.
|
||||
The complete implementation is in the header file.
|
||||
A serious implementation would probably break the code into two files:
|
||||
1) a header, and 2) the implementation. The description consists of</p>
|
||||
<pre>
|
||||
class ExampleCounter;
|
||||
typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
|
||||
|
||||
class ExampleCounter :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleCounter);
|
||||
static ExampleCounterPtr create(
|
||||
epics::pvData::String const & recordName);
|
||||
virtual ~ExampleCounter();
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
private:
|
||||
ExampleCounter(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>This is example specific but each support could provide
|
||||
a similar static method.
|
||||
</dd>
|
||||
<dt>~ExampleCounter<dt>
|
||||
<dd>The destructor must be declared virtual.</dd>
|
||||
<dt><destroy</dt>
|
||||
<dd>Called when the record is being destroyed.
|
||||
This must call the base class destroy method.
|
||||
<dt>init<dt>
|
||||
<dd>A method to initialize the support. It returns true
|
||||
if initialization is successful and false if not.
|
||||
NOTE that this is a virtual method of PVRecord itself.</dd>
|
||||
<dt>process<dt>
|
||||
<dd>
|
||||
This again is a virtual method of PVRecord.
|
||||
</dd>
|
||||
<dt>ExampleCounter<dt>
|
||||
<dd>For the example this is private.</dd>
|
||||
<dt>pvValue</dt>
|
||||
<dd>This is the field of the top level structure that process
|
||||
accesses.
|
||||
</dd>
|
||||
<dl>
|
||||
<p>The implementation of create method is:</p>
|
||||
<pre>
|
||||
ExampleCounterPtr ExampleCounter::create(
|
||||
epics::pvData::String const & recordName)
|
||||
{
|
||||
epics::pvData::PVStructurePtr pvStructure =
|
||||
epics::pvData::getStandardPVField()->scalar(
|
||||
epics::pvData::pvDouble,"timeStamp,alarm"");
|
||||
ExampleCounterPtr pvRecord(
|
||||
new ExampleCounter(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Creates the top level structure.</li>
|
||||
<li>Creates a ExampleCounterPtr via the constructor.</li>
|
||||
<li>Calls init and if it fails resets the shared pointer.</li>
|
||||
<li>Returns the shared pointer to the newly created record.</li>
|
||||
</ul>
|
||||
<p>The private constructor method is:</p>
|
||||
<pre>
|
||||
ExampleCounter::ExampleCounter(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
}
|
||||
</pre>
|
||||
The example is very simple. It just calls the base class constructor.
|
||||
<p>The destructor and destroy methods are:</p>
|
||||
<pre>
|
||||
ExampleCounter::~ExampleCounter()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void ExampleCounter::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
</pre>
|
||||
The destructor just calls destroy.
|
||||
The destroy method, which is virtual, just calls the destroy method of the base class.
|
||||
A more complicated example can clean up any resources it used but must call the base
|
||||
class destroy method.
|
||||
<p>The implementation of init is:</p>
|
||||
<pre>
|
||||
bool ExampleCounter::init()
|
||||
{
|
||||
|
||||
initPVRecord();
|
||||
epics::pvData::PVFieldPtr pvField;
|
||||
pvValue = getPVStructure()->getLongField("value");
|
||||
if(pvValue.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Calls initRecord which is implemented by the base class.
|
||||
It MUST be called.</li>
|
||||
<li>Calls getLongField to get the interface to the value field,
|
||||
which must be a scalar with type long.</li>
|
||||
<li>If a long value field was not found it returns false.</li>
|
||||
<li>Returns true</li>
|
||||
</ul>
|
||||
<p>The implementation of process is:</p>
|
||||
<pre>
|
||||
void ExampleCounter::process()
|
||||
{
|
||||
pvValue->put(pvValue->get() + 1.0);
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
</pre>
|
||||
It adds 1.0 to the current value.
|
||||
It then sets the timeStamp to the current time.
|
||||
<h4>exampleCounterMain.cpp</h4>
|
||||
<p>This is in test/server.
|
||||
The main program is:</p>
|
||||
<pre>
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||
String recordName("exampleCounter");
|
||||
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
pvRecord.reset();
|
||||
cout << "exampleServer\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Gets a pointer to the master database.</li>
|
||||
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||
<li>Creates a ExampleCounter record with the name exampleCounter
|
||||
</li>
|
||||
<li>Prints exampleCounter on standard out.</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
<h3>Phased Development</h3>
|
||||
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
||||
<dl>
|
||||
<dt>pvRecord</d>
|
||||
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
|
||||
<dt>pvDatabase</d>
|
||||
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
||||
<dt>Local Channel Provider</dt>
|
||||
<dd>Complete implementation of ChannelProvider and Channel.
|
||||
This means that pvCopy and monitor are also implemented.</dd>
|
||||
</dl>
|
||||
<p>Future phases of pvDatabaseCPP might include:</p>
|
||||
<dl>
|
||||
<dt>Install</dt>
|
||||
<dd>This provides complete support for on-line add and delete
|
||||
of sets of records.
|
||||
With the first phase each "service" is responsible for it's own implementation.
|
||||
All that is provided is addRecord and removeRecord.
|
||||
</dd>
|
||||
<dt>Field support</dt>
|
||||
<dd>Add the ability to optionally add support to fields.
|
||||
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
|
||||
<dt>XML parser</dt>
|
||||
<dd>This provides the ability to create record instances without writing any code.</dd>
|
||||
</dl>
|
||||
<p>The completion of each phase provides useful features that can be used without waiting for the
|
||||
completion of later phases.
|
||||
The rest of this document discusses only the first phase.</p>
|
||||
<h3>Features Required for localChannelProvider</h3>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>Creates a PVStructure that contains a copy of an arbitary
|
||||
subset of the fields of another top level PVStructure.
|
||||
It can copy data between the two and maintains a bitSet that show
|
||||
which fields are changed.<dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||
<dt>PVRecord and PVDatabase</dt>
|
||||
<dd>Defined below.</dd>
|
||||
<dt>The localChannelProvider itself</dt>
|
||||
<dd>This is the pvAccess package in pvIOCJava.
|
||||
The localChannelProvider will access data from PVRecords.
|
||||
It will implement all channel methods.</dd>
|
||||
</dl>
|
||||
<h3>Minumum Features Required for pvRecord</h3>
|
||||
<p>The first phase will only implement record processing, i. e.
|
||||
the process method has to do everything itself without any generic field support.
|
||||
This will be sufficient for starting to implement services.
|
||||
The following are the minimium features required</p>
|
||||
<dl>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This, and a set of related interfaces, provides the following:
|
||||
<dl>
|
||||
<dt>Access to top level PVStructure</dt>
|
||||
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
||||
<dt>Record locking</dt>
|
||||
<dd>A record can be locked and unlocked.
|
||||
A record must be locked whenever data in the pvStructure is accessed.</dd>
|
||||
<dt>Trapping data changes</dt>
|
||||
<dd>A client can request to be notified when data in the pvStructure is modified.
|
||||
It can do this on a field by field basis.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The following sections describes the classes required for the first phase.</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<p>This directory has the following files:</p>
|
||||
<dl>
|
||||
<dt>pvDatabase.h</dt>
|
||||
<dd>
|
||||
This is what is described in this section.
|
||||
</dd>
|
||||
<dt>pvDatabase.cpp</dt>
|
||||
<dd>
|
||||
The implementation of PVDatabase.
|
||||
</dd>
|
||||
<dt>pvRecord.cpp</dt>
|
||||
<dd>
|
||||
The implementation of the base class for PVREcord.
|
||||
It can also implement record instances with a process
|
||||
method does nothing.
|
||||
This can be used to create a "dumb" record where all changes are
|
||||
done by clients.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
<dt>exampleCounter.h</dt>
|
||||
<dd>
|
||||
This was described in the introduction.
|
||||
</dd>
|
||||
<dt>powerSupplyRecordTest.h</dt>
|
||||
<dd>
|
||||
This provides code that simulates a power supply.
|
||||
It computes the current from the voltage and power.
|
||||
It is used for testing.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The classes in pvDatabase.h describe a database of memory resident
|
||||
smart records.
|
||||
It describes the following classes:</p>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
|
||||
<dt>PVRecordField</dt>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
|
||||
can be implemented.</dd>
|
||||
<dt>PVRecordClient</dt>
|
||||
<dd>This is called by anything that acceses PVRecord.</dd>
|
||||
<dt>PVListener</dt>
|
||||
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This is a database of PVRecords.</dd>
|
||||
</dl>
|
||||
<p>Each class is described in a separate subsection.</p>
|
||||
<h3>C++ namespace and typedefs</h3>
|
||||
<pre>
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVRecord;
|
||||
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
||||
typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap;
|
||||
|
||||
class PVRecordField;
|
||||
typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
|
||||
typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray;
|
||||
typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr;
|
||||
|
||||
class PVRecordStructure;
|
||||
typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr;
|
||||
|
||||
class PVRecordClient;
|
||||
typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
|
||||
|
||||
class PVListener;
|
||||
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
||||
|
||||
class RecordProcessRequester;
|
||||
typedef std::tr1::shared_ptr<RecordProcessRequester> RecordProcessRequesterPtr;
|
||||
|
||||
class RecordPutRequester;
|
||||
typedef std::tr1::shared_ptr<RecordPutRequester> RecordPutRequesterPtr;
|
||||
|
||||
class PVDatabase;
|
||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
</pre>
|
||||
|
||||
<h3>class PVRecord</h3>
|
||||
<p>NOTES:
|
||||
<ul>
|
||||
<li>This section uses the name record instead of "an instance of PVRecord".</li>
|
||||
<li>Most clients will access a record via the local channel provider,
|
||||
i. e. via pvAccess.
|
||||
Thus this section is mainly of interest to
|
||||
the local channel provider and record implementers.</li>
|
||||
<li>Most readers will not care about most of the PVRecord methods.
|
||||
Most of the methods are used by the pvAccess code.
|
||||
Service implementers will mostly be interested in methods init and process.
|
||||
These are described first.
|
||||
</ul>
|
||||
<hr>PVRecord Methods</h4>
|
||||
<pre>
|
||||
class PVRecord
|
||||
public epics::pvData::Requester,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
|
||||
virtual bool init() {initPVRecord(); return true;}
|
||||
virtual void process() {}
|
||||
|
||||
static PVRecordPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PVRecord();
|
||||
virtual void destroy();
|
||||
epics::pvData::String getRecordName();
|
||||
PVRecordStructurePtr getPVRecordStructure();
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void detachClients();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
bool removeListener(PVListenerPtr const & pvListener);
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
epics::pvData::String getRequesterName() {return getRecordName();}
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void message(
|
||||
PVRecordFieldPtr const & pvRecordField,
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void toString(epics::pvData::StringBuilder buf);
|
||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||
protected:
|
||||
PVRecord(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
void initPVRecord();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
PVRecordPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
private:
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
<p>The methods are:</h3>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
This method Must call initPVRecord.</p>
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
The base implementation does nothing.</p>
|
||||
</dd>
|
||||
<dt>create</dt>
|
||||
<dd>Static method to create dumb records, i.e. records with a process method
|
||||
that does nothing.</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The destructor which must be virtual. A derived class must also have
|
||||
a virtual destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is a virtual method.
|
||||
</dd>
|
||||
<dt>getRecordName</dt>
|
||||
<dd>Return the recordName.</dd>
|
||||
<dt>getPVRecordStructure</dt>
|
||||
<dd>Get the top level PVStructure.</dd>
|
||||
<dt>findPVRecordField</dt>
|
||||
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
|
||||
<dt>addRequester</dt>
|
||||
<dd>Add a requester to receive messages.</dd>
|
||||
<dt>removeRequester</dt>
|
||||
<dd>Remove a message requester.</dd>
|
||||
<dt>lock_guard</dt>
|
||||
<dd>This is an inline method that locks the record. The record will automatically
|
||||
be unlocked when control leaves the block that has the call.
|
||||
<dt>lock</dt>
|
||||
<dt>unlock</dt>
|
||||
<dd>Lock and Unlock the record.
|
||||
Any code accessing the data in the record or calling other PVRecord methods
|
||||
must have the record locked.</dd>
|
||||
<dt>tryLock</dt>
|
||||
<dd>If true then just like lock.
|
||||
If falseclient can not access record.
|
||||
A client can try to simultaneously hold the lock for more than two records
|
||||
by calling this method. But must be willing to accept failure.
|
||||
</dd>
|
||||
<dt>lockOtherRecord</dt>
|
||||
<dd>A client that holds the lock for one record can lock one other record.
|
||||
A client must not call this if the client already has the lock for
|
||||
more then one record.
|
||||
</dd>
|
||||
<dt>addPVRecordClient</dt>
|
||||
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
|
||||
<dt>removePVRecordClient</dt>
|
||||
<dd>Client is no longer accessing the record.</dd>
|
||||
<dt>detachClients</dt>
|
||||
<dd>Ask all clients to detach from the record</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>Begin a group of puts.
|
||||
This results in all registered PVListeners being called</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>End a group of puts.
|
||||
This results in all registered PVListeners being called.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>virtual method of Requester
|
||||
</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
<dt>toString</dt>
|
||||
<dd>Just calls the top level PVStructure toString method.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||
<dt>initPVRecord</dt>
|
||||
<dd>This method must be called by derived class.</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Called by derived class.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordField</h3>
|
||||
<pre>
|
||||
class PVRecordField {
|
||||
public virtual epics::pvData::PostHandler,
|
||||
public std::tr1::enable_shared_from_this<PVRecordField>
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordField);
|
||||
PVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField,
|
||||
PVRecordStructurePtr const &parent,
|
||||
PVRecordPtr const & pvRecord);
|
||||
virtual ~PVRecordField();
|
||||
virtual void destroy();
|
||||
PVRecordStructurePtr getParent();
|
||||
epics::pvData::PVFieldPtr getPVField();
|
||||
epics::pvData::String getFullFieldName();
|
||||
epics::pvData::String getFullName();
|
||||
PVRecordPtr getPVRecord();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
protected:
|
||||
PVRecordFieldPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>PVRecordField</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordField</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>Called by PVRecordStructure when it's destroy method is called.</dd>
|
||||
<dt>getParent</dt>
|
||||
<dd>Get the parent PVRecordStructure for this field.</dd>
|
||||
<dt>getPVField</dt>
|
||||
<dd>Get the PVField associated with this PVRecordField.</dd>
|
||||
<dt>getFullFieldName</dt>
|
||||
<dd>This gets the full name of the field, i.e. field,field,..</dd>
|
||||
<dt>getFullName</dt>
|
||||
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
|
||||
<dt>getPVRecord</dt>
|
||||
<dd>Returns the PVRecord to which this field belongs.</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add A PVListener to this field.
|
||||
Whenever this field or any subfield if this field is modified the listener will be notified.
|
||||
PVListener is described below.
|
||||
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordStructure</h3>
|
||||
<pre>
|
||||
class PVRecordStructure : public PVRecordField {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordStructure);
|
||||
PVRecordStructure(
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
PVRecordFieldPtrArrayPtr const & pvRecordField);
|
||||
virtual ~PVRecordStructure();
|
||||
virtual void destroy();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
protected:
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
<dl>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordStructure</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getPVRecordFields</dt>
|
||||
<dd>Get the PVRecordField array for the subfields</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Get the PVStructure for this field.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<h3>class PVRecordClient</h3>
|
||||
<pre>
|
||||
class PVRecordClient {
|
||||
POINTER_DEFINITIONS(PVRecordClient);
|
||||
virtual ~PVRecordClient();
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVRecordClient</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>detach</dt>
|
||||
<dd>The record is being removed from the master database,</dd>
|
||||
</dl>
|
||||
</dl>
|
||||
<h3>class PVListener</h3>
|
||||
<pre>
|
||||
class PVListener {
|
||||
virtual public PVRecordClient
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVListener);
|
||||
virtual ~PVListener();
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVListener</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>dataPut(PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
|
||||
<dt>dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
Requested is the field to which the requester issued a pvField-&addListener.
|
||||
This is called if the listener has called PVRecordField-&addListener for requested.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>A related set of changes is being started.</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>A related set of changes is done.</dd>
|
||||
</dl>
|
||||
<h3>class PVDatabase</h3>
|
||||
<pre>
|
||||
class PVDatabase : virtual public epics::pvData::Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDatabase);
|
||||
static PVDatabasePtr getMaster();
|
||||
virtual ~PVDatabase();
|
||||
virtual void destroy();
|
||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
virtual epics::pvData::String getRequesterName();
|
||||
virtual void message(
|
||||
epics::pvData::String const &message,
|
||||
epics::pvData::MessageType messageType);
|
||||
private:
|
||||
PVDatabase();
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>getMaster</dt>
|
||||
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
|
||||
<dt>~PVDatabase</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is called by remote channelAccess when process exits.
|
||||
This destroys and removes all records in the PVDatabase.</dd>
|
||||
<dt>findRecord</dt>
|
||||
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
|
||||
<dt>addRecord</dt>
|
||||
<dd>Add a record to the database.
|
||||
If the record already exists it is not modified and false is returned.</dd>
|
||||
<dt>removeRecord</dt>
|
||||
<dd>Remove a record from the database.
|
||||
If the record was not in the database false is returned.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>Virtual method of Requester</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Virtual message of Requester.</dd>
|
||||
</dl>
|
||||
<h2>pvAccess</h2>
|
||||
<p>Not yet described.
|
||||
It is only of interest to someone who wants to understand how it works.
|
||||
</p>
|
||||
<p>A brief description is that it implements the following components of pvIOCJava:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dt>monitor</dt>
|
||||
<dt>local ChannelProvider and Channel</dt>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,871 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>pvDatabaseCPP</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
||||
<style type="text/css">
|
||||
/*<![CDATA[*/
|
||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||
table { margin-left: auto; margin-right: auto }
|
||||
.diagram { text-align: center; margin: 2.5em 0 }
|
||||
span.opt { color: grey }
|
||||
span.nterm { font-style:italic }
|
||||
span.term { font-family:courier }
|
||||
span.user { font-family:courier }
|
||||
span.user:before { content:"<" }
|
||||
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>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 16-May-2013</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
</dl>
|
||||
|
||||
<p class="copyright">This product is made available subject to acceptance of the <a
|
||||
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
|
||||
<p>This document describes pvDatabaseCPP,
|
||||
which is a framework for implementing a network accessable database of smart memory resident
|
||||
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.
|
||||
The framework can be extended in order to create record instances that implements services.
|
||||
The minimum that an extenson must provide is a top level PVStructure and a process method.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 16-May-2013 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>The following Channel methods are implemented and working: getField,
|
||||
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
|
||||
But lots of work remains:</p>
|
||||
<dl>
|
||||
<dt>Other Channel Methods</dt>
|
||||
<dd>ChannelArray is next.</dd>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have no been implemented.
|
||||
Thus all monitors are onPut.</dd>
|
||||
<dt>Lifecycle problems</dt>
|
||||
<dd>Problems when channel clients disconnect.
|
||||
May need help from Matej</dd>
|
||||
<dt>Memory leaks at exit</dt>
|
||||
<dd>May need help from Matej.</dd>
|
||||
<dt>Scalar Arrays</dt>
|
||||
<dd>Have not been tested. Share has not been implemented.</dd>
|
||||
<dt>Structure Arrays</dt>
|
||||
<dd>Has not been implemented</dd>
|
||||
<dt>Testing</dt>
|
||||
<dd>Needs lots more testing</dd>
|
||||
</dl>
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
</div>
|
||||
<div id="contents" class="contents">
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>A brief description of a pvDatabase is that it is a set of network accessible, smart,
|
||||
memory resident records.
|
||||
Each record has data composed of a top level PVStructure.
|
||||
Each record has a name which is the channelName for pvAccess.
|
||||
A local Channel Provider implements the complete ChannelProvider and
|
||||
Channel interfaces as defined by pvAccess.
|
||||
The local provider provides access to the records in the pvDatabase.
|
||||
This local provider is accessed by the remote pvAccess server.
|
||||
A record is smart because code can be attached to a record, which is accessed via a method named process.</p>
|
||||
|
||||
<p>This document describes components that provides the following features:
|
||||
<dl>
|
||||
<dt>database<dt>
|
||||
<dd>This encapsulates the concept of a database of memory resident smart records.
|
||||
The two main components are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>This encapsulates the concept of a smart record. It can be processed.
|
||||
Changes to field values can be trapped. A record can be locked.</dd>
|
||||
<dt>pvDatabase<dt>
|
||||
<dd>This is a database of pvRecords.
|
||||
Records can be added and removed from a database.</dd>
|
||||
</dl>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>This is a complete implementation of ChannelProvider and Channel
|
||||
as defined by pvAccess.
|
||||
It is used by the server side of pvAccess to attach to pvRecords.
|
||||
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||
</dl>
|
||||
<p>database provides base classes that make it easy to create record instances.
|
||||
The code attached to each record must create the top
|
||||
level PVStructure and the following two methods:</p>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>This is a method for initializing the support.
|
||||
It returns true if successful and false otherwise.
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>This is what makes a record smart.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Relationship with pvIOCJava.</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
|
||||
which also implements a pvDatabase.
|
||||
PVDatabaseCPP extracts the core components required to create a network accessible database of smart
|
||||
memory resident records.
|
||||
pvDatabaseCPP does not implement any of the specialized support that pvIOCJava
|
||||
provides.
|
||||
It is expected that many services will be created that do not require the full features provided
|
||||
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
|
||||
them named pvDatabaseJava.</p>
|
||||
<p>Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing.
|
||||
For pvDatabaseCPP the process method is allowed to block.
|
||||
Until a need is demonstrated this will remain true.
|
||||
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
|
||||
The server side of remote pvAccess creates two threads for each client and always accesses
|
||||
a record via these threads.
|
||||
It is expected that these threads will be sufficient to efficently handle all channel methods except
|
||||
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
|
||||
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
|
||||
then the scanning facility will have to provide some way of handling process requests that block.</p>
|
||||
</p>
|
||||
<h3>Example PVRecord Extension</h3>
|
||||
<p>The example implements a simple counter.
|
||||
The example can be run on linux as follows:</p>
|
||||
<pre>
|
||||
mrk> pwd
|
||||
/home/hg/pvDatabaseCPP
|
||||
mrk> bin/linux-x86_64/exampleCounter
|
||||
|
||||
</pre>
|
||||
<p>The example consists of two components:</p>
|
||||
<dl>
|
||||
<dt>ExampleCounter.h</dt>
|
||||
<dd>The source code for the counter.</dd>
|
||||
<dt>exampleCounterMain.cpp</dt>
|
||||
<dd>A main program that runs the example so that it can be accessed
|
||||
by a pvAccess client.</dd>
|
||||
</dl>
|
||||
<h4>ExampleCounter.h</h4>
|
||||
<p>The example resides in src/database.
|
||||
The complete implementation is in the header file.
|
||||
A serious implementation would probably break the code into two files:
|
||||
1) a header, and 2) the implementation. The description consists of</p>
|
||||
<pre>
|
||||
class ExampleCounter;
|
||||
typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
|
||||
|
||||
class ExampleCounter :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleCounter);
|
||||
static ExampleCounterPtr create(
|
||||
epics::pvData::String const & recordName);
|
||||
virtual ~ExampleCounter();
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
private:
|
||||
ExampleCounter(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>This is example specific but each support could provide
|
||||
a similar static method.
|
||||
</dd>
|
||||
<dt>~ExampleCounter<dt>
|
||||
<dd>The destructor must be declared virtual.</dd>
|
||||
<dt><destroy</dt>
|
||||
<dd>Called when the record is being destroyed.
|
||||
This must call the base class destroy method.
|
||||
<dt>init<dt>
|
||||
<dd>A method to initialize the support. It returns true
|
||||
if initialization is successful and false if not.
|
||||
NOTE that this is a virtual method of PVRecord itself.</dd>
|
||||
<dt>process<dt>
|
||||
<dd>
|
||||
This again is a virtual method of PVRecord.
|
||||
</dd>
|
||||
<dt>ExampleCounter<dt>
|
||||
<dd>For the example this is private.</dd>
|
||||
<dt>pvValue</dt>
|
||||
<dd>This is the field of the top level structure that process
|
||||
accesses.
|
||||
</dd>
|
||||
<dl>
|
||||
<p>The implementation of create method is:</p>
|
||||
<pre>
|
||||
ExampleCounterPtr ExampleCounter::create(
|
||||
epics::pvData::String const & recordName)
|
||||
{
|
||||
epics::pvData::PVStructurePtr pvStructure =
|
||||
epics::pvData::getStandardPVField()->scalar(
|
||||
epics::pvData::pvDouble,"timeStamp,alarm"");
|
||||
ExampleCounterPtr pvRecord(
|
||||
new ExampleCounter(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Creates the top level structure.</li>
|
||||
<li>Creates a ExampleCounterPtr via the constructor.</li>
|
||||
<li>Calls init and if it fails resets the shared pointer.</li>
|
||||
<li>Returns the shared pointer to the newly created record.</li>
|
||||
</ul>
|
||||
<p>The private constructor method is:</p>
|
||||
<pre>
|
||||
ExampleCounter::ExampleCounter(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
}
|
||||
</pre>
|
||||
The example is very simple. It just calls the base class constructor.
|
||||
<p>The destructor and destroy methods are:</p>
|
||||
<pre>
|
||||
ExampleCounter::~ExampleCounter()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void ExampleCounter::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
</pre>
|
||||
The destructor just calls destroy.
|
||||
The destroy method, which is virtual, just calls the destroy method of the base class.
|
||||
A more complicated example can clean up any resources it used but must call the base
|
||||
class destroy method.
|
||||
<p>The implementation of init is:</p>
|
||||
<pre>
|
||||
bool ExampleCounter::init()
|
||||
{
|
||||
|
||||
initPVRecord();
|
||||
epics::pvData::PVFieldPtr pvField;
|
||||
pvValue = getPVStructure()->getLongField("value");
|
||||
if(pvValue.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Calls initRecord which is implemented by the base class.
|
||||
It MUST be called.</li>
|
||||
<li>Calls getLongField to get the interface to the value field,
|
||||
which must be a scalar with type long.</li>
|
||||
<li>If a long value field was not found it returns false.</li>
|
||||
<li>Returns true</li>
|
||||
</ul>
|
||||
<p>The implementation of process is:</p>
|
||||
<pre>
|
||||
void ExampleCounter::process()
|
||||
{
|
||||
pvValue->put(pvValue->get() + 1.0);
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
</pre>
|
||||
It adds 1.0 to the current value.
|
||||
It then sets the timeStamp to the current time.
|
||||
<h4>exampleCounterMain.cpp</h4>
|
||||
<p>This is in test/server.
|
||||
The main program is:</p>
|
||||
<pre>
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||
String recordName("exampleCounter");
|
||||
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
pvRecord.reset();
|
||||
cout << "exampleServer\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Gets a pointer to the master database.</li>
|
||||
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||
<li>Creates a ExampleCounter record with the name exampleCounter
|
||||
</li>
|
||||
<li>Prints exampleCounter on standard out.</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
<h3>Phased Development</h3>
|
||||
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
||||
<dl>
|
||||
<dt>pvRecord</d>
|
||||
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
|
||||
<dt>pvDatabase</d>
|
||||
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
||||
<dt>Local Channel Provider</dt>
|
||||
<dd>Complete implementation of ChannelProvider and Channel.
|
||||
This means that pvCopy and monitor are also implemented.</dd>
|
||||
</dl>
|
||||
<p>Future phases of pvDatabaseCPP might include:</p>
|
||||
<dl>
|
||||
<dt>Install</dt>
|
||||
<dd>This provides complete support for on-line add and delete
|
||||
of sets of records.
|
||||
With the first phase each "service" is responsible for it's own implementation.
|
||||
All that is provided is addRecord and removeRecord.
|
||||
</dd>
|
||||
<dt>Field support</dt>
|
||||
<dd>Add the ability to optionally add support to fields.
|
||||
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
|
||||
<dt>XML parser</dt>
|
||||
<dd>This provides the ability to create record instances without writing any code.</dd>
|
||||
</dl>
|
||||
<p>The completion of each phase provides useful features that can be used without waiting for the
|
||||
completion of later phases.
|
||||
The rest of this document discusses only the first phase.</p>
|
||||
<h3>Features Required for localChannelProvider</h3>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>Creates a PVStructure that contains a copy of an arbitary
|
||||
subset of the fields of another top level PVStructure.
|
||||
It can copy data between the two and maintains a bitSet that show
|
||||
which fields are changed.<dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||
<dt>PVRecord and PVDatabase</dt>
|
||||
<dd>Defined below.</dd>
|
||||
<dt>The localChannelProvider itself</dt>
|
||||
<dd>This is the pvAccess package in pvIOCJava.
|
||||
The localChannelProvider will access data from PVRecords.
|
||||
It will implement all channel methods.</dd>
|
||||
</dl>
|
||||
<h3>Minumum Features Required for pvRecord</h3>
|
||||
<p>The first phase will only implement record processing, i. e.
|
||||
the process method has to do everything itself without any generic field support.
|
||||
This will be sufficient for starting to implement services.
|
||||
The following are the minimium features required</p>
|
||||
<dl>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This, and a set of related interfaces, provides the following:
|
||||
<dl>
|
||||
<dt>Access to top level PVStructure</dt>
|
||||
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
||||
<dt>Record locking</dt>
|
||||
<dd>A record can be locked and unlocked.
|
||||
A record must be locked whenever data in the pvStructure is accessed.</dd>
|
||||
<dt>Trapping data changes</dt>
|
||||
<dd>A client can request to be notified when data in the pvStructure is modified.
|
||||
It can do this on a field by field basis.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The following sections describes the classes required for the first phase.</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<p>This directory has the following files:</p>
|
||||
<dl>
|
||||
<dt>pvDatabase.h</dt>
|
||||
<dd>
|
||||
This is what is described in this section.
|
||||
</dd>
|
||||
<dt>pvDatabase.cpp</dt>
|
||||
<dd>
|
||||
The implementation of PVDatabase.
|
||||
</dd>
|
||||
<dt>pvRecord.cpp</dt>
|
||||
<dd>
|
||||
The implementation of the base class for PVREcord.
|
||||
It can also implement record instances with a process
|
||||
method does nothing.
|
||||
This can be used to create a "dumb" record where all changes are
|
||||
done by clients.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
<dt>exampleCounter.h</dt>
|
||||
<dd>
|
||||
This was described in the introduction.
|
||||
</dd>
|
||||
<dt>powerSupplyRecordTest.h</dt>
|
||||
<dd>
|
||||
This provides code that simulates a power supply.
|
||||
It computes the current from the voltage and power.
|
||||
It is used for testing.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The classes in pvDatabase.h describe a database of memory resident
|
||||
smart records.
|
||||
It describes the following classes:</p>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
|
||||
<dt>PVRecordField</dt>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
|
||||
can be implemented.</dd>
|
||||
<dt>PVRecordClient</dt>
|
||||
<dd>This is called by anything that acceses PVRecord.</dd>
|
||||
<dt>PVListener</dt>
|
||||
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This is a database of PVRecords.</dd>
|
||||
</dl>
|
||||
<p>Each class is described in a separate subsection.</p>
|
||||
<h3>C++ namespace and typedefs</h3>
|
||||
<pre>
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVRecord;
|
||||
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
||||
typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap;
|
||||
|
||||
class PVRecordField;
|
||||
typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
|
||||
typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray;
|
||||
typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr;
|
||||
|
||||
class PVRecordStructure;
|
||||
typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr;
|
||||
|
||||
class PVRecordClient;
|
||||
typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
|
||||
|
||||
class PVListener;
|
||||
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
||||
|
||||
class RecordProcessRequester;
|
||||
typedef std::tr1::shared_ptr<RecordProcessRequester> RecordProcessRequesterPtr;
|
||||
|
||||
class RecordPutRequester;
|
||||
typedef std::tr1::shared_ptr<RecordPutRequester> RecordPutRequesterPtr;
|
||||
|
||||
class PVDatabase;
|
||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
</pre>
|
||||
|
||||
<h3>class PVRecord</h3>
|
||||
<p>NOTES:
|
||||
<ul>
|
||||
<li>This section uses the name record instead of "an instance of PVRecord".</li>
|
||||
<li>Most clients will access a record via the local channel provider,
|
||||
i. e. via pvAccess.
|
||||
Thus this section is mainly of interest to
|
||||
the local channel provider and record implementers.</li>
|
||||
<li>Most readers will not care about most of the PVRecord methods.
|
||||
Most of the methods are used by the pvAccess code.
|
||||
Service implementers will mostly be interested in methods init and process.
|
||||
These are described first.
|
||||
</ul>
|
||||
<hr>PVRecord Methods</h4>
|
||||
<pre>
|
||||
class PVRecord
|
||||
public epics::pvData::Requester,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
|
||||
virtual bool init() {initPVRecord(); return true;}
|
||||
virtual void process() {}
|
||||
|
||||
static PVRecordPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PVRecord();
|
||||
virtual void destroy();
|
||||
epics::pvData::String getRecordName();
|
||||
PVRecordStructurePtr getPVRecordStructure();
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void detachClients();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
bool removeListener(PVListenerPtr const & pvListener);
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
epics::pvData::String getRequesterName() {return getRecordName();}
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void message(
|
||||
PVRecordFieldPtr const & pvRecordField,
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void toString(epics::pvData::StringBuilder buf);
|
||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||
protected:
|
||||
PVRecord(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
void initPVRecord();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
PVRecordPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
private:
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
<p>The methods are:</h3>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
This method Must call initPVRecord.</p>
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
The base implementation does nothing.</p>
|
||||
</dd>
|
||||
<dt>create</dt>
|
||||
<dd>Static method to create dumb records, i.e. records with a process method
|
||||
that does nothing.</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The destructor which must be virtual. A derived class must also have
|
||||
a virtual destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is a virtual method.
|
||||
</dd>
|
||||
<dt>getRecordName</dt>
|
||||
<dd>Return the recordName.</dd>
|
||||
<dt>getPVRecordStructure</dt>
|
||||
<dd>Get the top level PVStructure.</dd>
|
||||
<dt>findPVRecordField</dt>
|
||||
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
|
||||
<dt>addRequester</dt>
|
||||
<dd>Add a requester to receive messages.</dd>
|
||||
<dt>removeRequester</dt>
|
||||
<dd>Remove a message requester.</dd>
|
||||
<dt>lock_guard</dt>
|
||||
<dd>This is an inline method that locks the record. The record will automatically
|
||||
be unlocked when control leaves the block that has the call.
|
||||
<dt>lock</dt>
|
||||
<dt>unlock</dt>
|
||||
<dd>Lock and Unlock the record.
|
||||
Any code accessing the data in the record or calling other PVRecord methods
|
||||
must have the record locked.</dd>
|
||||
<dt>tryLock</dt>
|
||||
<dd>If true then just like lock.
|
||||
If falseclient can not access record.
|
||||
A client can try to simultaneously hold the lock for more than two records
|
||||
by calling this method. But must be willing to accept failure.
|
||||
</dd>
|
||||
<dt>lockOtherRecord</dt>
|
||||
<dd>A client that holds the lock for one record can lock one other record.
|
||||
A client must not call this if the client already has the lock for
|
||||
more then one record.
|
||||
</dd>
|
||||
<dt>addPVRecordClient</dt>
|
||||
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
|
||||
<dt>removePVRecordClient</dt>
|
||||
<dd>Client is no longer accessing the record.</dd>
|
||||
<dt>detachClients</dt>
|
||||
<dd>Ask all clients to detach from the record</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>Begin a group of puts.
|
||||
This results in all registered PVListeners being called</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>End a group of puts.
|
||||
This results in all registered PVListeners being called.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>virtual method of Requester
|
||||
</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
<dt>toString</dt>
|
||||
<dd>Just calls the top level PVStructure toString method.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||
<dt>initPVRecord</dt>
|
||||
<dd>This method must be called by derived class.</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Called by derived class.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordField</h3>
|
||||
<pre>
|
||||
class PVRecordField {
|
||||
public virtual epics::pvData::PostHandler,
|
||||
public std::tr1::enable_shared_from_this<PVRecordField>
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordField);
|
||||
PVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField,
|
||||
PVRecordStructurePtr const &parent,
|
||||
PVRecordPtr const & pvRecord);
|
||||
virtual ~PVRecordField();
|
||||
virtual void destroy();
|
||||
PVRecordStructurePtr getParent();
|
||||
epics::pvData::PVFieldPtr getPVField();
|
||||
epics::pvData::String getFullFieldName();
|
||||
epics::pvData::String getFullName();
|
||||
PVRecordPtr getPVRecord();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
protected:
|
||||
PVRecordFieldPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>PVRecordField</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordField</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>Called by PVRecordStructure when it's destroy method is called.</dd>
|
||||
<dt>getParent</dt>
|
||||
<dd>Get the parent PVRecordStructure for this field.</dd>
|
||||
<dt>getPVField</dt>
|
||||
<dd>Get the PVField associated with this PVRecordField.</dd>
|
||||
<dt>getFullFieldName</dt>
|
||||
<dd>This gets the full name of the field, i.e. field,field,..</dd>
|
||||
<dt>getFullName</dt>
|
||||
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
|
||||
<dt>getPVRecord</dt>
|
||||
<dd>Returns the PVRecord to which this field belongs.</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add A PVListener to this field.
|
||||
Whenever this field or any subfield if this field is modified the listener will be notified.
|
||||
PVListener is described below.
|
||||
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordStructure</h3>
|
||||
<pre>
|
||||
class PVRecordStructure : public PVRecordField {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordStructure);
|
||||
PVRecordStructure(
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
PVRecordFieldPtrArrayPtr const & pvRecordField);
|
||||
virtual ~PVRecordStructure();
|
||||
virtual void destroy();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
protected:
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
<dl>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordStructure</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getPVRecordFields</dt>
|
||||
<dd>Get the PVRecordField array for the subfields</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Get the PVStructure for this field.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<h3>class PVRecordClient</h3>
|
||||
<pre>
|
||||
class PVRecordClient {
|
||||
POINTER_DEFINITIONS(PVRecordClient);
|
||||
virtual ~PVRecordClient();
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVRecordClient</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>detach</dt>
|
||||
<dd>The record is being removed from the master database,</dd>
|
||||
</dl>
|
||||
</dl>
|
||||
<h3>class PVListener</h3>
|
||||
<pre>
|
||||
class PVListener {
|
||||
virtual public PVRecordClient
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVListener);
|
||||
virtual ~PVListener();
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVListener</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>dataPut(PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
|
||||
<dt>dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
Requested is the field to which the requester issued a pvField-&addListener.
|
||||
This is called if the listener has called PVRecordField-&addListener for requested.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>A related set of changes is being started.</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>A related set of changes is done.</dd>
|
||||
</dl>
|
||||
<h3>class PVDatabase</h3>
|
||||
<pre>
|
||||
class PVDatabase : virtual public epics::pvData::Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDatabase);
|
||||
static PVDatabasePtr getMaster();
|
||||
virtual ~PVDatabase();
|
||||
virtual void destroy();
|
||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
virtual epics::pvData::String getRequesterName();
|
||||
virtual void message(
|
||||
epics::pvData::String const &message,
|
||||
epics::pvData::MessageType messageType);
|
||||
private:
|
||||
PVDatabase();
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>getMaster</dt>
|
||||
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
|
||||
<dt>~PVDatabase</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is called by remote channelAccess when process exits.
|
||||
This destroys and removes all records in the PVDatabase.</dd>
|
||||
<dt>findRecord</dt>
|
||||
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
|
||||
<dt>addRecord</dt>
|
||||
<dd>Add a record to the database.
|
||||
If the record already exists it is not modified and false is returned.</dd>
|
||||
<dt>removeRecord</dt>
|
||||
<dd>Remove a record from the database.
|
||||
If the record was not in the database false is returned.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>Virtual method of Requester</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Virtual message of Requester.</dd>
|
||||
</dl>
|
||||
<h2>pvAccess</h2>
|
||||
<p>Not yet described.
|
||||
It is only of interest to someone who wants to understand how it works.
|
||||
</p>
|
||||
<p>A brief description is that it implements the following components of pvIOCJava:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dt>monitor</dt>
|
||||
<dt>local ChannelProvider and Channel</dt>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,996 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>pvDatabaseCPP</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
||||
<style type="text/css">
|
||||
/*<![CDATA[*/
|
||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||
table { margin-left: auto; margin-right: auto }
|
||||
.diagram { text-align: center; margin: 2.5em 0 }
|
||||
span.opt { color: grey }
|
||||
span.nterm { font-style:italic }
|
||||
span.term { font-family:courier }
|
||||
span.user { font-family:courier }
|
||||
span.user:before { content:"<" }
|
||||
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>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 23-May-2013</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
</dl>
|
||||
|
||||
<p class="copyright">This product is made available subject to acceptance of the <a
|
||||
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
|
||||
<p>This document describes pvDatabaseCPP,
|
||||
which is a framework for implementing a network accessable database of smart memory resident
|
||||
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.
|
||||
The framework can be extended in order to create record instances that implements services.
|
||||
The minimum that an extenson must provide is a top level PVStructure and a process method.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 23-May-2013 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>The following Channel methods are implemented and working: getField,
|
||||
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
|
||||
But lots of work remains:</p>
|
||||
<dl>
|
||||
<dt>Other Channel Methods</dt>
|
||||
<dd>Only ChannelArray remains.
|
||||
Note that pvIOCJava does not implement the pvRequest for channelArray
|
||||
correctly. It uses a private convention rather than using the output
|
||||
of CreateRequest. This will be fixed before pvDatabaseCPP implements ChannelArray.
|
||||
</dd>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have not been implemented.
|
||||
Thus all monitors are onPut.</dd>
|
||||
<dt>Lifecycle problems</dt>
|
||||
<dd>Problems when channel clients disconnect.
|
||||
I am asking for help from Matej</dd>
|
||||
<dt>Memory leak at exit</dt>
|
||||
<dd>I am asking for help from Matej</dd>
|
||||
<dt>Scalar Arrays</dt>
|
||||
<dd>Share has not been implemented.
|
||||
This will wait until Michael has new implementation of ScalarArray.</dd>
|
||||
<dt>Structure Arrays</dt>
|
||||
<dd>Has not been implemented</dd>
|
||||
<dt>Testing</dt>
|
||||
<dd>Needs lots more testing</dd>
|
||||
</dl>
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
</div>
|
||||
<div id="contents" class="contents">
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>A brief description of a pvDatabase is that it is a set of network accessible, smart,
|
||||
memory resident records.
|
||||
Each record has data composed of a top level PVStructure.
|
||||
Each record has a name which is the channelName for pvAccess.
|
||||
A local Channel Provider implements the complete ChannelProvider and
|
||||
Channel interfaces as defined by pvAccess.
|
||||
The local provider provides access to the records in the pvDatabase.
|
||||
This local provider is accessed by the remote pvAccess server.
|
||||
A record is smart because code can be attached to a record, which is accessed via a method named process.</p>
|
||||
|
||||
<p>This document describes components that provide the following features:
|
||||
<dl>
|
||||
<dt>database<dt>
|
||||
<dd>This encapsulates the concept of a database of memory resident smart records.
|
||||
The two main components are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>This encapsulates the concept of a smart record. It can be processed.
|
||||
Changes to field values can be trapped. A record can be locked.</dd>
|
||||
<dt>pvDatabase<dt>
|
||||
<dd>This is a database of pvRecords.
|
||||
Records can be added and removed from a database.</dd>
|
||||
</dl>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>This is a complete implementation of ChannelProvider and Channel
|
||||
as defined by pvAccess.
|
||||
It is used by the server side of pvAccess to attach to pvRecords.
|
||||
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||
</dl>
|
||||
<p>database provides base classes that make it easy to create record instances.
|
||||
The code attached to each record must create the top
|
||||
level PVStructure and the following two methods:</p>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>This is a method for initializing the support.
|
||||
It returns true if successful and false otherwise.
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>This is what makes a record smart.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Relationship with pvIOCJava.</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
|
||||
which also implements a pvDatabase.
|
||||
PVDatabaseCPP extracts the core components required to create a network accessible database of smart
|
||||
memory resident records.
|
||||
pvDatabaseCPP does not implement any of the specialized support that pvIOCJava
|
||||
provides.
|
||||
It is expected that many services will be created that do not require the full features provided
|
||||
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
|
||||
them named pvDatabaseJava.</p>
|
||||
<p>Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing.
|
||||
For pvDatabaseCPP the process method is allowed to block.
|
||||
Until a need is demonstrated this will remain true.
|
||||
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
|
||||
The server side of remote pvAccess creates two threads for each client and always accesses
|
||||
a record via these threads.
|
||||
It is expected that these threads will be sufficient to efficently handle all channel methods except
|
||||
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
|
||||
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
|
||||
then the scanning facility will have to provide some way of handling process requests that block.</p>
|
||||
</p>
|
||||
<h3>Example PVRecord Extension</h3>
|
||||
<p>The example implements a simple counter.
|
||||
The example can be run on linux as follows:</p>
|
||||
<pre>
|
||||
mrk> pwd
|
||||
/home/hg/pvDatabaseCPP
|
||||
mrk> bin/linux-x86_64/exampleCounter
|
||||
|
||||
</pre>
|
||||
<p>The example consists of two components:</p>
|
||||
<dl>
|
||||
<dt>ExampleCounter.h</dt>
|
||||
<dd>The source code for the counter.</dd>
|
||||
<dt>exampleCounterMain.cpp</dt>
|
||||
<dd>A main program that runs the example so that it can be accessed
|
||||
by a pvAccess client.</dd>
|
||||
</dl>
|
||||
<h4>ExampleCounter.h</h4>
|
||||
<p>The example resides in src/database.
|
||||
The complete implementation is in the header file.
|
||||
A serious implementation might break the code into a header and an
|
||||
implementation file.<p>
|
||||
</p>The description consists of</p>
|
||||
<pre>
|
||||
class ExampleCounter;
|
||||
typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
|
||||
|
||||
class ExampleCounter :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleCounter);
|
||||
static ExampleCounterPtr create(
|
||||
epics::pvData::String const & recordName);
|
||||
virtual ~ExampleCounter();
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
private:
|
||||
ExampleCounter(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>This is example specific but each support could provide
|
||||
a similar static method.
|
||||
</dd>
|
||||
<dt>~ExampleCounter<dt>
|
||||
<dd>The destructor must be declared virtual.</dd>
|
||||
<dt><destroy</dt>
|
||||
<dd>Called when the record is being destroyed.
|
||||
This must call the base class destroy method.
|
||||
<dt>init<dt>
|
||||
<dd>A method to initialize the support. It returns true
|
||||
if initialization is successful and false if not.
|
||||
NOTE that this is a virtual method of PVRecord itself.</dd>
|
||||
<dt>process<dt>
|
||||
<dd>
|
||||
This again is a virtual method of PVRecord.
|
||||
</dd>
|
||||
<dt>ExampleCounter<dt>
|
||||
<dd>For the example this is private.</dd>
|
||||
<dt>pvValue</dt>
|
||||
<dd>This is the field of the top level structure that process
|
||||
accesses.
|
||||
</dd>
|
||||
<dl>
|
||||
<p>The implementation of create method is:</p>
|
||||
<pre>
|
||||
ExampleCounterPtr ExampleCounter::create(
|
||||
epics::pvData::String const & recordName)
|
||||
{
|
||||
epics::pvData::PVStructurePtr pvStructure =
|
||||
epics::pvData::getStandardPVField()->scalar(
|
||||
epics::pvData::pvDouble,"timeStamp,alarm"");
|
||||
ExampleCounterPtr pvRecord(
|
||||
new ExampleCounter(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Creates the top level structure.</li>
|
||||
<li>Creates a ExampleCounterPtr via the constructor.</li>
|
||||
<li>Calls init and if it fails resets the shared pointer.</li>
|
||||
<li>Returns the shared pointer to the newly created record.</li>
|
||||
</ul>
|
||||
<p>The private constructor method is:</p>
|
||||
<pre>
|
||||
ExampleCounter::ExampleCounter(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
}
|
||||
</pre>
|
||||
The example is very simple. It just calls the base class constructor.
|
||||
<p>The destructor and destroy methods are:</p>
|
||||
<pre>
|
||||
ExampleCounter::~ExampleCounter()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void ExampleCounter::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
</pre>
|
||||
The destructor just calls destroy.
|
||||
The destroy method, which is virtual, just calls the destroy method of the base class.
|
||||
A more complicated example can clean up any resources it used but must call the base
|
||||
class destroy method.
|
||||
<p>The implementation of init is:</p>
|
||||
<pre>
|
||||
bool ExampleCounter::init()
|
||||
{
|
||||
|
||||
initPVRecord();
|
||||
epics::pvData::PVFieldPtr pvField;
|
||||
pvValue = getPVStructure()->getLongField("value");
|
||||
if(pvValue.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Calls initRecord which is implemented by the base class.
|
||||
It MUST be called.</li>
|
||||
<li>Calls getLongField to get the interface to the value field,
|
||||
which must be a scalar with type long.</li>
|
||||
<li>If a long value field was not found it returns false.</li>
|
||||
<li>Returns true</li>
|
||||
</ul>
|
||||
<p>The implementation of process is:</p>
|
||||
<pre>
|
||||
void ExampleCounter::process()
|
||||
{
|
||||
pvValue->put(pvValue->get() + 1.0);
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
</pre>
|
||||
It adds 1.0 to the current value.
|
||||
It then sets the timeStamp to the current time.
|
||||
<h4>exampleCounterMain.cpp</h4>
|
||||
<p>This is in test/server.
|
||||
The main program is:</p>
|
||||
<pre>
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||
String recordName("exampleCounter");
|
||||
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
pvRecord.reset();
|
||||
cout << "exampleServer\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Gets a pointer to the master database.</li>
|
||||
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||
<li>Creates a ExampleCounter record with the name exampleCounter
|
||||
</li>
|
||||
<li>Prints exampleCounter on standard out.</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
<h3>Phased Development</h3>
|
||||
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
||||
<dl>
|
||||
<dt>pvRecord</d>
|
||||
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
|
||||
<dt>pvDatabase</d>
|
||||
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
||||
<dt>Local Channel Provider</dt>
|
||||
<dd>Complete implementation of ChannelProvider and Channel.
|
||||
This means that pvCopy and monitor are also implemented.</dd>
|
||||
</dl>
|
||||
<p>Future phases of pvDatabaseCPP might include:</p>
|
||||
<dl>
|
||||
<dt>Install</dt>
|
||||
<dd>This provides complete support for on-line add and delete
|
||||
of sets of records.
|
||||
With the first phase each "service" is responsible for it's own implementation.
|
||||
All that is provided is addRecord and removeRecord.
|
||||
</dd>
|
||||
<dt>Field support</dt>
|
||||
<dd>Add the ability to optionally add support to fields.
|
||||
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
|
||||
<dt>XML parser</dt>
|
||||
<dd>This provides the ability to create record instances without writing any code.</dd>
|
||||
</dl>
|
||||
<p>The completion of each phase provides useful features that can be used without waiting for the
|
||||
completion of later phases.
|
||||
The rest of this document discusses only the first phase.</p>
|
||||
<h3>Features Required for localChannelProvider</h3>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>Creates a PVStructure that contains a copy of an arbitary
|
||||
subset of the fields of another top level PVStructure.
|
||||
It can copy data between the two and maintains a bitSet that show
|
||||
which fields are changed.<dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||
<dt>PVRecord and PVDatabase</dt>
|
||||
<dd>Defined below.</dd>
|
||||
<dt>The localChannelProvider itself</dt>
|
||||
<dd>This is the pvAccess package in pvIOCJava.
|
||||
The localChannelProvider will access data from PVRecords.
|
||||
It will implement all channel methods.</dd>
|
||||
</dl>
|
||||
<h3>Minumum Features Required for pvRecord</h3>
|
||||
<p>The first phase will only implement record processing, i. e.
|
||||
the process method has to do everything itself without any generic field support.
|
||||
This will be sufficient for starting to implement services.
|
||||
The following are the minimium features required</p>
|
||||
<dl>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This, and a set of related interfaces, provides the following:
|
||||
<dl>
|
||||
<dt>Access to top level PVStructure</dt>
|
||||
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
||||
<dt>Record locking</dt>
|
||||
<dd>A record can be locked and unlocked.
|
||||
A record must be locked whenever data in the pvStructure is accessed.</dd>
|
||||
<dt>Trapping data changes</dt>
|
||||
<dd>A client can request to be notified when data in the pvStructure is modified.
|
||||
It can do this on a field by field basis.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The following sections describes the classes required for the first phase.</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<p>This directory has the following files:</p>
|
||||
<dl>
|
||||
<dt>pvDatabase.h</dt>
|
||||
<dd>
|
||||
This is what is described in this section.
|
||||
</dd>
|
||||
<dt>pvDatabase.cpp</dt>
|
||||
<dd>
|
||||
The implementation of PVDatabase.
|
||||
</dd>
|
||||
<dt>pvRecord.cpp</dt>
|
||||
<dd>
|
||||
The implementation of the base class for PVREcord.
|
||||
It can also implement record instances with a process
|
||||
method does nothing.
|
||||
This can be used to create a "dumb" record where all changes are
|
||||
done by clients.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
<dt>exampleCounter.h</dt>
|
||||
<dd>
|
||||
This was described in the introduction.
|
||||
</dd>
|
||||
<dt>powerSupplyRecordTest.h</dt>
|
||||
<dd>
|
||||
This provides code that simulates a power supply.
|
||||
It computes the current from the voltage and power.
|
||||
It is used for testing.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
<dt>recordList.h</dt>
|
||||
<dd>This implements a PVRecord that provides a list of the names
|
||||
of the records in the PVDatabase.
|
||||
It also serves as an example of how to implement a service.
|
||||
The testExampleServer creates an instance via the following code:
|
||||
<pre>
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
</pre>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
<p>The classes in pvDatabase.h describe a database of memory resident
|
||||
smart records.
|
||||
It describes the following classes:</p>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
|
||||
<dt>PVRecordField</dt>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
|
||||
can be implemented.</dd>
|
||||
<dt>PVRecordClient</dt>
|
||||
<dd>This is called by anything that acceses PVRecord.</dd>
|
||||
<dt>PVListener</dt>
|
||||
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This is a database of PVRecords.</dd>
|
||||
</dl>
|
||||
<p>Each class is described in a separate subsection.</p>
|
||||
<h3>C++ namespace and typedefs</h3>
|
||||
<pre>
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVRecord;
|
||||
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
||||
typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap;
|
||||
|
||||
class PVRecordField;
|
||||
typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
|
||||
typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray;
|
||||
typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr;
|
||||
|
||||
class PVRecordStructure;
|
||||
typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr;
|
||||
|
||||
class PVRecordClient;
|
||||
typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
|
||||
|
||||
class PVListener;
|
||||
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
||||
|
||||
class RecordProcessRequester;
|
||||
typedef std::tr1::shared_ptr<RecordProcessRequester> RecordProcessRequesterPtr;
|
||||
|
||||
class RecordPutRequester;
|
||||
typedef std::tr1::shared_ptr<RecordPutRequester> RecordPutRequesterPtr;
|
||||
|
||||
class PVDatabase;
|
||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
</pre>
|
||||
|
||||
<h3>class PVRecord</h3>
|
||||
<p>NOTES:
|
||||
<ul>
|
||||
<li>This section uses the name record instead of "an instance of PVRecord".</li>
|
||||
<li>Most clients will access a record via the local channel provider,
|
||||
i. e. via pvAccess.
|
||||
Thus this section is mainly of interest to
|
||||
the local channel provider and record implementers.</li>
|
||||
<li>Most readers will not care about most of the PVRecord methods.
|
||||
Most of the methods are used by the pvAccess code.
|
||||
Service implementers will mostly be interested in methods init and process.
|
||||
These are described first.
|
||||
</ul>
|
||||
<hr>PVRecord Methods</h4>
|
||||
<pre>
|
||||
class PVRecord
|
||||
public epics::pvData::Requester,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
|
||||
virtual bool init() {initPVRecord(); return true;}
|
||||
virtual void process() {}
|
||||
|
||||
static PVRecordPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PVRecord();
|
||||
virtual void destroy();
|
||||
epics::pvData::String getRecordName();
|
||||
PVRecordStructurePtr getPVRecordStructure();
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void detachClients();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
bool removeListener(PVListenerPtr const & pvListener);
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
epics::pvData::String getRequesterName() {return getRecordName();}
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void message(
|
||||
PVRecordFieldPtr const & pvRecordField,
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void toString(epics::pvData::StringBuilder buf);
|
||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||
protected:
|
||||
PVRecord(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
void initPVRecord();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
PVRecordPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
private:
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
<p>The methods are:</h3>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
This method Must call initPVRecord.</p>
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
The base implementation does nothing.</p>
|
||||
</dd>
|
||||
<dt>create</dt>
|
||||
<dd>Static method to create dumb records, i.e. records with a process method
|
||||
that does nothing.</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The destructor which must be virtual. A derived class must also have
|
||||
a virtual destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is a virtual method.
|
||||
</dd>
|
||||
<dt>getRecordName</dt>
|
||||
<dd>Return the recordName.</dd>
|
||||
<dt>getPVRecordStructure</dt>
|
||||
<dd>Get the top level PVStructure.</dd>
|
||||
<dt>findPVRecordField</dt>
|
||||
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
|
||||
<dt>addRequester</dt>
|
||||
<dd>Add a requester to receive messages.</dd>
|
||||
<dt>removeRequester</dt>
|
||||
<dd>Remove a message requester.</dd>
|
||||
<dt>lock_guard</dt>
|
||||
<dd>This is an inline method that locks the record. The record will automatically
|
||||
be unlocked when control leaves the block that has the call.
|
||||
<dt>lock</dt>
|
||||
<dt>unlock</dt>
|
||||
<dd>Lock and Unlock the record.
|
||||
Any code accessing the data in the record or calling other PVRecord methods
|
||||
must have the record locked.</dd>
|
||||
<dt>tryLock</dt>
|
||||
<dd>If true then just like lock.
|
||||
If falseclient can not access record.
|
||||
A client can try to simultaneously hold the lock for more than two records
|
||||
by calling this method. But must be willing to accept failure.
|
||||
</dd>
|
||||
<dt>lockOtherRecord</dt>
|
||||
<dd>A client that holds the lock for one record can lock one other record.
|
||||
A client must not call this if the client already has the lock for
|
||||
more then one record.
|
||||
</dd>
|
||||
<dt>addPVRecordClient</dt>
|
||||
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
|
||||
<dt>removePVRecordClient</dt>
|
||||
<dd>Client is no longer accessing the record.</dd>
|
||||
<dt>detachClients</dt>
|
||||
<dd>Ask all clients to detach from the record</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>Begin a group of puts.
|
||||
This results in all registered PVListeners being called</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>End a group of puts.
|
||||
This results in all registered PVListeners being called.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>virtual method of Requester
|
||||
</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
<dt>toString</dt>
|
||||
<dd>Just calls the top level PVStructure toString method.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||
<dt>initPVRecord</dt>
|
||||
<dd>This method must be called by derived class.</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Called by derived class.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordField</h3>
|
||||
<pre>
|
||||
class PVRecordField {
|
||||
public virtual epics::pvData::PostHandler,
|
||||
public std::tr1::enable_shared_from_this<PVRecordField>
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordField);
|
||||
PVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField,
|
||||
PVRecordStructurePtr const &parent,
|
||||
PVRecordPtr const & pvRecord);
|
||||
virtual ~PVRecordField();
|
||||
virtual void destroy();
|
||||
PVRecordStructurePtr getParent();
|
||||
epics::pvData::PVFieldPtr getPVField();
|
||||
epics::pvData::String getFullFieldName();
|
||||
epics::pvData::String getFullName();
|
||||
PVRecordPtr getPVRecord();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
protected:
|
||||
PVRecordFieldPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>PVRecordField</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordField</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>Called by PVRecordStructure when it's destroy method is called.</dd>
|
||||
<dt>getParent</dt>
|
||||
<dd>Get the parent PVRecordStructure for this field.</dd>
|
||||
<dt>getPVField</dt>
|
||||
<dd>Get the PVField associated with this PVRecordField.</dd>
|
||||
<dt>getFullFieldName</dt>
|
||||
<dd>This gets the full name of the field, i.e. field,field,..</dd>
|
||||
<dt>getFullName</dt>
|
||||
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
|
||||
<dt>getPVRecord</dt>
|
||||
<dd>Returns the PVRecord to which this field belongs.</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add A PVListener to this field.
|
||||
Whenever this field or any subfield if this field is modified the listener will be notified.
|
||||
PVListener is described below.
|
||||
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordStructure</h3>
|
||||
<pre>
|
||||
class PVRecordStructure : public PVRecordField {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordStructure);
|
||||
PVRecordStructure(
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
PVRecordFieldPtrArrayPtr const & pvRecordField);
|
||||
virtual ~PVRecordStructure();
|
||||
virtual void destroy();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
protected:
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
<dl>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordStructure</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getPVRecordFields</dt>
|
||||
<dd>Get the PVRecordField array for the subfields</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Get the PVStructure for this field.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<h3>class PVRecordClient</h3>
|
||||
<pre>
|
||||
class PVRecordClient {
|
||||
POINTER_DEFINITIONS(PVRecordClient);
|
||||
virtual ~PVRecordClient();
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVRecordClient</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>detach</dt>
|
||||
<dd>The record is being removed from the master database,</dd>
|
||||
</dl>
|
||||
</dl>
|
||||
<h3>class PVListener</h3>
|
||||
<pre>
|
||||
class PVListener {
|
||||
virtual public PVRecordClient
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVListener);
|
||||
virtual ~PVListener();
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVListener</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>dataPut(PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
|
||||
<dt>dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
Requested is the field to which the requester issued a pvField-&addListener.
|
||||
This is called if the listener has called PVRecordField-&addListener for requested.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>A related set of changes is being started.</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>A related set of changes is done.</dd>
|
||||
</dl>
|
||||
<h3>class PVDatabase</h3>
|
||||
<pre>
|
||||
class PVDatabase : virtual public epics::pvData::Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDatabase);
|
||||
static PVDatabasePtr getMaster();
|
||||
virtual ~PVDatabase();
|
||||
virtual void destroy();
|
||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
virtual epics::pvData::String getRequesterName();
|
||||
virtual void message(
|
||||
epics::pvData::String const &message,
|
||||
epics::pvData::MessageType messageType);
|
||||
private:
|
||||
PVDatabase();
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>getMaster</dt>
|
||||
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
|
||||
<dt>~PVDatabase</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is called by remote channelAccess when process exits.
|
||||
This destroys and removes all records in the PVDatabase.</dd>
|
||||
<dt>findRecord</dt>
|
||||
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
|
||||
<dt>addRecord</dt>
|
||||
<dd>Add a record to the database.
|
||||
If the record already exists it is not modified and false is returned.</dd>
|
||||
<dt>removeRecord</dt>
|
||||
<dd>Remove a record from the database.
|
||||
If the record was not in the database false is returned.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>Virtual method of Requester</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Virtual message of Requester.</dd>
|
||||
</dl>
|
||||
<h2>pvAccess</h2>
|
||||
<p>This is code that provides an implementation of channelProvider as
|
||||
defined by pvAccess.
|
||||
It provides access to PVRecords and is access by the server side of remote pvAccess.</p>
|
||||
<h3>channelProviderLocal</h3>
|
||||
<p>This is a complete implementation of channelProvider and ,
|
||||
except for channelRPC, provides a complete implementation of Channel
|
||||
as defined by pvAccess.
|
||||
For monitors it calls the code described in the following sections.</p>
|
||||
<h3>ChannelLocalDebug</h3>
|
||||
<p>The channelProvider implementation provides the ability to generate
|
||||
debug messages based a debug level with the following meaning:</p>
|
||||
<dl>
|
||||
<dt><=0</dt>
|
||||
<dd>No debug messages </dd>
|
||||
<dt>>0</dt>
|
||||
<dd>Generate a message when anything is created or destroyed</dd>
|
||||
<dt>>1</dt>
|
||||
<dd>Also generate processing messages.</dd>
|
||||
</dl>
|
||||
<p>ChannelProviderLocal has a method:</p>
|
||||
<pre>
|
||||
void createChannelLocalDebugRecord(
|
||||
String const & recordName);
|
||||
</pre>
|
||||
<p>This method creates a PVRecord that allows a pvAccess client to set the
|
||||
debug level.</p>
|
||||
<h3>pvCopy</h3>
|
||||
<p>This provides code that creates a top level PVStructure that is an arbitrary
|
||||
subset of the fields in the PVStructure from a PVRecord.
|
||||
In addition it provides code that monitors changes to the fields in a PVRecord.
|
||||
A client configures the desired set of subfields and monitoring options
|
||||
via a pvRequest structure.
|
||||
pvAccess provides a class CreatePVRequest that creates a pvRequest.
|
||||
The pvCopy code provides the same functionality as the pvCopy code in pvIOCJava.
|
||||
</p>
|
||||
<h3>monitorAlgorithm</h3>
|
||||
<p>Currently all that is implemented is a header file.
|
||||
The only algorithm currently implemented is <b>onPut</b>
|
||||
</p>
|
||||
<h3>monitorFactory</h3>
|
||||
<h4>Overview</h4>
|
||||
<p><b>epics::pvData::monitor</b> defines the monitor interfaces
|
||||
as seen by a client.
|
||||
See
|
||||
<a href="http://epics-pvdata.sourceforge.net/docbuild/pvDatabaseCPP/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
For details.</p>
|
||||
<p>
|
||||
monitorFactory implements the
|
||||
monitoring interfaces for a PVRecord.
|
||||
It implements queueSize=0 and queueSize>=2.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The implementation uses PVCopy and PVCopyMonitor which are implemented in pvCopy.
|
||||
When PVCopyMonitor tells monitor that changes
|
||||
have occurred, monitor applies the appropriate algorithm to each changed field.</p>
|
||||
|
||||
<p>Currently only algorithm <b>onPut</b> is implemented but,
|
||||
like pvIOCJava there are plans to support for the following monitor algorithms:</p>
|
||||
<dl>
|
||||
<dt>onPut</dt>
|
||||
<dd>A monitor is issued whenever a put is issued to the field. This is the
|
||||
default unless the record defines deadbands for a field. An exception is
|
||||
the top level timeStamp which by default is made onChange and monitor
|
||||
will not be raised.</dd>
|
||||
<dt>onChange</dt>
|
||||
<dd>This provides two options: 1) A monitor is raised whenever a field
|
||||
changes value, and 2) A monitor will never be raised for the field.</dd>
|
||||
<dt>deadband</dt>
|
||||
<dd>The field must be a numeric scalar. Whenever the absolute or percentage
|
||||
value of the field changes by more than a deadband a monitor is issued.
|
||||
The record instance can also define deadbands.</dd>
|
||||
<dt>periodic</dt>
|
||||
<dd>A monitor is issued at a periodic rate if a put was issued to any field
|
||||
being monitored.</dd>
|
||||
</dl>
|
||||
<h4>MonitorFactory</h4>
|
||||
<p>MonitorFactory provides the following methods:</p>
|
||||
<pre>class MonitorFactory
|
||||
{
|
||||
static MonitorPtr create(
|
||||
PVRecordPtr const & pvRecord,
|
||||
MonitorRequester::shared_pointer const & monitorRequester,
|
||||
PVStructurePtr const & pvRequest);
|
||||
static void registerMonitorAlgorithmCreater(
|
||||
MonitorAlgorithmCreatePtr const & monitorAlgorithmCreate,
|
||||
String const & algorithmName);
|
||||
}</pre>
|
||||
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create</dt>
|
||||
<dd>Create a monitor. The arguments are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>The record being monitored.</dd>
|
||||
<dt>monitorRequester</dt>
|
||||
<dd>The monitor requester. This is the code to which monitot events
|
||||
will be delivered.</dd>
|
||||
<dt>pvRequest</dt>
|
||||
<dd>The request options</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>registerMonitorAlgorithmCreater</dt>
|
||||
<dd>Called by code that implements a monitor algorithm.</dd>
|
||||
</dl>
|
||||
<h3>channelLocalDebugRecord</h3>
|
||||
<p>This implements a PVRecord that allows a client to set
|
||||
a debug level for the local channel provider implementation.
|
||||
The top level structure has a single integer field named value.
|
||||
See ChannelProviderLocal for the meaning associated with value.</p>
|
||||
<p>ChannelProviderLocal has a method:</p>
|
||||
<pre>
|
||||
void createChannelLocalDebugRecord(String const & recordName);
|
||||
</pre>
|
||||
<p>This creates an instance of a ChannelLocalDebugRecord and installs it
|
||||
into the PVDatabase.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS += src
|
||||
DIRS += record
|
||||
DIRS += pvCopy
|
||||
DIRS += exampleCounter
|
||||
DIRS += exampleServer
|
||||
DIRS += examplePVADoubleArrayGet
|
||||
DIRS += arrayPerformance
|
||||
DIRS += v3IOC
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += arrayPerformanceMain
|
||||
arrayPerformanceMain_SRCS += arrayPerformanceMain.cpp
|
||||
arrayPerformanceMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
arrayPerformanceMain_LIBS += pvDatabaseExample
|
||||
|
||||
PROD_HOST += longArrayMonitorMain
|
||||
longArrayMonitorMain_SRCS += longArrayMonitorMain.cpp
|
||||
longArrayMonitorMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
longArrayMonitorMain_LIBS += pvDatabaseExample
|
||||
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*arrayPerformanceMain.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.08.08
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/arrayPerformance.h>
|
||||
#include <pv/longArrayMonitor.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.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;
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
bool result(false);
|
||||
String recordName;
|
||||
recordName = "arrayPerformance";
|
||||
size_t size = 50000000;
|
||||
double delay = .01;
|
||||
String providerName("local");
|
||||
size_t nMonitor = 1;
|
||||
bool useQueue = false;
|
||||
if(argc==2 && String(argv[1])==String("-help")) {
|
||||
cout << "arrayPerformanceMain recordName size";
|
||||
cout << " delay providerName nMonitor useQueue" << endl;
|
||||
cout << "default" << endl;
|
||||
cout << "arrayPerformance ";
|
||||
cout << recordName << " ";
|
||||
cout << size << " ";
|
||||
cout << delay << " ";
|
||||
cout << providerName << " ";
|
||||
cout << nMonitor << " ";
|
||||
cout << (useQueue ? "true" : "false") << endl;
|
||||
return 0;
|
||||
}
|
||||
if(argc>1) recordName = argv[1];
|
||||
if(argc>2) size = strtoul(argv[2],0,0);
|
||||
if(argc>3) delay = atof(argv[3]);
|
||||
if(argc>4) providerName = argv[4];
|
||||
if(argc>5) nMonitor = strtoul(argv[5],0,0);
|
||||
if(argc>6) useQueue = (argv[6]==String("true") ? true : false);
|
||||
cout << "arrayPerformance ";
|
||||
cout << recordName << " ";
|
||||
cout << size << " ";
|
||||
cout << delay << " ";
|
||||
cout << providerName << " ";
|
||||
cout << nMonitor << " ";
|
||||
cout << (useQueue ? "true" : "false") << endl;
|
||||
ClientFactory::start();
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
pvRecord = ArrayPerformance::create(recordName,size,delay);
|
||||
result = master->addRecord(pvRecord);
|
||||
pvRecord = TraceRecord::create("traceRecordPGRPC");
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
pvRecord.reset();
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
std::vector<LongArrayMonitorPtr> longArrayMonitor(nMonitor);
|
||||
for(size_t i=0; i<nMonitor; ++i) {
|
||||
longArrayMonitor[i]
|
||||
= LongArrayMonitor::create(providerName,recordName,useQueue);
|
||||
}
|
||||
for(size_t i=0; i<nMonitor; ++i) longArrayMonitor[i]->start();
|
||||
cout << "arrayPerformance\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
for(size_t i=0; i<nMonitor; ++i) longArrayMonitor[i]->stop();
|
||||
pvaServer->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
pvaServer->destroy();
|
||||
ClientFactory::stop();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*longArrayMonitorMain.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.08.10
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/arrayPerformance.h>
|
||||
#include <pv/longArrayMonitor.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.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;
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
String channelName("arrayPerformance");
|
||||
bool useQueue = false;
|
||||
if(argc==2 && String(argv[1])==String("-help")) {
|
||||
cout << "longArrayMonitorMain channelName useQueue" << endl;
|
||||
cout << "default" << endl;
|
||||
cout << "longArrayMonitorMain " << channelName << " ";
|
||||
cout << (useQueue ? "true" : "false") << endl;
|
||||
return 0;
|
||||
}
|
||||
ClientFactory::start();
|
||||
if(argc>1) channelName = argv[1];
|
||||
if(argc>2) useQueue = (String(argv[2])==String("true") ? true : false);
|
||||
cout << "longArrayMonitorMain " << channelName << " ";
|
||||
cout << (useQueue ? "true" : "false") << endl;
|
||||
LongArrayMonitorPtr longArrayMonitor
|
||||
= LongArrayMonitor::create("pvAccess",channelName,useQueue);
|
||||
longArrayMonitor->start();
|
||||
cout << "longArrayMonitor\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
longArrayMonitor->destroy();
|
||||
longArrayMonitor.reset();
|
||||
ClientFactory::stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,13 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += exampleCounterMain
|
||||
exampleCounterMain_SRCS += exampleCounterMain.cpp
|
||||
exampleCounterMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*ExampleCounterMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/exampleCounter.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result(false);
|
||||
String recordName;
|
||||
recordName = "exampleCounter";
|
||||
pvRecord = ExampleCounter::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
recordName = "traceRecordPGRPC";
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
pvRecord.reset();
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
cout << "exampleCounter\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
pvaServer->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
pvaServer->destroy();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += examplePVADoubleArrayGetMain
|
||||
examplePVADoubleArrayGetMain_SRCS += examplePVADoubleArrayGetMain.cpp
|
||||
examplePVADoubleArrayGetMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
examplePVADoubleArrayGetMain_LIBS += pvDatabaseExample
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*ExamplePVADoubleArrayGetMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/examplePVADoubleArrayGet.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.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;
|
||||
|
||||
static StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ClientFactory::start();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result(false);
|
||||
String recordName;
|
||||
PVStructurePtr pvStructure = standardPVField->scalarArray(
|
||||
pvDouble,"alarm,timeStamp");
|
||||
recordName = "doubleArray";
|
||||
pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
recordName = "examplePVADoubleArrayGet";
|
||||
if(argc>1) recordName = argv[1];
|
||||
String providerName("local");
|
||||
if(argc>2) providerName = argv[2];
|
||||
String channelName("doubleArray");
|
||||
if(argc>3) channelName = argv[3];
|
||||
pvRecord = ExamplePVADoubleArrayGet::create(
|
||||
recordName,providerName,channelName);
|
||||
if(pvRecord!=NULL) {
|
||||
result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
} else {
|
||||
cout << "ExamplePVADoubleArrayGet::create failed" << endl;
|
||||
}
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
serverContext->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
serverContext->destroy();
|
||||
ClientFactory::stop();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += exampleServerMain
|
||||
exampleServerMain_SRCS += exampleServerMain.cpp
|
||||
exampleServerMain_LIBS += pvDatabase pvDatabaseExample pvAccess pvData Com
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*exampleServerMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/exampleServerCreateRecords.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
ExampleServerCreateRecords::create();
|
||||
ServerContext::shared_pointer ctx =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
cout << "exampleServer\n";
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
String buffer;
|
||||
pvNames->toString(&buffer);
|
||||
cout << "recordNames" << endl << buffer << endl;
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
ctx->destroy();
|
||||
epicsThreadSleep(1.0);
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += testPVCopy
|
||||
testPVCopy_SRCS += testPVCopy.cpp
|
||||
testPVCopy_LIBS += pvDatabase pvAccess pvData Com
|
||||
|
||||
PROD_HOST += testPVRecord
|
||||
testPVRecord_SRCS += testPVRecord.cpp
|
||||
testPVRecord_LIBS += pvDatabase pvAccess pvData Com
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,423 +0,0 @@
|
||||
/*testPVCopyMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/powerSupplyRecordTest.h>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
|
||||
class MyRequester;
|
||||
typedef std::tr1::shared_ptr<MyRequester> MyRequesterPtr;
|
||||
|
||||
class MyRequester : public Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(MyRequester);
|
||||
MyRequester(String const &requesterName)
|
||||
: requesterName(requesterName)
|
||||
{}
|
||||
virtual ~MyRequester() {}
|
||||
virtual String getRequesterName() { return requesterName;}
|
||||
virtual void message(String const & message,MessageType messageType)
|
||||
{
|
||||
cout << message << endl;
|
||||
}
|
||||
private:
|
||||
String requesterName;
|
||||
};
|
||||
|
||||
static PVRecordPtr createScalar(
|
||||
String const & recordName,
|
||||
ScalarType scalarType,
|
||||
String const & properties)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalar(scalarType,properties);
|
||||
return PVRecord::create(recordName,pvStructure);
|
||||
}
|
||||
|
||||
static PVRecordPtr createScalarArray(
|
||||
String const & recordName,
|
||||
ScalarType scalarType,
|
||||
String const & properties)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalarArray(scalarType,properties);
|
||||
return PVRecord::create(recordName,pvStructure);
|
||||
}
|
||||
|
||||
static PowerSupplyRecordTestPtr createPowerSupply(String const & recordName)
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
StandardFieldPtr standardField = getStandardField();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
size_t nfields = 5;
|
||||
StringArray names;
|
||||
names.reserve(nfields);
|
||||
FieldConstPtrArray powerSupply;
|
||||
powerSupply.reserve(nfields);
|
||||
names.push_back("alarm");
|
||||
powerSupply.push_back(standardField->alarm());
|
||||
names.push_back("timeStamp");
|
||||
powerSupply.push_back(standardField->timeStamp());
|
||||
String properties("alarm,display");
|
||||
names.push_back("voltage");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("power");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("current");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
return PowerSupplyRecordTest::create(recordName,
|
||||
pvDataCreate->createPVStructure(
|
||||
fieldCreate->createStructure(names,powerSupply)));
|
||||
}
|
||||
|
||||
static void testPVScalar(
|
||||
String const & valueNameRecord,
|
||||
String const & valueNameCopy,
|
||||
PVRecordPtr const & pvRecord,
|
||||
PVCopyPtr const & pvCopy)
|
||||
{
|
||||
PVRecordFieldPtr pvRecordField;
|
||||
PVStructurePtr pvStructureRecord;
|
||||
PVStructurePtr pvStructureCopy;
|
||||
PVFieldPtr pvField;
|
||||
PVScalarPtr pvValueRecord;
|
||||
PVScalarPtr pvValueCopy;
|
||||
BitSetPtr bitSet;
|
||||
String builder;
|
||||
size_t offset;
|
||||
ConvertPtr convert = getConvert();
|
||||
|
||||
cout << endl;
|
||||
pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
|
||||
pvField = pvStructureRecord->getSubField(valueNameRecord);
|
||||
pvValueRecord = static_pointer_cast<PVScalar>(pvField);
|
||||
convert->fromDouble(pvValueRecord,.04);
|
||||
StructureConstPtr structure = pvCopy->getStructure();
|
||||
builder.clear(); structure->toString(&builder);
|
||||
cout << "structure from copy" << endl << builder << endl;
|
||||
pvStructureCopy = pvCopy->createPVStructure();
|
||||
pvField = pvStructureCopy->getSubField(valueNameCopy);
|
||||
pvValueCopy = static_pointer_cast<PVScalar>(pvField);
|
||||
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
pvCopy->initCopy(pvStructureCopy, bitSet);
|
||||
cout << "after initCopy pvValueCopy " << convert->toDouble(pvValueCopy);
|
||||
cout << endl;
|
||||
convert->fromDouble(pvValueRecord,.06);
|
||||
pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
cout << "after put(.06) pvValueCopy " << convert->toDouble(pvValueCopy);
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
pvRecordField = pvRecord->findPVRecordField(pvValueRecord);
|
||||
offset = pvCopy->getCopyOffset(pvRecordField);
|
||||
cout << "getCopyOffset() " << offset;
|
||||
cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset();
|
||||
cout << " pvValueRecord->getOffset() " << pvValueRecord->getFieldOffset();
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
bitSet->clear();
|
||||
convert->fromDouble(pvValueRecord,1.0);
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << "before updateCopyFromBitSet";
|
||||
cout << " recordValue " << convert->toDouble(pvValueRecord);
|
||||
cout << " copyValue " << convert->toDouble(pvValueCopy);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
bitSet->set(0);
|
||||
pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
|
||||
cout << "after updateCopyFromBitSet";
|
||||
cout << " recordValue " << convert->toDouble(pvValueRecord);
|
||||
cout << " copyValue " << convert->toDouble(pvValueCopy);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
convert->fromDouble(pvValueCopy,2.0);
|
||||
bitSet->set(0);
|
||||
cout << "before updateRecord";
|
||||
cout << " recordValue " << convert->toDouble(pvValueRecord);
|
||||
cout << " copyValue " << convert->toDouble(pvValueCopy);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
pvCopy->updateRecord(pvStructureCopy,bitSet);
|
||||
cout << "after updateRecord";
|
||||
cout << " recordValue " << convert->toDouble(pvValueRecord);
|
||||
cout << " copyValue " << convert->toDouble(pvValueCopy);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
static void testPVScalarArray(
|
||||
ScalarType scalarType,
|
||||
String const & valueNameRecord,
|
||||
String const & valueNameCopy,
|
||||
PVRecordPtr const & pvRecord,
|
||||
PVCopyPtr const & pvCopy)
|
||||
{
|
||||
PVRecordFieldPtr pvRecordField;
|
||||
PVStructurePtr pvStructureRecord;
|
||||
PVStructurePtr pvStructureCopy;
|
||||
PVScalarArrayPtr pvValueRecord;
|
||||
PVScalarArrayPtr pvValueCopy;
|
||||
BitSetPtr bitSet;
|
||||
String builder;
|
||||
size_t offset;
|
||||
size_t n = 5;
|
||||
shared_vector<double> values(n);
|
||||
cout << endl;
|
||||
pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
|
||||
pvValueRecord = pvStructureRecord->getScalarArrayField(valueNameRecord,scalarType);
|
||||
for(size_t i=0; i<n; i++) values[i] = i;
|
||||
const shared_vector<const double> xxx(freeze(values));
|
||||
pvValueRecord->putFrom(xxx);
|
||||
StructureConstPtr structure = pvCopy->getStructure();
|
||||
builder.clear(); structure->toString(&builder);
|
||||
cout << "structure from copy" << endl << builder << endl;
|
||||
pvStructureCopy = pvCopy->createPVStructure();
|
||||
pvValueCopy = pvStructureCopy->getScalarArrayField(valueNameCopy,scalarType);
|
||||
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
pvCopy->initCopy(pvStructureCopy, bitSet);
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << "after initCopy pvValueCopy " << builder << endl;
|
||||
cout << endl;
|
||||
values.resize(n);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + .06;
|
||||
const shared_vector<const double> yyy(freeze(values));
|
||||
pvValueRecord->putFrom(yyy);
|
||||
pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << "after put(i+ .06) pvValueCopy " << builder << endl;
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
pvRecordField = pvRecord->findPVRecordField(pvValueRecord);
|
||||
offset = pvCopy->getCopyOffset(pvRecordField);
|
||||
cout << "getCopyOffset() " << offset;
|
||||
cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset();
|
||||
cout << " pvValueRecord->getOffset() " << pvValueRecord->getFieldOffset();
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
bitSet->clear();
|
||||
values.resize(n);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + 1.0;
|
||||
const shared_vector<const double> zzz(freeze(values));
|
||||
pvValueRecord->putFrom(zzz);
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << "before updateCopyFromBitSet";
|
||||
builder.clear(); pvValueRecord->toString(&builder);
|
||||
cout << " recordValue " << builder << endl;
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << " copyValue " << builder << endl;
|
||||
cout << " bitSet " << builder;
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << endl;
|
||||
bitSet->set(0);
|
||||
pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
|
||||
cout << "after updateCopyFromBitSet";
|
||||
builder.clear(); pvValueRecord->toString(&builder);
|
||||
cout << " recordValue " << builder << endl;
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << " copyValue " << builder << endl;
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
values.resize(n);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + 2.0;
|
||||
const shared_vector<const double> ttt(freeze(values));
|
||||
pvValueRecord->putFrom(ttt);
|
||||
bitSet->set(0);
|
||||
cout << "before updateRecord";
|
||||
builder.clear(); pvValueRecord->toString(&builder);
|
||||
cout << " recordValue " << builder << endl;
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << " copyValue " << builder << endl;
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
pvCopy->updateRecord(pvStructureCopy,bitSet);
|
||||
cout << "after updateRecord";
|
||||
builder.clear(); pvValueRecord->toString(&builder);
|
||||
cout << " recordValue " << builder << endl;
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << " copyValue " << builder << endl;
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
static void scalarTest()
|
||||
{
|
||||
cout << endl << endl << "****scalarTest****" << endl;
|
||||
RequesterPtr requester(new MyRequester("exampleTest"));
|
||||
PVRecordPtr pvRecord;
|
||||
String request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVRecordFieldPtr pvRecordField;
|
||||
PVCopyPtr pvCopy;
|
||||
String builder;
|
||||
String valueNameRecord;
|
||||
String valueNameCopy;
|
||||
|
||||
pvRecord = createScalar("doubleRecord",pvDouble,"alarm,timeStamp,display");
|
||||
valueNameRecord = request = "value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl;
|
||||
cout << "pvRequest" << endl << builder;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "";
|
||||
valueNameRecord = "value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl << "pvRequest" << endl << builder << endl;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "alarm,timeStamp,value";
|
||||
valueNameRecord = "value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl << "pvRequest" << endl << builder << endl;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
{
|
||||
cout << endl << endl << "****arrayTest****" << endl;
|
||||
RequesterPtr requester(new MyRequester("exampleTest"));
|
||||
PVRecordPtr pvRecord;
|
||||
String request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVRecordFieldPtr pvRecordField;
|
||||
PVCopyPtr pvCopy;
|
||||
String builder;
|
||||
String valueNameRecord;
|
||||
String valueNameCopy;
|
||||
|
||||
pvRecord = createScalarArray("doubleArrayRecord",pvDouble,"alarm,timeStamp");
|
||||
valueNameRecord = request = "value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl;
|
||||
cout << "pvRequest" << endl << builder;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(pvDouble,valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "";
|
||||
valueNameRecord = "value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl << "pvRequest" << endl << builder << endl;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(pvDouble,valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "alarm,timeStamp,value";
|
||||
valueNameRecord = "value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl << "pvRequest" << endl << builder << endl;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(pvDouble,valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void powerSupplyTest()
|
||||
{
|
||||
cout << endl << endl << "****powerSupplyTest****" << endl;
|
||||
RequesterPtr requester(new MyRequester("exampleTest"));
|
||||
PowerSupplyRecordTestPtr pvRecord;
|
||||
String request;
|
||||
PVStructurePtr pvRequest;
|
||||
PVRecordFieldPtr pvRecordField;
|
||||
PVCopyPtr pvCopy;
|
||||
String builder;
|
||||
String valueNameRecord;
|
||||
String valueNameCopy;
|
||||
|
||||
pvRecord = createPowerSupply("powerSupply");
|
||||
valueNameRecord = request = "power.value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl;
|
||||
cout << "pvRequest" << endl << builder;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "";
|
||||
valueNameRecord = "power.value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl << "pvRequest" << endl << builder << endl;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "power.value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "alarm,timeStamp,voltage.value,power.value,current.value";
|
||||
valueNameRecord = "power.value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl << "pvRequest" << endl << builder << endl;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "power";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "alarm,timeStamp,voltage{value,alarm},power{value,alarm,display},current.value";
|
||||
valueNameRecord = "power.value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,requester);
|
||||
builder.clear(); pvRequest->toString(&builder);
|
||||
cout << "request " << request << endl << "pvRequest" << endl << builder << endl;
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
valueNameCopy = "power.value";
|
||||
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
scalarTest();
|
||||
arrayTest();
|
||||
powerSupplyTest();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/*testPVRecordMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <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/pvCopy.h>
|
||||
#include <pv/powerSupplyRecordTest.h>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
static PVRecordPtr createScalar(
|
||||
String const & recordName,
|
||||
ScalarType scalarType,
|
||||
String const & properties)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalar(scalarType,properties);
|
||||
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
pvStructure.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
static PVRecordPtr createScalarArray(
|
||||
String const & recordName,
|
||||
ScalarType scalarType,
|
||||
String const & properties)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalarArray(scalarType,properties);
|
||||
return PVRecord::create(recordName,pvStructure);
|
||||
}
|
||||
|
||||
static PowerSupplyRecordTestPtr createPowerSupply(String const & recordName)
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
StandardFieldPtr standardField = getStandardField();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
size_t nfields = 5;
|
||||
StringArray names;
|
||||
names.reserve(nfields);
|
||||
FieldConstPtrArray powerSupply;
|
||||
powerSupply.reserve(nfields);
|
||||
names.push_back("alarm");
|
||||
powerSupply.push_back(standardField->alarm());
|
||||
names.push_back("timeStamp");
|
||||
powerSupply.push_back(standardField->timeStamp());
|
||||
String properties("alarm,display");
|
||||
names.push_back("voltage");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("power");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("current");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
return PowerSupplyRecordTest::create(recordName,
|
||||
pvDataCreate->createPVStructure(
|
||||
fieldCreate->createStructure(names,powerSupply)));
|
||||
}
|
||||
|
||||
static void scalarTest()
|
||||
{
|
||||
cout << endl << endl << "****scalarTest****" << endl;
|
||||
PVRecordPtr pvRecord;
|
||||
pvRecord = createScalar("doubleRecord",pvDouble,"alarm,timeStamp.display");
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void arrayTest()
|
||||
{
|
||||
cout << endl << endl << "****arrayTest****" << endl;
|
||||
PVRecordPtr pvRecord;
|
||||
pvRecord = createScalarArray("doubleArrayRecord",pvDouble,"alarm,timeStamp");
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
static void powerSupplyTest()
|
||||
{
|
||||
cout << endl << endl << "****powerSupplyTest****" << endl;
|
||||
PowerSupplyRecordTestPtr pvRecord;
|
||||
pvRecord = createPowerSupply("powerSupply");
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
scalarTest();
|
||||
arrayTest();
|
||||
powerSupplyTest();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += testExampleRecord
|
||||
testExampleRecord_SRCS += testExampleRecordMain.cpp
|
||||
testExampleRecord_LIBS += pvDatabase pvAccess pvData Com
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/*testExampleRecordMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <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 <epicsExport.h>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/powerSupplyRecordTest.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
|
||||
static PVStructurePtr createPowerSupply()
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
StandardFieldPtr standardField = getStandardField();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
size_t nfields = 5;
|
||||
StringArray names;
|
||||
names.reserve(nfields);
|
||||
FieldConstPtrArray powerSupply;
|
||||
powerSupply.reserve(nfields);
|
||||
names.push_back("alarm");
|
||||
powerSupply.push_back(standardField->alarm());
|
||||
names.push_back("timeStamp");
|
||||
powerSupply.push_back(standardField->timeStamp());
|
||||
String properties("alarm,display");
|
||||
names.push_back("voltage");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("power");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("current");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
return pvDataCreate->createPVStructure(
|
||||
fieldCreate->createStructure(names,powerSupply));
|
||||
}
|
||||
|
||||
|
||||
void test()
|
||||
{
|
||||
StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
String properties;
|
||||
ScalarType scalarType;
|
||||
String recordName;
|
||||
properties = "alarm,timeStamp";
|
||||
scalarType = pvDouble;
|
||||
recordName = "exampleDouble";
|
||||
PVStructurePtr pvStructure;
|
||||
pvStructure = standardPVField->scalar(scalarType,properties);
|
||||
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
{
|
||||
pvRecord->lock();
|
||||
pvRecord->process();
|
||||
pvRecord->unlock();
|
||||
}
|
||||
cout << "processed exampleDouble " << endl;
|
||||
pvRecord->destroy();
|
||||
pvRecord.reset();
|
||||
recordName = "powerSupplyExample";
|
||||
pvStructure.reset();
|
||||
pvStructure = createPowerSupply();
|
||||
PowerSupplyRecordTestPtr psr =
|
||||
PowerSupplyRecordTest::create(recordName,pvStructure);
|
||||
if(psr.get()==NULL) {
|
||||
cout << "PowerSupplyRecordTest::create failed" << endl;
|
||||
return;
|
||||
}
|
||||
pvStructure.reset();
|
||||
double voltage,power,current;
|
||||
{
|
||||
psr->lock();
|
||||
voltage = psr->getVoltage();
|
||||
power = psr->getPower();
|
||||
current = psr->getCurrent();
|
||||
psr->unlock();
|
||||
}
|
||||
cout << "initial ";
|
||||
cout << " voltage " << voltage ;
|
||||
cout << " power " << power;
|
||||
cout << " current " << current;
|
||||
cout << endl;
|
||||
voltage = 1.0;
|
||||
power = 1.0;
|
||||
cout << "before put ";
|
||||
cout << " voltage " << voltage ;
|
||||
cout << " power " << power;
|
||||
cout << endl;
|
||||
{
|
||||
psr->lock();
|
||||
psr->put(power,voltage);
|
||||
psr->process();
|
||||
psr->unlock();
|
||||
}
|
||||
{
|
||||
psr->lock();
|
||||
cout << "after put ";
|
||||
cout << " voltage " << psr->getVoltage() ;
|
||||
cout << " power " << psr->getPower();
|
||||
cout << " current " << psr->getCurrent();
|
||||
cout << endl;
|
||||
psr->unlock();
|
||||
}
|
||||
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
|
||||
pvDatabase->addRecord(psr);
|
||||
psr.reset();
|
||||
pvDatabase->destroy();
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
EXAMPLESRC = $(TOP)/example/src/
|
||||
|
||||
LIBRARY_IOC += pvDatabaseExample
|
||||
pvDatabaseExample_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
pvDatabaseExample_LIBS += Com pvData pvAccess pvDatabase
|
||||
|
||||
SRC_DIRS += $(EXAMPLESRC)/exampleCounter
|
||||
INC += exampleCounter.h
|
||||
|
||||
SRC_DIRS += $(EXAMPLESRC)/exampleServer
|
||||
INC+= exampleServerCreateRecords.h
|
||||
LIBSRCS += exampleServerCreateRecords.cpp
|
||||
|
||||
SRC_DIRS += $(EXAMPLESRC)/examplePVADoubleArrayGet
|
||||
INC+= examplePVADoubleArrayGet.h
|
||||
LIBSRCS += examplePVADoubleArrayGet.cpp
|
||||
|
||||
SRC_DIRS += $(EXAMPLESRC)/arrayPerformance
|
||||
INC+= arrayPerformance.h
|
||||
LIBSRCS += arrayPerformance.cpp
|
||||
INC+= longArrayMonitor.h
|
||||
LIBSRCS += longArrayMonitor.cpp
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/* arrayPerformance.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.08.08
|
||||
*/
|
||||
#include <pv/lock.h>
|
||||
#include <pv/arrayPerformance.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
ArrayPerformancePtr ArrayPerformance::create(
|
||||
epics::pvData::String const & recordName,
|
||||
size_t size,
|
||||
double delay)
|
||||
{
|
||||
epics::pvData::PVStructurePtr pvStructure =
|
||||
epics::pvData::getStandardPVField()->scalarArray(epics::pvData::pvLong,"timeStamp,alarm");
|
||||
ArrayPerformancePtr pvRecord(
|
||||
new ArrayPerformance(recordName,pvStructure,size,delay));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ArrayPerformance::ArrayPerformance(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
size_t size,
|
||||
double delay)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
size(size),
|
||||
delay(delay),
|
||||
isDestroyed(false)
|
||||
{
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
}
|
||||
|
||||
ArrayPerformance::~ArrayPerformance()
|
||||
{
|
||||
}
|
||||
|
||||
bool ArrayPerformance::init()
|
||||
{
|
||||
|
||||
initPVRecord();
|
||||
PVScalarArrayPtr pvScalarArray = getPVStructure()->getScalarArrayField("value",pvLong);
|
||||
if(pvScalarArray==NULL) return false;
|
||||
pvValue = static_pointer_cast<PVLongArray>(pvScalarArray);
|
||||
ArrayPerformancePtr xxx = dynamic_pointer_cast<ArrayPerformance>(getPtrSelf());
|
||||
arrayPerformanceThread = ArrayPerformanceThreadPtr(new ArrayPerformanceThread(xxx));
|
||||
arrayPerformanceThread->init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArrayPerformance::start()
|
||||
{
|
||||
arrayPerformanceThread->start();
|
||||
}
|
||||
|
||||
void ArrayPerformance::process()
|
||||
{
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
|
||||
void ArrayPerformance::destroy()
|
||||
{
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
arrayPerformanceThread->destroy();
|
||||
arrayPerformanceThread.reset();
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
ArrayPerformanceThread::ArrayPerformanceThread(ArrayPerformancePtr const & arrayPerformance)
|
||||
:
|
||||
arrayPerformance(arrayPerformance),
|
||||
isDestroyed(false),
|
||||
runReturned(false),
|
||||
threadName("arrayPerformance")
|
||||
{}
|
||||
|
||||
void ArrayPerformanceThread::init()
|
||||
{
|
||||
thread = std::auto_ptr<epicsThread>(new epicsThread(
|
||||
*this,
|
||||
threadName.c_str(),
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
epicsThreadPriorityHigh));
|
||||
}
|
||||
|
||||
void ArrayPerformanceThread::start()
|
||||
{
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void ArrayPerformanceThread::destroy()
|
||||
{
|
||||
Lock lock(mutex);
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
while(true) {
|
||||
if(runReturned) break;
|
||||
lock.unlock();
|
||||
epicsThreadSleep(.01);
|
||||
lock.lock();
|
||||
}
|
||||
thread->exitWait();
|
||||
thread.reset();
|
||||
arrayPerformance.reset();
|
||||
}
|
||||
|
||||
void ArrayPerformanceThread::run()
|
||||
{
|
||||
TimeStamp timeStamp;
|
||||
TimeStamp timeStampLast;
|
||||
timeStampLast.getCurrent();
|
||||
int nSinceLastReport = 0;
|
||||
while(true) {
|
||||
if(arrayPerformance->delay>0.0) epicsThreadSleep(arrayPerformance->delay);
|
||||
{
|
||||
Lock lock(mutex);
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
timeStamp.getCurrent();
|
||||
double diff = TimeStamp::diff(timeStamp,timeStampLast);
|
||||
if(diff>=1.0) {
|
||||
cout << "arrayPerformance value " << value;
|
||||
cout << " time " << diff;
|
||||
double iterations = nSinceLastReport;
|
||||
iterations /= diff;
|
||||
cout << " iterations/sec " << iterations;
|
||||
double elementSize = arrayPerformance->size;
|
||||
double elementsPerSecond = elementSize*nSinceLastReport;
|
||||
elementsPerSecond /= diff;
|
||||
elementsPerSecond /= 1e6;
|
||||
cout << " elements/sec " << elementsPerSecond << "million" << endl;
|
||||
cout.flush();
|
||||
timeStampLast = timeStamp;
|
||||
nSinceLastReport = 0;
|
||||
}
|
||||
++nSinceLastReport;
|
||||
shared_vector<int64> xxx(arrayPerformance->size,value++);
|
||||
shared_vector<const int64> data(freeze(xxx));
|
||||
arrayPerformance->lock();
|
||||
try {
|
||||
arrayPerformance->beginGroupPut();
|
||||
arrayPerformance->pvValue->replace(data);
|
||||
arrayPerformance->process();
|
||||
arrayPerformance->endGroupPut();
|
||||
} catch(...) {
|
||||
arrayPerformance->unlock();
|
||||
throw;
|
||||
}
|
||||
arrayPerformance->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/* arrayPerformance.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.08.08
|
||||
*/
|
||||
#ifndef ARRAYPERFORMANCE_H
|
||||
#define ARRAYPERFORMANCE_H
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class ArrayPerformance;
|
||||
typedef std::tr1::shared_ptr<ArrayPerformance> ArrayPerformancePtr;
|
||||
|
||||
class ArrayPerformanceThread;
|
||||
typedef std::tr1::shared_ptr<ArrayPerformanceThread> ArrayPerformanceThreadPtr;
|
||||
|
||||
class ArrayPerformance :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ArrayPerformance);
|
||||
static ArrayPerformancePtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
size_t size,
|
||||
double delay);
|
||||
virtual ~ArrayPerformance();
|
||||
virtual bool init();
|
||||
virtual void start();
|
||||
virtual void process();
|
||||
virtual void destroy();
|
||||
private:
|
||||
ArrayPerformance(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
size_t size,
|
||||
double delay);
|
||||
size_t size;
|
||||
double delay;
|
||||
bool isDestroyed;
|
||||
epics::pvData::PVLongArrayPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
ArrayPerformanceThreadPtr arrayPerformanceThread;
|
||||
friend class ArrayPerformanceThread;
|
||||
};
|
||||
|
||||
class ArrayPerformanceThread :
|
||||
public epicsThreadRunable
|
||||
{
|
||||
public:
|
||||
ArrayPerformanceThread(ArrayPerformancePtr const & arrayPerformance);
|
||||
virtual ~ArrayPerformanceThread(){};
|
||||
void init();
|
||||
void start();
|
||||
virtual void run();
|
||||
void destroy();
|
||||
private:
|
||||
ArrayPerformancePtr arrayPerformance;
|
||||
bool isDestroyed;
|
||||
bool runReturned;
|
||||
epics::pvData::String threadName;
|
||||
epics::pvData::Mutex mutex;
|
||||
epics::pvData::int64 value;
|
||||
std::auto_ptr<epicsThread> thread;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* ARRAYPERFORMANCE_H */
|
||||
@@ -1,284 +0,0 @@
|
||||
/* longArrayMonitor.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.08.09
|
||||
*/
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/longArrayMonitor.h>
|
||||
#include <pv/caProvider.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
static String requesterName("longArrayMonitor");
|
||||
|
||||
static void messagePvt(String const & message, MessageType messageType)
|
||||
{
|
||||
cout << requesterName << " message " << message << endl;
|
||||
}
|
||||
|
||||
class LAMChannelRequester :
|
||||
public ChannelRequester
|
||||
{
|
||||
public:
|
||||
LAMChannelRequester(LongArrayMonitorPtr const &longArrayMonitor)
|
||||
: longArrayMonitor(longArrayMonitor)
|
||||
{}
|
||||
virtual ~LAMChannelRequester(){}
|
||||
virtual String getRequesterName() { return requesterName;}
|
||||
virtual void message(String const & message, MessageType messageType)
|
||||
{ messagePvt(message,messageType);}
|
||||
virtual void channelCreated(const Status& status, Channel::shared_pointer const & channel);
|
||||
virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState);
|
||||
private:
|
||||
LongArrayMonitorPtr longArrayMonitor;
|
||||
};
|
||||
|
||||
void LAMChannelRequester::channelCreated(const Status& status, Channel::shared_pointer const & channel)
|
||||
{
|
||||
if(!status.isOK()) messagePvt(status.getMessage(),errorMessage);
|
||||
longArrayMonitor->status = status;
|
||||
longArrayMonitor->channel = channel;
|
||||
longArrayMonitor->event.signal();
|
||||
}
|
||||
|
||||
void LAMChannelRequester::channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState)
|
||||
{
|
||||
MessageType messageType = (connectionState==Channel::CONNECTED ? infoMessage : errorMessage);
|
||||
messagePvt("channelStateChange",messageType);
|
||||
}
|
||||
|
||||
|
||||
class LAMMonitorRequester :
|
||||
public MonitorRequester,
|
||||
public epicsThreadRunable
|
||||
{
|
||||
public:
|
||||
LAMMonitorRequester(LongArrayMonitorPtr const &longArrayMonitor)
|
||||
: longArrayMonitor(longArrayMonitor),
|
||||
isDestroyed(false),
|
||||
runReturned(false),
|
||||
threadName("longArrayMonitor")
|
||||
{}
|
||||
virtual ~LAMMonitorRequester(){}
|
||||
void init();
|
||||
virtual void destroy();
|
||||
virtual void run();
|
||||
virtual String getRequesterName() { return requesterName;}
|
||||
virtual void message(String const & message, MessageType messageType)
|
||||
{ messagePvt(message,messageType);}
|
||||
virtual void monitorConnect(Status const & status,
|
||||
MonitorPtr const & monitor, StructureConstPtr const & structure);
|
||||
virtual void monitorEvent(MonitorPtr const & monitor);
|
||||
virtual void unlisten(MonitorPtr const & monitor);
|
||||
private:
|
||||
void handleMonitor();
|
||||
LongArrayMonitorPtr longArrayMonitor;
|
||||
bool isDestroyed;
|
||||
bool runReturned;
|
||||
epics::pvData::String threadName;
|
||||
Event event;
|
||||
std::auto_ptr<epicsThread> thread;
|
||||
};
|
||||
|
||||
void LAMMonitorRequester::init()
|
||||
{
|
||||
thread = std::auto_ptr<epicsThread>(new epicsThread(
|
||||
*this,
|
||||
threadName.c_str(),
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
epicsThreadPriorityLow));
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void LAMMonitorRequester::destroy()
|
||||
{
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
event.signal();
|
||||
while(true) {
|
||||
if(runReturned) break;
|
||||
epicsThreadSleep(.01);
|
||||
}
|
||||
thread->exitWait();
|
||||
longArrayMonitor.reset();
|
||||
}
|
||||
|
||||
|
||||
void LAMMonitorRequester::monitorConnect(Status const & status,
|
||||
MonitorPtr const & monitor, StructureConstPtr const & structure)
|
||||
{
|
||||
longArrayMonitor->status = status;
|
||||
longArrayMonitor->monitor = monitor;
|
||||
if(!status.isOK()) {
|
||||
messagePvt(status.getMessage(),errorMessage);
|
||||
longArrayMonitor->event.signal();
|
||||
return;
|
||||
}
|
||||
bool structureOK(true);
|
||||
FieldConstPtr field = structure->getField("timeStamp");
|
||||
if(field==NULL) structureOK = false;
|
||||
field = structure->getField("value");
|
||||
if(field==NULL) {
|
||||
structureOK = false;
|
||||
} else {
|
||||
if(field->getType()!=scalarArray) {
|
||||
structureOK = false;
|
||||
} else {
|
||||
ScalarArrayConstPtr scalarArray = dynamic_pointer_cast<const ScalarArray>(field);
|
||||
if(scalarArray->getElementType()!=pvLong) structureOK = false;
|
||||
}
|
||||
}
|
||||
if(!structureOK) {
|
||||
String message("monitorConnect: illegal structure");
|
||||
messagePvt(message,errorMessage);
|
||||
longArrayMonitor->status = Status(Status::STATUSTYPE_ERROR,message);
|
||||
}
|
||||
longArrayMonitor->event.signal();
|
||||
}
|
||||
|
||||
void LAMMonitorRequester::run()
|
||||
{
|
||||
PVLongArrayPtr pvValue;
|
||||
PVTimeStamp pvTimeStamp;
|
||||
TimeStamp timeStamp;
|
||||
TimeStamp timeStampLast;
|
||||
timeStampLast.getCurrent();
|
||||
while(true) {
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
while(true) {
|
||||
MonitorElementPtr monitorElement = longArrayMonitor->monitor->poll();
|
||||
if(monitorElement==NULL) break;
|
||||
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
pvTimeStamp.get(timeStamp);
|
||||
pvValue = dynamic_pointer_cast<PVLongArray>(pvStructure->getSubField("value"));
|
||||
shared_vector<const int64> data = pvValue->view();
|
||||
if(data.size()>0) {
|
||||
int64 first = data[0];
|
||||
int64 last = data[data.size()-1];
|
||||
int64 sum = 0;
|
||||
for(size_t i=0; i<data.size(); ++i) sum += data[i];
|
||||
double diff = TimeStamp::diff(timeStamp,timeStampLast);
|
||||
double elementsPerSecond = data.size();
|
||||
elementsPerSecond = 1e-6*elementsPerSecond/diff;
|
||||
cout.flush();
|
||||
cout << "first " << first << " last " << last << " sum " << sum;
|
||||
cout << " elements/sec " << elementsPerSecond << "million";
|
||||
BitSetPtr changed = monitorElement->changedBitSet;
|
||||
BitSetPtr overrun = monitorElement->overrunBitSet;
|
||||
String buffer;
|
||||
changed->toString(&buffer);
|
||||
cout << " changed " << buffer;
|
||||
buffer.clear();
|
||||
overrun->toString(&buffer);
|
||||
cout << " overrun " << buffer;
|
||||
cout << endl;
|
||||
cout.flush();
|
||||
timeStampLast = timeStamp;
|
||||
} else {
|
||||
cout << "size = 0" << endl;
|
||||
}
|
||||
longArrayMonitor->monitor->release(monitorElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LAMMonitorRequester::monitorEvent(MonitorPtr const & monitor)
|
||||
{
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void LAMMonitorRequester::unlisten(MonitorPtr const & monitor)
|
||||
{
|
||||
messagePvt("unlisten called",errorMessage);
|
||||
}
|
||||
|
||||
|
||||
LongArrayMonitorPtr LongArrayMonitor::create(
|
||||
String const &providerName,
|
||||
String const & channelName,
|
||||
bool useQueue)
|
||||
{
|
||||
LongArrayMonitorPtr longArrayMonitor(new LongArrayMonitor());
|
||||
if(!longArrayMonitor->init(providerName,channelName,useQueue)) longArrayMonitor.reset();
|
||||
return longArrayMonitor;
|
||||
}
|
||||
|
||||
LongArrayMonitor::LongArrayMonitor() {}
|
||||
|
||||
LongArrayMonitor::~LongArrayMonitor() {}
|
||||
|
||||
bool LongArrayMonitor::init(
|
||||
String const &providerName,
|
||||
String const &channelName,
|
||||
bool useQueue)
|
||||
{
|
||||
channelRequester = LAMChannelRequesterPtr(new LAMChannelRequester(getPtrSelf()));
|
||||
monitorRequester = LAMMonitorRequesterPtr(new LAMMonitorRequester(getPtrSelf()));
|
||||
monitorRequester->init();
|
||||
ChannelProvider::shared_pointer channelProvider = getChannelAccess()->getProvider(providerName);
|
||||
if(channelProvider==NULL) {
|
||||
cout << "provider " << providerName << " not found" << endl;
|
||||
return false;
|
||||
}
|
||||
channel = channelProvider->createChannel(channelName,channelRequester,0);
|
||||
event.wait();
|
||||
if(!status.isOK()) return false;
|
||||
String queueSize("0");
|
||||
if(useQueue) queueSize="2";
|
||||
String request("record[queueSize=");
|
||||
request += queueSize;
|
||||
request += "]field(value,timeStamp,alarm)";
|
||||
PVStructurePtr pvRequest =
|
||||
getCreateRequest()->createRequest(request,channelRequester);
|
||||
if(pvRequest==NULL) {
|
||||
cout << "request logic error " << request << endl;
|
||||
return false;
|
||||
}
|
||||
monitor = channel->createMonitor(monitorRequester,pvRequest);
|
||||
event.wait();
|
||||
if(!status.isOK()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LongArrayMonitor::start()
|
||||
{
|
||||
monitor->start();
|
||||
}
|
||||
|
||||
void LongArrayMonitor::stop()
|
||||
{
|
||||
monitor->stop();
|
||||
}
|
||||
|
||||
void LongArrayMonitor::destroy()
|
||||
{
|
||||
monitorRequester->destroy();
|
||||
monitorRequester.reset();
|
||||
monitor->destroy();
|
||||
monitor.reset();
|
||||
channel->destroy();
|
||||
channel.reset();
|
||||
channelRequester.reset();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/* longArrayMonitor.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.08.09
|
||||
*/
|
||||
#ifndef LONGARRAYMONITOR_H
|
||||
#define LONGARRAYMONITOR_H
|
||||
|
||||
#include <pv/event.h>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/pvAccess.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class LongArrayMonitor;
|
||||
typedef std::tr1::shared_ptr<LongArrayMonitor> LongArrayMonitorPtr;
|
||||
|
||||
class LAMChannelRequester;
|
||||
typedef std::tr1::shared_ptr<LAMChannelRequester> LAMChannelRequesterPtr;
|
||||
|
||||
class LAMMonitorRequester;
|
||||
typedef std::tr1::shared_ptr<LAMMonitorRequester> LAMMonitorRequesterPtr;
|
||||
|
||||
class LongArrayMonitor :
|
||||
public std::tr1::enable_shared_from_this<LongArrayMonitor>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(LongArrayMonitor);
|
||||
static LongArrayMonitorPtr create(
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName,
|
||||
bool useQueue = false);
|
||||
~LongArrayMonitor();
|
||||
void start();
|
||||
void stop();
|
||||
void destroy();
|
||||
private:
|
||||
static epics::pvData::Mutex printMutex;
|
||||
bool init(
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName,
|
||||
bool useQueue);
|
||||
LongArrayMonitorPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
LongArrayMonitor();
|
||||
|
||||
LAMChannelRequesterPtr channelRequester;
|
||||
LAMMonitorRequesterPtr monitorRequester;
|
||||
epics::pvAccess::Channel::shared_pointer channel;
|
||||
epics::pvData::Monitor::shared_pointer monitor;
|
||||
epics::pvData::Event event;
|
||||
epics::pvData::Status status;
|
||||
friend class LAMChannelRequester;
|
||||
friend class LAMMonitorRequester;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* LONGARRAYMONITOR_H */
|
||||
@@ -1,92 +0,0 @@
|
||||
/* exampleCounter.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.02
|
||||
*/
|
||||
#ifndef EXAMPLECOUNTER_H
|
||||
#define EXAMPLECOUNTER_H
|
||||
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class ExampleCounter;
|
||||
typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
|
||||
|
||||
class ExampleCounter :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleCounter);
|
||||
static ExampleCounterPtr create(
|
||||
epics::pvData::String const & recordName);
|
||||
virtual ~ExampleCounter();
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
private:
|
||||
ExampleCounter(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
};
|
||||
|
||||
ExampleCounterPtr ExampleCounter::create(
|
||||
epics::pvData::String const & recordName)
|
||||
{
|
||||
epics::pvData::PVStructurePtr pvStructure =
|
||||
epics::pvData::getStandardPVField()->scalar(epics::pvData::pvLong,"timeStamp,alarm");
|
||||
ExampleCounterPtr pvRecord(
|
||||
new ExampleCounter(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ExampleCounter::ExampleCounter(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
}
|
||||
|
||||
ExampleCounter::~ExampleCounter()
|
||||
{
|
||||
}
|
||||
|
||||
void ExampleCounter::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
bool ExampleCounter::init()
|
||||
{
|
||||
|
||||
initPVRecord();
|
||||
epics::pvData::PVFieldPtr pvField;
|
||||
pvValue = getPVStructure()->getLongField("value");
|
||||
if(pvValue.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExampleCounter::process()
|
||||
{
|
||||
pvValue->put(pvValue->get() + 1.0);
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif /* EXAMPLECOUNTER_H */
|
||||
@@ -1,161 +0,0 @@
|
||||
/* examplePVADoubleArrayGet.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.08.02
|
||||
*/
|
||||
|
||||
#include <pv/examplePVADoubleArrayGet.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/convert.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
ExamplePVADoubleArrayGetPtr ExamplePVADoubleArrayGet::create(
|
||||
String const & recordName,
|
||||
String const & providerName,
|
||||
String const & channelName)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalarArray(
|
||||
pvDouble,"alarm.timeStamp");
|
||||
ExamplePVADoubleArrayGetPtr pvRecord(
|
||||
new ExamplePVADoubleArrayGet(
|
||||
recordName,providerName,channelName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ExamplePVADoubleArrayGet::ExamplePVADoubleArrayGet(
|
||||
String const & recordName,
|
||||
String providerName,
|
||||
String channelName,
|
||||
PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
providerName(providerName),
|
||||
channelName(channelName),
|
||||
convert(getConvert())
|
||||
{
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
bool ExamplePVADoubleArrayGet::init()
|
||||
{
|
||||
initPVRecord();
|
||||
|
||||
PVStructurePtr pvStructure = getPVRecordStructure()->getPVStructure();
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
pvAlarm.attach(pvStructure->getSubField("alarm"));
|
||||
pvValue = static_pointer_cast<PVDoubleArray>(
|
||||
pvStructure->getScalarArrayField("value",pvDouble));
|
||||
if(pvValue==NULL) {
|
||||
return false;
|
||||
}
|
||||
ChannelAccess::shared_pointer channelAccess = getChannelAccess();
|
||||
ChannelProvider::shared_pointer provider =
|
||||
channelAccess->getProvider(providerName);
|
||||
if(provider==NULL) {
|
||||
cout << getRecordName() << " provider "
|
||||
<< providerName << " does not exist" << endl;
|
||||
return false;
|
||||
}
|
||||
ChannelRequester::shared_pointer channelRequester =
|
||||
dynamic_pointer_cast<ChannelRequester>(getPtrSelf());
|
||||
channel = provider->createChannel(channelName,channelRequester);
|
||||
event.wait();
|
||||
if(!status.isOK()) {
|
||||
cout << getRecordName() << " createChannel failed "
|
||||
<< status.getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
ChannelGetRequester::shared_pointer channelGetRequester =
|
||||
dynamic_pointer_cast<ChannelGetRequester>(getPtrSelf());
|
||||
PVStructurePtr pvRequest = getCreateRequest()->createRequest(
|
||||
"value,alarm,timeStamp",getPtrSelf());
|
||||
channelGet = channel->createChannelGet(channelGetRequester,pvRequest);
|
||||
event.wait();
|
||||
if(!status.isOK()) {
|
||||
cout << getRecordName() << " createChannelGet failed "
|
||||
<< status.getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
getPVValue = static_pointer_cast<PVDoubleArray>(
|
||||
getPVStructure->getScalarArrayField("value",pvDouble));
|
||||
if(getPVValue==NULL) {
|
||||
cout << getRecordName() << " get value not PVDoubleArray" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::process()
|
||||
{
|
||||
status = Status::Ok;
|
||||
channelGet->get(false);
|
||||
event.wait();
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
AlarmSeverity severity(noAlarm);
|
||||
if(!status.isOK()) {
|
||||
switch(status.getType()) {
|
||||
case Status::STATUSTYPE_OK: severity = noAlarm; break;
|
||||
case Status::STATUSTYPE_WARNING: severity = minorAlarm; break;
|
||||
case Status::STATUSTYPE_ERROR: severity = majorAlarm; break;
|
||||
case Status::STATUSTYPE_FATAL: severity = invalidAlarm; break;
|
||||
}
|
||||
alarm.setSeverity(severity);
|
||||
} else {
|
||||
convert->copy(getPVValue,pvValue);
|
||||
}
|
||||
alarm.setMessage(status.getMessage());
|
||||
pvAlarm.set(alarm);
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelCreated(
|
||||
const Status& status,
|
||||
Channel::shared_pointer const & channel)
|
||||
{
|
||||
this->status = status;
|
||||
this->channel = channel;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelStateChange(
|
||||
Channel::shared_pointer const & channel,
|
||||
Channel::ConnectionState connectionState)
|
||||
{
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelGetConnect(
|
||||
const Status& status,
|
||||
ChannelGet::shared_pointer const & channelGet,
|
||||
PVStructure::shared_pointer const & pvStructure,
|
||||
BitSet::shared_pointer const & bitSet)
|
||||
{
|
||||
this->status = status;
|
||||
this->channelGet = channelGet;
|
||||
this->getPVStructure = pvStructure;
|
||||
this->bitSet = bitSet;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::getDone(const Status& status)
|
||||
{
|
||||
this->status = status;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,82 +0,0 @@
|
||||
/* examplePVADoubleArrayGet.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.08.02
|
||||
*/
|
||||
#ifndef EXAMPLEPVADOUBLEARRAYGET_H
|
||||
#define EXAMPLEPVADOUBLEARRAYGET_H
|
||||
|
||||
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/alarm.h>
|
||||
#include <pv/pvAlarm.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class ExamplePVADoubleArrayGet;
|
||||
typedef std::tr1::shared_ptr<ExamplePVADoubleArrayGet> ExamplePVADoubleArrayGetPtr;
|
||||
|
||||
class ExamplePVADoubleArrayGet :
|
||||
public PVRecord,
|
||||
public epics::pvAccess::ChannelRequester,
|
||||
public epics::pvAccess::ChannelGetRequester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExamplePVADoubleArrayGet);
|
||||
static ExamplePVADoubleArrayGetPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName
|
||||
);
|
||||
virtual ~ExamplePVADoubleArrayGet() {}
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
virtual void channelCreated(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::Channel::shared_pointer const & channel);
|
||||
virtual void channelStateChange(
|
||||
epics::pvAccess::Channel::shared_pointer const & channel,
|
||||
epics::pvAccess::Channel::ConnectionState connectionState);
|
||||
virtual void channelGetConnect(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::ChannelGet::shared_pointer const & channelGet,
|
||||
epics::pvData::PVStructure::shared_pointer const & pvStructure,
|
||||
epics::pvData::BitSet::shared_pointer const & bitSet);
|
||||
virtual void getDone(const epics::pvData::Status& status);
|
||||
private:
|
||||
ExamplePVADoubleArrayGet(epics::pvData::String const & recordName,
|
||||
epics::pvData::String providerName,
|
||||
epics::pvData::String channelName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::String providerName;
|
||||
epics::pvData::String channelName;
|
||||
epics::pvData::ConvertPtr convert;
|
||||
epics::pvData::PVDoubleArrayPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
epics::pvData::PVAlarm pvAlarm;
|
||||
epics::pvData::Alarm alarm;
|
||||
epics::pvAccess::Channel::shared_pointer channel;
|
||||
epics::pvAccess::ChannelGet::shared_pointer channelGet;
|
||||
epics::pvData::Event event;
|
||||
epics::pvData::Status status;
|
||||
epics::pvData::PVStructurePtr getPVStructure;
|
||||
epics::pvData::BitSetPtr bitSet;
|
||||
epics::pvData::PVDoubleArrayPtr getPVValue;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* EXAMPLEPVADOUBLEARRAYGET_H */
|
||||
@@ -1,142 +0,0 @@
|
||||
/*exampleServerCreateRecords.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.07.24
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/powerSupplyRecordTest.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/exampleCounter.h>
|
||||
#include <pv/recordList.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/exampleServerCreateRecords.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
static FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
static StandardFieldPtr standardField = getStandardField();
|
||||
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
static StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
|
||||
static PVStructurePtr createPowerSupply()
|
||||
{
|
||||
size_t nfields = 5;
|
||||
StringArray names;
|
||||
names.reserve(nfields);
|
||||
FieldConstPtrArray powerSupply;
|
||||
powerSupply.reserve(nfields);
|
||||
names.push_back("alarm");
|
||||
powerSupply.push_back(standardField->alarm());
|
||||
names.push_back("timeStamp");
|
||||
powerSupply.push_back(standardField->timeStamp());
|
||||
String properties("alarm,display");
|
||||
names.push_back("voltage");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("power");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("current");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
return pvDataCreate->createPVStructure(
|
||||
fieldCreate->createStructure(names,powerSupply));
|
||||
}
|
||||
|
||||
static void createStructureArrayRecord(
|
||||
PVDatabasePtr const &master,
|
||||
ScalarType scalarType,
|
||||
String const &recordName)
|
||||
{
|
||||
StructureConstPtr structure = standardField->scalar(
|
||||
pvDouble,
|
||||
String("value,alarm,timeStamp"));
|
||||
StringArray names(2);
|
||||
FieldConstPtrArray fields(2);
|
||||
names[0] = "timeStamp";
|
||||
names[1] = "value";
|
||||
fields[0] = standardField->timeStamp();
|
||||
fields[1] = fieldCreate->createStructureArray(structure);
|
||||
StructureConstPtr top = fieldCreate->createStructure(names,fields);
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
|
||||
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
|
||||
static void createRecords(
|
||||
PVDatabasePtr const &master,
|
||||
ScalarType scalarType,
|
||||
String const &recordNamePrefix,
|
||||
String const &properties)
|
||||
{
|
||||
String recordName = recordNamePrefix;
|
||||
PVStructurePtr pvStructure = standardPVField->scalar(scalarType,properties);
|
||||
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName += "Array";
|
||||
pvStructure = standardPVField->scalarArray(scalarType,properties);
|
||||
pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
result = master->addRecord(pvRecord);
|
||||
}
|
||||
|
||||
void ExampleServerCreateRecords::create()
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
PVRecordPtr pvRecord;
|
||||
String recordName;
|
||||
bool result(false);
|
||||
recordName = "traceRecordPGRPC";
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
String properties;
|
||||
recordName = "exampleCounter";
|
||||
pvRecord = ExampleCounter::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
properties = "alarm,timeStamp";
|
||||
createRecords(master,pvBoolean,"exampleBoolean",properties);
|
||||
createRecords(master,pvByte,"exampleByte",properties);
|
||||
createRecords(master,pvShort,"exampleShort",properties);
|
||||
createRecords(master,pvInt,"exampleInt",properties);
|
||||
createRecords(master,pvLong,"exampleLong",properties);
|
||||
createRecords(master,pvFloat,"exampleFloat",properties);
|
||||
createRecords(master,pvDouble,"exampleDouble",properties);
|
||||
createRecords(master,pvString,"exampleString",properties);
|
||||
createStructureArrayRecord(master,pvDouble,"exampleStructureArray");
|
||||
recordName = "examplePowerSupply";
|
||||
PVStructurePtr pvStructure = createPowerSupply();
|
||||
PowerSupplyRecordTestPtr psr =
|
||||
PowerSupplyRecordTest::create(recordName,pvStructure);
|
||||
if(psr.get()==NULL) {
|
||||
cout << "PowerSupplyRecordTest::create failed" << endl;
|
||||
return;
|
||||
}
|
||||
result = master->addRecord(psr);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/* exampleServerCreateRecords.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.07.24
|
||||
*/
|
||||
#ifndef EXAMPLESERVERCREATERECORDS_H
|
||||
#define EXAMPLESERVERCREATERECORDS_H
|
||||
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class ExampleServerCreateRecords {
|
||||
public:
|
||||
static void create();
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* EXAMPLESERVERCREATERECORDS_H */
|
||||
@@ -1,7 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS += exampleCounter
|
||||
DIRS += exampleServer
|
||||
DIRS += examplePVADoubleArrayGet
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
TOP=../../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
|
||||
#----------------------------------------------------
|
||||
# Optimization of db files using dbst (DEFAULT: NO)
|
||||
#DB_OPT = YES
|
||||
|
||||
#----------------------------------------------------
|
||||
# Create and install (or just install)
|
||||
# databases, templates, substitutions like this
|
||||
DB += ai.db
|
||||
#----------------------------------------------------
|
||||
# If <anyname>.db template is not named <anyname>*.template add
|
||||
# <anyname>_TEMPLATE = <templatename>
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
record(ai, "$(name)")
|
||||
{
|
||||
field(PREC, "1")
|
||||
field(EGU, "amps")
|
||||
field(HIHI, "8")
|
||||
field(HIGH, "6")
|
||||
field(LOW, "4")
|
||||
field(LOLO, "2")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HSV, "MINOR")
|
||||
field(LSV, "MINOR")
|
||||
field(LLSV, "MAJOR")
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#==================================================
|
||||
# Build an IOC support library
|
||||
#
|
||||
|
||||
DBD += exampleCounter.dbd
|
||||
|
||||
LIBRARY_IOC += exampleCounterSupport
|
||||
exampleCounterSupport_SRCS += exampleCounter.cpp
|
||||
exampleCounterSupport_LIBS += pvData
|
||||
exampleCounterSupport_LIBS += pvAccess
|
||||
exampleCounterSupport_LIBS += pvDatabase
|
||||
exampleCounterSupport_LIBS += pvDatabaseExample
|
||||
exampleCounterSupport_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#=============================
|
||||
# build an ioc application
|
||||
|
||||
PROD_IOC += exampleCounter
|
||||
|
||||
|
||||
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
|
||||
exampleCounter_SRCS += exampleCounter_registerRecordDeviceDriver.cpp
|
||||
exampleCounter_SRCS_DEFAULT += exampleCounterMain.cpp
|
||||
exampleCounter_SRCS_vxWorks += -nil-
|
||||
|
||||
|
||||
# The following adds support from base/src/vxWorks
|
||||
exampleCounter_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
|
||||
|
||||
exampleCounter_LIBS += pvData pvAccess
|
||||
exampleCounter_LIBS += pvDatabase
|
||||
exampleCounter_LIBS += pvDatabaseExample
|
||||
exampleCounter_LIBS += exampleCounterSupport
|
||||
exampleCounter_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*exampleCounter.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.07.24
|
||||
*/
|
||||
|
||||
|
||||
/* 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 <epicsExport.h>
|
||||
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/exampleCounter.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
static const iocshArg testArg0 = { "recordName", iocshArgString };
|
||||
static const iocshArg *testArgs[] = {
|
||||
&testArg0};
|
||||
|
||||
static const iocshFuncDef exampleCounterFuncDef = {
|
||||
"exampleCounterCreateRecord", 1, testArgs};
|
||||
static void exampleCounterCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
char *recordName = args[0].sval;
|
||||
ExampleCounterPtr record = ExampleCounter::create(recordName);
|
||||
bool result = PVDatabase::getMaster()->addRecord(record);
|
||||
if(!result) cout << "recordname" << " not added" << endl;
|
||||
}
|
||||
|
||||
static void exampleCounterRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&exampleCounterFuncDef, exampleCounterCallFunc);
|
||||
}
|
||||
}
|
||||
epicsExportRegistrar(exampleCounterRegister);
|
||||
@@ -1,3 +0,0 @@
|
||||
include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
registrar("exampleCounterRegister")
|
||||
@@ -1,31 +0,0 @@
|
||||
/* exampleCounterMain.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.07.24
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "epicsThread.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
if(argc>=2) {
|
||||
iocsh(argv[1]);
|
||||
epicsThreadSleep(.2);
|
||||
}
|
||||
iocsh(NULL);
|
||||
epicsExit(0);
|
||||
return(0);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
TOP=../../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
|
||||
#----------------------------------------------------
|
||||
# Optimization of db files using dbst (DEFAULT: NO)
|
||||
#DB_OPT = YES
|
||||
|
||||
#----------------------------------------------------
|
||||
# Create and install (or just install)
|
||||
# databases, templates, substitutions like this
|
||||
DB += ai.db
|
||||
#----------------------------------------------------
|
||||
# If <anyname>.db template is not named <anyname>*.template add
|
||||
# <anyname>_TEMPLATE = <templatename>
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
record(ai, "$(name)")
|
||||
{
|
||||
field(PREC, "1")
|
||||
field(EGU, "amps")
|
||||
field(HIHI, "8")
|
||||
field(HIGH, "6")
|
||||
field(LOW, "4")
|
||||
field(LOLO, "2")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HSV, "MINOR")
|
||||
field(LSV, "MINOR")
|
||||
field(LLSV, "MAJOR")
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#==================================================
|
||||
# Build an IOC support library
|
||||
#
|
||||
|
||||
DBD += examplePVADoubleArrayGet.dbd
|
||||
|
||||
LIBRARY_IOC += examplePVADoubleArrayGetSupport
|
||||
examplePVADoubleArrayGetSupport_SRCS += examplePVADoubleArrayGet.cpp
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvData
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvAccess
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvDatabase
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvDatabaseExample
|
||||
examplePVADoubleArrayGetSupport_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#=============================
|
||||
# build an ioc application
|
||||
|
||||
PROD_IOC += examplePVADoubleArrayGet
|
||||
|
||||
|
||||
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
|
||||
examplePVADoubleArrayGet_SRCS += examplePVADoubleArrayGet_registerRecordDeviceDriver.cpp
|
||||
examplePVADoubleArrayGet_SRCS_DEFAULT += examplePVADoubleArrayGetMain.cpp
|
||||
examplePVADoubleArrayGet_SRCS_vxWorks += -nil-
|
||||
|
||||
|
||||
# The following adds support from base/src/vxWorks
|
||||
examplePVADoubleArrayGet_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
|
||||
|
||||
examplePVADoubleArrayGet_LIBS += pvData pvAccess
|
||||
examplePVADoubleArrayGet_LIBS += pvDatabase
|
||||
examplePVADoubleArrayGet_LIBS += pvDatabaseExample
|
||||
examplePVADoubleArrayGet_LIBS += examplePVADoubleArrayGetSupport
|
||||
examplePVADoubleArrayGet_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*examplePVADoubleArrayGet.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.07.24
|
||||
*/
|
||||
|
||||
|
||||
/* 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 <epicsExport.h>
|
||||
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/examplePVADoubleArrayGet.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
static StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
|
||||
static const iocshArg testArg0 = { "recordName", iocshArgString };
|
||||
static const iocshArg testArg1 = { "providerName", iocshArgString };
|
||||
static const iocshArg testArg2 = { "channelName", iocshArgString };
|
||||
static const iocshArg *testArgs[] = {
|
||||
&testArg0,&testArg1,&testArg2};
|
||||
|
||||
static const iocshFuncDef examplePVADoubleArrayGetFuncDef = {
|
||||
"examplePVADoubleArrayGetCreateRecord", 3, testArgs};
|
||||
static void examplePVADoubleArrayGetCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result(false);
|
||||
String recordName;
|
||||
PVStructurePtr pvStructure = standardPVField->scalarArray(
|
||||
pvDouble,"alarm,timeStamp");
|
||||
pvRecord = PVRecord::create("doubleArray",pvStructure);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
|
||||
recordName = args[0].sval;
|
||||
char *providerName = args[1].sval;
|
||||
char *channelName = args[2].sval;
|
||||
ExamplePVADoubleArrayGetPtr record = ExamplePVADoubleArrayGet::create(recordName,providerName,channelName);
|
||||
if(record!=NULL)
|
||||
result = master->addRecord(record);
|
||||
if(!result) cout << "recordname" << " not added" << endl;
|
||||
}
|
||||
|
||||
static void examplePVADoubleArrayGetRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&examplePVADoubleArrayGetFuncDef, examplePVADoubleArrayGetCallFunc);
|
||||
}
|
||||
}
|
||||
epicsExportRegistrar(examplePVADoubleArrayGetRegister);
|
||||
@@ -1,4 +0,0 @@
|
||||
include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
include "PVAClientRegister.dbd"
|
||||
registrar("examplePVADoubleArrayGetRegister")
|
||||
@@ -1,31 +0,0 @@
|
||||
/* examplePVADoubleArrayGetMain.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.07.24
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "epicsThread.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
if(argc>=2) {
|
||||
iocsh(argv[1]);
|
||||
epicsThreadSleep(.2);
|
||||
}
|
||||
iocsh(NULL);
|
||||
epicsExit(0);
|
||||
return(0);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
TOP=../../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
|
||||
#----------------------------------------------------
|
||||
# Optimization of db files using dbst (DEFAULT: NO)
|
||||
#DB_OPT = YES
|
||||
|
||||
#----------------------------------------------------
|
||||
# Create and install (or just install)
|
||||
# databases, templates, substitutions like this
|
||||
DB += dbScalar.db
|
||||
DB += dbInteger.db
|
||||
DB += dbArray.db
|
||||
DB += dbString.db
|
||||
DB += dbStringArray.db
|
||||
DB += dbEnum.db
|
||||
DB += dbCounter.db
|
||||
|
||||
#----------------------------------------------------
|
||||
# If <anyname>.db template is not named <anyname>*.template add
|
||||
# <anyname>_TEMPLATE = <templatename>
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
record(waveform, "$(name)")
|
||||
{
|
||||
field(NELM,"5")
|
||||
field(NORD,"5")
|
||||
field(FTVL,"$(type)")
|
||||
field(EGU, "Counts")
|
||||
field(HOPR, "10")
|
||||
field(LOPR, "0")
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
record(calc, "${name}")
|
||||
{
|
||||
field(DESC, "Counter")
|
||||
field(SCAN,"1 second")
|
||||
field(CALC, "(A<B)?(A+C):D")
|
||||
field(INPA, "${name} NPP NMS")
|
||||
field(INPB, "9")
|
||||
field(INPC, "1")
|
||||
field(INPD, "0")
|
||||
field(EGU, "Counts")
|
||||
field(HOPR, "10")
|
||||
field(HIHI, "8")
|
||||
field(HIGH, "6")
|
||||
field(LOW, "4")
|
||||
field(LOLO, "2")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HSV, "MINOR")
|
||||
field(LSV, "MINOR")
|
||||
field(LLSV, "MAJOR")
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
record(mbbo, "$(name)")
|
||||
{
|
||||
field(NOBT,"2")
|
||||
field(ZRVL,"0")
|
||||
field(ONVL,"1")
|
||||
field(TWVL,"2")
|
||||
field(THVL,"3")
|
||||
field(ZRST,"zero")
|
||||
field(ONST,"one")
|
||||
field(TWST,"two")
|
||||
field(THST,"three")
|
||||
field(TWSV,"MINOR")
|
||||
field(THSV,"MAJOR")
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
record($(type), "$(name)")
|
||||
{
|
||||
field(EGU, "Counts")
|
||||
field(HOPR, "10")
|
||||
field(LOPR, "0")
|
||||
field(DRVH, "9")
|
||||
field(DRVL, "0")
|
||||
field(HIHI, "8")
|
||||
field(HIGH, "6")
|
||||
field(LOW, "4")
|
||||
field(LOLO, "2")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HSV, "MINOR")
|
||||
field(LSV, "MINOR")
|
||||
field(LLSV, "MAJOR")
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
record($(type), "$(name)")
|
||||
{
|
||||
field(PREC, "1")
|
||||
field(EGU, "Counts")
|
||||
field(HOPR, "10")
|
||||
field(LOPR, "0")
|
||||
field(DRVH, "9.9")
|
||||
field(DRVL, "-0.1")
|
||||
field(HIHI, "8")
|
||||
field(HIGH, "6")
|
||||
field(LOW, "4")
|
||||
field(LOLO, "2")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HSV, "MINOR")
|
||||
field(LSV, "MINOR")
|
||||
field(LLSV, "MAJOR")
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
record(stringout, "$(name)")
|
||||
{
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
record(waveform, "${name}")
|
||||
{
|
||||
field(NELM,"5")
|
||||
field(FTVL,"STRING")
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#==================================================
|
||||
# Build an IOC support library
|
||||
#
|
||||
|
||||
DBD += exampleServer.dbd
|
||||
|
||||
LIBRARY_IOC += exampleServerSupport
|
||||
exampleServerSupport_SRCS += exampleServer.cpp
|
||||
exampleServerSupport_LIBS += pvData
|
||||
exampleServerSupport_LIBS += pvAccess
|
||||
exampleServerSupport_LIBS += pvDatabase
|
||||
exampleServerSupport_LIBS += pvDatabaseExample
|
||||
exampleServerSupport_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#=============================
|
||||
# build an ioc application
|
||||
|
||||
PROD_IOC += exampleServer
|
||||
|
||||
|
||||
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
|
||||
exampleServer_SRCS += exampleServer_registerRecordDeviceDriver.cpp
|
||||
exampleServer_SRCS_DEFAULT += exampleServerMain.cpp
|
||||
exampleServer_SRCS_vxWorks += -nil-
|
||||
|
||||
|
||||
# The following adds support from base/src/vxWorks
|
||||
exampleServer_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
|
||||
|
||||
exampleServer_LIBS += pvData pvAccess
|
||||
exampleServer_LIBS += pvDatabase
|
||||
exampleServer_LIBS += pvDatabaseExample
|
||||
exampleServer_LIBS += exampleServerSupport
|
||||
exampleServer_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*exampleServer.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.07.24
|
||||
*/
|
||||
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
#include <cantProceed.h>
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
#include <iocsh.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/exampleServerCreateRecords.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
static const iocshArg testArg0 = { "prefix", iocshArgString };
|
||||
static const iocshArg *testArgs[] = {
|
||||
&testArg0};
|
||||
|
||||
static const iocshFuncDef exampleServerFuncDef = {
|
||||
"exampleServerCreateRecords", 1, testArgs};
|
||||
static void exampleServerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
char *prefix = args[0].sval;
|
||||
ExampleServerCreateRecords::create();
|
||||
}
|
||||
|
||||
static void exampleServerRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&exampleServerFuncDef, exampleServerCallFunc);
|
||||
}
|
||||
}
|
||||
epicsExportRegistrar(exampleServerRegister);
|
||||
@@ -1,3 +0,0 @@
|
||||
include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
registrar("exampleServerRegister")
|
||||
@@ -1,31 +0,0 @@
|
||||
/* exampleServerMain.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.07.24
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "epicsThread.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
if(argc>=2) {
|
||||
iocsh(argv[1]);
|
||||
epicsThreadSleep(.2);
|
||||
}
|
||||
iocsh(NULL);
|
||||
epicsExit(0);
|
||||
return(0);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS += $(wildcard *ioc*)
|
||||
DIRS += $(wildcard as*)
|
||||
DIRS += $(wildcard example*)
|
||||
include $(EPICS_BASE)/configure/RULES_DIRS
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = $(EPICS_HOST_ARCH)
|
||||
TARGETS = envPaths
|
||||
include $(TOP)/configure/RULES.ioc
|
||||
@@ -1,17 +0,0 @@
|
||||
< envPaths
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/exampleCounter.dbd")
|
||||
exampleCounter_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/ai.db","name=double01")
|
||||
|
||||
cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
epicsThreadSleep(2.0)
|
||||
casr
|
||||
exampleCounterCreateRecord exampleCounter
|
||||
startPVAServer
|
||||
@@ -1,5 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = $(EPICS_HOST_ARCH)
|
||||
TARGETS = envPaths
|
||||
include $(TOP)/configure/RULES.ioc
|
||||
@@ -1,16 +0,0 @@
|
||||
< envPaths
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/examplePVADoubleArrayGet.dbd")
|
||||
examplePVADoubleArrayGet_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/dbArray.db","name=double01,type=DOUBLE")
|
||||
|
||||
cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
examplePVADoubleArrayGetCreateRecord examplePVADoubleArrayGet local doubleArray
|
||||
@@ -1,16 +0,0 @@
|
||||
< envPaths
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/examplePVADoubleArrayGet.dbd")
|
||||
examplePVADoubleArrayGet_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/dbArray.db","name=double01,type=DOUBLE")
|
||||
|
||||
cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
examplePVADoubleArrayGetCreateRecord examplePVADoubleArrayGet pvAccess arrayDouble
|
||||
@@ -1,5 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = $(EPICS_HOST_ARCH)
|
||||
TARGETS = envPaths
|
||||
include $(TOP)/configure/RULES.ioc
|
||||
@@ -1,20 +0,0 @@
|
||||
< envPaths
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/exampleServer.dbd")
|
||||
exampleServer_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/dbScalar.db","name=double01,type=ao")
|
||||
dbLoadRecords("db/dbStringArray.db","name=stringArray01")
|
||||
dbLoadRecords("db/dbEnum.db","name=enum01")
|
||||
dbLoadRecords("db/dbCounter.db","name=counter01");
|
||||
|
||||
cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
epicsThreadSleep(2.0)
|
||||
casr
|
||||
exampleServerCreateRecords
|
||||
startPVAServer
|
||||
79
jenkins/cloudbees_build
Normal file
79
jenkins/cloudbees_build
Normal file
@@ -0,0 +1,79 @@
|
||||
# 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
|
||||
66
jenkins/cloudbees_doc
Normal file
66
jenkins/cloudbees_doc
Normal file
@@ -0,0 +1,66 @@
|
||||
# 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
|
||||
67
src/Makefile
67
src/Makefile
@@ -1,42 +1,47 @@
|
||||
# Makefile for the pvDatabase library
|
||||
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
DATABASE = $(TOP)/src/
|
||||
PVDATABASE_SRC = $(TOP)/src
|
||||
|
||||
LIBRARY_IOC += pvDatabase
|
||||
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
pvDatabase_LIBS += Com pvData pvAccess
|
||||
|
||||
SRC_DIRS += $(DATABASE)/pvData
|
||||
INC += pvSubArrayCopy.h
|
||||
LIBSRCS += pvSubArrayCopy.cpp
|
||||
INC += pv/pvPlugin.h
|
||||
INC += pv/pvStructureCopy.h
|
||||
INC += pv/pvArrayPlugin.h
|
||||
INC += pv/pvDeadbandPlugin.h
|
||||
INC += pv/pvTimestampPlugin.h
|
||||
|
||||
SRC_DIRS += $(DATABASE)/database
|
||||
INC += pvDatabase.h
|
||||
LIBSRCS += pvRecord.cpp
|
||||
LIBSRCS += pvDatabase.cpp
|
||||
INC += pv/pvDatabase.h
|
||||
|
||||
SRC_DIRS += $(DATABASE)/pvAccess
|
||||
INC += channelProviderLocal.h
|
||||
INC += pvCopy.h
|
||||
INC += monitorAlgorithm.h
|
||||
LIBSRCS += channelProviderLocal.cpp
|
||||
LIBSRCS += pvCopy.cpp
|
||||
LIBSRCS += channelLocal.cpp
|
||||
LIBSRCS += monitorFactory.cpp
|
||||
INC += pv/channelProviderLocal.h
|
||||
|
||||
SRC_DIRS += $(DATABASE)/V3IOC
|
||||
DBD += PVAServerRegister.dbd
|
||||
DBD += PVAClientRegister.dbd
|
||||
LIBSRCS += PVAServerRegister.cpp
|
||||
LIBSRCS += PVAClientRegister.cpp
|
||||
INC += pv/pvSupport.h
|
||||
INC += pv/controlSupport.h
|
||||
INC += pv/scalarAlarmSupport.h
|
||||
|
||||
SRC_DIRS += $(DATABASE)/special
|
||||
INC += recordList.h
|
||||
INC += traceRecord.h
|
||||
INC += powerSupplyRecordTest.h
|
||||
LIBSRCS += recordList.cpp
|
||||
LIBSRCS += traceRecord.cpp
|
||||
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)/database/Makefile
|
||||
include $(PVDATABASE_SRC)/pvAccess/Makefile
|
||||
include $(PVDATABASE_SRC)/support/Makefile
|
||||
include $(PVDATABASE_SRC)/special/Makefile
|
||||
|
||||
LIBRARY += pvDatabase
|
||||
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
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*PVAClientRegister.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.08.05
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <iocsh.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/clientFactory.h>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
|
||||
|
||||
static const iocshFuncDef startPVAClientFuncDef = {
|
||||
"startPVAClient", 0, 0
|
||||
};
|
||||
extern "C" void startPVAClient(const iocshArgBuf *args)
|
||||
{
|
||||
ClientFactory::start();
|
||||
}
|
||||
|
||||
static const iocshFuncDef stopPVAClientFuncDef = {
|
||||
"stopPVAClient", 0, 0
|
||||
};
|
||||
extern "C" void stopPVAClient(const iocshArgBuf *args)
|
||||
{
|
||||
ClientFactory::stop();
|
||||
}
|
||||
|
||||
|
||||
static void startPVAClientRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&startPVAClientFuncDef, startPVAClient);
|
||||
}
|
||||
}
|
||||
|
||||
static void stopPVAClientRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&stopPVAClientFuncDef, stopPVAClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
epicsExportRegistrar(startPVAClientRegister);
|
||||
epicsExportRegistrar(stopPVAClientRegister);
|
||||
@@ -1,2 +0,0 @@
|
||||
registrar("startPVAClientRegister")
|
||||
registrar("stopPVAClientRegister")
|
||||
@@ -1,155 +0,0 @@
|
||||
/*PVAServerRegister.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.07.24
|
||||
*/
|
||||
|
||||
/* 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 <epicsExport.h>
|
||||
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
class PVAServerCTX;
|
||||
typedef std::tr1::shared_ptr<PVAServerCTX> PVAServerCTXPtr;
|
||||
|
||||
class PVAServerCTX :
|
||||
public std::tr1::enable_shared_from_this<PVAServerCTX>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVAServerCTX);
|
||||
static PVAServerCTXPtr getPVAServerCTX();
|
||||
void start();
|
||||
void stop();
|
||||
virtual ~PVAServerCTX() {}
|
||||
private:
|
||||
PVAServerCTX() {}
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
ServerContext::shared_pointer ctx;
|
||||
};
|
||||
|
||||
void PVAServerCTX::start()
|
||||
{
|
||||
if(ctx!=NULL) {
|
||||
cout<< "PVAServer already started" << endl;
|
||||
return;
|
||||
}
|
||||
ctx = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
}
|
||||
|
||||
void PVAServerCTX::stop()
|
||||
{
|
||||
if(ctx==NULL) {
|
||||
cout<< "PVAServer already stopped" << endl;
|
||||
return;
|
||||
}
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
ctx->destroy();
|
||||
ctx.reset();
|
||||
epicsThreadSleep(1.0);
|
||||
channelProvider->destroy();
|
||||
}
|
||||
|
||||
PVAServerCTXPtr PVAServerCTX::getPVAServerCTX()
|
||||
{
|
||||
static PVAServerCTXPtr pvPVAServerCTX;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
|
||||
if(pvPVAServerCTX==NULL) {
|
||||
pvPVAServerCTX = PVAServerCTXPtr(new PVAServerCTX());
|
||||
}
|
||||
return pvPVAServerCTX;
|
||||
}
|
||||
|
||||
|
||||
static const iocshFuncDef startPVAServerFuncDef = {
|
||||
"startPVAServer", 0, 0
|
||||
};
|
||||
extern "C" void startPVAServer(const iocshArgBuf *args)
|
||||
{
|
||||
PVAServerCTX::getPVAServerCTX()->start();
|
||||
}
|
||||
|
||||
static const iocshFuncDef stopPVAServerFuncDef = {
|
||||
"stopPVAServer", 0, 0
|
||||
};
|
||||
extern "C" void stopPVAServer(const iocshArgBuf *args)
|
||||
{
|
||||
PVAServerCTX::getPVAServerCTX()->stop();
|
||||
}
|
||||
|
||||
|
||||
static const iocshFuncDef pvdblFuncDef = {
|
||||
"pvdbl", 0, 0
|
||||
};
|
||||
extern "C" void pvdbl(const iocshArgBuf *args)
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
PVStringArray::const_svector xxx = pvNames->view();
|
||||
for(size_t i=0; i<xxx.size(); ++i) cout<< xxx[i] << endl;
|
||||
}
|
||||
|
||||
static void startPVAServerRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&startPVAServerFuncDef, startPVAServer);
|
||||
}
|
||||
}
|
||||
|
||||
static void stopPVAServerRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&stopPVAServerFuncDef, stopPVAServer);
|
||||
}
|
||||
}
|
||||
|
||||
static void pvdblRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&pvdblFuncDef, pvdbl);
|
||||
getChannelProviderLocal();
|
||||
}
|
||||
}
|
||||
|
||||
epicsExportRegistrar(startPVAServerRegister);
|
||||
epicsExportRegistrar(stopPVAServerRegister);
|
||||
epicsExportRegistrar(pvdblRegister);
|
||||
@@ -1,3 +0,0 @@
|
||||
registrar("startPVAServerRegister")
|
||||
registrar("stopPVAServerRegister")
|
||||
registrar("pvdblRegister")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user