178 Commits
4.3.0 ... 4.7.0

Author SHA1 Message Date
Andrew Johnson
ee3027f641 Update release notes and version numbers for release 2022-09-07 12:10:55 -05:00
Andrew Johnson
6cd0a1bdb0 Merge pull request #76 from sveseli/master
Resolve monitor overrun issue from PR #75.
2022-06-24 10:29:44 -05:00
Sinisa Veseli
0d85561481 this resolves issue with monitor overrun counter; master field listeners will be called only once, before calling listeners for the first subfield 2022-03-14 09:17:33 -05:00
Andrew Johnson
05d54c61e1 Merge pull request #75 from sveseli/master
Support requests to apply a pvCopy filter plugin to a whole PVRecord structure by using a field name `_` in the pvRequest.
2021-12-06 11:28:22 -06:00
Sinisa Veseli
182eee57e2 add tests for whole structure request 2021-12-01 14:36:50 -06:00
Sinisa Veseli
8daf322025 update module release notes 2021-12-01 14:36:20 -06:00
Sinisa Veseli
a68ef61a10 use _ instead of masterField to designate top level structure in the request 2021-11-30 10:32:38 -06:00
Sinisa Veseli
9dfebf1897 allow writing pvCopy plugins for the master field 2021-11-30 08:54:57 -06:00
Andrew Johnson
0cf706511e Set next development version 2021-07-02 15:52:05 -05:00
Andrew Johnson
8cac3975cc Update version numbers for release 2021-07-02 15:49:24 -05:00
Marty Kraimer
219e5eaf94 Merge pull request #73 from epics-base/pvdbcr_changes
more work on special; all pvdbcr* redone
2021-04-14 11:20:46 -04:00
mrkraimer
f345651b67 more work on special; all pvdbcr* redone 2021-04-14 10:26:30 -04:00
Marty Kraimer
4895107854 Merge pull request #72 from epics-base/pvdbcr_changes
changes were made to all the special code, i.e. all pvdbcr*.
2021-04-12 12:19:35 -04:00
mrkraimer
1c121b3f1e changes were made to all the special code, i.e. all pvdbcr*.
All now have a .h file in src/pv.
Each can now be used via an iocshell command or by a PVDatabase application that not part of an ioc database.
2021-04-12 09:30:50 -04:00
Marty Kraimer
d493e52dda Merge pull request #71 from epics-base/jenkins_problem
another attempt to fix jenkins failure
2021-04-08 07:03:56 -04:00
mrkraimer
91d4d2a423 another attempt to fix jenkins failure 2021-04-08 06:11:52 -04:00
Marty Kraimer
d54031a2fb Merge pull request #70 from epics-base/jenkins_problem
another attempt to fix jenkins failure
2021-04-07 11:55:18 -04:00
mrkraimer
1e1d5455a8 another attempt to fix jenkins failure 2021-04-07 11:08:16 -04:00
Marty Kraimer
426af714a1 Merge pull request #69 from epics-base/jenkins_problem
another atrempt to fix jenkins failure
2021-04-07 08:45:46 -04:00
mrkraimer
68bbb55370 another atrempt to fix jenkins failure 2021-04-07 07:57:56 -04:00
Marty Kraimer
716ec9857c Merge pull request #68 from epics-base/jenkins_problem
another attempt to fix jenkins_problem
2021-04-03 08:59:19 -04:00
mrkraimer
e91b4b1b66 another attempt to fix jenkins_problem 2021-04-03 07:14:31 -04:00
mrkraimer
2c4e98db8c another attempt to fix jenkins_problem 2021-04-03 06:30:09 -04:00
Marty Kraimer
d4a13397d7 Merge pull request #67 from epics-base/jenkins_problem
another attempt to fix jenkins_problem
2021-04-03 05:52:10 -04:00
mrkraimer
a622f66a94 another attempt to fix jenkins_problem 2021-04-02 18:09:38 -04:00
mrkraimer
81abd5f413 another attempt to fix jenkins_problem 2021-04-02 17:00:51 -04:00
Marty Kraimer
4df01038c3 Merge pull request #66 from epics-base/jenkins_problem
another attempt to fix jenkins_problem
2021-04-02 15:31:12 -04:00
mrkraimer
e648cba659 another attempt to fix jenkins_problem 2021-04-02 13:36:32 -04:00
Marty Kraimer
42747b167c Merge pull request #65 from epics-base/jenkins_problem
another attempt to fix jenkins_problem
2021-04-02 11:20:11 -04:00
mrkraimer
0a893a331b attempt to fix jenkins_problem 2021-04-02 10:06:38 -04:00
Marty Kraimer
e95c959cfd Merge pull request #64 from epics-base/jenkins_problem
attempt to fix jenkins_problem
2021-04-02 08:17:07 -04:00
mrkraimer
e51c29d147 attempt to fix jenkins_problem 2021-04-02 07:00:59 -04:00
Marty Kraimer
fec903fb06 Merge pull request #63 from epics-base/accesss-security
Accesss security
2021-04-01 12:15:38 -04:00
mrkraimer
ca066bc088 addRecord,removeRecord,processRecord.traceRecord replaced by pvdbcr versions 2021-04-01 10:20:18 -04:00
mrkraimer
0481a7bf5b redo addRecord, removeRecord, processRecord, and traceRecord 2021-04-01 08:22:34 -04:00
mrkraimer
17f43b4452 another attempt to get pull request to build 2021-04-01 07:15:26 -04:00
mrkraimer
a1514e5206 another attempt to get pull request to build 2021-04-01 06:15:46 -04:00
mrkraimer
72c2489921 another attempt to get pull request to build 2021-03-31 14:31:06 -04:00
mrkraimer
895698c3cd another attempt to get pull request to build 2021-03-31 13:05:51 -04:00
mrkraimer
9d10b039fb another attempt to get pull request to build 2021-03-31 12:25:44 -04:00
mrkraimer
bf82de407e still more work on includes 2021-03-31 10:57:48 -04:00
mrkraimer
58a603556b add using std::tr1::static_pointer_cast 2021-03-31 08:32:34 -04:00
mrkraimer
22e849c6f7 remove all references to pvaClient 2021-03-31 07:39:56 -04:00
mrkraimer
2a4d3a15f8 try adding pvaClient to src/Makefile 2021-03-31 05:58:46 -04:00
mrkraimer
7143a8585f more changes to includes 2021-03-30 18:29:11 -04:00
mrkraimer
2d61b4c0f3 fix include order 2021-03-30 16:04:50 -04:00
mrkraimer
120fa22558 remove nt 2021-03-30 12:58:01 -04:00
mrkraimer
4ed8e6d625 change order of includes 2021-03-30 10:48:22 -04:00
mrkraimer
4718021e39 update documentation 2021-03-30 09:50:23 -04:00
mrkraimer
b1822f5fbd 1) added canRead for access security
2) main documentation moved to https://mrkraimer.github.io/website/developerGuide/pvDatabase/pvDatabaseCPP.html
2021-03-24 14:35:05 -04:00
mrkraimer
333cd44da0 The following were made to all special pvdbcr modules
1) Much cleaner implementation.
2) pvdbSpecialRegister.dbd is new
2021-03-20 10:48:08 -04:00
Andrew Johnson
a514ab7b51 Add missing removal instructions for destroy() 2021-03-15 12:12:15 -05:00
mrkraimer
dafc37b585 The following changes were made:
1) PVRecord now has two new methods: setAsLevel and setAsGroup.
2) The following special records are DEPRECATED: addRecord,processRecord,removeRecord, and traceRecord.
    They are replaced by pvdbcrAddRecord,pvdbcrProcessRecord,pvdbcrRemoveRecord, and pvdbcrTraceRecord.
3) A new convention is that all special records start with pvdbcr, which means pvDatabase Create Record.
4) pvdbcrAddRecord,pvdbcrProcessRecord,pvdbcrRemoveRecord, and pvdbcrTraceRecord are like what they replace.
   But they also allow the asLevel to be set when they are created.
5) pvdbcrScalar and pvdbcrScalarArray are new special records.
   They created records that have fields value, alarm, and timeStamp.
   value can have any of the allowed scalar types, i.e. boolean,byte,...,string.
2021-03-15 07:04:32 -04:00
Andrew Johnson
2432f85784 Fix for Windows DLL builds 2021-03-12 17:38:51 -06:00
mrkraimer
bd1054f247 Changes were to check for null pointer after calling lock on a weak pointer. 2021-03-06 14:14:39 -05:00
Marty Kraimer
bc70b5f449 Merge pull request #58 from sveseli/master
Enable Access Security
2021-03-05 13:11:30 -05:00
Andrew Johnson
93a259cbde Set next development version after tag 2021-02-28 17:01:22 -06:00
Andrew Johnson
09423edeab Release version 4.5.3 for EPICS 7.0.5 2021-02-28 16:57:31 -06:00
Sinisa Veseli
ac1de6770e enable access security for PV Database 2021-02-28 16:31:36 -06:00
Sinisa Veseli
5427311390 initialize PVRecord with access security group/level 2021-02-28 16:28:54 -06:00
Marty Kraimer
b62b047f63 Merge pull request #57 from epics-base/removedestroy
remove all destroy methods
2020-07-23 07:58:30 -04:00
mrkraimer
3bc89bfe0e remove all destroy methods 2020-07-21 10:33:50 -04:00
Andrew Johnson
cb5d9f976a Set next development version 2020-05-28 16:26:01 -05:00
Andrew Johnson
3f5bfd067f Update version numbers for release 2020-05-28 16:14:30 -05:00
mrkraimer
85165e6579 get ready for next epics7 release 2020-05-20 14:03:13 -04:00
Marty Kraimer
476a8f1e32 Merge pull request #56 from dirk-zimoch/CleanupWhitespace
Cleanup whitespace
2020-05-20 08:47:32 -04:00
31e883dbbc removed empty lines at end of file 2020-04-15 18:00:08 +02:00
57cbf66833 removed spaces at end of line 2020-04-15 17:58:14 +02:00
7f31332a80 replaced tabs with spaces 2020-04-15 17:54:47 +02:00
Marty Kraimer
12015309d8 Merge pull request #55 from epics-base/arrayfilterforunion
Arrayfilterforunion
2020-04-13 06:27:41 -04:00
mrkraimer
1e62844a22 testPlugin found bug: added unionArrayTest 2020-04-12 14:01:22 -04:00
mrkraimer
ad479309b0 fix bitset bug 2020-04-08 11:06:59 -04:00
mrkraimer
2f7c82757f pvArrayPlugin now supports union scalarArray 2020-04-07 12:53:01 -04:00
Marty Kraimer
634153a28d Merge pull request #54 from epics-base/issue53
Issue53
2020-02-18 05:39:58 -05:00
Heesterman, Peter J
e664037063 static analysis during the Codathon at Diamond. 2020-02-17 12:06:08 +00:00
mrkraimer
75c16bd423 pvDatabase::removeRecord and pvRecord::remove no longer call eachother directly 2020-02-12 09:13:19 -05:00
mrkraimer
083dffac3c pvDatabase::removeRecord and pvRecord::remove changes;descructors now have at most a print statement 2020-02-10 06:15:59 -05:00
mrkraimer
42ba054e5f add createdestroy example 2020-02-07 10:58:55 -05:00
mrkraimer
3173e9aeae problems with examples 2020-02-07 09:17:08 -05:00
mrkraimer
785d654129 first attempt to fix issue 53; add example 2020-02-07 08:54:18 -05:00
Ralph Lange
22ce4440b7 Fix bug preventing "whole structure" bitset(0) copy
(fixes #52)
(this should have a test added, but I am not familiar enough with the code)
2020-01-28 15:44:27 +01:00
Andrew Johnson
80baccfd9c Incr version and set development flag after release 2019-11-01 12:52:23 -05:00
Andrew Johnson
0c92f07749 Clear development flag for 4.5.1 release 2019-11-01 12:50:11 -05:00
Andrew Johnson
73a9f1f84f Release notes for 4.5.1 2019-11-01 12:48:58 -05:00
Marty Kraimer
3c3f0ab7f1 Merge pull request #51 from mrkraimer/master
addRecord is new
2019-09-13 10:00:22 -04:00
Marty Kraimer
803098922a Update .travis.yml 2019-09-13 09:04:54 -04:00
mrkraimer
c028af8b6d addRecord is new 2019-09-11 10:17:09 -04:00
Ralph Lange
d33d03189e rtd-ci: add read-the-docs integration 2019-09-06 14:19:00 +02:00
Andrew Johnson
d7bd5628d4 Update version number to 4.5.1 DEVELOPMENT 2019-08-13 11:04:36 -05:00
Andrew Johnson
70ee857782 Set version number in Release Notes 2019-07-30 14:26:56 -05:00
Andrew Johnson
07f09e0759 Set SHRLIB_VERSION from new CONFIG_PVDATABASE_VERSION file 2019-07-30 14:26:37 -05:00
Marty Kraimer
ba832ddfd0 Merge pull request #50 from mrkraimer/master
another attempt to fix jenkins win64 build
2019-07-10 10:37:58 -04:00
mrkraimer
93c2284091 another attempt to fix jenkins win64 build 2019-07-10 10:09:30 -04:00
Marty Kraimer
cc5b6f6351 Merge pull request #49 from mrkraimer/master
try to fix jenkins win64 build that fails
2019-07-10 09:44:30 -04:00
mrkraimer
a26a625e49 try to fix jenkins win64 build that fails 2019-07-10 09:14:58 -04:00
Marty Kraimer
93b4892528 Merge pull request #48 from mrkraimer/master
copy lib now part of pvDatabase
2019-06-26 13:03:07 -04:00
mrkraimer
e57348a4c5 copy lib now part of pvDatabase 2019-06-26 10:47:58 -04:00
Marty Kraimer
7059cb0354 Merge pull request #46 from mrkraimer/master
add record support and processRecord
2019-06-25 09:17:35 -04:00
mrkraimer
f2d6e05816 WIN32 follow Michael's advice about O.yyy/*.d files 2019-06-24 15:23:19 -04:00
mrkraimer
e949493722 WIN32 DLL; copy build. now for pvDatabase 2019-06-24 09:53:56 -04:00
mrkraimer
6969bbd571 WIN32 DLL another try 2019-06-23 15:30:29 -04:00
mrkraimer
9edea59ab9 WIN32 DLL making progresss but still not there 2019-06-23 14:41:34 -04:00
mrkraimer
1928b87634 pvCopy depends of pvPlugin not the other way 2019-06-23 14:03:16 -04:00
mrkraimer
d9ed321298 WIN32 another try 2019-06-23 10:40:09 -04:00
mrkraimer
935f915e5d WIN32 another try 2019-06-23 09:55:52 -04:00
mrkraimer
6263f4c335 WIN32 another try 2019-06-23 09:24:09 -04:00
mrkraimer
62134efd19 WIN32 another try 2019-06-23 08:40:09 -04:00
mrkraimer
8a06b9ee8e win32 yet another try 2019-06-23 08:08:33 -04:00
mrkraimer
bc6fd2b9ff wrong ifdef 2019-06-23 07:22:27 -04:00
mrkraimer
3b6f23515f pvCopy first 2019-06-23 06:18:28 -04:00
mrkraimer
3c5f419ce7 src depends on configure src/copy 2019-06-22 17:00:41 -04:00
mrkraimer
3418c22cde WIN32 make pvCopy be a seperate lib instead of part of pvDatabase 2019-06-22 16:14:40 -04:00
mrkraimer
22806c5301 almost running out of ideas to make WIN32 build 2019-06-22 13:01:31 -04:00
mrkraimer
62fb27fdf8 WIN32 is really a pain 2019-06-22 11:48:01 -04:00
mrkraimer
6250625036 yet one more attempt to make WIN32 build 2019-06-22 10:16:57 -04:00
mrkraimer
d77ec8a978 yet one more time to make WIN32 build 2019-06-22 07:53:01 -04:00
mrkraimer
322bb4800b another attempt to build for WIN32 2019-06-22 06:38:28 -04:00
mrkraimer
0437602236 fix bug in deadband plugin; attempt to make support build on win32 2019-06-21 15:53:31 -04:00
mrkraimer
bd37756ba3 fix bug in processRecord; attempt to make support build on WINE 2019-06-21 13:39:50 -04:00
mrkraimer
fb4e7f0fc1 update doc; fix bug in scalarAlarmSupport 2019-06-19 09:36:52 -04:00
mrkraimer
5279e4e739 array plugin for put failed if increment not 1 2019-06-14 14:13:52 -04:00
mrkraimer
ffef21e58c doc changes; processRecord catch exceptions 2019-06-10 10:41:08 -04:00
mrkraimer
e901ae3ea0 handle out of control limits better 2019-06-09 16:14:25 -04:00
mrkraimer
8a050e0f81 add processRecord 2019-06-08 13:24:20 -04:00
mrkraimer
a72112f928 process reports if it changed fields 2019-06-08 05:52:03 -04:00
mrkraimer
be701cc98a still more work on support 2019-06-06 09:52:39 -04:00
mrkraimer
9b000ffe6c support hysteresis 2019-06-04 14:56:18 -04:00
mrkraimer
6c91249340 add scalarAlarmSupport 2019-06-04 14:21:38 -04:00
mrkraimer
b052e28788 add support 2019-06-01 12:28:21 -04:00
mrkraimer
247839b94d add numericRecord, removeRecordRegister, traceRecordRegister 2019-06-01 06:59:23 -04:00
Marty Kraimer
ecdf70d858 Merge pull request #45 from mrkraimer/master
remove new method for PVRecord
2019-05-22 14:22:11 -04:00
mrkraimer
a004f7ea08 remove new method for PVRecord 2019-05-22 10:41:55 -04:00
Marty Kraimer
898868d5f4 Merge pull request #43 from mrkraimer/master
PVCOPY::updateMaster put to fields that did not change
2019-05-21 09:43:11 -04:00
mrkraimer
eb4dab73e9 another fix for updateMaster nug 2019-05-18 10:56:30 -04:00
mrkraimer
e1adfe30df updateMaster was putting to every client field instead of only changed fields 2019-05-18 10:11:00 -04:00
Andrew Johnson
2715f585e0 Update version numbers to 4.4.2 for EPICS 7.0.2.2 release 2019-04-15 11:48:15 -05:00
mrkraimer
c2e3315f54 update RELEASE_NOTES 2019-04-11 13:59:57 -04:00
Marty Kraimer
d0ddcead24 Merge pull request #42 from mrkraimer/master
pvRequest - asking for subfield of non structure field crashes IOC; allow subfield of union
2019-04-04 05:27:41 -04:00
mrkraimer
5f42eec15a better exception messages 2019-03-31 15:38:13 -04:00
mrkraimer
20e55d5bca minor changes 2019-03-31 07:33:51 -04:00
mrkraimer
6d2d63621e address issue 41 2019-03-29 11:22:49 -04:00
Andrew Johnson
b3f96f730f SHRLIB_VERSION for 4.4.1 2019-03-20 15:10:43 -05:00
Andrew Johnson
02930b78a0 Release notes for 4.4.1 2019-03-20 15:10:09 -05:00
Heinz Junkes
68cc5e3b28 Merge pull request #40 from hjunkes/SimplificationsForRtems
Simplify rtemsTestHarness
2019-03-18 13:40:50 +01:00
Heinz Junkes
0c0a77def5 Simplify rtemsTestHarness 2019-03-18 12:05:56 +01:00
Marty Kraimer
79b05db5e2 Merge pull request #38 from mrkraimer/master
fix warning messages; at least on linux
2019-03-14 14:47:09 -04:00
mrkraimer
cd653a809f fix warning messages; at least on linux 2019-03-13 09:10:40 -04:00
Andrew Johnson
07a951c3a2 Update version numbers and formatting in documentation 2018-12-17 16:26:05 -06:00
Andrew Johnson
9cfbc7983c Update SHRLIB_VERSION 2018-12-17 16:24:53 -06:00
Andrew Johnson
761c62050d Update and unify README.md 2018-12-17 16:24:28 -06:00
Michael Davidsaver
d508792f2a update travis-ci 2018-10-29 18:04:29 -07:00
Andrew Johnson
4b98e70ce0 Fix Windows build issues 2018-10-29 14:11:02 -05:00
Marty Kraimer
2450e356f5 Merge pull request #37 from mrkraimer/master
pvCopy.h now pvStructureCopy.h; copy name space now epics::pvCopy
2018-10-02 06:15:28 -04:00
mrkraimer
14442774ab with help from Andrew another attempt to fix windows build 2018-10-02 05:49:29 -04:00
mrkraimer
3f320fac32 another attempt to fix windows build 2018-10-01 06:36:44 -04:00
mrkraimer
4ad470d3f4 yet another attempt to make windows build 2018-09-30 11:48:53 -04:00
mrkraimer
fd97c9ac8e yet another attempt to make windows build 2018-09-30 09:00:43 -04:00
mrkraimer
93c6305952 another attempt to fix windows build 2018-09-30 07:12:27 -04:00
mrkraimer
7e0bc0c45a another attempt to fix windows build 2018-09-29 12:18:29 -04:00
mrkraimer
ebd4e3827c attemptb to fix windows build 2018-09-29 06:48:02 -04:00
mrkraimer
11393ce6b1 pvCopy.h now pvStructureCopy.h; copy name space now epics::pvCopy 2018-09-28 07:17:09 -04:00
Marty Kraimer
4a13cab5a4 Merge pull request #36 from mrkraimer/master
plugin support
2018-09-22 11:13:31 -04:00
mrkraimer
7529f58b63 with help from andrew another attempt to fix windows build 2018-09-20 09:16:30 -04:00
mrkraimer
7491f3b531 attempt to fix windows build 2018-09-19 09:55:54 -04:00
mrkraimer
595163a1fa add link to pvRequest.html 2018-09-18 09:58:30 -04:00
mrkraimer
6fe27251f1 Merge https://github.com/epics-base/pvDatabaseCPP 2018-09-18 06:50:29 -04:00
mrkraimer
a2a07a1d33 add test for plugin 2018-07-13 11:50:27 -04:00
mrkraimer
3e0282d956 implement copy instead of taking it from pvDataCPP; implement plugin support 2018-07-12 14:05:15 -04:00
Marty Kraimer
e667e39573 Merge pull request #34 from mrkraimer/master
address issue #33 and #35
2018-05-25 09:55:13 -04:00
mrkraimer
6239ef0c0c also address issue 35 2018-05-24 10:21:28 -04:00
mrkraimer
87ccf78a9b address issue #33 2018-05-19 10:11:48 -04:00
Andrew Johnson
bbb5fa2c64 Move epicsExit() call into pvDatabaseAllTests()
Needed on VxWorks to display the test summary.
2018-03-13 15:18:41 -05:00
Andrew Johnson
8e04875a45 Rename vxTestHarness and rtemsTestHarness -> pvDbTestHarness
Avoids name clash with similar programs from other modules.
2018-03-13 15:17:48 -05:00
Marty Kraimer
83101e210a Merge pull request #32 from anjohnson/master
Fix master build
2018-02-06 06:23:26 -05:00
Andrew Johnson
e31aae5f5d Remove call to now-absent destroy() routine 2018-02-05 17:18:48 -06:00
Andrew Johnson
2469fc04b5 Replace deprecated "Service" with RPCServiceAsync
MD removed the typedef that equated the two from pvAccessCPP recently.
2018-02-05 17:10:20 -06:00
Andrew Johnson
e0cb7d7f93 Clean up Clang++ warnings
Removed unnecessary checks of size_t < 0
2018-01-04 15:27:51 -06:00
Ralph Lange
2904e00b3d jenkins-ci: fix/update CloudBees jobs 2017-12-19 09:35:18 +01:00
85 changed files with 5746 additions and 1698 deletions

View File

@@ -1,21 +1,10 @@
#!/bin/sh
set -e -x
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make tapfiles
make -s test-results
make -j2 tapfiles
make -j2 -s test-results
fi

View File

@@ -3,35 +3,6 @@ set -e -x
CURDIR="$PWD"
QDIR="$HOME/.cache/qemu"
if [ -n "$RTEMS" -a "$TEST" = "YES" ]
then
git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
cd "$HOME/.build/qemu"
HEAD=`git log -n1 --pretty=format:%H`
echo "HEAD revision $HEAD"
[ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
echo "Cached revision $BUILT"
if [ "$HEAD" != "$BUILT" ]
then
echo "Building QEMU"
git submodule --quiet update --init
install -d "$HOME/.build/qemu/build"
cd "$HOME/.build/qemu/build"
"$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
make -j2
make install
echo "$HEAD" > "$HOME/.cache/qemu/built"
fi
fi
cat << EOF > $CURDIR/configure/RELEASE.local
EPICS_BASE=$HOME/.source/epics-base
EOF
@@ -39,24 +10,6 @@ EOF
install -d "$HOME/.source"
cd "$HOME/.source"
add_base_module() {
MODULE=$1
BRANCH=$2
( cd epics-base/modules && \
git clone --quiet --depth 5 --branch $MODULE/$BRANCH https://github.com/${REPOBASE:-epics-base}/epics-base.git $MODULE && \
cd $MODULE && git log -n1 )
}
add_gh_module() {
MODULE=$1
REPOOWNER=$2
REPONAME=$3
BRANCH=$4
( cd epics-base/modules && \
git clone --quiet --depth 5 --branch $BRANCH https://github.com/$REPOOWNER/$REPONAME.git $MODULE && \
cd $MODULE && git log -n1 )
}
add_gh_flat() {
MODULE=$1
REPOOWNER=$2
@@ -71,21 +24,11 @@ ${MODULE_UC}=$HOME/.source/$MODULE
EOF
}
if [ "$BRBASE" ]
then
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}
else
git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
( cd epics-base && git log -n1 )
add_base_module libcom "${BRLIBCOM:-master}"
add_base_module ca "${BRCA:-master}"
add_base_module database "${BRDATABASE:-master}"
add_gh_module pvData ${REPOPVD:-epics-base} pvDataCPP ${BRPVD:-master}
add_gh_module pvAccess ${REPOPVA:-epics-base} pvAccessCPP ${BRPVA:-master}
fi
# 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
@@ -148,30 +91,19 @@ EOF
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
install -d /home/travis/.cache
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \
| tar -C /home/travis/.cache -xj
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/travis/.cache/rtems${RTEMS}-i386
RTEMS_BASE=$HOME/.rtems
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
EOF
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 -C epics-base $EXTRA
if [ "$BRBASE" ]
then
make -j2 -C pvData $EXTRA
make -j2 -C pvAccess $EXTRA
fi

17
.readthedocs.yml Normal file
View File

@@ -0,0 +1,17 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation in the documentation/ directory with Sphinx
sphinx:
configuration: documentation/conf.py
# Build documentation with MkDocs
#mkdocs:
# configuration: mkdocs.yml
# Optionally build your docs in additional formats such as PDF and ePub
formats: all

View File

@@ -11,19 +11,21 @@ addons:
- perl
- clang
- g++-mingw-w64-i686
- qemu-system-x86
install:
- ./.ci/travis-prepare.sh
script:
- ./.ci/travis-build.sh
env:
- BRCORE=master BRLIBCOM=master BRPVD=master BRPVA=master
- CMPLR=clang
- USR_CXXFLAGS=-std=c++11
- CMPLR=clang USR_CXXFLAGS=-std=c++11
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=NO
- RTEMS=4.9 TEST=NO
- BRBASE=7.0
- BRBASE=7.0 CMPLR=clang
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++98"
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++11"
- BRBASE=7.0 CMPLR=clang EXTRA="CMD_CXXFLAGS=-std=c++11"
- BRBASE=7.0 WINE=32 TEST=NO STATIC=YES
- BRBASE=7.0 WINE=32 TEST=NO STATIC=NO
- BRBASE=7.0 RTEMS=4.10 TEST=NO
- BRBASE=7.0 RTEMS=4.9 TEST=NO
- BRBASE=3.16
- BRBASE=3.15
- BRBASE=3.14

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = pvDatabaseCPP
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
PROJECT_NUMBER = 4.7.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -765,7 +765,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = include
INPUT = src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1035,7 +1035,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = documentation/html
HTML_OUTPUT = html/doxygen
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).

View File

@@ -1,38 +1,21 @@
pvaDatabaseCPP
============
# pvDatabaseCPP
The EPICS **pvDatabase** module provides a set of network accessible, smart, memory resident records with a C++ API. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider gives access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.
A brief description of a pvDatabase is that it is a set of network accessible, smart, memory resident records. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider provides access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.
pvaDatabase is a synchronous Database interface to pvAccess,
which is callback based.
pvaDatabase is thus easier to use than pvAccess itself.
The pvDatabase module implements a synchronous C++ server interface to pvAccessCPP that was designed to be easier to use than the basic pvAccess server API.
See documentation/pvaDatabaseCPP.html for details.
## Links
Building
--------
- General information about EPICS can be found at the
[EPICS Controls website](https://epics-controls.org).
- API documentation for this module can be found in its
documentation directory, in particular the file
pvDatabaseCPP.html
If a proper RELEASE.local file exists one directory level above pvaDatabaseCPP
then just type:
## Building
make
It can also be built by:
cp configure/ExampleRELEASE.local configure/RELEASE.local
edit configure/RELEASE.local
make
Examples
------------
Examples are available in exampleCPP.
Status
------
* The API is for EPICS Version 4 release 4.6.0
This module is included as a submodule of a full EPICS 7 release and will be compiled during builds of that software.
## Examples
Some examples are available in the separate exampleCPP module.

View File

@@ -0,0 +1,12 @@
# Version number for the PV Database API and shared library
EPICS_PVDATABASE_MAJOR_VERSION = 4
EPICS_PVDATABASE_MINOR_VERSION = 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

View File

@@ -2,6 +2,8 @@ TOP=..
include $(TOP)/configure/CONFIG
CFG += CONFIG_PVDATABASE_VERSION
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@@ -1,23 +1,92 @@
# pvDatabaseCPP Module
EPICS V4 release 4.6
====================
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 the can be ran via
The test is now a regression test which can be run using:
make runtests
EPICS V4 release 4.5
====================
This release is one component of EPICS V4 release 4.5.
## Release 4.1 (EPICS V4.5, Oct 2015)
This is the first release of pvDatabaseCPP.
It provides functionality equivalent to pvDatabaseJava.

View File

@@ -1,19 +0,0 @@
TODO
===========
monitorPlugin
-------------
A debate is on-going about what semantics should be.
Must test record delete.
-------------------
Must test removing a record from the PVDatabase while a pvAccess client
is attached. Also why do both unlisten and detach exists?
create more regression tests
----------------
Currently only some simple tests exist. Most of the testing has been via the examples

View File

@@ -0,0 +1,7 @@
.wy-side-nav-search {
background-color: #18334B;
}
.wy-side-nav-search input[type="text"] {
border-color: #18334b;
}

80
documentation/conf.py Normal file
View File

@@ -0,0 +1,80 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- Project information -----------------------------------------------------
project = 'normativeTypes (C++)'
copyright = '2019, EPICS Controls.'
author = 'EPICS'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.intersphinx',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# Intersphinx links to subprojects
intersphinx_mapping = {
}
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_css_files = [
'css/custom.css',
]
master_doc = 'index'
html_theme_options = {
'logo_only': True,
}
html_logo = "images/EPICS_white_logo_v02.png"
html_extra_path = [
'../html',
'pvDatabaseCPP.html',
]
# -- Run Doxygen ------------------------------------------------------------
import subprocess
subprocess.call('cd ..; mkdir -p html/doxygen; doxygen', shell=True)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

17
documentation/index.rst Normal file
View File

@@ -0,0 +1,17 @@
pvDatabase (C++) Library
========================
.. toctree::
:hidden:
EPICS Website <https://epics-controls.org>
EPICS Documentation Home <https://docs.epics-controls.org>
.. toctree::
:maxdepth: 1
:caption: pvDatabaseCPP
Reference Manual <https://docs.epics-controls.org/projects/pvdatabase-cpp/en/latest/pvDatabaseCPP.html>
API Documentation <https://docs.epics-controls.org/projects/pvdatabase-cpp/en/latest/doxygen>
Source Code Repository on GitHub <https://github.com/epics-base/pvDatabaseCPP>

View File

@@ -4,70 +4,61 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>pvDatabaseCPP</title>
<title>EPICS pvDatabaseCPP</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
href="https://mrkraimer.github.io/website/css/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
href="https://mrkraimer.github.io/website/css/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
/*<![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>
body { margin-right: 10% }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript" src="https://mrkraimer.github.io/website/css/tocgen.js"></script>
</head>
<body>
<div class="head">
<h1>pvDatabaseCPP</h1>
<h2 class="nocount">Release 4.2-SNAPSHOT - 2016.07.14</h2>
<h1>EPICS pvDatabaseCPP</h1>
<h2 class="nocount">Release 4.6.0 - March 2021</h2>
<h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP,
which is a framework for implementing a network accessible database of smart memory resident
<p><b>pvDatabase</b> is a framework for implementing a network accessible database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
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 extension must provide is a top level PVStructure and a process method.
</p>
<!-- last para of Abstract is boilerplate reference to EPICS -->
<p>For more information about EPICS generally, please refer to the home page of the <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System</a>.</p>
</div>
</div> <!-- head -->
<div id="toc">
<h2 class="nocount">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<div id="contents" class="contents">
<hr />
<h2>Overview</h2>
<p>
pvDatabaseCPP is one of the components of
<a href="http://epics-pvdata.sourceforge.net">
EPICS Version 4
Documentation for pvDatabaseCPP is available at:
<a
href="https://mrkraimer.github.io/website/developerGuide/pvDatabase/pvDatabaseCPP.html">
pvDatabase
</a>
</p>
<p>
pvDatabaseCPP is one of the components of
<a href="https://epics-controls.org/resources-and-support/base/epics-7/">
EPICS-7
</a>
</p>
<p>This document is only a guide to help locate code and documentation related to pvDatabaseCPP
@@ -78,114 +69,32 @@ It is intended for developers that want to use pvDatabaseCPP.
<h2>Developer Guide</h2>
<p>A guide for developers is available at
<a
href="http://epics-pvdata.sourceforge.net/informative/developerGuide/developerGuide.html">
href="https://mrkraimer.github.io/website/developerGuide/developerGuide.html">
developerGuide
</a>
</p>
<p>This guide discusses all the components that are part of an <b>EPICS V4</b> release.
<p>This guide provides an overview of the components that are part of an <b>EPICS V4</b> release.
Some understanding of the components and how they are related is necessary in order to
develop code that uses pvDatabaseCPP.
In particular read everything related to pvDatabase.
</p>
<p>The developerGuide discusses code in a way that applies to both CPP and C++.
For the descriptions of the CPP specific code consult the next section.
In particular read everything related to pvaClient.
</p>
<h2>doxygen</h2>
<p>doxygen documentation is available at
<a
href="./html/index.html">doxgen</a>
href="./html/index.html">doxygen</a>
</p>
<h2>pvDatabaseCPP</h2>
<p>pvDatabaseCPP itself has the following implementations of a <b>PVRecord</b></p>
<dl>
<dt>RemoveRecord.cpp</dt>
<dd>
This is the code that is used to delete another record in the same <b>IOC</b>.
</dd>
<dt>TraceRecord.cpp</dt>
<dd>
This is the code that is used to set the trace level
in another record in the same <b>IOC</b>.
</dd>
</dl>
<h2>exampleCPP</h2>
<p>Example code is available as part of this release.
<p>Example code is available at
<a
href="http://epics-pvdata.sourceforge.net/docbuild/exampleCPP/tip/documentation/exampleCPP.html">
href="https://github.com/epics-base/exampleCPP">
exampleCPP
</a>
</p>
<p>In particular look at the example code mentioned in the following sub-sections.
<p>In particular look at database, exampleLink, and helloPutGet.
</p>
<h3>database</h3>
<p>This has many examples of how to create both soft records and records that implement
other functionality.</p>
<dl>
<dt>exampleDatabase.cpp</dt>
<dd>
This shows how to create soft records of each pvData type.<br />
In addition shows how to create instances of the following two records.
</dd>
<dt>exampleHelloRecord.cpp</dt>
<dd>
This is a simple "hello world" that is intentended to be used via a channelPutGet request.
</dd>
<dt>exampleHelloRPC.cpp</dt>
<dd>
This is a simple "hello world" that is intentended to be used via a channelRPC request.
</dd>
<dt>exampleDatabaseMain.cpp</dt>
<dd>
This shows how to create a standalone IOC.
</dd>
<dt>ioc and iocBoot</dt>
<dd>
This has code and examples to create a V3 IOC which also has a PVDatabase.
</dd>
</dl>
<h3>exampleLink</h3>
<p>This shows how to implement a record that has a link to another record</p>
<dl>
<dt>exampleMonitorLinkRecord</dt>
<dd>
This creates a monitor link to another record.
</dd>
<dt>exampleGetLinkRecord</dt>
<dd>
This creates a get link to another record.
</dd>
<dt>examplePutLinkRecord</dt>
<dd>
This creates a put link to another record.
</dd>
</dl>
<h2>iocshell commands</h2>
<p>Shell commands are made available via the standard DBD include mechanism
provided by iocCore.
The following provide EPICS V4 shell commands:</p>
<pre>
pvAccessCPP
pvaSrv
pvDatabaseCPP
</pre>
<p>pvDatabaseCPP provides the following iocshell command.</p>
<dl>
<dt>registerChannelProviderLocal</dt>
<dd>Including <b>registerChannelProviderLocal.dbd</b> as a dbd file automatically starts provider local
and also creates the pvdbl shell command.
</dd>
<dt>pvdbl</dt>
<dd>Provides a list of all the pvRecords in database <b>master</b>
</dd>
</dl>
<p>In addition any code that implements a PVRecord must implement an ioc command.
Look at any of the examples in <b>exampleCPP</b> to see how to implement shell commands.</p>
</div>
</div> <!-- class="contents" -->
</body>
</html>

25
example/createdestroy/Makefile Executable file
View File

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

View File

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

View File

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

View File

@@ -74,6 +74,6 @@ make distclean all
make runtests
###########################################
# Create distribution
# Create cache
tar -czf pvDatabase.CB-dist.tar.gz lib include dbd LICENSE

View File

@@ -21,14 +21,7 @@ installE4 () {
local module=$1
local branch=$2
# If microbench version does not exist, try without
if [ "${MB}" = "WITH_MICROBENCH" ]; then
if ! wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
else
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
tar -xzf ${module}.CB-dist.tar.gz
}
@@ -38,7 +31,6 @@ installE4 () {
BASE=3.15.4
PUBLISH=${PUBLISH:-NO}
BRANCH=${BRANCH:-master}
MB=NO_MICROBENCH
###########################################
# Fetch and unpack dependencies

View File

@@ -5,21 +5,43 @@ include $(TOP)/configure/CONFIG
PVDATABASE_SRC = $(TOP)/src
LIBRARY += pvDatabase
# shared library ABI version.
SHRLIB_VERSION ?= 4.3.0
INC += pv/pvPlugin.h
INC += pv/pvStructureCopy.h
INC += pv/pvArrayPlugin.h
INC += pv/pvDeadbandPlugin.h
INC += pv/pvTimestampPlugin.h
INC += pv/pvDatabase.h
INC += pv/channelProviderLocal.h
INC += pv/pvDatabase.h
INC += pv/traceRecord.h
INC += pv/removeRecord.h
INC += pv/pvSupport.h
INC += pv/controlSupport.h
INC += pv/scalarAlarmSupport.h
INC += pv/pvdbcrScalarRecord.h
INC += pv/pvdbcrScalarArrayRecord.h
INC += pv/pvdbcrAddRecord.h
INC += pv/pvdbcrRemoveRecord.h
INC += pv/pvdbcrProcessRecord.h
INC += pv/pvdbcrTraceRecord.h
include $(PVDATABASE_SRC)/copy/Makefile
include $(PVDATABASE_SRC)/database/Makefile
include $(PVDATABASE_SRC)/pvAccess/Makefile
include $(PVDATABASE_SRC)/support/Makefile
include $(PVDATABASE_SRC)/special/Makefile
pvDatabase_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
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

12
src/copy/Makefile Normal file
View File

@@ -0,0 +1,12 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATABASE_SRC)/copy
LIBSRCS += pvPlugin.cpp
LIBSRCS += pvCopy.cpp
LIBSRCS += pvArrayPlugin.cpp
LIBSRCS += pvDeadbandPlugin.cpp
LIBSRCS += pvTimestampPlugin.cpp

225
src/copy/pvArrayPlugin.cpp Normal file
View File

@@ -0,0 +1,225 @@
/* pvArrayPlugin.cpp */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
#include <stdlib.h>
#include <pv/pvData.h>
#include <pv/bitSet.h>
#include <pv/convert.h>
#include <pv/pvSubArrayCopy.h>
#define epicsExportSharedSymbols
#include "pv/pvArrayPlugin.h"
using std::string;
using std::size_t;
using std::cout;
using std::endl;
using std::tr1::static_pointer_cast;
using std::vector;
using namespace epics::pvData;
namespace epics { namespace pvCopy{
static ConvertPtr convert = getConvert();
static std::string name("array");
PVArrayPlugin::PVArrayPlugin()
{
}
PVArrayPlugin::~PVArrayPlugin()
{
}
void PVArrayPlugin::create()
{
static bool firstTime = true;
if(firstTime) {
firstTime = false;
PVArrayPluginPtr pvPlugin = PVArrayPluginPtr(new PVArrayPlugin());
PVPluginRegistry::registerPlugin(name,pvPlugin);
}
}
PVFilterPtr PVArrayPlugin::create(
const std::string & requestValue,
const PVCopyPtr & pvCopy,
const PVFieldPtr & master)
{
return PVArrayFilter::create(requestValue,master);
}
PVArrayFilter::~PVArrayFilter()
{
}
static vector<string> split(string const & colonSeparatedList) {
string::size_type numValues = 1;
string::size_type index=0;
while(true) {
string::size_type pos = colonSeparatedList.find(':',index);
if(pos==string::npos) break;
numValues++;
index = pos +1;
}
vector<string> valueList(numValues,"");
index=0;
for(size_t i=0; i<numValues; i++) {
size_t pos = colonSeparatedList.find(':',index);
string value = colonSeparatedList.substr(index,pos-index);
valueList[i] = value;
index = pos +1;
}
return valueList;
}
PVArrayFilterPtr PVArrayFilter::create(
const std::string & requestValue,
const PVFieldPtr & masterField)
{
bool masterIsUnion = false;
PVUnionPtr pvUnion;
Type type = masterField->getField()->getType();
if(type==epics::pvData::union_) {
pvUnion = std::tr1::static_pointer_cast<PVUnion>(masterField);
PVFieldPtr pvField = pvUnion->get();
if(pvField) {
masterIsUnion = true;
type = pvField->getField()->getType();
}
}
if(type!=scalarArray) {
PVArrayFilterPtr filter = PVArrayFilterPtr();
return filter;
}
long start =0;
long increment =1;
long end = -1;
vector<string> values(split(requestValue));
long num = values.size();
bool ok = true;
string value;
if(num==1) {
value = values[0];
start = strtol(value.c_str(),0,10);
} else if(num==2) {
value = values[0];
start = strtol(value.c_str(),0,10);
value = values[1];
end = strtol(value.c_str(),0,10);
} else if(num==3) {
value = values[0];
start = strtol(value.c_str(),0,10);
value = values[1];
increment = strtol(value.c_str(),0,10);
value = values[2];
end = strtol(value.c_str(),0,10);
} else {
ok = false;
}
if(!ok) {
PVArrayFilterPtr filter = PVArrayFilterPtr();
return filter;
}
PVScalarArrayPtr masterArray;
if(masterIsUnion) {
masterArray = static_pointer_cast<PVScalarArray>(pvUnion->get());
} else {
masterArray = static_pointer_cast<PVScalarArray>(masterField);
}
PVArrayFilterPtr filter =
PVArrayFilterPtr(
new PVArrayFilter(start,increment,end,masterField,masterArray));
return filter;
}
PVArrayFilter::PVArrayFilter(
long start,long increment,long end,
const PVFieldPtr & masterField,
const epics::pvData::PVScalarArrayPtr masterArray)
: start(start),
increment(increment),
end(end),
masterField(masterField),
masterArray(masterArray)
{
}
bool PVArrayFilter::filter(const PVFieldPtr & pvField,const BitSetPtr & bitSet,bool toCopy)
{
PVFieldPtr pvCopy = pvField;
PVScalarArrayPtr copyArray;
bool isUnion = false;
Type type = masterField->getField()->getType();
if(type==epics::pvData::union_) {
isUnion = true;
PVUnionPtr pvMasterUnion = std::tr1::static_pointer_cast<PVUnion>(masterField);
PVUnionPtr pvCopyUnion = std::tr1::static_pointer_cast<PVUnion>(pvCopy);
if(toCopy) pvCopyUnion->copy(*pvMasterUnion);
PVFieldPtr pvField = pvCopyUnion->get();
copyArray = static_pointer_cast<PVScalarArray>(pvField);
} else {
copyArray = static_pointer_cast<PVScalarArray>(pvCopy);
}
long len = 0;
long start = this->start;
long end = this->end;
long no_elements = masterArray->getLength();
if(start<0) {
start = no_elements+start;
if(start<0) start = 0;
}
if (end < 0) {
end = no_elements + end;
if (end < 0) end = 0;
}
if(toCopy) {
if (end >= no_elements) end = no_elements - 1;
if (end - start >= 0) len = 1 + (end - start) / increment;
if(len<=0 || start>=no_elements) {
copyArray->setLength(0);
return true;
}
long indfrom = start;
long indto = 0;
copyArray->setCapacity(len);
if(increment==1) {
copy(*masterArray,indfrom,1,*copyArray,indto,1,len);
} else {
for(long i=0; i<len; ++i) {
copy(*masterArray,indfrom,1,*copyArray,indto,1,1);
indfrom += increment;
indto += 1;
}
}
copyArray->setLength(len);
bitSet->set(pvField->getFieldOffset());
return true;
}
if (end - start >= 0) len = 1 + (end - start) / increment;
if(len<=0) return true;
if(no_elements<=end) masterArray->setLength(end+1);
long indfrom = 0;
long indto = start;
if(increment==1) {
copy(*copyArray,indfrom,1,*masterArray,indto,1,len);
} else {
for(long i=0; i<len; ++i) {
copy(*copyArray,indfrom,1,*masterArray,indto,1,1);
indfrom += 1;
indto += increment;
}
}
if(isUnion) masterField->postPut();
return true;
}
string PVArrayFilter::getName()
{
return name;
}
}}

792
src/copy/pvCopy.cpp Normal file
View File

@@ -0,0 +1,792 @@
/* pvCopy.cpp */
/*
* License terms for this software can be found in the file LICENSE that is included with the distribution
*/
/**
* @author Marty Kraimer
* @date 2013.04
*/
#include <string>
#include <stdexcept>
#include <memory>
#include <sstream>
#include <epicsThread.h>
#include <pv/pvData.h>
#include <pv/bitSet.h>
#include <pv/thread.h>
#define epicsExportSharedSymbols
#include "pv/pvPlugin.h"
#include "pv/pvStructureCopy.h"
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::string;
using std::size_t;
using std::cout;
using std::endl;
using std::vector;
using namespace epics::pvData;
namespace epics { namespace pvCopy {
/**
* Convenience method for implementing dump.
* It generates a newline and inserts blanks at the beginning of the newline.
* @param builder The std::string * being constructed.
* @param indentLevel Indent level, Each level is four spaces.
*/
static void newLine(string *buffer, int indentLevel)
{
*buffer += "\n";
*buffer += string(indentLevel*4, ' ');
}
static PVCopyPtr NULLPVCopy;
static StructureConstPtr NULLStructure;
static PVStructurePtr NULLPVStructure;
struct CopyNode {
CopyNode()
: isStructure(false),
structureOffset(0),
nfields(0)
{}
PVFieldPtr masterPVField;
bool isStructure;
size_t structureOffset; // In the copy
size_t nfields;
PVStructurePtr options;
vector<PVFilterPtr> pvFilters;
};
static CopyNodePtr NULLCopyNode;
typedef std::vector<CopyNodePtr> CopyNodePtrArray;
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
struct CopyStructureNode : public CopyNode {
CopyNodePtrArrayPtr nodes;
};
PVCopyPtr PVCopy::create(
PVStructurePtr const &pvMaster,
PVStructurePtr const &pvRequest,
string const & structureName)
{
PVStructurePtr pvStructure(pvRequest);
if(structureName.size()>0) {
if(pvStructure->getStructure()->getNumberFields()>0) {
pvStructure = pvRequest->getSubField<PVStructure>(structureName);
if(!pvStructure) return NULLPVCopy;
}
} else if(pvRequest->getSubField<PVStructure>("field")) {
pvStructure = pvRequest->getSubField<PVStructure>("field");
}
PVCopyPtr pvCopy = PVCopyPtr(new PVCopy(pvMaster));
bool result = pvCopy->init(pvStructure);
if(!result) return PVCopyPtr();
pvCopy->traverseMasterInitPlugin();
return pvCopy;
}
PVStructurePtr PVCopy::getPVMaster()
{
return pvMaster;
}
void PVCopy::traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback)
{
traverseMaster(headNode,callback);
}
StructureConstPtr PVCopy::getStructure()
{
return structure;
}
PVStructurePtr PVCopy::createPVStructure()
{
if(cacheInitStructure) {
PVStructurePtr save = cacheInitStructure;
cacheInitStructure.reset();
return save;
}
PVStructurePtr pvStructure =
getPVDataCreate()->createPVStructure(structure);
return pvStructure;
}
size_t PVCopy::getCopyOffset(PVFieldPtr const &masterPVField)
{
if(!headNode->isStructure) {
CopyNodePtr node = static_pointer_cast<CopyNode>(headNode);
if((node->masterPVField.get())==masterPVField.get()) {
return headNode->structureOffset;
}
PVStructure * parent = masterPVField->getParent();
size_t offsetParent = parent->getFieldOffset();
size_t off = masterPVField->getFieldOffset();
size_t offdiff = off -offsetParent;
if(offdiff<node->nfields) return headNode->structureOffset + offdiff;
return string::npos;
}
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(headNode);
CopyNodePtr node = getCopyOffset(structNode,masterPVField);
if(node) return node->structureOffset;
return string::npos;
}
size_t PVCopy::getCopyOffset(
PVStructurePtr const &masterPVStructure,
PVFieldPtr const &masterPVField)
{
CopyNodePtr node;
if(!headNode->isStructure) {
node = static_pointer_cast<CopyNode>(headNode);
if(node->masterPVField.get()!=masterPVStructure.get()) return string::npos;
} else {
CopyStructureNodePtr snode = static_pointer_cast<CopyStructureNode>(headNode);
node = getCopyOffset(snode,masterPVField);
}
if(!node) return string::npos;
size_t diff = masterPVField->getFieldOffset()
- masterPVStructure->getFieldOffset();
return node->structureOffset + diff;
}
PVFieldPtr PVCopy::getMasterPVField(size_t structureOffset)
{
CopyNodePtr node;
if(!headNode->isStructure) {
node = headNode;
} else {
CopyStructureNodePtr snode = static_pointer_cast<CopyStructureNode>(headNode);
node = getMasterNode(snode,structureOffset);
}
if(!node) {
throw std::logic_error(
"PVCopy::getMasterPVField: structureOffset not valid");
}
size_t diff = structureOffset - node->structureOffset;
PVFieldPtr pvMasterField = node->masterPVField;
if(diff==0) return pvMasterField;
PVStructurePtr pvStructure
= static_pointer_cast<PVStructure>(pvMasterField);
return pvStructure->getSubField(
pvMasterField->getFieldOffset() + diff);
}
void PVCopy::initCopy(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
bitSet->set(i,true);
}
updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
}
bool PVCopy::updateCopySetBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
updateCopySetBitSet(copyPVStructure,headNode,bitSet);
return checkIgnore(copyPVStructure,bitSet);
}
bool PVCopy::updateCopyFromBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
if(bitSet->get(0)) {
for(size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
bitSet->set(i,true);
}
}
updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
return checkIgnore(copyPVStructure,bitSet);
}
void PVCopy::updateMasterField(
CopyNodePtr const & node,
PVFieldPtr const & pvCopy,
PVFieldPtr const &pvMaster,
BitSetPtr const &bitSet)
{
bool result = false;
for(size_t i=0; i< node->pvFilters.size(); ++i) {
PVFilterPtr pvFilter = node->pvFilters[i];
if(pvFilter->filter(pvCopy,bitSet,false)) result = true;
}
if(result) return;
pvMaster->copyUnchecked(*pvCopy);
}
void PVCopy::updateMasterCheckBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet,
size_t nextSet)
{
if(!bitSet->get(nextSet)) {
size_t next = bitSet->nextSetBit(nextSet);
if(next==string::npos) return;
updateMasterCheckBitSet(copyPVStructure,bitSet,next);
return;
}
PVFieldPtr pvField = copyPVStructure;
if(nextSet!=0) pvField = copyPVStructure->getSubField(nextSet);
if(pvField->getField()->getType()==epics::pvData::structure) {
bitSet->clear(nextSet);
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvField);
PVFieldPtrArray pvFieldArray = pv->getPVFields();
for(size_t i=0; i<pvFieldArray.size(); ++i) {
PVFieldPtr pvField = pvFieldArray[i];
bitSet->set(pvField->getFieldOffset());
}
}
size_t next = bitSet->nextSetBit(nextSet+1);
if(next==string::npos) return;
updateMasterCheckBitSet(copyPVStructure,bitSet,next);
}
CopyNodePtr PVCopy::getCopyNode(std::size_t fieldOffset)
{
if(fieldOffset==0) return headNode;
CopyNodePtr node = headNode;
while(true) {
if(!node->isStructure) return node;
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structNode->nodes;
bool okToContinue = false;
for(size_t i=0; i< nodes->size(); i++) {
node = (*nodes)[i];
size_t soff = node->structureOffset;
if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
okToContinue = true;
break;
}
}
if(okToContinue) continue;
}
throw std::logic_error("PVCopy::getCopyNode fieldOffset not valid");
}
void PVCopy::updateMaster(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
updateMasterCheckBitSet(copyPVStructure,bitSet,0);
size_t nextSet =0;
while(true) {
nextSet = bitSet->nextSetBit(nextSet);
if(nextSet==string::npos) return;
PVFieldPtr pvCopy = copyPVStructure->getSubField(nextSet);
PVFieldPtr pvMaster = headNode->masterPVField;
if(pvMaster->getField()->getType()==epics::pvData::structure) {
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvMaster);
pvMaster = pv->getSubField(pvCopy->getFullName());
}
updateMasterField(getCopyNode(nextSet),pvCopy,pvMaster,bitSet);
bitSet->clear(nextSet);
}
}
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
{
if(fieldOffset==0) return headNode->options;
CopyNodePtr node = headNode;
while(true) {
if(node->structureOffset==fieldOffset) return node->options;
if(!node->isStructure) return NULLPVStructure;
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structNode->nodes;
bool okToContinue = false;
for(size_t i=0; i< nodes->size(); i++) {
node = (*nodes)[i];
size_t soff = node->structureOffset;
if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
if(fieldOffset==soff) return node->options;
if(!node->isStructure) {
return NULLPVStructure;
}
okToContinue = true;
break;
}
}
if(okToContinue) continue;
throw std::logic_error("PVCopy::getOptions logic error: fieldOffset not valid");
}
}
string PVCopy::dump()
{
string builder;
dump(&builder,headNode,0);
return builder;
}
void PVCopy::traverseMaster(
CopyNodePtr const &innode,
PVCopyTraverseMasterCallbackPtr const & callback)
{
CopyNodePtr node = innode;
if(!node->isStructure) {
callback->nextMasterPVField(node->masterPVField);
return;
}
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structNode->nodes;
for(size_t i=0; i< nodes->size(); i++) {
node = (*nodes)[i];
traverseMaster(node,callback);
}
}
void PVCopy::updateCopySetBitSet(
PVFieldPtr const & pvCopy,
PVFieldPtr const & pvMaster,
BitSetPtr const & bitSet)
{
if(pvCopy->getField()->getType()!=epics::pvData::structure) {
if(*pvCopy==*pvMaster) return;
pvCopy->copy(*pvMaster);
bitSet->set(pvCopy->getFieldOffset());
return;
}
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
for(size_t i=0; i<pvCopyFields.size(); ++i) {
PVFieldPtr master = getMasterPVField(pvCopyFields[i]->getFieldOffset());
updateCopySetBitSet(pvCopyFields[i],master,bitSet);
}
}
void PVCopy::updateCopySetBitSet(
PVFieldPtr const & pvCopy,
CopyNodePtr const & node,
BitSetPtr const & bitSet)
{
bool result = false;
for(size_t i=0; i< node->pvFilters.size(); ++i) {
PVFilterPtr pvFilter = node->pvFilters[i];
if(pvFilter->filter(pvCopy,bitSet,true)) result = true;
}
if(!node->isStructure) {
if(result) return;
updateCopySetBitSet(pvCopy,node->masterPVField,bitSet);
return;
}
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
for(size_t i=0; i<pvCopyFields.size(); ++i) {
updateCopySetBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
}
}
void PVCopy::updateCopyFromBitSet(
PVFieldPtr const & pvCopy,
CopyNodePtr const & node,
BitSetPtr const & bitSet)
{
bool result = false;
bool update = bitSet->get(pvCopy->getFieldOffset());
if(update) {
for(size_t i=0; i< node->pvFilters.size(); ++i) {
PVFilterPtr pvFilter = node->pvFilters[i];
if(pvFilter->filter(pvCopy,bitSet,true)) result = true;
}
}
if(!node->isStructure) {
if(result) return;
PVFieldPtr pvMaster = node->masterPVField;
pvCopy->copy(*pvMaster);
return;
}
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
size_t offset = structureNode->structureOffset;
size_t nextSet = bitSet->nextSetBit(offset);
if(nextSet==string::npos) return;
if(offset>=pvCopy->getNextFieldOffset()) return;
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
for(size_t i=0; i<pvCopyFields.size(); ++i) {
updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
}
}
PVCopy::PVCopy(
PVStructurePtr const &pvMaster)
: pvMaster(pvMaster)
{
}
bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
{
PVStructurePtr pvMasterStructure = pvMaster;
size_t len = pvRequest->getPVFields().size();
bool entireMaster = false;
PVStructurePtr pvOptions;
if(len==0) {
entireMaster = true;
}
else {
// If "_" is in the request, but not in the master structure,
// then assume the top level PV structure is requested
PVStructurePtr masterFieldPtr = pvMaster->getSubField<PVStructure>("_");
PVStructurePtr requestFieldPtr = pvRequest->getSubField<PVStructure>("_");
if (!masterFieldPtr && requestFieldPtr) {
entireMaster = true;
pvOptions = requestFieldPtr->getSubField<PVStructure>("_options");
}
}
if(entireMaster) {
structure = pvMasterStructure->getStructure();
CopyNodePtr node(new CopyNode());
headNode = node;
node->options = pvOptions;
node->isStructure = false;
node->structureOffset = 0;
node->masterPVField = pvMasterStructure;
node->nfields = pvMasterStructure->getNumberFields();
return true;
}
structure = createStructure(pvMasterStructure,pvRequest);
if(!structure) return false;
cacheInitStructure = createPVStructure();
ignorechangeBitSet = BitSetPtr(new BitSet(cacheInitStructure->getNumberFields()));
headNode = createStructureNodes(
pvMaster,
pvRequest,
cacheInitStructure);
return true;
}
StructureConstPtr PVCopy::createStructure(
PVStructurePtr const &pvMaster,
PVStructurePtr const &pvFromRequest)
{
if(pvFromRequest->getStructure()->getNumberFields()==0) {
return pvMaster->getStructure();
}
PVFieldPtrArray const &pvFromRequestFields = pvFromRequest->getPVFields();
StringArray const &fromRequestFieldNames = pvFromRequest->getStructure()->getFieldNames();
size_t length = pvFromRequestFields.size();
if(length==0) return NULLStructure;
FieldConstPtrArray fields; fields.reserve(length);
StringArray fieldNames; fieldNames.reserve(length);
for(size_t i=0; i<length; ++i) {
string const &fieldName = fromRequestFieldNames[i];
PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
if(!pvMasterField) continue;
FieldConstPtr field = pvMasterField->getField();
if(field->getType()==epics::pvData::structure) {
PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
pvFromRequestFields[i]);
if(pvRequestStructure->getNumberFields()>0) {
StringArray const &names = pvRequestStructure->getStructure()->
getFieldNames();
size_t num = names.size();
if(num>0 && names[0].compare("_options")==0) --num;
if(num>0) {
if(pvMasterField->getField()->getType()!=epics::pvData::structure) continue;
fieldNames.push_back(fieldName);
fields.push_back(createStructure(
static_pointer_cast<PVStructure>(pvMasterField),
pvRequestStructure));
continue;
}
}
}
fieldNames.push_back(fieldName);
fields.push_back(field);
}
size_t numsubfields = fields.size();
if(numsubfields==0) {
std::stringstream ss;
ss << pvFromRequest << "\n";
string val("no fields from the following request were found\n");
val += ss.str();
throw std::invalid_argument(val);
}
return getFieldCreate()->createStructure(fieldNames, fields);
}
CopyNodePtr PVCopy::createStructureNodes(
PVStructurePtr const &pvMasterStructure,
PVStructurePtr const &pvFromRequest,
PVStructurePtr const &pvFromCopy)
{
PVFieldPtrArray const & copyPVFields = pvFromCopy->getPVFields();
PVStructurePtr pvOptions = pvFromRequest->getSubField<PVStructure>("_options");
size_t number = copyPVFields.size();
CopyNodePtrArrayPtr nodes(new CopyNodePtrArray());
nodes->reserve(number);
for(size_t i=0; i<number; i++) {
PVFieldPtr copyPVField = copyPVFields[i];
string fieldName = copyPVField->getFieldName();
PVStructurePtr requestPVStructure =
pvFromRequest->getSubField<PVStructure>(fieldName);
PVStructurePtr pvSubFieldOptions =
requestPVStructure->getSubField<PVStructure>("_options");
PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
if(!pvMasterField) {
throw std::logic_error("PVCopy::createStructureNodes did not find field in master");
}
size_t numberRequest = requestPVStructure->getPVFields().size();
bool haveOptions = false;
if(pvSubFieldOptions) {
numberRequest--;
haveOptions = true;
}
if(numberRequest>0) {
Type copyType = copyPVField->getField()->getType();
if(copyType==epics::pvData::structure) {
nodes->push_back(createStructureNodes(
static_pointer_cast<PVStructure>(pvMasterField),
requestPVStructure,
static_pointer_cast<PVStructure>(copyPVField)));
continue;
}
if(copyType==epics::pvData::union_) {
if(numberRequest!=1) {
std::stringstream ss;
ss << pvFromRequest << "\n";
string val("In the following request a union field has more than one subfield in\n");
val += ss.str();
throw std::invalid_argument(val);
}
PVUnionPtr pvUnion = static_pointer_cast<PVUnion>(pvMasterField);
std::string selectedName = pvUnion->getSelectedFieldName();
PVFieldPtrArray const & pvFields = requestPVStructure->getPVFields();
size_t len = pvFields.size();
if(len>2 || (haveOptions && len!=2)) {
std::stringstream ss;
ss << pvFromRequest << "\n";
string val("PVCopy logic error: pvRequest is\n");
val += ss.str();
throw std::logic_error(val);
}
size_t indRequestValue = 0;
if((pvFields[0]->getFieldName().compare("_options"))==0) indRequestValue = 1;
PVFieldPtr pvRequestValue = pvFields[indRequestValue];
if(pvRequestValue) {
string requestName = pvRequestValue->getFieldName();
if(requestName.compare(selectedName)!=0) {
std::stringstream ss;
ss << pvFromCopy << "\n";
string requestName = pvRequestValue->getFieldName();
string val("field ");
val += requestName + " does not match union type in\n";
val += ss.str();
throw std::invalid_argument(val);
}
}
} else {
std::stringstream ss;
ss << pvFromCopy << "\n";
string val("requested a subfield of field ");
val += fieldName + " which does not have type structure in\n";
val += ss.str();
throw std::invalid_argument(val);
}
}
CopyNodePtr node(new CopyNode());
node->options = pvSubFieldOptions;
node->isStructure = false;
node->masterPVField = pvMasterField;
node->nfields = copyPVField->getNumberFields();
node->structureOffset = copyPVField->getFieldOffset();
nodes->push_back(node);
}
CopyStructureNodePtr structureNode(new CopyStructureNode());
structureNode->masterPVField = pvMasterStructure;
structureNode->isStructure = true;
structureNode->nodes = nodes;
structureNode->structureOffset = pvFromCopy->getFieldOffset();
structureNode->nfields = pvFromCopy->getNumberFields();
structureNode->options = pvOptions;
return structureNode;
}
void PVCopy::initPlugin(
CopyNodePtr const & node,
PVStructurePtr const & pvOptions,
PVFieldPtr const & pvMasterField)
{
PVFieldPtrArray const & pvFields = pvOptions->getPVFields();
size_t num = pvFields.size();
vector<PVFilterPtr> pvFilters(num);
size_t numfilter = 0;
for(size_t i=0; i<num; ++i) {
PVStringPtr pvOption = static_pointer_cast<PVString>(pvFields[i]);
string name = pvOption->getFieldName();
string value = pvOption->get();
PVPluginPtr pvPlugin = PVPluginRegistry::find(name);
if(!pvPlugin) {
if(name.compare("ignore")==0) setIgnore(node);
continue;
}
pvFilters[numfilter] = pvPlugin->create(value,shared_from_this(),pvMasterField);
if(pvFilters[numfilter]) ++numfilter;
}
if(numfilter==0) return;
node->pvFilters.resize(numfilter);
for(size_t i=0; i<numfilter; ++i) node->pvFilters[i] = pvFilters[i];
}
void PVCopy::traverseMasterInitPlugin()
{
traverseMasterInitPlugin(headNode);
}
void PVCopy::traverseMasterInitPlugin(CopyNodePtr const & node)
{
PVFieldPtr pvField = node->masterPVField;
PVStructurePtr pvOptions = node->options;
if(pvOptions) initPlugin(node,pvOptions,pvField);
if(!node->isStructure) return;
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i< nodes->size(); i++) {
traverseMasterInitPlugin((*nodes)[i]);
}
}
CopyNodePtr PVCopy::getCopyOffset(
CopyStructureNodePtr const &structureNode,
PVFieldPtr const &masterPVField)
{
size_t offset = masterPVField->getFieldOffset();
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i< nodes->size(); i++) {
CopyNodePtr node = (*nodes)[i];
if(!node->isStructure) {
size_t off = node->masterPVField->getFieldOffset();
size_t nextOffset = node->masterPVField->getNextFieldOffset();
if(offset>= off && offset<nextOffset) return node;
} else {
CopyStructureNodePtr subNode =
static_pointer_cast<CopyStructureNode>(node);
CopyNodePtr node =
getCopyOffset(subNode,masterPVField);
if(node) return node;
}
}
return NULLCopyNode;
}
bool PVCopy::checkIgnore(
PVStructurePtr const & copyPVStructure,
BitSetPtr const & bitSet)
{
if(!ignorechangeBitSet) {
return (bitSet->nextSetBit(0)<0) ? false : true;
}
int32 numFields = copyPVStructure->getNumberFields();
BitSet temp(numFields);
temp = *bitSet;
int32 ind = 0;
while(true) {
ind = ignorechangeBitSet->nextSetBit(ind);
if(ind<0) break;
temp.clear(ind);
ind++;
if(ind>=numFields) break;
}
return (temp.nextSetBit(0)<0) ? false : true;
}
void PVCopy::setIgnore(CopyNodePtr const &node) {
ignorechangeBitSet->set(node->structureOffset);
if(node->isStructure) {
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i<nodes->size(); ++i) {
CopyNodePtr node = (*nodes)[i];
setIgnore(node); }
} else {
size_t num = node->masterPVField->getNumberFields();
if(num>1) {
for(size_t i=1; i<num; ++i) {
ignorechangeBitSet->set(node->structureOffset+i);
}
}
}
}
CopyNodePtr PVCopy::getMasterNode(
CopyStructureNodePtr const &structureNode,
std::size_t structureOffset)
{
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i<nodes->size(); ++i) {
CopyNodePtr node = (*nodes)[i];
if(structureOffset>=(node->structureOffset + node->nfields)) continue;
if(!node->isStructure) return node;
CopyStructureNodePtr subNode =
static_pointer_cast<CopyStructureNode>(node);
return getMasterNode(subNode,structureOffset);
}
return NULLCopyNode;
}
void PVCopy::dump(string *builder,CopyNodePtr const &node,int indentLevel)
{
newLine(builder,indentLevel);
std::stringstream ss;
ss << (node->isStructure ? "structureNode" : "node");
ss << " structureOffset " << node->structureOffset;
ss << " nfields " << node->nfields;
*builder += ss.str();
PVStructurePtr options = node->options;
if(options) {
newLine(builder,indentLevel +1);
*builder += options->getFieldName();
PVFieldPtrArray pvFields = options->getPVFields();
for(size_t i=0; i< pvFields.size() ; ++i) {
PVStringPtr pvString = static_pointer_cast<PVString>(pvFields[i]);
newLine(builder,indentLevel +2);
*builder += pvString->getFieldName() + " " + pvString->get();
}
}
string name = node->masterPVField->getFullName();
newLine(builder,indentLevel +1);
*builder += "masterField " + name;
if(node->pvFilters.size()>0) {
newLine(builder,indentLevel +2);
*builder += "filters:";
for(size_t i=0; i< node->pvFilters.size(); ++i) {
PVFilterPtr pvFilter = node->pvFilters[i];
*builder += " " + pvFilter->getName();
}
}
if(!node->isStructure) return;
CopyStructureNodePtr structureNode =
static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i<nodes->size(); ++i) {
CopyNodePtr node = (*nodes)[i];
if(!node) {
newLine(builder,indentLevel +1);
ss.str("");
ss << "node[" << i << "] is null";
*builder += ss.str();
continue;
}
dump(builder,node,indentLevel+1);
}
}
}}

View File

@@ -0,0 +1,134 @@
/* pvDeadbandPlugin.cpp */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
#include <stdlib.h>
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h>
#include <pv/bitSet.h>
#include <pv/convert.h>
#define epicsExportSharedSymbols
#include "pv/pvDeadbandPlugin.h"
using std::string;
using std::size_t;
using std::cout;
using std::endl;
using std::tr1::static_pointer_cast;
using std::vector;
using namespace epics::pvData;
namespace epics { namespace pvCopy{
static ConvertPtr convert = getConvert();
static std::string name("deadband");
PVDeadbandPlugin::PVDeadbandPlugin()
{
}
PVDeadbandPlugin::~PVDeadbandPlugin()
{
}
void PVDeadbandPlugin::create()
{
static bool firstTime = true;
if(firstTime) {
firstTime = false;
PVDeadbandPluginPtr pvPlugin = PVDeadbandPluginPtr(new PVDeadbandPlugin());
PVPluginRegistry::registerPlugin(name,pvPlugin);
}
}
PVFilterPtr PVDeadbandPlugin::create(
const std::string & requestValue,
const PVCopyPtr & pvCopy,
const PVFieldPtr & master)
{
return PVDeadbandFilter::create(requestValue,master);
}
PVDeadbandFilter::~PVDeadbandFilter()
{
}
PVDeadbandFilterPtr PVDeadbandFilter::create(
const std::string & requestValue,
const PVFieldPtr & master)
{
FieldConstPtr field =master->getField();
Type type = field->getType();
if(type!=scalar) return PVDeadbandFilterPtr();
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
if(!ScalarTypeFunc::isNumeric(scalar->getScalarType())) return PVDeadbandFilterPtr();
bool absolute = false;
if(requestValue.find("abs")==0) {
absolute = true;
} else if(requestValue.find("rel")==0) {
absolute = false;
} else {
return PVDeadbandFilterPtr();
}
size_t ind = requestValue.find(':');
if(ind==string::npos) return PVDeadbandFilterPtr();
string svalue = requestValue.substr(ind+1);
double deadband = atof(svalue.c_str());
if(deadband==0.0) return PVDeadbandFilterPtr();
PVDeadbandFilterPtr filter =
PVDeadbandFilterPtr(
new PVDeadbandFilter(
absolute,deadband,static_pointer_cast<PVScalar>(master)));
return filter;
}
PVDeadbandFilter::PVDeadbandFilter(bool absolute,double deadband,PVScalarPtr const & master)
: absolute(absolute),
deadband(deadband),
master(master),
firstTime(true),
lastReportedValue(0.0)
{
}
bool PVDeadbandFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
{
if(!toCopy) return false;
double value = convert->toDouble(master);
double diff = value - lastReportedValue;
if(diff<0.0) diff = - diff;
bool report = true;
if(firstTime) {
firstTime = false;
} else if(absolute) {
if(diff<deadband) report = false;
} else {
double last = lastReportedValue;
if(last<0.0) last = -last;
if(last>1e-20) {
double percent = (diff/last)*100.0;
if(percent<deadband) report = false;
}
}
PVScalarPtr copy = static_pointer_cast<PVScalar>(pvCopy);
convert->fromDouble(copy,value);
if(report) {
lastReportedValue = value;
bitSet->set(pvCopy->getFieldOffset());
} else {
bitSet->clear(pvCopy->getFieldOffset());
}
return true;
}
string PVDeadbandFilter::getName()
{
return name;
}
}}

40
src/copy/pvPlugin.cpp Normal file
View File

@@ -0,0 +1,40 @@
/* pvPlugin.cpp */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
#include <pv/pvData.h>
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/bitSet.h>
#define epicsExportSharedSymbols
#include "pv/pvPlugin.h"
using namespace epics::pvData;
namespace epics { namespace pvCopy{
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
static PVPluginMap pluginMap;
static Mutex mutex;
void PVPluginRegistry::registerPlugin(const std::string & name,const PVPluginPtr & pvPlugin)
{
Lock xx(mutex);
PVPluginMap::iterator iter = pluginMap.find(name);
if(iter!=pluginMap.end()) throw std::logic_error("plugin already registered");
pluginMap.insert(PVPluginMap::value_type(name,pvPlugin));
}
PVPluginPtr PVPluginRegistry::find(const std::string & name)
{
Lock xx(mutex);
PVPluginMap::iterator iter = pluginMap.find(name);
if(iter!=pluginMap.end()) return (*iter).second;
return PVPluginPtr();
}
}}

View File

@@ -0,0 +1,126 @@
/* pvTimestampPlugin.cpp */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h>
#include <pv/bitSet.h>
#include <pv/convert.h>
#include <pv/pvTimeStamp.h>
#define epicsExportSharedSymbols
#include "pv/pvPlugin.h"
#include "pv/pvTimestampPlugin.h"
using std::string;
using std::size_t;
using std::cout;
using std::endl;
using std::tr1::static_pointer_cast;
using std::vector;
using namespace epics::pvData;
namespace epics { namespace pvCopy{
static ConvertPtr convert = getConvert();
static std::string name("timestamp");
PVTimestampPlugin::PVTimestampPlugin()
{
}
PVTimestampPlugin::~PVTimestampPlugin()
{
}
void PVTimestampPlugin::create()
{
static bool firstTime = true;
if(firstTime) {
firstTime = false;
PVTimestampPluginPtr pvPlugin = PVTimestampPluginPtr(new PVTimestampPlugin());
PVPluginRegistry::registerPlugin(name,pvPlugin);
}
}
PVFilterPtr PVTimestampPlugin::create(
const std::string & requestValue,
const PVCopyPtr & pvCopy,
const PVFieldPtr & master)
{
return PVTimestampFilter::create(requestValue,master);
}
PVTimestampFilter::~PVTimestampFilter()
{
}
PVTimestampFilterPtr PVTimestampFilter::create(
const std::string & requestValue,
const PVFieldPtr & master)
{
PVTimeStamp pvTimeStamp;
if(!pvTimeStamp.attach(master)) return PVTimestampFilterPtr();
bool current = false;
bool copy = false;
if(requestValue.compare("current")==0) {
current = true;
} else if(requestValue.compare("copy")==0){
copy = true;
} else {
return PVTimestampFilterPtr();
}
PVTimestampFilterPtr filter = PVTimestampFilterPtr(
new PVTimestampFilter(current,copy,master));
return filter;
}
PVTimestampFilter::PVTimestampFilter(bool current,bool copy,PVFieldPtr const & master)
: current(current),
copy(copy),
master(master)
{
}
bool PVTimestampFilter::filter(const PVFieldPtr & pvCopy,const BitSetPtr & bitSet,bool toCopy)
{
if(current) {
timeStamp.getCurrent();
if(toCopy) {
if(!pvTimeStamp.attach(pvCopy)) return false;
} else {
if(!pvTimeStamp.attach(master)) return false;
}
pvTimeStamp.set(timeStamp);
bitSet->set(pvCopy->getFieldOffset());
return true;
}
if(copy) {
if(toCopy) {
if(!pvTimeStamp.attach(master)) return false;
pvTimeStamp.get(timeStamp);
if(!pvTimeStamp.attach(pvCopy)) return false;
pvTimeStamp.set(timeStamp);
bitSet->set(pvCopy->getFieldOffset());
} else {
if(!pvTimeStamp.attach(pvCopy)) return false;
pvTimeStamp.get(timeStamp);
if(!pvTimeStamp.attach(master)) return false;
pvTimeStamp.set(timeStamp);
}
return true;
}
return false;
}
string PVTimestampFilter::getName()
{
return name;
}
}}

View File

@@ -10,32 +10,52 @@
*/
#include <epicsGuard.h>
#include <list>
#include <map>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#define epicsExportSharedSymbols
#include <pv/pvDatabase.h>
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
#include "pv/pvPlugin.h"
#include "pv/pvArrayPlugin.h"
#include "pv/pvTimestampPlugin.h"
#include "pv/pvDeadbandPlugin.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvCopy;
using namespace std;
namespace epics { namespace pvDatabase {
#define DEBUG_LEVEL 0
static PVDatabasePtr pvDatabaseMaster;
PVDatabasePtr PVDatabase::getMaster()
{
if(!pvDatabaseMaster) pvDatabaseMaster = PVDatabasePtr(new PVDatabase());
static bool firstTime = true;
if(firstTime) {
firstTime = false;
pvDatabaseMaster = PVDatabasePtr(new PVDatabase());
PVArrayPlugin::create();
PVTimestampPlugin::create();
PVDeadbandPlugin::create();
}
return pvDatabaseMaster;
}
PVDatabase::PVDatabase()
{
if(DEBUG_LEVEL>0) cout << "PVDatabase::PVDatabase()\n";
}
PVDatabase::~PVDatabase()
{
cout << "PVDatabase::~PVDatabase()\n";
if(DEBUG_LEVEL>0) cout << "PVDatabase::~PVDatabase()\n";
}
void PVDatabase::lock() {
@@ -72,18 +92,28 @@ bool PVDatabase::addRecord(PVRecordPtr const & record)
return true;
}
bool PVDatabase::removeRecord(PVRecordPtr const & record)
PVRecordWPtr PVDatabase::removeFromMap(PVRecordPtr const & record)
{
if(record->getTraceLevel()>0) {
cout << "PVDatabase::removeRecord " << record->getRecordName() << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
string recordName = record->getRecordName();
PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) {
PVRecordPtr pvRecord = (*iter).second;
recordMap.erase(iter);
if(pvRecord) pvRecord->destroy();
return pvRecord->shared_from_this();
}
return PVRecordWPtr();
}
bool PVDatabase::removeRecord(PVRecordPtr const & record)
{
if(record->getTraceLevel()>0) {
cout << "PVDatabase::removeRecord " << record->getRecordName() << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
PVRecordWPtr pvRecord = removeFromMap(record);
if(pvRecord.use_count()!=0) {
pvRecord.lock()->unlistenClients();
return true;
}
return false;

View File

@@ -8,25 +8,40 @@
* @author mrk
* @date 2012.11.21
*/
#include <list>
#include <epicsGuard.h>
#include <epicsThread.h>
#include <pv/status.h>
#include <pv/pvAccess.h>
#include <pv/createRequest.h>
#include <pv/pvaVersion.h>
#include <pv/pvaVersionNum.h>
#include <pv/monitor.h>
#include <pv/convert.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
#include <pv/pvData.h>
#include <pv/rpcService.h>
#include <pv/pvTimeStamp.h>
#define epicsExportSharedSymbols
#include <pv/pvDatabase.h>
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvDatabase;
using namespace std;
namespace epics { namespace pvDatabase {
PVRecordPtr PVRecord::create(
string const &recordName,
PVStructurePtr const & pvStructure)
PVStructurePtr const & pvStructure,
int asLevel,
const std::string& asGroup)
{
PVRecordPtr pvRecord(new PVRecord(recordName,pvStructure));
PVRecordPtr pvRecord(new PVRecord(recordName,pvStructure,asLevel,asGroup));
if(!pvRecord->init()) {
pvRecord.reset();
}
@@ -36,13 +51,16 @@ PVRecordPtr PVRecord::create(
PVRecord::PVRecord(
string const & recordName,
PVStructurePtr const & pvStructure)
PVStructurePtr const & pvStructure,
int asLevel_,
const std::string& asGroup_)
: recordName(recordName),
pvStructure(pvStructure),
depthGroupPut(0),
traceLevel(0),
isDestroyed(false),
isAddListener(false)
isAddListener(false),
asLevel(asLevel_),
asGroup(asGroup_)
{
}
@@ -53,6 +71,48 @@ PVRecord::~PVRecord()
}
}
void PVRecord::unlistenClients()
{
epicsGuard<epics::pvData::Mutex> guard(mutex);
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
iter!=pvListenerList.end();
iter++ )
{
PVListenerPtr listener = iter->lock();
if(!listener) continue;
if(traceLevel>0) {
cout << "PVRecord::remove() calling listener->unlisten " << recordName << endl;
}
listener->unlisten(shared_from_this());
}
pvListenerList.clear();
for (std::list<PVRecordClientWPtr>::iterator iter = clientList.begin();
iter!=clientList.end();
iter++ )
{
PVRecordClientPtr client = iter->lock();
if(!client) continue;
if(traceLevel>0) {
cout << "PVRecord::remove() calling client->detach " << recordName << endl;
}
client->detach(shared_from_this());
}
clientList.clear();
}
void PVRecord::remove()
{
if(traceLevel>0) {
cout << "PVRecord::remove() " << recordName << endl;
}
unlistenClients();
epicsGuard<epics::pvData::Mutex> guard(mutex);
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
if(pvDatabase) pvDatabase->removeFromMap(shared_from_this());
pvTimeStamp.detach();
}
void PVRecord::initPVRecord()
{
PVRecordStructurePtr parent;
@@ -63,49 +123,6 @@ void PVRecord::initPVRecord()
if(pvField) pvTimeStamp.attach(pvField);
}
void PVRecord::destroy()
{
{
epicsGuard<epics::pvData::Mutex> guard(mutex);
if(traceLevel>0) {
cout << "PVRecord::destroy() " << recordName
<< " isDestroyed " << (isDestroyed ? "true" : "false")
<< endl;
}
if(isDestroyed) {
return;
}
isDestroyed = true;
}
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
if(pvDatabase) pvDatabase->removeRecord(shared_from_this());
pvTimeStamp.detach();
for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
iter!=pvListenerList.end();
iter++ )
{
PVListenerPtr listener = iter->lock();
if(!listener) continue;
if(traceLevel>0) {
cout << "PVRecord::destroy() calling listener->unlisten " << recordName << endl;
}
listener->unlisten(shared_from_this());
}
pvListenerList.clear();
for (std::list<PVRecordClientPtr>::iterator iter = clientList.begin();
iter!=clientList.end();
iter++ )
{
PVRecordClientPtr client = *iter;
if(!client) continue;
if(traceLevel>0) {
cout << "PVRecord::destroy() calling client->detach " << recordName << endl;
}
client->detach(shared_from_this());
}
clientList.clear();
}
void PVRecord::process()
{
if(traceLevel>2) {
@@ -191,70 +208,39 @@ bool PVRecord::addPVRecordClient(PVRecordClientPtr const & pvRecordClient)
cout << "PVRecord::addPVRecordClient() " << recordName << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
if(isDestroyed) {
return false;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = clientList.begin();
iter!=clientList.end();
iter++ )
{
PVRecordClientPtr client = *iter;
if(client==pvRecordClient) {
return false;
// clean clientList
bool clientListClean = false;
while(!clientListClean) {
if(clientList.empty()) break;
clientListClean = true;
std::list<PVRecordClientWPtr>::iterator iter;
for (iter = clientList.begin();
iter!=clientList.end();
iter++ )
{
PVRecordClientPtr client = iter->lock();
if(client) continue;
if(traceLevel>1) {
cout << "PVRecord::addPVRecordClient() erasing client"
<< recordName << endl;
}
clientList.erase(iter);
clientListClean = false;
break;
}
}
if(traceLevel>1) {
cout << "PVRecord::addPVRecordClient() calling clientList.push_back(pvRecordClient)" << recordName << endl;
}
clientList.push_back(pvRecordClient);
return true;
}
bool PVRecord::removePVRecordClient(PVRecordClientPtr const & pvRecordClient)
{
if(traceLevel>1) {
cout << "PVRecord::removePVRecordClient() " << recordName << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
if(isDestroyed) {
return false;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = clientList.begin();
iter!=clientList.end();
iter++ )
{
PVRecordClientPtr client = *iter;
if(!client) continue;
if(client==pvRecordClient) {
clientList.erase(iter);
return true;
}
}
return false;
}
bool PVRecord::addListener(
PVListenerPtr const & pvListener,
PVCopyPtr const & pvCopy)
epics::pvCopy::PVCopyPtr const & pvCopy)
{
if(traceLevel>1) {
cout << "PVRecord::addListener() " << recordName << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
if(isDestroyed) {
return false;
}
std::list<PVListenerWPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
PVListenerPtr listener = iter->lock();
if(!listener.get()) continue;
if(listener.get()==pvListener.get()) {
return false;
}
}
pvListenerList.push_back(pvListener);
this->pvListener = pvListener;
isAddListener = true;
@@ -268,7 +254,7 @@ void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
PVRecordFieldPtr pvRecordField = findPVRecordField(pvField);
PVListenerPtr listener = pvListener.lock();
if(!listener.get()) return;
if(isAddListener) {
if(isAddListener) {
pvRecordField->addListener(listener);
} else {
pvRecordField->removeListener(listener);
@@ -277,15 +263,12 @@ void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
bool PVRecord::removeListener(
PVListenerPtr const & pvListener,
PVCopyPtr const & pvCopy)
epics::pvCopy::PVCopyPtr const & pvCopy)
{
if(traceLevel>1) {
cout << "PVRecord::removeListener() " << recordName << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
if(isDestroyed) {
return false;
}
std::list<PVListenerWPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
@@ -349,6 +332,7 @@ PVRecordField::PVRecordField(
PVRecordPtr const & pvRecord)
: pvField(pvField),
isStructure(pvField->getField()->getType()==structure ? true : false),
master(),
parent(parent),
pvRecord(pvRecord)
{
@@ -394,21 +378,13 @@ bool PVRecordField::addListener(PVListenerPtr const & pvListener)
if(pvRecord && pvRecord->getTraceLevel()>1) {
cout << "PVRecordField::addListener() " << getFullName() << endl;
}
std::list<PVListenerWPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
PVListenerPtr listener = iter->lock();
if(!listener.get()) continue;
if(listener.get()==pvListener.get()) {
return false;
}
}
pvListenerList.push_back(pvListener);
return true;
}
void PVRecordField::removeListener(PVListenerPtr const & pvListener)
{
PVRecordPtr pvRecord(this->pvRecord.lock());
PVRecordPtr pvRecord(this->pvRecord.lock());
if(pvRecord && pvRecord->getTraceLevel()>1) {
cout << "PVRecordField::removeListener() " << getFullName() << endl;
}
@@ -443,14 +419,22 @@ void PVRecordField::postParent(PVRecordFieldPtr const & subField)
listener->dataPut(pvrs,subField);
}
PVRecordStructurePtr parent(this->parent.lock());
if(parent) parent->postParent(subField);
if(parent) {
parent->postParent(subField);
}
}
void PVRecordField::postSubField()
{
// Master field pointer will be set in only one subfield
PVRecordStructurePtr master(this->master.lock());
if(master) {
master->callListener();
}
callListener();
if(isStructure) {
PVRecordStructurePtr pvrs = static_pointer_cast<PVRecordStructure>(shared_from_this());
PVRecordStructurePtr pvrs =
static_pointer_cast<PVRecordStructure>(shared_from_this());
PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields();
PVRecordFieldPtrArray::iterator iter;
for(iter = pvRecordFields->begin() ; iter !=pvRecordFields->end(); iter++) {
@@ -489,7 +473,12 @@ void PVRecordStructure::init()
PVRecordStructurePtr self =
static_pointer_cast<PVRecordStructure>(shared_from_this());
PVRecordPtr pvRecord = getPVRecord();
for(size_t i=0; i<numFields; i++) {
static bool masterFieldCallbackSet = false;
bool isMasterField = (!getFullFieldName().size());
if (isMasterField) {
masterFieldCallbackSet = false;
}
for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
if(pvField->getField()->getType()==structure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
@@ -502,6 +491,17 @@ void PVRecordStructure::init()
new PVRecordField(pvField,self,pvRecord));
pvRecordFields->push_back(pvRecordField);
pvRecordField->init();
// Master field listeners will be called before
// calling listeners for the first subfield
if (!masterFieldCallbackSet) {
masterFieldCallbackSet = true;
// Find master field
PVRecordStructurePtr p = pvRecordField->parent.lock();
while (p) {
pvRecordField->master = p;
p = p->parent.lock();
}
}
}
}
}

View File

@@ -11,11 +11,6 @@
#ifndef CHANNELPROVIDERLOCAL_H
#define CHANNELPROVIDERLOCAL_H
#ifdef epicsExportSharedSymbols
# define channelProviderLocalEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <string>
#include <cstring>
#include <stdexcept>
@@ -25,74 +20,29 @@
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/pvData.h>
#include <pv/pvCopy.h>
#include <pv/pvAccess.h>
#include <pv/status.h>
#include <pv/serverContext.h>
#ifdef channelProviderLocalEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef channelProviderLocalEpicsExportSharedSymbols
#endif
#include <shareLib.h>
#include <pv/pvStructureCopy.h>
#include <pv/pvDatabase.h>
#include <shareLib.h>
#include <asLib.h>
namespace epics { namespace pvDatabase {
class MonitorFactory;
typedef std::tr1::shared_ptr<MonitorFactory> MonitorFactoryPtr;
class MonitorLocal;
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
namespace epics { namespace pvDatabase {
class ChannelProviderLocal;
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
typedef std::tr1::weak_ptr<ChannelProviderLocal> ChannelProviderLocalWPtr;
class ChannelLocal;
typedef std::tr1::shared_ptr<ChannelLocal> ChannelLocalPtr;
typedef std::tr1::weak_ptr<ChannelLocal> ChannelLocalWPtr;
epicsShareFunc MonitorFactoryPtr getMonitorFactory();
/**
* @brief MonitorFactory
*
* This class provides a static method to create a monitor for a PVRecord
*/
class epicsShareClass MonitorFactory
{
public:
POINTER_DEFINITIONS(MonitorFactory);
/**
* @brief Destructor
*/
virtual ~MonitorFactory();
/**
* @brief Create a monitor on a record.
*
* This is called by the local channel provider.
* @param pvRecord The record to monitor.
* @param monitorRequester The client callback.
* @param pvRequest Options specified by the client.
* This includes the subset of the fields in the record to monitor.
* @return A shared pointer to the newly created monitor.
* If the monitor can not be created a null monitor is returned.
* This means the pvRequest specified options that could not be satisfied.
*/
epics::pvData::MonitorPtr createMonitor(
PVRecordPtr const & pvRecord,
epics::pvData::MonitorRequester::shared_pointer const & monitorRequester,
epics::pvData::PVStructurePtr const & pvRequest);
private:
MonitorFactory();
friend class MonitorLocal;
friend epicsShareFunc MonitorFactoryPtr getMonitorFactory();
epics::pvData::Mutex mutex;
};
epicsShareFunc epics::pvData::MonitorPtr createMonitorLocal(
PVRecordPtr const & pvRecord,
epics::pvData::MonitorRequester::shared_pointer const & monitorRequester,
epics::pvData::PVStructurePtr const & pvRequest);
epicsShareFunc ChannelProviderLocalPtr getChannelProviderLocal();
@@ -109,6 +59,19 @@ class epicsShareClass ChannelProviderLocal :
{
public:
POINTER_DEFINITIONS(ChannelProviderLocal);
/**
* @brief Initialize access security configuration
* @param filePath AS definition file path
* @param substitutions macro substitutions
* @throws std::runtime_error in case of configuration problem
*/
static void initAs(const std::string& filePath, const std::string& substitutions="");
/**
* @brief Is access security active?
* @return true is AS is active
*/
static bool isAsActive();
/**
* @brief Constructor
*/
@@ -117,18 +80,15 @@ public:
* @brief Destructor
*/
virtual ~ChannelProviderLocal();
/**
* @brief Destroy the channel provider.
*
*/
virtual void destroy() EPICS_DEPRECATED {};
/**
* @brief Returns the channel provider name.
*
* @return <b>local</b>
*/
virtual std::string getProviderName();
/**
* @brief Returns either a null channelFind or a channelFind for records in the PVDatabase.
*
* @param channelName The name of the channel desired.
* @param channelFindRequester The client callback.
* @return shared pointer to ChannelFind.
@@ -142,7 +102,7 @@ public:
virtual epics::pvAccess::ChannelFind::shared_pointer channelFind(
std::string const &channelName,
epics::pvAccess::ChannelFindRequester::shared_pointer const & channelFindRequester);
/**
/**
* @brief Calls method channelListRequester::channelListResult.
*
* This provides the caller with a list of the record names on the PVDatabase.
@@ -150,7 +110,7 @@ public:
* @param channelListRequester The client callback.
* @return shared pointer to ChannelFind.
* The interface for SyncChannelFind is defined by pvAccessCPP.
*/
*/
virtual epics::pvAccess::ChannelFind::shared_pointer channelList(
epics::pvAccess::ChannelListRequester::shared_pointer const & channelListRequester);
/**
@@ -204,15 +164,15 @@ public:
* @brief ChannelFind method.
*
*/
virtual void cancel();
virtual void cancel() {}
private:
friend epicsShareFunc ChannelProviderLocalPtr getChannelProviderLocal();
PVDatabasePtr pvDatabase;
epics::pvData::Mutex mutex;
PVDatabaseWPtr pvDatabase;
int traceLevel;
friend class ChannelProviderLocalRun;
};
/**
* @brief Channel for accessing a PVRecord.
*
@@ -236,29 +196,23 @@ public:
epics::pvAccess::ChannelRequester::shared_pointer const & requester,
PVRecordPtr const & pvRecord
);
/**
/**
* @brief Destructor
*/
virtual ~ChannelLocal();
/**
* @brief Destroy the channel.
*
*/
virtual void destroy() EPICS_DEPRECATED {};
/**
/**
* @brief Detach from the record.
*
* This is called when a record is being removed from the database.
* Calls destroy.
* @param pvRecord The record being destroyed.
* @param pvRecord The record being removed.
*/
virtual void detach(PVRecordPtr const &pvRecord);
/**
/**
* @brief Get the requester name.
* @return returns the name of the channel requester.
*/
virtual std::string getRequesterName();
/**
/**
* @brief Passes the message to the channel requester.
* @param message The message.
* @param messageType The message type.
@@ -266,40 +220,37 @@ public:
virtual void message(
std::string const & message,
epics::pvData::MessageType messageType);
/**
/**
* @brief Get the channel provider
* @return The provider.
*/
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider()
{
return provider;
}
/**
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider();
/**
* @brief Get the remote address
* @return <b>local</b>
*/
virtual std::string getRemoteAddress();
/**
/**
* Get the connection state.
* @return Channel::CONNECTED.
*/
virtual epics::pvAccess::Channel::ConnectionState getConnectionState();
/**
/**
* @brief Get the channel name.
* @return the record name.
*/
virtual std::string getChannelName();
/**
/**
* @brief Get the channel requester
* @return The channel requester.
*/
virtual epics::pvAccess::ChannelRequester::shared_pointer getChannelRequester();
/**
/**
* @brief Is the channel connected?
* @return true.
*/
virtual bool isConnected();
/**
/**
* @brief Get the introspection interface for subField.
*
* The introspection interface is given via GetFieldRequester::getDone.
@@ -311,14 +262,14 @@ public:
virtual void getField(
epics::pvAccess::GetFieldRequester::shared_pointer const &requester,
std::string const & subField);
/**
/**
* Get the access rights for the record.
* This throws an exception because it is assumed that access rights are
* handled by a higher level.
*/
virtual epics::pvAccess::AccessRights getAccessRights(
epics::pvData::PVField::shared_pointer const &pvField);
/**
/**
* @brief Create a channelProcess.
*
* @param requester The client callback.
@@ -329,9 +280,9 @@ public:
virtual epics::pvAccess::ChannelProcess::shared_pointer createChannelProcess(
epics::pvAccess::ChannelProcessRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest);
/**
/**
* @brief Create a channelGet.
*
*
* @param requester The client callback.
* @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation.
@@ -340,7 +291,7 @@ public:
virtual epics::pvAccess::ChannelGet::shared_pointer createChannelGet(
epics::pvAccess::ChannelGetRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest);
/**
/**
* @brief Create a channelPut.
*
* @param requester The client callback.
@@ -351,9 +302,9 @@ public:
virtual epics::pvAccess::ChannelPut::shared_pointer createChannelPut(
epics::pvAccess::ChannelPutRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest);
/**
/**
* @brief Create a channelPutGet.
*
*
* @param requester The client callback.
* @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation.
@@ -362,7 +313,7 @@ public:
virtual epics::pvAccess::ChannelPutGet::shared_pointer createChannelPutGet(
epics::pvAccess::ChannelPutGetRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest);
/**
/**
* @brief Create a channelRPC.
*
* The PVRecord must implement <b>getService</b> or an empty shared pointer is returned.
@@ -373,9 +324,9 @@ public:
virtual epics::pvAccess::ChannelRPC::shared_pointer createChannelRPC(
epics::pvAccess::ChannelRPCRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest);
/**
/**
* @brief Create a monitor.
*
*
* @param requester The client callback.
* @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation.
@@ -384,9 +335,9 @@ public:
virtual epics::pvData::Monitor::shared_pointer createMonitor(
epics::pvData::MonitorRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest);
/**
/**
* @brief Create a channelArray.
*
*
* @param requester The client callback.
* @param pvRequest The options specified by the client.
* @return A shared pointer to the newly created implementation.
@@ -395,16 +346,28 @@ public:
virtual epics::pvAccess::ChannelArray::shared_pointer createChannelArray(
epics::pvAccess::ChannelArrayRequester::shared_pointer const &requester,
epics::pvData::PVStructurePtr const &pvRequest);
/**
/**
* @brief calls printInfo(std::cout);
*/
virtual void printInfo();
/**
/**
* @brief displays a message
*
*
* @param out the stream on which the message is displayed.
*/
virtual void printInfo(std::ostream& out);
/**
* @brief determines if client can write
*
* @return true if client can write
*/
virtual bool canWrite();
/**
* @brief determines if client can read
*
* @return true if client can read
*/
virtual bool canRead();
protected:
shared_pointer getPtrSelf()
{
@@ -412,9 +375,22 @@ protected:
}
private:
epics::pvAccess::ChannelRequester::shared_pointer requester;
ChannelProviderLocalPtr provider;
PVRecordPtr pvRecord;
ChannelProviderLocalWPtr provider;
PVRecordWPtr pvRecord;
epics::pvData::Mutex mutex;
// AS-specific variables/methods
std::vector<char> toCharArray(const std::string& s);
std::vector<char> getAsGroup(const PVRecordPtr& pvRecord);
std::vector<char> getAsUser(const epics::pvAccess::ChannelRequester::shared_pointer& requester);
std::vector<char> getAsHost(const epics::pvAccess::ChannelRequester::shared_pointer& requester);
int asLevel;
std::vector<char> asGroup;
std::vector<char> asUser;
std::vector<char> asHost;
ASMEMBERPVT asMemberPvt;
ASCLIENTPVT asClientPvt;
};
}}

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

@@ -0,0 +1,89 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#ifndef CONTROLSUPPORT_H
#define CONTROLSUPPORT_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class ControlSupport;
typedef std::tr1::shared_ptr<ControlSupport> ControlSupportPtr;
/**
* @brief Base interface for a ControlSupport.
*
*/
class epicsShareClass ControlSupport :
PVSupport
{
public:
POINTER_DEFINITIONS(ControlSupport);
/**
* The Destructor.
*/
virtual ~ControlSupport();
/**
* @brief Connects to contol fields.
*
* @param pvValue The field to support.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVFieldPtr const & pvSupport);
/**
* @brief Honors control fields.
*
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual bool process();
/**
* @brief If implementing minSteps it sets isMinStep to false.
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual void reset();
/**
* @brief create a ControlSupport
*
* @param pvRecord - The pvRecord to which the support is attached.
* @return The new ControlSupport
*/
static ControlSupportPtr create(PVRecordPtr const & pvRecord);
/**
* @brief create a controlSupport required by ControlSupport
*
* @param scalarType The type for outputValue.
* @return The controlField introspection structure.
*/
static epics::pvData::StructureConstPtr controlField(epics::pvData::ScalarType scalarType);
private:
ControlSupport(PVRecordPtr const & pvRecord);
PVRecordPtr pvRecord;
epics::pvData::PVScalarPtr pvValue;
epics::pvData::PVStructurePtr pvControl;
epics::pvData::PVDoublePtr pvLimitLow;
epics::pvData::PVDoublePtr pvLimitHigh;
epics::pvData::PVDoublePtr pvMinStep;
epics::pvData::PVScalarPtr pvOutputValue;
double currentValue;
bool isMinStep;
};
}}
#endif /* CONTROLSUPPORT_H */

101
src/pv/pvArrayPlugin.h Normal file
View File

@@ -0,0 +1,101 @@
/* pvArrayPlugin.h */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
#ifndef PVARRAYPLUGIN_H
#define PVARRAYPLUGIN_H
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h>
#include <pv/pvPlugin.h>
#include <shareLib.h>
namespace epics { namespace pvCopy{
class PVArrayPlugin;
class PVArrayFilter;
typedef std::tr1::shared_ptr<PVArrayPlugin> PVArrayPluginPtr;
typedef std::tr1::shared_ptr<PVArrayFilter> PVArrayFilterPtr;
/**
* @brief A plugin for a filter that gets a sub array from a PVScalarArray.
*
* @author mrk
* @since date 2017.02.23
*/
class epicsShareClass PVArrayPlugin : public PVPlugin
{
private:
PVArrayPlugin();
public:
POINTER_DEFINITIONS(PVArrayPlugin);
virtual ~PVArrayPlugin();
/**
* Factory
*/
static void create();
/**
* Create a PVFilter.
* @param requestValue The value part of a name=value request option.
* @param pvCopy The PVCopy to which the PVFilter will be attached.
* @param master The field in the master PVStructure to which the PVFilter will be attached
* @return The PVFilter.
* Null is returned if master or requestValue is not appropriate for the plugin.
*/
virtual PVFilterPtr create(
const std::string & requestValue,
const PVCopyPtr & pvCopy,
const epics::pvData::PVFieldPtr & master);
};
/**
* @brief A filter that gets a sub array from a PVScalarArray.
*/
class epicsShareClass PVArrayFilter : public PVFilter
{
private:
long start;
long increment;
long end;
epics::pvData::PVFieldPtr masterField;
epics::pvData::PVScalarArrayPtr masterArray;
PVArrayFilter(
long start,long increment,long end,
const epics::pvData::PVFieldPtr & masterField,
const epics::pvData::PVScalarArrayPtr masterArray);
public:
POINTER_DEFINITIONS(PVArrayFilter);
virtual ~PVArrayFilter();
/**
* Create a PVArrayFilter.
* @param requestValue The value part of a name=value request option.
* @param master The field in the master PVStructure to which the PVFilter will be attached.
* @return The PVFilter.
* A null is returned if master or requestValue is not appropriate for the plugin.
*/
static PVArrayFilterPtr create(const std::string & requestValue,const epics::pvData::PVFieldPtr & master);
/**
* Perform a filter operation
* @param pvCopy The field in the copy PVStructure.
* @param bitSet A bitSet for copyPVStructure.
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
* @return if filter (modified, did not modify) destination.
* Null is returned if master or requestValue is not appropriate for the plugin.
*/
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
/**
* Get the filter name.
* @return The name.
*/
std::string getName();
};
}}
#endif /* PVARRAYPLUGIN_H */

View File

@@ -6,29 +6,17 @@
#ifndef PVDATABASE_H
#define PVDATABASE_H
#ifdef epicsExportSharedSymbols
# define pvdatabaseEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <list>
#include <map>
#include <deque>
#include <pv/pvData.h>
#include <pv/pvCopy.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#ifdef pvdatabaseEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef pvdatabaseEpicsExportSharedSymbols
#endif
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
namespace epics { namespace pvDatabase {
class PVRecord;
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
@@ -46,6 +34,7 @@ typedef std::tr1::weak_ptr<PVRecordStructure> PVRecordStructureWPtr;
class PVRecordClient;
typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
typedef std::tr1::weak_ptr<PVRecordClient> PVRecordClientWPtr;
class PVListener;
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
@@ -53,6 +42,7 @@ typedef std::tr1::weak_ptr<PVListener> PVListenerWPtr;
class PVDatabase;
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
typedef std::tr1::weak_ptr<PVDatabase> PVDatabaseWPtr;
/**
* @brief Base interface for a PVRecord.
@@ -64,11 +54,12 @@ typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
* @date 2012.11.20
*/
class epicsShareClass PVRecord :
public epics::pvData::PVCopyTraverseMasterCallback,
public epics::pvCopy::PVCopyTraverseMasterCallback,
public std::tr1::enable_shared_from_this<PVRecord>
{
public:
POINTER_DEFINITIONS(PVRecord);
/**
* The Destructor.
*/
@@ -97,36 +88,39 @@ public:
*/
virtual void process();
/**
* @brief Optional method for derived class.
* @brief remove record from database.
*
* Destroy the PVRecord. Release any resources used and
* Remove the PVRecord. Release any resources used and
* get rid of listeners and requesters.
* If derived class overrides this then it must call PVRecord::destroy()
* If derived class overrides this then it must call PVRecord::remove()
* after it has destroyed any resorces it uses.
*/
virtual void destroy();
virtual void remove();
/**
* @brief Optional method for derived class.
*
* Return a service corresponding to the specified request PVStructure.
* @param pvRequest The request PVStructure
* @param pvRequest The request PVStructure
* @return The corresponding service
*/
virtual epics::pvAccess::Service::shared_pointer getService(
virtual epics::pvAccess::RPCServiceAsync::shared_pointer getService(
epics::pvData::PVStructurePtr const & pvRequest)
{
return epics::pvAccess::Service::shared_pointer();
return epics::pvAccess::RPCServiceAsync::shared_pointer();
}
/**
* @brief Creates a <b>soft</b> record.
* @brief Creates a <b>soft</b> record.
*
* @param recordName The name of the record, which is also the channelName.
* @param pvStructure The top level structure.
* @param asLevel AS level (default: ASL0)
* @param asGroup AS group (default: DEFAULT)
* @return A shared pointer to the newly created record.
*/
static PVRecordPtr create(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure);
epics::pvData::PVStructurePtr const & pvStructure,
int asLevel = 0, const std::string& asGroup = "DEFAULT");
/**
* @brief Get the name of the record.
*
@@ -195,13 +189,6 @@ public:
* @return <b>true</b> if the client is added.
*/
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
/**
* @brief Remove a client.
*
* @param pvRecordClient The client.
* @return <b>true</b> if the client is removed.
*/
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
/**
* @brief Add a PVListener.
*
@@ -212,7 +199,7 @@ public:
*/
bool addListener(
PVListenerPtr const & pvListener,
epics::pvData::PVCopyPtr const & pvCopy);
epics::pvCopy::PVCopyPtr const & pvCopy);
/**
* @brief PVCopyTraverseMasterCallback method
*
@@ -228,7 +215,7 @@ public:
*/
bool removeListener(
PVListenerPtr const & pvListener,
epics::pvData::PVCopyPtr const & pvCopy);
epics::pvCopy::PVCopyPtr const & pvCopy);
/**
@@ -249,22 +236,50 @@ public:
* @param level The level
*/
void setTraceLevel(int level) {traceLevel = level;}
/**
* @brief Get the ASlevel
*
* @return The level.
*/
int getAsLevel() const {return asLevel;}
/**
* @brief Get the AS group name
*
* @return The name.
*/
std::string getAsGroup() const {return asGroup;}
/**
* @brief set access security level.
* @param level The level
*/
void setAsLevel(int level) {asLevel=level;}
/**
* @brief set access security group
* @param group The group name
*/
void setAsGroup(const std::string& group) {asGroup = group;}
protected:
/**
* @brief Constructor
* @param recordName The name of the record
* @param pvStructure The top level PVStructutre
* @param asLevel AS level (default: ASL0)
* @param asGroup AS group (default: DEFAULT)
*/
PVRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure);
epics::pvData::PVStructurePtr const & pvStructure,
int asLevel = 0, const std::string& asGroup = "DEFAULT");
/**
* @brief Initializes the base class.
*
*
* Must be called by derived classes.
*/
void initPVRecord();
private:
friend class PVDatabase;
void unlistenClients();
PVRecordFieldPtr findPVRecordField(
PVRecordStructurePtr const & pvrs,
epics::pvData::PVFieldPtr const & pvField);
@@ -273,18 +288,19 @@ private:
epics::pvData::PVStructurePtr pvStructure;
PVRecordStructurePtr pvRecordStructure;
std::list<PVListenerWPtr> pvListenerList;
std::list<PVRecordClientPtr> clientList;
std::list<PVRecordClientWPtr> clientList;
epics::pvData::Mutex mutex;
std::size_t depthGroupPut;
int traceLevel;
bool isDestroyed;
// following only valid while addListener or removeListener is active.
bool isAddListener;
PVListenerWPtr pvListener;
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
// following only valid while addListener or removeListener is active.
bool isAddListener;
PVListenerWPtr pvListener;
int asLevel;
std::string asGroup;
};
epicsShareFunc std::ostream& operator<<(std::ostream& o, const PVRecord& record);
@@ -360,6 +376,7 @@ private:
std::list<PVListenerWPtr> pvListenerList;
epics::pvData::PVField::weak_pointer pvField;
bool isStructure;
PVRecordStructureWPtr master;
PVRecordStructureWPtr parent;
PVRecordWPtr pvRecord;
std::string fullName;
@@ -513,6 +530,7 @@ public:
/**
* @brief Remove a record.
* @param record The record to remove.
*
* @return <b>true</b> if record was removed.
*/
bool removeRecord(PVRecordPtr const & record);
@@ -522,14 +540,17 @@ public:
*/
epics::pvData::PVStringArrayPtr getRecordNames();
private:
friend class PVRecord;
PVRecordWPtr removeFromMap(PVRecordPtr const & record);
PVDatabase();
void lock();
void unlock();
PVRecordMap recordMap;
epics::pvData::Mutex mutex;
static bool getMasterFirstCall;
};
}}
#endif /* PVDATABASE_H */

102
src/pv/pvDeadbandPlugin.h Normal file
View File

@@ -0,0 +1,102 @@
/* pvDeadbandPlugin.h */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
#ifndef PVDEADBANDPLUGIN_H
#define PVDEADBANDPLUGIN_H
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h>
#include <pv/pvPlugin.h>
#include <shareLib.h>
namespace epics { namespace pvCopy{
class PVDeadbandPlugin;
class PVDeadbandFilter;
typedef std::tr1::shared_ptr<PVDeadbandPlugin> PVDeadbandPluginPtr;
typedef std::tr1::shared_ptr<PVDeadbandFilter> PVDeadbandFilterPtr;
/**
* @brief A plugin for a filter that gets a sub array from a PVScalarDeadband.
*
* @author mrk
* @since date 2017.02.23
*/
class epicsShareClass PVDeadbandPlugin : public PVPlugin
{
private:
PVDeadbandPlugin();
public:
POINTER_DEFINITIONS(PVDeadbandPlugin);
virtual ~PVDeadbandPlugin();
/**
* Factory
*/
static void create();
/**
* Create a PVFilter.
* @param requestValue The value part of a name=value request option.
* @param pvCopy The PVCopy to which the PVFilter will be attached.
* @param master The field in the master PVStructure to which the PVFilter will be attached
* @return The PVFilter.
* Null is returned if master or requestValue is not appropriate for the plugin.
*/
virtual PVFilterPtr create(
const std::string & requestValue,
const PVCopyPtr & pvCopy,
const epics::pvData::PVFieldPtr & master);
};
/**
* @brief A Plugin for a filter that gets a sub array from a PVScalarDeadband.
*/
class epicsShareClass PVDeadbandFilter : public PVFilter
{
private:
bool absolute;
double deadband;
epics::pvData::PVScalarPtr master;
bool firstTime;
double lastReportedValue;
PVDeadbandFilter(bool absolute,double deadband,epics::pvData::PVScalarPtr const & master);
public:
POINTER_DEFINITIONS(PVDeadbandFilter);
virtual ~PVDeadbandFilter();
/**
* Create a PVDeadbandFilter.
* @param requestValue The value part of a name=value request option.
* @param master The field in the master PVStructure to which the PVFilter will be attached.
* @return The PVFilter.
* A null is returned if master or requestValue is not appropriate for the plugin.
*/
static PVDeadbandFilterPtr create(
const std::string & requestValue,
const epics::pvData::PVFieldPtr & master);
/**
* Perform a filter operation
* @param pvCopy The field in the copy PVStructure.
* @param bitSet A bitSet for copyPVStructure.
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
* @return if filter (modified, did not modify) destination.
* Null is returned if master or requestValue is not appropriate for the plugin.
*/
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
/**
* Get the filter name.
* @return The name.
*/
std::string getName();
};
}}
#endif /* PVDEADBANDPLUGIN_H */

109
src/pv/pvPlugin.h Normal file
View File

@@ -0,0 +1,109 @@
/* pvPlugin.h */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
/**
* @author Marty Kraimer
* @date 2017.03
*/
#ifndef PVPLUGIN_H
#define PVPLUGIN_H
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/bitSet.h>
#include <shareLib.h>
namespace epics { namespace pvCopy{
class PVPlugin;
class PVFilter;
class PVPluginRegistry;
class PVCopy;
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
typedef std::tr1::shared_ptr<PVPlugin> PVPluginPtr;
typedef std::tr1::shared_ptr<PVFilter> PVFilterPtr;
typedef std::map<std::string,PVPluginPtr> PVPluginMap;
/**
* @brief A filter plugin that attaches to a field of a PVStrcture.
*
* PVCopy looks for plugins defined in pvRequest and calls the filter when a pvCopy is updated.
* @author mrk
* @since 2017.03.17
*
* Interface for a filter plugin for PVCopy.
*
*/
class epicsShareClass PVPlugin {
public:
POINTER_DEFINITIONS(PVPlugin);
virtual ~PVPlugin() {}
/**
* Create a PVFilter.
* @param requestValue The value part of a name=value request option.
* @param pvCopy The PVCopy to which the PVFilter will be attached.
* @param master The field in the master PVStructure to which the PVFilter will be attached.
* @return The PVFilter.
* A null is returned if master or requestValue is not appropriate for the plugin.
*/
virtual PVFilterPtr create(
const std::string & requestValue,
const PVCopyPtr & pvCopy,
const epics::pvData::PVFieldPtr & master) = 0;
};
/**
* @brief A Filter that is called when a copy PVStructure is being updated.
*
* This interface defines a filter to update a copy of a field from a master PVStructure.
* of the data in the master.
*/
class epicsShareClass PVFilter {
public:
POINTER_DEFINITIONS(PVFilter);
virtual ~PVFilter() {}
/**
* Update copy or master.
* @param copy The data for copy.
* @param bitSet The BitSet for copy.
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
* @return (true,false) if filter modified destination.
*/
virtual bool filter(const epics::pvData::PVFieldPtr & copy,const epics::pvData::BitSetPtr & bitSet,bool toCopy) = 0;
/**
* Get the filter name.
* This is the name part of a request name=value pair.
* @return The name.
*/
virtual std::string getName() = 0;
};
/**
* @brief A registry for filter plugins for PVCopy.
*
*/
class epicsShareClass PVPluginRegistry {
public:
/**
* Register a plugin.
* @param name The name that appears in [name=value] of a field request option.
* @param pvPlugin The implementation for the plugin.
*/
static void registerPlugin(const std::string & name,const PVPluginPtr & pvPlugin);
/**
* Find a plugin.
* @param name The name that appears in [name=value] of a field request option.
* @return The plugin implementation or null if no pluging by that name has been registered.
*/
static PVPluginPtr find(const std::string & name);
};
}}
#endif /* PVPLUGIN_H */

247
src/pv/pvStructureCopy.h Normal file
View File

@@ -0,0 +1,247 @@
/* pvStructureCopy.h */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author Marty Kraimer
* @date 2013.04
*/
#ifndef PVSTRUCTURECOPY_H
#define PVSTRUCTURECOPY_H
#include <string>
#include <stdexcept>
#include <memory>
#include <pv/pvData.h>
#include <pv/bitSet.h>
#include <shareLib.h>
namespace epics { namespace pvCopy{
class PVCopyTraverseMasterCallback;
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr;
/**
* @brief Callback for traversing master structure
*
* Must be implemented by code that creates pvCopy.
*
* This was originally name pvCopy.h and implemented in pvDataCPP
* When it was moved to pvDatabaseCPP it was renamed to prevent conflicts with
* the version in pvDataCPP.
* Also the namespace was changed from epics::pvData to epics::pvCopy
*/
class epicsShareClass PVCopyTraverseMasterCallback
{
public:
POINTER_DEFINITIONS(PVCopyTraverseMasterCallback);
virtual ~PVCopyTraverseMasterCallback() {}
/**
* Called once for each field in master.
* @param pvField The field in master.
*/
virtual void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField) = 0;
};
class PVCopy;
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
struct CopyNode;
typedef std::tr1::shared_ptr<CopyNode> CopyNodePtr;
struct CopyStructureNode;
typedef std::tr1::shared_ptr<CopyStructureNode> CopyStructureNodePtr;
/**
* @brief Support for subset of fields in a pvStructure.
*
* Class that manages one or more PVStructures that holds an arbitrary subset of the fields
* in another PVStructure called master.
*/
class epicsShareClass PVCopy :
public std::tr1::enable_shared_from_this<PVCopy>
{
public:
POINTER_DEFINITIONS(PVCopy);
/**
* Create a new pvCopy
* @param pvMaster The top-level structure for which a copy of
* an arbitrary subset of the fields in master will be created and managed.
* @param pvRequest Selects the set of subfields desired and options for each field.
* @param structureName The name for the top level of any PVStructure created.
*/
static PVCopyPtr create(
epics::pvData::PVStructurePtr const &pvMaster,
epics::pvData::PVStructurePtr const &pvRequest,
std::string const & structureName);
virtual ~PVCopy(){}
/**
* Get the top-level structure of master
* @returns The master top-level structure.
* This should not be modified.
*/
epics::pvData::PVStructurePtr getPVMaster();
/**
* Traverse all the fields in master.
* @param callback This is called for each field on master.
*/
void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
/**
* Get the introspection interface for a PVStructure for e copy.
*/
epics::pvData::StructureConstPtr getStructure();
/**
* Create a copy instance. Monitors keep a queue of monitor elements.
* Since each element needs a PVStructure, multiple top-level structures will be created.
*/
epics::pvData::PVStructurePtr createPVStructure();
/**
* Given a field in pvMaster. return the offset in copy for the same field.
* A value of std::string::npos means that the copy does not have this field.
* @param masterPVField The field in master.
*/
std::size_t getCopyOffset(epics::pvData::PVFieldPtr const &masterPVField);
/**
* Given a field in pvMaster. return the offset in copy for the same field.
* A value of std::string::npos means that the copy does not have this field.
* @param masterPVStructure A structure in master that has masterPVField.
* @param masterPVField The field in master.
*/
std::size_t getCopyOffset(
epics::pvData::PVStructurePtr const &masterPVStructure,
epics::pvData::PVFieldPtr const &masterPVField);
/**
* Given an offset in the copy get the corresponding field in pvMaster.
* @param structureOffset The offset in the copy.
*/
epics::pvData::PVFieldPtr getMasterPVField(std::size_t structureOffset);
/**
* Initialize the fields in copyPVStructure by giving each field
* the value from the corresponding field in pvMaster.
* bitSet will be set to show that all fields are changed.
* @param copyPVStructure A copy top-level structure.
* @param bitSet A bitSet for copyPVStructure.
*/
void initCopy(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet);
/**
* Set all fields in copyPVStructure to the value of the corresponding field in pvMaster.
* Each field that is changed has it's corresponding bit set in bitSet.
* @param copyPVStructure A copy top-level structure.
* @param bitSet A bitSet for copyPVStructure.
* @returns (false,true) if client (should not,should) receive changes.
*/
bool updateCopySetBitSet(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet);
/**
* For each set bit in bitSet
* set the field in copyPVStructure to the value of the corresponding field in pvMaster.
* @param copyPVStructure A copy top-level structure.
* @param bitSet A bitSet for copyPVStructure.
* @returns (false,true) if client (should not,should) receive changes.
*/
bool updateCopyFromBitSet(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet);
/**
* For each set bit in bitSet
* set the field in pvMaster to the value of the corresponding field in copyPVStructure
* @param copyPVStructure A copy top-level structure.
* @param bitSet A bitSet for copyPVStructure.
*/
void updateMaster(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet);
/**
* Get the options for the field at the specified offset.
* @param fieldOffset the offset in copy.
* @returns A NULL is returned if no options were specified for the field.
* If options were specified,PVStructurePtr is a structures
* with a set of PVString subfields that specify name,value pairs.s
* name is the subField name and value is the subField value.
*/
epics::pvData::PVStructurePtr getOptions(std::size_t fieldOffset);
/**
* For debugging.
*/
std::string dump();
private:
PVCopyPtr getPtrSelf()
{
return shared_from_this();
}
epics::pvData::PVStructurePtr pvMaster;
epics::pvData::StructureConstPtr structure;
CopyNodePtr headNode;
epics::pvData::PVStructurePtr cacheInitStructure;
epics::pvData::BitSetPtr ignorechangeBitSet;
void traverseMaster(
CopyNodePtr const &node,
PVCopyTraverseMasterCallbackPtr const & callback);
void updateCopySetBitSet(
epics::pvData::PVFieldPtr const &pvCopy,
epics::pvData::PVFieldPtr const &pvMaster,
epics::pvData::BitSetPtr const &bitSet);
void updateCopySetBitSet(
epics::pvData::PVFieldPtr const &pvCopy,
CopyNodePtr const &node,
epics::pvData::BitSetPtr const &bitSet);
void updateCopyFromBitSet(
epics::pvData::PVFieldPtr const &pvCopy,
CopyNodePtr const &node,
epics::pvData::BitSetPtr const &bitSet);
void updateMasterField(
CopyNodePtr const & node,
epics::pvData::PVFieldPtr const & pvCopy,
epics::pvData::PVFieldPtr const &pvMaster,
epics::pvData::BitSetPtr const &bitSet);
void updateMasterCheckBitSet(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet,
size_t nextSet);
CopyNodePtr getCopyNode(std::size_t fieldOffset);
PVCopy(epics::pvData::PVStructurePtr const &pvMaster);
bool init(epics::pvData::PVStructurePtr const &pvRequest);
epics::pvData::StructureConstPtr createStructure(
epics::pvData::PVStructurePtr const &pvMaster,
epics::pvData::PVStructurePtr const &pvFromRequest);
CopyNodePtr createStructureNodes(
epics::pvData::PVStructurePtr const &pvMasterStructure,
epics::pvData::PVStructurePtr const &pvFromRequest,
epics::pvData::PVStructurePtr const &pvFromField);
void initPlugin(
CopyNodePtr const & node,
epics::pvData::PVStructurePtr const & pvOptions,
epics::pvData::PVFieldPtr const & pvMasterField);
void traverseMasterInitPlugin();
void traverseMasterInitPlugin(CopyNodePtr const & node);
CopyNodePtr getCopyOffset(
CopyStructureNodePtr const &structureNode,
epics::pvData::PVFieldPtr const &masterPVField);
bool checkIgnore(
epics::pvData::PVStructurePtr const & copyPVStructure,
epics::pvData::BitSetPtr const & bitSet);
void setIgnore(CopyNodePtr const & node);
CopyNodePtr getMasterNode(
CopyStructureNodePtr const &structureNode,
std::size_t structureOffset);
void dump(
std::string *builder,
CopyNodePtr const &node,
int indentLevel);
};
}}
#endif /* PVSTRUCTURECOPY_H */

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

@@ -0,0 +1,77 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#ifndef PVSUPPORT_H
#define PVSUPPORT_H
#include <list>
#include <map>
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class PVSupport;
typedef std::tr1::shared_ptr<PVSupport> PVSupportPtr;
/**
* @brief Base interface for a PVSupport.
*
*/
class epicsShareClass PVSupport
{
public:
POINTER_DEFINITIONS(PVSupport);
/**
* The Destructor.
*/
virtual ~PVSupport(){}
/**
* @brief Optional initialization method.
*
* Called after PVRecord is created but before record is installed into PVDatabase.
*
* @param pvValue The field to support.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVFieldPtr const & pvSupport) {return true;}
/**
* @brief Optional method for derived class.
*
* It is called before record is added to database.
*/
virtual void start() {}
/**
* @brief Virtual method for derived class.
*
* Called when record is processed.
* It is the method that implements support.
* It is called each time the record is processed.
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual bool process() = 0;
/**
* @brief Optional method for derived class.
*
*/
virtual void reset() {};
};
}}
#endif /* PVSUPPORT_H */

100
src/pv/pvTimestampPlugin.h Normal file
View File

@@ -0,0 +1,100 @@
/* pvTimeStampPlugin.h */
/*
* The License for this software can be found in the file LICENSE that is included with the distribution.
*/
#ifndef PVTIMESTAMPPLUGIN_H
#define PVTIMESTAMPPLUGIN_H
#include <string>
#include <map>
#include <pv/lock.h>
#include <pv/pvData.h>
#include <pv/pvPlugin.h>
#include <pv/pvTimeStamp.h>
#include <shareLib.h>
namespace epics { namespace pvCopy{
class PVTimestampPlugin;
class PVTimestampFilter;
typedef std::tr1::shared_ptr<PVTimestampPlugin> PVTimestampPluginPtr;
typedef std::tr1::shared_ptr<PVTimestampFilter> PVTimestampFilterPtr;
/**
* @brief A plugin for a filter that sets a timeStamp to the current time.
*
* @author mrk
* @since date 2017.03.24
*/
class epicsShareClass PVTimestampPlugin : public PVPlugin
{
private:
PVTimestampPlugin();
public:
POINTER_DEFINITIONS(PVTimestampPlugin);
virtual ~PVTimestampPlugin();
/**
* Factory
*/
static void create();
/**
* Create a PVFilter.
* @param requestValue The value part of a name=value request option.
* @param pvCopy The PVCopy to which the PVFilter will be attached.
* @param master The field in the master PVStructure to which the PVFilter will be attached
* @return The PVFilter.
* Null is returned if master or requestValue is not appropriate for the plugin.
*/
virtual PVFilterPtr create(
const std::string & requestValue,
const PVCopyPtr & pvCopy,
const epics::pvData::PVFieldPtr & master);
};
/**
* @brief A filter that sets a timeStamp to/from the current field or pvCopy.
*/
class epicsShareClass PVTimestampFilter : public PVFilter
{
private:
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
bool current;
bool copy;
epics::pvData::PVFieldPtr master;
PVTimestampFilter(bool current,bool copy,epics::pvData::PVFieldPtr const & pvField);
public:
POINTER_DEFINITIONS(PVTimestampFilter);
virtual ~PVTimestampFilter();
/**
* Create a PVTimestampFilter.
* @param requestValue The value part of a name=value request option.
* @param master The field in the master PVStructure to which the PVFilter will be attached.
* @return The PVFilter.
* A null is returned if master or requestValue is not appropriate for the plugin.
*/
static PVTimestampFilterPtr create(const std::string & requestValue,const epics::pvData::PVFieldPtr & master);
/**
* Perform a filter operation
* @param pvCopy The field in the copy PVStructure.
* @param bitSet A bitSet for copyPVStructure.
* @param toCopy (true,false) means copy (from master to copy,from copy to master)
* @return if filter (modified, did not modify) destination.
* Null is returned if master or requestValue is not appropriate for the plugin.
*/
bool filter(const epics::pvData::PVFieldPtr & pvCopy,const epics::pvData::BitSetPtr & bitSet,bool toCopy);
/**
* Get the filter name.
* @return The name.
*/
std::string getName();
};
}}
#endif /* PVTIMESTAMPPLUGIN_H */

67
src/pv/pvdbcrAddRecord.h Normal file
View File

@@ -0,0 +1,67 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2021.04.11
*/
#ifndef PVDBCRADDARRAY_H
#define PVDBCRADDARRAY_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class PvdbcrAddRecord;
typedef std::tr1::shared_ptr<PvdbcrAddRecord> PvdbcrAddRecordPtr;
/**
* @brief PvdbcrAddRecord A record that adds a record to the master database.
*
*/
class epicsShareClass PvdbcrAddRecord :
public PVRecord
{
private:
PvdbcrAddRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup);
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVStringPtr pvResult;
public:
POINTER_DEFINITIONS(PvdbcrAddRecord);
/**
* The Destructor.
*/
virtual ~PvdbcrAddRecord() {}
/**
* @brief Create a record.
*
* @param recordName The record name.
* @param asLevel The access security level.
* @param asGroup The access security group.
* @return The PVRecord
*/
static PvdbcrAddRecordPtr create(
std::string const & recordName,
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
/**
* @brief a PVRecord method
* @return success or failure
*/
virtual bool init();
/**
* @brief process method that adds a record to the master database.
*/
virtual void process();
};
}}
#endif /* PVDBCRADDARRAY_H */

View File

@@ -0,0 +1,105 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2021.04.11
*/
#ifndef PVDBCRPROCESSARRAY_H
#define PVDBCRPROCESSARRAY_H
#include <epicsThread.h>
#include <epicsGuard.h>
#include <pv/event.h>
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
class PvdbcrProcessRecord;
typedef std::tr1::shared_ptr<PvdbcrProcessRecord> PvdbcrProcessRecordPtr;
/**
* @brief PvdbcrProcessRecord A record that processes other records in the master database.
*
*/
class epicsShareClass PvdbcrProcessRecord :
public PVRecord,
public epicsThreadRunable
{
private:
PvdbcrProcessRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
double delay,
int asLevel,std::string const & asGroup);
double delay;
EpicsThreadPtr thread;
epics::pvData::Event runStop;
epics::pvData::Event runReturn;
PVDatabasePtr pvDatabase;
PVRecordMap pvRecordMap;
epics::pvData::PVStringPtr pvCommand;
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVStringPtr pvResult;
epics::pvData::Mutex mutex;
public:
POINTER_DEFINITIONS(PvdbcrProcessRecord);
/**
* The Destructor.
*/
virtual ~PvdbcrProcessRecord() {}
/**
* @brief Create a record.
*
* @param recordName The record name.
* @param asLevel The access security level.
* @param asGroup The access security group.
* @return The PVRecord
*/
static PvdbcrProcessRecordPtr create(
std::string const & recordName,
double delay= 1.0,
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
/**
* @brief set the delay between prcocessing.
*
* @param delay in seconds
*/
void setDelay(double delay);
/**
* @brief get the delay between prcocessing.
*
* @return delay in seconds
*/
double getDelay();
/**
* @brief a PVRecord method
* @return success or failure
*/
virtual bool init();
/**
* @brief method that processes other records in the master database.
*/
virtual void process();
/**
* @brief thread method
*/
virtual void run();
/**
* @brief thread method
*/
void startThread();
/**
* @brief thread method
*/
void stop();
};
}}
#endif /* PVDBCRPROCESSARRAY_H */

View File

@@ -0,0 +1,67 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2021.04.11
*/
#ifndef PVDBCRREMOVEARRAY_H
#define PVDBCRREMOVEARRAY_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class PvdbcrRemoveRecord;
typedef std::tr1::shared_ptr<PvdbcrRemoveRecord> PvdbcrRemoveRecordPtr;
/**
* @brief PvdbcrRemoveRecord A record that removes a record from the master database.
*
*/
class epicsShareClass PvdbcrRemoveRecord :
public PVRecord
{
private:
PvdbcrRemoveRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup);
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVStringPtr pvResult;
public:
POINTER_DEFINITIONS(PvdbcrRemoveRecord);
/**
* The Destructor.
*/
virtual ~PvdbcrRemoveRecord() {}
/**
* @brief Create a record.
*
* @param recordName The record name.
* @param asLevel The access security level.
* @param asGroup The access security group.
* @return The PVRecord
*/
static PvdbcrRemoveRecordPtr create(
std::string const & recordName,
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
/**
* @brief a PVRecord method
* @return success or failure
*/
virtual bool init();
/**
* @brief process method that removes a record from the master database.
*/
virtual void process();
};
}}
#endif /* PVDBCRREMOVEARRAY_H */

View File

@@ -0,0 +1,57 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2021.04.11
*/
#ifndef PVDBCRSCALARARRAYRECORD_H
#define PVDBCRSCALARARRAYRECORD_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class PvdbcrScalarArrayRecord;
typedef std::tr1::shared_ptr<PvdbcrScalarArrayRecord> PvdbcrScalarArrayRecordPtr;
/**
* @brief PvdbcrScalarArrayRecord creates a record with a scalar array value, alarm, and timeStamp.
*
*/
class epicsShareClass PvdbcrScalarArrayRecord :
public PVRecord
{
private:
PvdbcrScalarArrayRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup);
public:
POINTER_DEFINITIONS(PvdbcrScalarArrayRecord);
/**
* The Destructor.
*/
virtual ~PvdbcrScalarArrayRecord() {}
/**
* @brief Create a record.
*
* @param recordName The record name.
* @param scalarType The type for the value field
* @param asLevel The access security level.
* @param asGroup The access security group.
* @return The PVRecord
*/
static PvdbcrScalarArrayRecordPtr create(
std::string const & recordName,std::string const & scalarType,
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
};
}}
#endif /* PVDBCRSCALARARRAYRECORD_H */

View File

@@ -0,0 +1,57 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2021.04.11
*/
#ifndef PVDBCRSCALARRECORD_H
#define PVDBCRSCALARRECORD_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class PvdbcrScalarRecord;
typedef std::tr1::shared_ptr<PvdbcrScalarRecord> PvdbcrScalarRecordPtr;
/**
* @brief PvdbcrScalarRecord creates a record with a scalar value, alarm, and timeStamp.
*
*/
class epicsShareClass PvdbcrScalarRecord :
public PVRecord
{
private:
PvdbcrScalarRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup);
public:
POINTER_DEFINITIONS(PvdbcrScalarRecord);
/**
* The Destructor.
*/
virtual ~PvdbcrScalarRecord() {}
/**
* @brief Create a record.
*
* @param recordName The record name.
* @param scalarType The type for the value field
* @param asLevel The access security level.
* @param asGroup The access security group.
* @return The PVRecord
*/
static PvdbcrScalarRecordPtr create(
std::string const & recordName,std::string const & scalarType,
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
};
}}
#endif /* PVDBCRSCALARRECORD_H */

View File

@@ -0,0 +1,68 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2021.04.11
*/
#ifndef PVDBCRTRACEARRAY_H
#define PVDBCRTRACEARRAY_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class PvdbcrTraceRecord;
typedef std::tr1::shared_ptr<PvdbcrTraceRecord> PvdbcrTraceRecordPtr;
/**
* @brief PvdbcrTraceRecord A record sets trace level for a record in the master database.
*
*/
class epicsShareClass PvdbcrTraceRecord :
public PVRecord
{
private:
PvdbcrTraceRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup);
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVIntPtr pvLevel;
epics::pvData::PVStringPtr pvResult;
public:
POINTER_DEFINITIONS(PvdbcrTraceRecord);
/**
* The Destructor.
*/
virtual ~PvdbcrTraceRecord() {}
/**
* @brief Create a record.
*
* @param recordName The record name.
* @param asLevel The access security level.
* @param asGroup The access security group.
* @return The PVRecord
*/
static PvdbcrTraceRecordPtr create(
std::string const & recordName,
int asLevel=0,std::string const & asGroup = std::string("DEFAULT"));
/**
* @brief a PVRecord method
* @return success or failure
*/
virtual bool init();
/**
* @brief process method that sets trace level for a record in the master database.
*/
virtual void process();
};
}}
#endif /* PVDBCRTRACEARRAY_H */

View File

@@ -1,63 +0,0 @@
/* removeRecord.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#ifndef REMOVERECORD_H
#define REMOVERECORD_H
#include <shareLib.h>
#include <pv/channelProviderLocal.h>
namespace epics { namespace pvDatabase {
class RemoveRecord;
typedef std::tr1::shared_ptr<RemoveRecord> RemoveRecordPtr;
/**
* @brief Remove another record in the same database.
*
* A record to remove another record
* It is meant to be used via a channelPutGet request.
* The argument has one field: recordName.
* The result has a field named status.
*/
class epicsShareClass RemoveRecord :
public PVRecord
{
public:
POINTER_DEFINITIONS(RemoveRecord);
/**
* Factory methods to create RemoveRecord.
* @param recordName The name for the RemoveRecord.
* @return A shared pointer to RemoveRecord..
*/
static RemoveRecordPtr create(
std::string const & recordName);
/**
* standard init method required by PVRecord
* @return true unless record name already exists.
*/
virtual bool init();
/**
* @brief Remove the record specified by recordName.
*/
virtual void process();
private:
RemoveRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure);
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVStringPtr pvResult;
};
}}
#endif /* REMOVERECORD_H */

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

@@ -0,0 +1,110 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#ifndef SCALARALARMSUPPORT_H
#define SCALARALARMSUPPORT_H
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvStructureCopy.h>
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class ScalarAlarmSupport;
typedef std::tr1::shared_ptr<ScalarAlarmSupport> ScalarAlarmSupportPtr;
/**
* @brief Base interface for a ScalarAlarmSupport.
*
*/
class epicsShareClass ScalarAlarmSupport :
PVSupport
{
public:
POINTER_DEFINITIONS(ScalarAlarmSupport);
/**
* The Destructor.
*/
virtual ~ScalarAlarmSupport();
/**
* @brief Connects to contol fields.
*
* @param pvValue The field to support.
* @param pvAlarm The alarm field.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVStructurePtr const & pvAlarm,
epics::pvData::PVFieldPtr const & pvSupport);
/**
* @brief Honors scalarAlarm fields.
*
*
* @return Returns true is any fields were modified; otherwise false.
*/
virtual bool process();
/**
* @brief If implementing minSteps it sets isMinStep to false.
*
*/
virtual void reset();
/**
* @brief create a ScalarAlarm
*
* @param pvRecord - The pvRecord to which the support is attached.
* @return The new ScalarAlarm
*/
static ScalarAlarmSupportPtr create(PVRecordPtr const & pvRecord);
/**
* @brief create a scalarAlarm required by ScalarAlarm
*
* @return The scalarAlarmField introspection structure.
*/
static epics::pvData::StructureConstPtr scalarAlarmField();
private:
ScalarAlarmSupport(PVRecordPtr const & pvRecord);
enum {
range_Lolo = 0,
range_Low,
range_Normal,
range_High,
range_Hihi,
range_Invalid,
range_Undefined
} AlarmRange;
void setAlarm(
epics::pvData::PVStructurePtr const & pvAlarm,
int alarmRange);
PVRecordPtr pvRecord;
int prevAlarmRange;
epics::pvData::PVScalarPtr pvValue;
epics::pvData::PVStructurePtr pvAlarm;
epics::pvData::PVStructurePtr pvScalarAlarm;
epics::pvData::PVBooleanPtr pvActive;
epics::pvData::PVDoublePtr pvLowAlarmLimit;
epics::pvData::PVDoublePtr pvLowWarningLimit;
epics::pvData::PVDoublePtr pvHighWarningLimit;
epics::pvData::PVDoublePtr pvHighAlarmLimit;
epics::pvData::PVDoublePtr pvHysteresis;
double requestedValue;
double currentValue;
bool isHystersis;
};
}}
#endif /* SCALARALARMSUPPORT_H */

View File

@@ -1,65 +0,0 @@
/* traceRecord.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#ifndef TRACERECORD_H
#define TRACERECORD_H
#include <shareLib.h>
#include <pv/channelProviderLocal.h>
namespace epics { namespace pvDatabase {
class TraceRecord;
typedef std::tr1::shared_ptr<TraceRecord> TraceRecordPtr;
/**
* @brief Trace activity of PVRecord.
*
* A record to set the trace value for another record
* It is meant to be used via a channelPutGet request.
* The argument has two fields: recordName and level.
* The result has a field named status.
*/
class epicsShareClass TraceRecord :
public PVRecord
{
public:
POINTER_DEFINITIONS(TraceRecord);
/**
* @brief Factory method to create TraceRecord.
*
* @param recordName The name for the TraceRecord.
* @return A shared pointer to TraceRecord..
*/
static TraceRecordPtr create(
std::string const & recordName);
/**
* standard init method required by PVRecord
* @return true unless record name already exists.
*/
virtual bool init();
/**
* @brief Set the trace level for record specified by recordName.
*/
virtual void process();
private:
TraceRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure);
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVIntPtr pvLevel;
epics::pvData::PVStringPtr pvResult;
};
}}
#endif /* TRACERECORD_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* channelChannelProviderLocal.cpp */
/* channelProviderLocal.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
@@ -10,34 +10,34 @@
*/
#include <epicsThread.h>
#include <asLib.h>
#include <pv/serverContext.h>
#include <pv/syncChannelFind.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
#define epicsExportSharedSymbols
#include <pv/channelProviderLocal.h>
#include <pv/traceRecord.h>
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvCopy;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::cout;
using std::endl;
using std::string;
namespace epics { namespace pvDatabase {
class LocalChannelProviderFactory;
typedef std::tr1::shared_ptr<LocalChannelProviderFactory> LocalChannelProviderFactoryPtr;
namespace epics { namespace pvDatabase {
static string providerName("local");
static ChannelProviderLocalPtr channelProvider;
class LocalChannelProviderFactory : public ChannelProviderFactory
{
{
public:
POINTER_DEFINITIONS(LocalChannelProviderFactory);
virtual string getFactoryName() { return providerName;}
@@ -48,8 +48,8 @@ public:
}
virtual ChannelProvider::shared_pointer newInstance()
{
cout << "LocalChannelProviderFactory::newInstance()\n";
throw std::logic_error("newInstance not Implemented");
throw std::logic_error(
"LocalChannelProviderFactory::newInstance() not Implemented");
}
};
@@ -72,12 +72,15 @@ ChannelProviderLocal::ChannelProviderLocal()
: pvDatabase(PVDatabase::getMaster()),
traceLevel(0)
{
if(traceLevel>0) {
cout << "ChannelProviderLocal::ChannelProviderLocal()\n";
}
}
ChannelProviderLocal::~ChannelProviderLocal()
{
if(traceLevel>0) {
cout << "ChannelProviderLocal::~ChannelProviderLocal() \n";
cout << "ChannelProviderLocal::~ChannelProviderLocal()\n";
}
}
@@ -86,11 +89,6 @@ std::tr1::shared_ptr<ChannelProvider> ChannelProviderLocal::getChannelProvider()
return shared_from_this();
}
void ChannelProviderLocal::cancel()
{
}
string ChannelProviderLocal::getProviderName()
{
return providerName;
@@ -103,14 +101,21 @@ ChannelFind::shared_pointer ChannelProviderLocal::channelFind(
if(traceLevel>1) {
cout << "ChannelProviderLocal::channelFind " << "channelName" << endl;
}
Lock xx(mutex);
PVRecordPtr pvRecord = pvDatabase->findRecord(channelName);
PVDatabasePtr pvdb(pvDatabase.lock());
if(!pvdb) {
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pvDatabase was deleted");
channelFindRequester->channelFindResult(
notFoundStatus,
shared_from_this(),
false);
}
PVRecordPtr pvRecord = pvdb->findRecord(channelName);
if(pvRecord) {
channelFindRequester->channelFindResult(
Status::Ok,
shared_from_this(),
true);
} else {
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found");
channelFindRequester->channelFindResult(
@@ -127,13 +132,11 @@ ChannelFind::shared_pointer ChannelProviderLocal::channelList(
if(traceLevel>1) {
cout << "ChannelProviderLocal::channelList\n";
}
PVStringArrayPtr records;
{
Lock guard(mutex);
records = pvDatabase->getRecordNames();
}
channelListRequester->channelListResult(Status::Ok, shared_from_this(), records->view(), false);
PVDatabasePtr pvdb(pvDatabase.lock());
if(!pvdb)throw std::logic_error("pvDatabase was deleted");
PVStringArrayPtr records(pvdb->getRecordNames());
channelListRequester->channelListResult(
Status::Ok, shared_from_this(), records->view(), false);
return shared_from_this();
}
@@ -145,23 +148,23 @@ Channel::shared_pointer ChannelProviderLocal::createChannel(
if(traceLevel>1) {
cout << "ChannelProviderLocal::createChannel " << "channelName" << endl;
}
Lock xx(mutex);
PVRecordPtr pvRecord = pvDatabase->findRecord(channelName);
if(pvRecord) {
ChannelLocalPtr channel(new ChannelLocal(
shared_from_this(),channelRequester,pvRecord));
channelRequester->channelCreated(
Status::Ok,
channel);
pvRecord->addPVRecordClient(channel);
return channel;
}
Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found");
channelRequester->channelCreated(
notFoundStatus,
Channel::shared_pointer());
return Channel::shared_pointer();
ChannelLocalPtr channel;
Status status = Status::Ok;
PVDatabasePtr pvdb(pvDatabase.lock());
if(!pvdb) {
status = Status::error("pvDatabase was deleted");
} else {
PVRecordPtr pvRecord = pvdb->findRecord(channelName);
if(pvRecord) {
channel = ChannelLocalPtr(new ChannelLocal(
shared_from_this(),channelRequester,pvRecord));
pvRecord->addPVRecordClient(channel);
} else {
status = Status::error("pv not found");
}
}
channelRequester->channelCreated(status,channel);
return channel;
}
Channel::shared_pointer ChannelProviderLocal::createChannel(
@@ -174,4 +177,18 @@ Channel::shared_pointer ChannelProviderLocal::createChannel(
return createChannel(channelName, channelRequester, priority);
}
void ChannelProviderLocal::initAs(const std::string& filePath, const std::string& substitutions)
{
int status = asInitFile(filePath.c_str(), substitutions.c_str());
if(status) {
throw std::runtime_error("Invalid AS configuration.");
}
}
bool ChannelProviderLocal::isAsActive()
{
return asActive;
}
}}

View File

@@ -14,28 +14,38 @@
#include <epicsGuard.h>
#include <pv/thread.h>
#include <pv/bitSetUtil.h>
#include <pv/pvData.h>
#include <pv/pvAccess.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/serverContext.h>
#include <pv/timeStamp.h>
#define epicsExportSharedSymbols
#include <pv/channelProviderLocal.h>
#include "pv/pvStructureCopy.h"
#include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvCopy;
using std::tr1::static_pointer_cast;
using std::cout;
using std::endl;
using std::string;
namespace epics { namespace pvDatabase {
namespace epics { namespace pvDatabase {
class MonitorLocal;
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
static MonitorPtr nullMonitor;
static MonitorElementPtr NULLMonitorElement;
static Status failedToCreateMonitorStatus(Status::STATUSTYPE_ERROR,"failed to create monitor");
static Status failedToCreateMonitorStatus(
Status::STATUSTYPE_ERROR,"failed to create monitor");
static Status alreadyStartedStatus(Status::STATUSTYPE_ERROR,"already started");
static Status notStartedStatus(Status::STATUSTYPE_ERROR,"not started");
static Status destroyedStatus(Status::STATUSTYPE_ERROR,"record is destroyed");
static Status deletedStatus(Status::STATUSTYPE_ERROR,"record is deleted");
class MonitorElementQueue;
typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
@@ -78,7 +88,7 @@ public:
nextGetUsed = 0;
nextReleaseUsed = 0;
}
MonitorElementPtr getFree()
{
if(numberFree==0) return MonitorElementPtr();
@@ -88,7 +98,7 @@ public:
if(nextGetFree>=size) nextGetFree = 0;
return elements[ind];
}
void setUsed(MonitorElementPtr const &element)
{
if(element!=elements[nextSetUsed++]) {
@@ -97,7 +107,7 @@ public:
numberUsed++;
if(nextSetUsed>=size) nextSetUsed = 0;
}
MonitorElementPtr getUsed()
{
if(numberUsed==0) return MonitorElementPtr();
@@ -121,20 +131,19 @@ public:
typedef std::tr1::shared_ptr<MonitorRequester> MonitorRequesterPtr;
class MonitorLocal :
public Monitor,
public PVListener,
public std::tr1::enable_shared_from_this<MonitorLocal>
{
enum MonitorState {idle,active,destroyed};
enum MonitorState {idle,active,deleted};
public:
POINTER_DEFINITIONS(MonitorLocal);
virtual ~MonitorLocal();
virtual Status start();
virtual Status stop();
virtual MonitorElementPtr poll();
virtual void destroy() EPICS_DEPRECATED {};
virtual void detach(PVRecordPtr const & pvRecord){}
virtual void release(MonitorElementPtr const & monitorElement);
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);
@@ -181,10 +190,7 @@ MonitorLocal::MonitorLocal(
MonitorLocal::~MonitorLocal()
{
if(pvRecord->getTraceLevel()>0)
{
cout << "MonitorLocal::~MonitorLocal()" << endl;
}
//cout << "MonitorLocal::~MonitorLocal()" << endl;
}
@@ -197,7 +203,7 @@ Status MonitorLocal::start()
{
Lock xx(mutex);
if(state==active) return alreadyStartedStatus;
if(state==destroyed) return destroyedStatus;
if(state==deleted) return deletedStatus;
}
pvRecord->addListener(getPtrSelf(),pvCopy);
epicsGuard <PVRecord> guard(*pvRecord);
@@ -221,7 +227,7 @@ Status MonitorLocal::stop()
{
Lock xx(mutex);
if(state==idle) return notStartedStatus;
if(state==destroyed) return destroyedStatus;
if(state==deleted) return deletedStatus;
state = idle;
}
pvRecord->removeListener(getPtrSelf(),pvCopy);
@@ -263,8 +269,8 @@ void MonitorLocal::releaseActiveElement()
{
Lock xx(queueMutex);
if(state!=active) return;
pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
if(activeElement->changedBitSet->nextSetBit(0)<0) return;
bool result = pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
if(!result) return;
MonitorElementPtr newActive = queue->getFree();
if(!newActive) return;
BitSetUtil::compress(activeElement->changedBitSet,activeElement->pvStructurePtr);
@@ -284,7 +290,7 @@ void MonitorLocal::dataPut(PVRecordFieldPtr const & pvRecordField)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::dataPut(pvRecordField)" << endl;
cout << "MonitorLocal::dataPut(pvRecordField)" << endl;
}
if(state!=active) return;
{
@@ -309,7 +315,7 @@ void MonitorLocal::dataPut(
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::dataPut(requested,pvRecordField)" << endl;
cout << "MonitorLocal::dataPut(requested,pvRecordField)" << endl;
}
if(state!=active) return;
{
@@ -336,7 +342,7 @@ void MonitorLocal::beginGroupPut(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::beginGroupPut()" << endl;
cout << "MonitorLocal::beginGroupPut()" << endl;
}
if(state!=active) return;
{
@@ -350,7 +356,7 @@ void MonitorLocal::endGroupPut(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::endGroupPut dataChanged " << dataChanged << endl;
cout << "MonitorLocal::endGroupPut dataChanged " << dataChanged << endl;
}
if(state!=active) return;
{
@@ -367,17 +373,17 @@ void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::unlisten\n";
cout << "MonitorLocal::unlisten\n";
}
{
Lock xx(mutex);
state = destroyed;
state = deleted;
}
MonitorRequesterPtr requester = monitorRequester.lock();
if(requester) {
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::unlisten calling requester->unlisten\n";
cout << "MonitorLocal::unlisten calling requester->unlisten\n";
}
requester->unlisten(getPtrSelf());
}
@@ -445,29 +451,19 @@ bool MonitorLocal::init(PVStructurePtr const & pvRequest)
return true;
}
MonitorFactory::MonitorFactory()
{
}
MonitorFactory::~MonitorFactory()
{
}
MonitorPtr MonitorFactory::createMonitor(
MonitorPtr createMonitorLocal(
PVRecordPtr const & pvRecord,
MonitorRequester::shared_pointer const & monitorRequester,
PVStructurePtr const & pvRequest)
{
Lock xx(mutex);
MonitorLocalPtr monitor(new MonitorLocal(
monitorRequester,pvRecord));
bool result = monitor->init(pvRequest);
if(!result) {
MonitorPtr monitor;
StructureConstPtr structure;
monitorRequester->monitorConnect(failedToCreateMonitorStatus,monitor,structure);
monitorRequester->monitorConnect(
failedToCreateMonitorStatus,monitor,structure);
return nullMonitor;
}
if(pvRecord->getTraceLevel()>0)
@@ -478,19 +474,4 @@ MonitorPtr MonitorFactory::createMonitor(
return monitor;
}
MonitorFactoryPtr getMonitorFactory()
{
static MonitorFactoryPtr monitorFactoryPtr;
static Mutex mutex;
Lock xx(mutex);
if(!monitorFactoryPtr) {
monitorFactoryPtr = MonitorFactoryPtr(
new MonitorFactory());
}
return monitorFactoryPtr;
}
}}

View File

@@ -11,30 +11,19 @@
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <cantProceed.h>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <shareLib.h>
#include <epicsExit.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/syncChannelFind.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/timeStamp.h>
// this declared epicsExportSharedSymbols
// The following must be the last include for code pvDatabase uses
#include <epicsExport.h>
#include <pv/channelProviderLocal.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/channelProviderLocal.h"
using std::cout;
using std::endl;
@@ -57,7 +46,6 @@ extern "C" void pvdbl(const iocshArgBuf *args)
static void registerChannelProviderLocal(void)
{
static int firstTime = 1;
cout << "registerChannelProviderLocal firstTime " << (firstTime ? "true" : "false") << endl;
if (firstTime) {
firstTime = 0;
iocshRegister(&pvdblFuncDef, pvdbl);

View File

@@ -2,5 +2,17 @@
SRC_DIRS += $(PVDATABASE_SRC)/special
LIBSRCS += traceRecord.cpp
LIBSRCS += removeRecord.cpp
DBD += pvdbcrScalarRecord.dbd
DBD += pvdbcrScalarArrayRecord.dbd
DBD += pvdbcrAddRecord.dbd
DBD += pvdbcrRemoveRecord.dbd
DBD += pvdbcrProcessRecord.dbd
DBD += pvdbcrTraceRecord.dbd
DBD += pvdbcrAllRecords.dbd
LIBSRCS += pvdbcrScalarRecord.cpp
LIBSRCS += pvdbcrScalarArrayRecord.cpp
LIBSRCS += pvdbcrAddRecord.cpp
LIBSRCS += pvdbcrRemoveRecord.cpp
LIBSRCS += pvdbcrProcessRecord.cpp
LIBSRCS += pvdbcrTraceRecord.cpp

View File

@@ -0,0 +1,147 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2021.04.07
*/
#include <iocsh.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/rpcService.h>
// The following must be the last include for code exampleLink uses
#include <epicsExport.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/pvdbcrAddRecord.h"
using namespace epics::pvData;
using namespace std;
namespace epics { namespace pvDatabase {
PvdbcrAddRecordPtr PvdbcrAddRecord::create(
std::string const & recordName,
int asLevel,std::string const & asGroup)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("recordName",pvString)->
addNestedUnion("union") ->
endNested()->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
PvdbcrAddRecordPtr pvRecord(
new PvdbcrAddRecord(recordName,pvStructure,asLevel,asGroup));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
PvdbcrAddRecord::PvdbcrAddRecord(
std::string const & recordName,
PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup)
: PVRecord(recordName,pvStructure,asLevel,asGroup)
{
}
bool PvdbcrAddRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
return true;
}
void PvdbcrAddRecord::process()
{
PVDataCreatePtr pvDataCreate = getPVDataCreate();
string name = pvRecordName->get();
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
if(pvRecord) {
pvResult->put(name + " already exists");
return;
}
PVUnionPtr pvUnion = getPVStructure()->getSubField<PVUnion>("argument.union");
if(!pvUnion) {
pvResult->put(name + " argument.union is NULL");
return;
}
PVFieldPtr pvField(pvUnion->get());
if(!pvField) {
pvResult->put(name + " union has no value");
return;
}
if(pvField->getField()->getType()!=epics::pvData::structure) {
pvResult->put(name + " union most be a structure");
return;
}
StructureConstPtr st = std::tr1::static_pointer_cast<const Structure>(pvField->getField());
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(st);
PVRecordPtr pvRec = PVRecord::create(name,pvStructure);
bool result = PVDatabase::getMaster()->addRecord(pvRec);
if(result) {
pvResult->put("success");
} else {
pvResult->put("failure");
}
}
}}
static const iocshArg arg0 = { "recordName", iocshArgString };
static const iocshArg arg1 = { "asLevel", iocshArgInt };
static const iocshArg arg2 = { "asGroup", iocshArgString };
static const iocshArg *args[] = {&arg0,&arg1,&arg2};
static const iocshFuncDef pvdbcrAddRecordFuncDef = {"pvdbcrAddRecord", 3,args};
static void pvdbcrAddRecordCallFunc(const iocshArgBuf *args)
{
char *sval = args[0].sval;
if(!sval) {
throw std::runtime_error("pvdbcrAddRecord recordName not specified");
}
string recordName = string(sval);
int asLevel = args[1].ival;
string asGroup("DEFAULT");
sval = args[2].sval;
if(sval) {
asGroup = string(sval);
}
epics::pvDatabase::PvdbcrAddRecordPtr record = epics::pvDatabase::PvdbcrAddRecord::create(recordName);
record->setAsLevel(asLevel);
record->setAsGroup(asGroup);
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
bool result = master->addRecord(record);
if(!result) cout << "recordname " << recordName << " not added" << endl;
}
static void pvdbcrAddRecord(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&pvdbcrAddRecordFuncDef, pvdbcrAddRecordCallFunc);
}
}
extern "C" {
epicsExportRegistrar(pvdbcrAddRecord);
}

View File

@@ -0,0 +1 @@
registrar("pvdbcrAddRecord")

View File

@@ -0,0 +1,6 @@
include "pvdbcrAddRecord.dbd"
include "pvdbcrRemoveRecord.dbd"
include "pvdbcrProcessRecord.dbd"
include "pvdbcrTraceRecord.dbd"
include "pvdbcrScalarRecord.dbd"
include "pvdbcrScalarArrayRecord.dbd"

View File

@@ -0,0 +1,206 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2021.04.07
*/
#include <epicsThread.h>
#include <epicsGuard.h>
#include <pv/event.h>
#include <pv/lock.h>
#include <iocsh.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/rpcService.h>
#include <epicsExport.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/pvdbcrProcessRecord.h"
using namespace epics::pvData;
using namespace std;
namespace epics { namespace pvDatabase {
PvdbcrProcessRecordPtr PvdbcrProcessRecord::create(
std::string const & recordName,double delay,
int asLevel,std::string const & asGroup)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("command",pvString)->
add("recordName",pvString)->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
PvdbcrProcessRecordPtr pvRecord(
new PvdbcrProcessRecord(recordName,pvStructure,delay,asLevel,asGroup));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
PvdbcrProcessRecord::PvdbcrProcessRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,double delay,
int asLevel,std::string const & asGroup)
: PVRecord(recordName,pvStructure,asLevel,asGroup),
delay(delay),
pvDatabase(PVDatabase::getMaster())
{
}
bool PvdbcrProcessRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvCommand = pvStructure->getSubField<PVString>("argument.command");
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
startThread();
return true;
}
void PvdbcrProcessRecord::setDelay(double delay) {this->delay = delay;}
double PvdbcrProcessRecord::getDelay() {return delay;}
void PvdbcrProcessRecord::startThread()
{
thread = EpicsThreadPtr(new epicsThread(
*this,
"processRecord",
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityLow));
thread->start();
}
void PvdbcrProcessRecord::stop()
{
runStop.signal();
runReturn.wait();
}
void PvdbcrProcessRecord::process()
{
string recordName = pvRecordName->get();
string command = pvCommand->get();
if(command.compare("add")==0) {
epicsGuard<epics::pvData::Mutex> guard(mutex);
std::map<std::string,PVRecordPtr>::iterator iter = pvRecordMap.find(recordName);
if(iter!=pvRecordMap.end()) {
pvResult->put(recordName + " already present");
return;
}
PVRecordPtr pvRecord = pvDatabase->findRecord(recordName);
if(!pvRecord) {
pvResult->put(recordName + " not in pvDatabase");
return;
}
pvRecordMap.insert(PVRecordMap::value_type(recordName,pvRecord));
pvResult->put("success");
return;
} else if(command.compare("remove")==0) {
epicsGuard<epics::pvData::Mutex> guard(mutex);
std::map<std::string,PVRecordPtr>::iterator iter = pvRecordMap.find(recordName);
if(iter==pvRecordMap.end()) {
pvResult->put(recordName + " not found");
return;
}
pvRecordMap.erase(iter);
pvResult->put("success");
return;
} else {
pvResult->put(command + " not a valid command: only add and remove are valid");
return;
}
}
void PvdbcrProcessRecord::run()
{
while(true) {
if(runStop.tryWait()) {
runReturn.signal();
return;
}
if(delay>0.0) epicsThreadSleep(delay);
epicsGuard<epics::pvData::Mutex> guard(mutex);
PVRecordMap::iterator iter;
for(iter = pvRecordMap.begin(); iter!=pvRecordMap.end(); ++iter) {
PVRecordPtr pvRecord = (*iter).second;
pvRecord->lock();
pvRecord->beginGroupPut();
try {
pvRecord->process();
} catch (std::exception& ex) {
std::cout << "record " << pvRecord->getRecordName() << "exception " << ex.what() << "\n";
} catch (...) {
std::cout<< "record " << pvRecord->getRecordName() << " process exception\n";
}
pvRecord->endGroupPut();
pvRecord->unlock();
}
}
}
}}
static const iocshArg arg0 = { "recordName", iocshArgString };
static const iocshArg arg1 = { "delay", iocshArgDouble };
static const iocshArg arg2 = { "asLevel", iocshArgInt };
static const iocshArg arg3 = { "asGroup", iocshArgString };
static const iocshArg *args[] = {&arg0,&arg1,&arg2,&arg3};
static const iocshFuncDef pvdbcrProcessRecordFuncDef = {"pvdbcrProcessRecord", 4,args};
static void pvdbcrProcessRecordCallFunc(const iocshArgBuf *args)
{
char *sval = args[0].sval;
if(!sval) {
throw std::runtime_error("pvdbcrProcessRecord recordName not specified");
}
string recordName = string(sval);
double delay = args[1].dval;
if(delay<0.0) delay = 1.0;
int asLevel = args[2].ival;
string asGroup("DEFAULT");
sval = args[3].sval;
if(sval) {
asGroup = string(sval);
}
epics::pvDatabase::PvdbcrProcessRecordPtr record
= epics::pvDatabase::PvdbcrProcessRecord::create(recordName,delay);
record->setAsLevel(asLevel);
record->setAsGroup(asGroup);
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
bool result = master->addRecord(record);
if(!result) cout << "recordname " << recordName << " not added" << endl;
}
static void pvdbcrProcessRecord(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&pvdbcrProcessRecordFuncDef, pvdbcrProcessRecordCallFunc);
}
}
extern "C" {
epicsExportRegistrar(pvdbcrProcessRecord);
}

View File

@@ -0,0 +1 @@
registrar("pvdbcrProcessRecord")

View File

@@ -0,0 +1,123 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2021.04.07
*/
#include <iocsh.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/rpcService.h>
#include <epicsExport.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/pvdbcrRemoveRecord.h"
using namespace epics::pvData;
using namespace std;
namespace epics { namespace pvDatabase {
PvdbcrRemoveRecordPtr PvdbcrRemoveRecord::create(
std::string const & recordName,
int asLevel,std::string const & asGroup)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("recordName",pvString)->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
PvdbcrRemoveRecordPtr pvRecord(
new PvdbcrRemoveRecord(recordName,pvStructure,
asLevel,asGroup));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
PvdbcrRemoveRecord::PvdbcrRemoveRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup)
: PVRecord(recordName,pvStructure,asLevel,asGroup)
{
}
bool PvdbcrRemoveRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
return true;
}
void PvdbcrRemoveRecord::process()
{
string name = pvRecordName->get();
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
if(!pvRecord) {
pvResult->put(name + " not found");
return;
}
pvRecord->remove();
pvResult->put("success");
}
}}
static const iocshArg arg0 = { "recordName", iocshArgString };
static const iocshArg arg1 = { "asLevel", iocshArgInt };
static const iocshArg arg2 = { "asGroup", iocshArgString };
static const iocshArg *args[] = {&arg0,&arg1,&arg2};
static const iocshFuncDef pvdbcrRemoveRecordFuncDef = {"pvdbcrRemoveRecord", 3,args};
static void pvdbcrRemoveRecordCallFunc(const iocshArgBuf *args)
{
char *sval = args[0].sval;
if(!sval) {
throw std::runtime_error("pvdbcrRemoveRecord recordName not specified");
}
string recordName = string(sval);
int asLevel = args[1].ival;
string asGroup("DEFAULT");
sval = args[2].sval;
if(sval) {
asGroup = string(sval);
}
epics::pvDatabase::PvdbcrRemoveRecordPtr record = epics::pvDatabase::PvdbcrRemoveRecord::create(recordName);
record->setAsLevel(asLevel);
record->setAsGroup(asGroup);
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
bool result = master->addRecord(record);
if(!result) cout << "recordname " << recordName << " not added" << endl;
}
static void pvdbcrRemoveRecord(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&pvdbcrRemoveRecordFuncDef, pvdbcrRemoveRecordCallFunc);
}
}
extern "C" {
epicsExportRegistrar(pvdbcrRemoveRecord);
}

View File

@@ -0,0 +1 @@
registrar("pvdbcrRemoveRecord")

View File

@@ -0,0 +1,103 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2021.04.07
*/
#include <iocsh.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/rpcService.h>
// The following must be the last include for code pvDatabase implements
#include <epicsExport.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/pvdbcrScalarArrayRecord.h"
using namespace epics::pvData;
using namespace std;
namespace epics { namespace pvDatabase {
PvdbcrScalarArrayRecord::PvdbcrScalarArrayRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup)
: PVRecord(recordName,pvStructure,asLevel,asGroup)
{}
PvdbcrScalarArrayRecordPtr PvdbcrScalarArrayRecord::create(
std::string const & recordName,std::string const & scalarType,
int asLevel,std::string const & asGroup)
{
ScalarType st = epics::pvData::ScalarTypeFunc::getScalarType(scalarType);
FieldCreatePtr fieldCreate = getFieldCreate();
StandardFieldPtr standardField = getStandardField();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr top = fieldCreate->createFieldBuilder()->
addArray("value",st) ->
add("timeStamp",standardField->timeStamp()) ->
add("alarm",standardField->alarm()) ->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
PvdbcrScalarArrayRecordPtr pvRecord(new PvdbcrScalarArrayRecord(recordName,pvStructure,asLevel,asGroup));
pvRecord->initPVRecord();
return pvRecord;
};
}}
static const iocshArg arg0 = { "recordName", iocshArgString };
static const iocshArg arg1 = { "scalarType", iocshArgString };
static const iocshArg arg2 = { "asLevel", iocshArgInt };
static const iocshArg arg3 = { "asGroup", iocshArgString };
static const iocshArg *args[] = {&arg0,&arg1,&arg2,&arg3};
static const iocshFuncDef pvdbcrScalarArrayFuncDef = {"pvdbcrScalarArrayRecord", 4,args};
static void pvdbcrScalarArrayCallFunc(const iocshArgBuf *args)
{
char *sval = args[0].sval;
if(!sval) {
throw std::runtime_error("pvdbcrScalarArrayRecord recordName not specified");
}
string recordName = string(sval);
sval = args[1].sval;
if(!sval) {
throw std::runtime_error("pvdbcrScalarArrayRecord scalarType not specified");
}
string scalarType = string(sval);
int asLevel = args[2].ival;
string asGroup("DEFAULT");
sval = args[3].sval;
if(sval) {
asGroup = string(sval);
}
epics::pvDatabase::PvdbcrScalarArrayRecordPtr record
= epics::pvDatabase::PvdbcrScalarArrayRecord::create(recordName,scalarType);
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
record->setAsLevel(asLevel);
record->setAsGroup(asGroup);
bool result = master->addRecord(record);
if(!result) cout << "recordname " << recordName << " not added" << endl;
}
static void pvdbcrScalarArrayRecord(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&pvdbcrScalarArrayFuncDef, pvdbcrScalarArrayCallFunc);
}
}
extern "C" {
epicsExportRegistrar(pvdbcrScalarArrayRecord);
}

View File

@@ -0,0 +1 @@
registrar("pvdbcrScalarArrayRecord")

View File

@@ -0,0 +1,103 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2021.04.07
*/
#include <iocsh.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/rpcService.h>
// The following must be the last include for code pvDatabase implements
#include <epicsExport.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/pvdbcrScalarRecord.h"
using namespace epics::pvData;
using namespace std;
namespace epics { namespace pvDatabase {
PvdbcrScalarRecord::PvdbcrScalarRecord(
std::string const & recordName,epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup)
: PVRecord(recordName,pvStructure,asLevel,asGroup)
{}
PvdbcrScalarRecordPtr PvdbcrScalarRecord::create(
std::string const & recordName,std::string const & scalarType,
int asLevel,std::string const & asGroup)
{
ScalarType st = epics::pvData::ScalarTypeFunc::getScalarType(scalarType);
FieldCreatePtr fieldCreate = getFieldCreate();
StandardFieldPtr standardField = getStandardField();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr top = fieldCreate->createFieldBuilder()->
add("value",st) ->
add("timeStamp",standardField->timeStamp()) ->
add("alarm",standardField->alarm()) ->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
PvdbcrScalarRecordPtr pvRecord(new PvdbcrScalarRecord(recordName,pvStructure,asLevel,asGroup));
pvRecord->initPVRecord();
return pvRecord;
};
}}
static const iocshArg arg0 = { "recordName", iocshArgString };
static const iocshArg arg1 = { "scalarType", iocshArgString };
static const iocshArg arg2 = { "asLevel", iocshArgInt };
static const iocshArg arg3 = { "asGroup", iocshArgString };
static const iocshArg *args[] = {&arg0,&arg1,&arg2,&arg3};
static const iocshFuncDef pvdbcrScalarFuncDef = {"pvdbcrScalarRecord", 4,args};
static void pvdbcrScalarCallFunc(const iocshArgBuf *args)
{
char *sval = args[0].sval;
if(!sval) {
throw std::runtime_error("pvdbcrScalarRecord recordName not specified");
}
string recordName = string(sval);
sval = args[1].sval;
if(!sval) {
throw std::runtime_error("pvdbcrScalarRecord scalarType not specified");
}
string scalarType = string(sval);
int asLevel = args[2].ival;
string asGroup("DEFAULT");
sval = args[3].sval;
if(sval) {
asGroup = string(sval);
}
epics::pvDatabase::PvdbcrScalarRecordPtr record
= epics::pvDatabase::PvdbcrScalarRecord::create(recordName,scalarType);
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
record->setAsLevel(asLevel);
record->setAsGroup(asGroup);
bool result = master->addRecord(record);
if(!result) cout << "recordname " << recordName << " not added" << endl;
}
static void pvdbcrScalarRecord(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&pvdbcrScalarFuncDef, pvdbcrScalarCallFunc);
}
}
extern "C" {
epicsExportRegistrar(pvdbcrScalarRecord);
}

View File

@@ -0,0 +1 @@
registrar("pvdbcrScalarRecord")

View File

@@ -0,0 +1,128 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
* @date 2021.04.07
*/
#include <iocsh.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#include <pv/pvAccess.h>
#include <pv/serverContext.h>
#include <pv/rpcService.h>
// The following must be the last include
#include <epicsExport.h>
#define epicsExportSharedSymbols
#include "pv/pvDatabase.h"
#include "pv/pvdbcrTraceRecord.h"
using namespace epics::pvData;
using namespace std;
namespace epics { namespace pvDatabase {
PvdbcrTraceRecordPtr PvdbcrTraceRecord::create(
std::string const & recordName,
int asLevel,std::string const & asGroup)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("recordName",pvString)->
add("level",pvInt)->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
PvdbcrTraceRecordPtr pvRecord(
new PvdbcrTraceRecord(recordName,pvStructure,asLevel,asGroup));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
PvdbcrTraceRecord::PvdbcrTraceRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,
int asLevel,std::string const & asGroup)
: PVRecord(recordName,pvStructure,asLevel,asGroup)
{
}
bool PvdbcrTraceRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvLevel = pvStructure->getSubField<PVInt>("argument.level");
if(!pvLevel) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
return true;
}
void PvdbcrTraceRecord::process()
{
string name = pvRecordName->get();
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
if(!pvRecord) {
pvResult->put(name + " not found");
return;
}
pvRecord->setTraceLevel(pvLevel->get());
pvResult->put("success");
}
}}
static const iocshArg arg0 = { "recordName", iocshArgString };
static const iocshArg arg1 = { "asLevel", iocshArgInt };
static const iocshArg arg2 = { "asGroup", iocshArgString };
static const iocshArg *args[] = {&arg0,&arg1,&arg2};
static const iocshFuncDef pvdbcrTraceRecordFuncDef = {"pvdbcrTraceRecord", 3,args};
static void pvdbcrTraceRecordCallFunc(const iocshArgBuf *args)
{
char *sval = args[0].sval;
if(!sval) {
throw std::runtime_error("pvdbcrTraceRecord recordName not specified");
}
string recordName = string(sval);
int asLevel = args[1].ival;
string asGroup("DEFAULT");
sval = args[2].sval;
if(sval) {
asGroup = string(sval);
}
epics::pvDatabase::PvdbcrTraceRecordPtr record
= epics::pvDatabase::PvdbcrTraceRecord::create(recordName);
record->setAsLevel(asLevel);
record->setAsGroup(asGroup);
epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster();
bool result = master->addRecord(record);
if(!result) cout << "recordname " << recordName << " not added" << endl;
}
static void pvdbcrTraceRecord(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&pvdbcrTraceRecordFuncDef, pvdbcrTraceRecordCallFunc);
}
}
extern "C" {
epicsExportRegistrar(pvdbcrTraceRecord);
}

View File

@@ -0,0 +1 @@
registrar("pvdbcrTraceRecord")

View File

@@ -1,74 +0,0 @@
/* removeRecord.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#define epicsExportSharedSymbols
#include <pv/removeRecord.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
RemoveRecordPtr RemoveRecord::create(
std::string const & recordName)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("recordName",pvString)->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
RemoveRecordPtr pvRecord(
new RemoveRecord(recordName,pvStructure));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
RemoveRecord::RemoveRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure)
: PVRecord(recordName,pvStructure)
{
}
bool RemoveRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
return true;
}
void RemoveRecord::process()
{
string name = pvRecordName->get();
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
if(!pvRecord) {
pvResult->put(name + " not found");
return;
}
pvRecord->destroy();
pvResult->put("success");
}
}}

View File

@@ -1,78 +0,0 @@
/* traceRecord.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#define epicsExportSharedSymbols
#include <pv/traceRecord.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
TraceRecordPtr TraceRecord::create(
std::string const & recordName)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("recordName",pvString)->
add("level",pvInt)->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
TraceRecordPtr pvRecord(
new TraceRecord(recordName,pvStructure));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
TraceRecord::TraceRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure)
: PVRecord(recordName,pvStructure)
{
}
bool TraceRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvLevel = pvStructure->getSubField<PVInt>("argument.level");
if(!pvLevel) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
return true;
}
void TraceRecord::process()
{
string name = pvRecordName->get();
PVRecordPtr pvRecord = PVDatabase::getMaster()->findRecord(name);
if(!pvRecord) {
pvResult->put(name + " not found");
return;
}
pvRecord->setTraceLevel(pvLevel->get());
pvResult->put("success");
}
}}

6
src/support/Makefile Normal file
View File

@@ -0,0 +1,6 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATABASE_SRC)/support
LIBSRCS += controlSupport.cpp
LIBSRCS += scalarAlarmSupport.cpp

View File

@@ -0,0 +1,138 @@
/* controlSupport.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#include <pv/pvData.h>
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/convert.h>
#include <pv/standardField.h>
#define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include <pv/pvSupport.h>
#include "pv/pvDatabase.h"
#include "pv/controlSupport.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
ControlSupport::~ControlSupport()
{
//cout << "ControlSupport::~ControlSupport()\n";
}
epics::pvData::StructureConstPtr ControlSupport::controlField(ScalarType scalarType)
{
return FieldBuilder::begin()
->setId("control_t")
->add("limitLow", pvDouble)
->add("limitHigh", pvDouble)
->add("minStep", pvDouble)
->add("outputValue", scalarType)
->createStructure();
}
ControlSupportPtr ControlSupport::create(PVRecordPtr const & pvRecord)
{
cerr << "ControlSupport IS DEPRECATED\n";
ControlSupportPtr support(new ControlSupport(pvRecord));
return support;
}
ControlSupport::ControlSupport(PVRecordPtr const & pvRecord)
: pvRecord(pvRecord)
{}
bool ControlSupport::init(PVFieldPtr const & pv,PVFieldPtr const & pvsup)
{
if(pv) {
if(pv->getField()->getType()==epics::pvData::scalar) {
ScalarConstPtr s = static_pointer_cast<const Scalar>(pv->getField());
if(ScalarTypeFunc::isNumeric(s->getScalarType())) {
pvValue = static_pointer_cast<PVScalar>(pv);
}
}
}
if(!pvValue) {
cout << "ControlSupport for record " << pvRecord->getRecordName()
<< " failed because not numeric scalar\n";
return false;
}
pvControl = static_pointer_cast<PVStructure>(pvsup);
if(pvControl) {
pvLimitLow = pvControl->getSubField<PVDouble>("limitLow");
pvLimitHigh = pvControl->getSubField<PVDouble>("limitHigh");
pvMinStep = pvControl->getSubField<PVDouble>("minStep");
pvOutputValue = pvControl->getSubField<PVScalar>("outputValue");
}
if(!pvControl || !pvLimitLow || !pvLimitHigh || !pvMinStep || !pvOutputValue) {
cout << "ControlSupport for record " << pvRecord->getRecordName()
<< " failed because pvSupport not a valid control structure\n";
return false;
}
ConvertPtr convert = getConvert();
currentValue = convert->toDouble(pvValue);
isMinStep = false;
return true;
}
bool ControlSupport::process()
{
ConvertPtr convert = getConvert();
double value = convert->toDouble(pvValue);
if(!isMinStep && value==currentValue) return false;
double limitLow = pvLimitLow->get();
double limitHigh = pvLimitHigh->get();
double minStep = pvMinStep->get();
bool setValue = false;
if(limitHigh>limitLow) {
if(value>limitHigh) {value = limitHigh;setValue=true;}
if(value<limitLow) {value = limitLow;setValue=true;}
}
if(setValue) convert->fromDouble(pvValue,value);
double diff = value - currentValue;
double outputValue = value;
if(minStep>0.0) {
if(diff<0.0) {
outputValue = currentValue - minStep;
if(limitHigh>limitLow && outputValue<=limitLow) outputValue = limitLow;
isMinStep = true;
if(outputValue<value) {
outputValue = value;
isMinStep = false;
}
} else {
outputValue = currentValue + minStep;
if(limitHigh>limitLow && outputValue>=limitHigh) outputValue = limitHigh;
isMinStep = true;
if(outputValue>value) {
outputValue = value;
isMinStep = false;
}
}
}
if(outputValue==currentValue) return false;
currentValue = outputValue;
convert->fromDouble(pvOutputValue,outputValue);
return true;
}
void ControlSupport::reset()
{
isMinStep = false;
}
}}

View File

@@ -0,0 +1,219 @@
/* scalarAlarmSupport.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#include <pv/pvTimeStamp.h>
#include <pv/rpcService.h>
#include <pv/convert.h>
#include <pv/standardField.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#define epicsExportSharedSymbols
#include "pv/pvStructureCopy.h"
#include "pv/pvSupport.h"
#include "pv/pvDatabase.h"
#include "pv/scalarAlarmSupport.h"
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
ScalarAlarmSupport::~ScalarAlarmSupport()
{
//cout << "ScalarAlarmSupport::~ScalarAlarmSupport()\n";
}
epics::pvData::StructureConstPtr ScalarAlarmSupport::scalarAlarmField()
{
return FieldBuilder::begin()
->setId("scalarAlarm_t")
->add("lowAlarmLimit", pvDouble)
->add("lowWarningLimit", pvDouble)
->add("highWarningLimit", pvDouble)
->add("highAlarmLimit", pvDouble)
->add("hysteresis", pvDouble)
->createStructure();
}
ScalarAlarmSupportPtr ScalarAlarmSupport::create(PVRecordPtr const & pvRecord)
{
cerr << "ScalarAlarmSupport IS DEPRECATED\n";
ScalarAlarmSupportPtr support(new ScalarAlarmSupport(pvRecord));
return support;
}
ScalarAlarmSupport::ScalarAlarmSupport(PVRecordPtr const & pvRecord)
: pvRecord(pvRecord),
prevAlarmRange(range_Undefined)
{}
bool ScalarAlarmSupport::init(
PVFieldPtr const & pvval,
PVStructurePtr const & pvalarm,
PVFieldPtr const & pvsup)
{
if(pvval->getField()->getType()==epics::pvData::scalar) {
ScalarConstPtr s = static_pointer_cast<const Scalar>(pvval->getField());
if(ScalarTypeFunc::isNumeric(s->getScalarType())) {
pvValue = static_pointer_cast<PVScalar>(pvval);
}
}
if(!pvValue) {
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
<< " failed because not numeric scalar\n";
return false;
}
pvScalarAlarm = static_pointer_cast<PVStructure>(pvsup);
if(pvScalarAlarm) {
pvLowAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("lowAlarmLimit");
pvLowWarningLimit = pvScalarAlarm->getSubField<PVDouble>("lowWarningLimit");
pvHighWarningLimit = pvScalarAlarm->getSubField<PVDouble>("highWarningLimit");
pvHighAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("highAlarmLimit");
pvHysteresis = pvScalarAlarm->getSubField<PVDouble>("hysteresis");
}
if(!pvScalarAlarm
|| !pvLowAlarmLimit || !pvLowWarningLimit
|| !pvLowWarningLimit || !pvHighAlarmLimit
|| !pvHysteresis)
{
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
<< " failed because pvSupport not a valid scalarAlarm structure\n";
return false;
}
pvAlarm = pvalarm;
ConvertPtr convert = getConvert();
requestedValue = convert->toDouble(pvValue);
currentValue = requestedValue;
isHystersis = false;
setAlarm(pvAlarm,range_Undefined);
return true;
}
bool ScalarAlarmSupport::process()
{
ConvertPtr convert = getConvert();
double value = convert->toDouble(pvValue);
double lowAlarmLimit = pvLowAlarmLimit->get();
double lowWarningLimit = pvLowWarningLimit->get();
double highWarningLimit = pvHighWarningLimit->get();
double highAlarmLimit = pvHighAlarmLimit->get();
double hysteresis = pvHysteresis->get();
int alarmRange = range_Normal;
if(highAlarmLimit>lowAlarmLimit) {
if(value>=highAlarmLimit
||(prevAlarmRange==range_Hihi && value>=highAlarmLimit-hysteresis)) {
alarmRange = range_Hihi;
} else if(value<=lowAlarmLimit
||(prevAlarmRange==range_Lolo && value<=lowAlarmLimit+hysteresis)) {
alarmRange = range_Lolo;
}
}
if(alarmRange==range_Normal && (highWarningLimit>lowWarningLimit)) {
if(value>=highWarningLimit
||(prevAlarmRange==range_High && value>=highWarningLimit-hysteresis)) {
alarmRange = range_High;
} else if(value<=lowWarningLimit
||(prevAlarmRange==range_Low && value<=lowWarningLimit+hysteresis)) {
alarmRange = range_Low;
}
}
bool retValue = false;
if(alarmRange!=prevAlarmRange) {
setAlarm(pvAlarm,alarmRange);
retValue = true;
}
prevAlarmRange = alarmRange;
currentValue = value;
return retValue;
}
void ScalarAlarmSupport::reset()
{
isHystersis = false;
}
void ScalarAlarmSupport::setAlarm(
epics::pvData::PVStructurePtr const & pva,
int alarmRange)
{
Alarm alarm;
PVAlarm pvAlarm;
if(!pvAlarm.attach(pva)) throw std::logic_error("bad alarm field");
epics::pvData::AlarmStatus status(epics::pvData::noStatus);
epics::pvData::AlarmSeverity severity(epics::pvData::noAlarm);
string message;
switch (alarmRange) {
case range_Lolo :
{
severity = epics::pvData::majorAlarm;
status = epics::pvData::recordStatus;
message = "major low alarm";
break;
}
case range_Low :
{
severity = epics::pvData::minorAlarm;
status = epics::pvData::recordStatus;
message = "minor low alarm";
break;
}
case range_Normal :
{
break;
}
case range_High :
{
severity = epics::pvData::minorAlarm;
status = epics::pvData::recordStatus;
message = "minor high alarm";
break;
}
case range_Hihi :
{
severity = epics::pvData::majorAlarm;
status = epics::pvData::recordStatus;
message = "major high alarm";
break;
}
case range_Invalid :
{
severity = epics::pvData::invalidAlarm;
status = epics::pvData::recordStatus;
message = "invalid alarm";
break;
}
case range_Undefined :
{
severity = epics::pvData::undefinedAlarm;
status = epics::pvData::recordStatus;
message = "undefined alarm";
break;
}
default:
{
severity = epics::pvData::undefinedAlarm;
status = epics::pvData::recordStatus;
message = "bad alarm definition";
break;
}
}
alarm.setStatus(status);
alarm.setSeverity(severity);
alarm.setMessage(message);
pvAlarm.set(alarm);
}
}}

View File

@@ -11,18 +11,22 @@ PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(PVDATABASE_TEST)/src/Makefile
# The testHarness runs all the test programs in a known working order.
# pvDatabaseAllTests runs all the test programs in a known working order.
testHarness_SRCS += pvDatabaseAllTests.c
PROD_vxWorks = vxTestHarness
vxTestHarness_SRCS += $(testHarness_SRCS)
TESTSPEC_vxWorks = vxTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
# Name the application pvDbTestHarness
pvDbTestHarness_SRCS = $(testHarness_SRCS)
PROD_RTEMS += rtemsTestHarness
rtemsTestHarness_SRCS += rtemsTestHarness.c rtemsConfig.c
rtemsTestHarness_SRCS += $(testHarness_SRCS)
TESTSPEC_RTEMS = rtemsTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
# Build for vxWorks
PROD_vxWorks = pvDbTestHarness
TESTSPEC_vxWorks = pvDbTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
# Build for RTEMS, with harness code & configuration
PROD_RTEMS += pvDbTestHarness
pvDbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
TESTSPEC_RTEMS = pvDbTestHarness.$(MUNCH_SUFFIX); pvDatabaseAllTests
# Build test scripts for hosts
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES

View File

@@ -8,10 +8,12 @@
#include <stdio.h>
#include <epicsThread.h>
#include <epicsUnitTest.h>
#include <epicsExit.h>
/* src */
int testExampleRecord(void);
int testPVCopy(void);
int testPlugin(void);
int testPVRecord(void);
int testLocalProvider(void);
int testPVAServer(void);
@@ -23,8 +25,10 @@ void pvDatabaseAllTests(void)
/* src */
runTest(testExampleRecord);
runTest(testPVCopy);
runTest(testPlugin);
runTest(testPVRecord);
runTest(testLocalProvider);
runTest(testPVAServer);
}
epicsExit(0); /* Trigger test harness */
}

View File

@@ -1,72 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS configuration for EPICS
* Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd
* Author: W. Eric Norum
* norume@aps.anl.gov
* (630) 252-4793
*/
#include <rtems.h>
/*
***********************************************************************
* RTEMS CONFIGURATION *
***********************************************************************
*/
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#if __RTEMS_MAJOR__>4 || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
# define CONFIGURE_UNIFIED_WORK_AREAS
#else
# define CONFIGURE_EXECUTIVE_RAM_SIZE (2000*1024)
#endif
#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30)
#define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500)
#define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20)
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5)
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 150
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
#define CONFIGURE_MAXIMUM_DRIVERS 8
#define CONFIGURE_MICROSECONDS_PER_TICK 20000
#define CONFIGURE_INIT_TASK_PRIORITY 80
#define CONFIGURE_MALLOC_STATISTICS 1
#define CONFIGURE_INIT
#define CONFIGURE_INIT_TASK_INITIAL_MODES (RTEMS_PREEMPT | \
RTEMS_NO_TIMESLICE | \
RTEMS_NO_ASR | \
RTEMS_INTERRUPT_LEVEL(0))
#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_FLOATING_POINT | RTEMS_LOCAL)
#define CONFIGURE_INIT_TASK_STACK_SIZE (16*1024)
rtems_task Init (rtems_task_argument argument);
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_FILESYSTEM_NFS
#define CONFIGURE_FILESYSTEM_IMFS
/*
* This should be made BSP dependent, not CPU dependent but I know of no
* appropriate conditionals to use.
* The new general time support makes including the RTC driver less important.
*/
#if !defined(mpc604) && !defined(__mc68040__) && !defined(__mcf5200__) && !defined(mpc7455) && !defined(__arm__) /* don't have RTC code */
#define CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
#endif
#include <bsp.h>
#include <rtems/confdefs.h>

View File

@@ -1,294 +0,0 @@
/*
* Network configuration -- QEMU NOT using DHCP
*
************************************************************
* EDIT THIS FILE TO REFLECT YOUR NETWORK CONFIGURATION *
* BEFORE RUNNING ANY RTEMS PROGRAMS WHICH USE THE NETWORK! *
************************************************************
*
* The dynamic probing is based upon the EPICS network
* configuration file written by:
* W. Eric Norum
* eric.norum@usask.ca
* (306) 966-5394
*/
#ifndef _RTEMS_NETWORKCONFIG_H_
#define _RTEMS_NETWORKCONFIG_H_
/* #define USE_LIBBSDPORT */
#if defined(USE_LIBBSDPORT)
#include <bsp/libbsdport_api.h>
#define CONFIGURE_MAXIMUM_TIMERS 10
#endif
/*
* For TFTP test application
*/
#if (defined (RTEMS_USE_BOOTP))
#define RTEMS_TFTP_TEST_HOST_NAME "BOOTP_HOST"
#define RTEMS_TFTP_TEST_FILE_NAME "BOOTP_FILE"
#else
#define RTEMS_TFTP_TEST_HOST_NAME "XXX.YYY.ZZZ.XYZ"
#define RTEMS_TFTP_TEST_FILE_NAME "tftptest"
#endif
/*
* For NFS test application
*
* NFS mount and a directory to ls once mounted
*/
#define RTEMS_NFS_SERVER "192.168.1.210"
#define RTEMS_NFS_SERVER_PATH "/home"
#define RTEMS_NFS_LS_PATH "/mnt/nfstest"
/*
* This file can be copied to an application source directory
* and modified to override the values shown below.
*
* The following CPP symbols may be passed from the Makefile:
*
* symbol default description
*
* NETWORK_TASK_PRIORITY 150 can be read by app from public
* var 'gesysNetworkTaskPriority'
* FIXED_IP_ADDR <undefined> hardcoded IP address (e.g.,
* "192.168.0.10"); disables BOOTP;
* must also define FIXED_NETMASK
* FIXED_NETMASK <undefined> IP netmask string
* (e.g. "255.255.255.0")
* MULTI_NETDRIVER <undefined> ugly hack; if defined try to probe
* a variety of PCI and ISA drivers
* (i386 ONLY) use is discouraged!
* NIC_NAME <undefined> Ethernet driver name (e.g. "pcn1");
* must also define NIC_ATTACH
* NIC_ATTACH <undefined> Ethernet driver attach function
* (e.g., rtems_fxp_attach).
* If these are undefined then
* a) MULTI_NETDRIVER is used
* (if defined)
* b) RTEMS_BSP_NETWORK_DRIVER_NAME/
* RTEMS_BSP_NETWORK_DRIVER_ATTACH
* are tried
* MEMORY_CUSTOM <undefined> Allocate the defined amount of
* memory for mbufs and mbuf clusters,
* respectively. Define to a comma ','
* separated pair of two numerical
* values, e.g: 100*1024,200*1024
* MEMORY_SCARCE <undefined> Allocate few memory for mbufs
* (hint for how much memory the
* board has)
* MEMORY_HUGE <undefined> Allocate a lot of memory for mbufs
* (hint for how much memory the
* board has)
* If none of MEMORY_CUSTOM/
* MEMORY_SCARCE/MEMORY_HUGE are
* defined then a medium amount of
* memory is allocated for mbufs.
*/
#include <rtems/bspIo.h>
#include <bsp.h>
#include <rtems/rtems_bsdnet.h>
#if 0
#ifdef HAVE_CONFIG_H
#include <config.h>
#else
#include "verscheck.h"
#endif
#endif
//#define MULTI_NETDRIVER
//#define RTEMS_BSP_NETWORK_DRIVER_NAME 1
#define FIXED_IP_ADDR "192.168.1.249"
#define FIXED_NETMASK "255.255.255.0"
#ifndef NETWORK_TASK_PRIORITY
#define NETWORK_TASK_PRIORITY 150 /* within EPICS' range */
#endif
/* make publicly available for startup scripts... */
const int gesysNetworkTaskPriority = NETWORK_TASK_PRIORITY;
#ifdef FIXED_IP_ADDR
#define RTEMS_DO_BOOTP 0
#else
#define RTEMS_DO_BOOTP rtems_bsdnet_do_bootp
#define FIXED_IP_ADDR 0
#undef FIXED_NETMASK
#define FIXED_NETMASK 0
#endif
#if !defined(NIC_NAME)
#ifdef MULTI_NETDRIVER
#if 0
#if RTEMS_VERSION_ATLEAST(4,6,99)
#define pcib_init pci_initialize
#endif
#endif
extern int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *, int);
extern int rtems_fxp_attach (struct rtems_bsdnet_ifconfig *, int);
extern int rtems_elnk_driver_attach (struct rtems_bsdnet_ifconfig *, int);
extern int rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *, int);
/* these don't probe and will be used even if there's no device :-( */
extern int rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *, int);
extern int rtems_wd_driver_attach (struct rtems_bsdnet_ifconfig *, int);
static struct rtems_bsdnet_ifconfig isa_netdriver_config[] = {
{
"ep0", rtems_3c509_driver_attach, isa_netdriver_config + 1,
},
{
"ne1", rtems_ne_driver_attach, 0, irno: 9 /* qemu cannot configure irq-no :-(; has it hardwired to 9 */
},
};
static struct rtems_bsdnet_ifconfig pci_netdriver_config[]={
{
"dc1", rtems_dec21140_driver_attach, pci_netdriver_config+1,
},
#if !defined(USE_LIBBSDPORT)
{
"fxp1", rtems_fxp_attach, pci_netdriver_config+2,
},
#else
{
"", libbsdport_netdriver_attach, pci_netdriver_config+2,
},
#endif
{
"elnk1", rtems_elnk_driver_attach, isa_netdriver_config,
},
};
static int pci_check(struct rtems_bsdnet_ifconfig *ocfg, int attaching)
{
struct rtems_bsdnet_ifconfig *cfg;
int if_index_pre;
extern int if_index;
if ( attaching ) {
cfg = pci_initialize() ?
isa_netdriver_config : pci_netdriver_config;
}
while ( cfg ) {
printk("Probing '%s'", cfg->name);
/* unfortunately, the return value is unreliable - some drivers report
* success even if they fail.
* Check if they chained an interface (ifnet) structure instead
*/
if_index_pre = if_index;
cfg->attach(cfg, attaching);
if ( if_index > if_index_pre ) {
/* assume success */
printk(" .. seemed to work\n");
ocfg->name = cfg->name;
ocfg->attach = cfg->attach;
return 0;
}
printk(" .. failed\n");
cfg = cfg->next;
}
return -1;
}
#define NIC_NAME "dummy"
#define NIC_ATTACH pci_check
#else
#if defined(RTEMS_BSP_NETWORK_DRIVER_NAME) /* Use NIC provided by BSP */
/* force ne2k_isa on i386 for qemu */
#if defined(__i386__)
# define NIC_NAME BSP_NE2000_NETWORK_DRIVER_NAME
# define NIC_ATTACH BSP_NE2000_NETWORK_DRIVER_ATTACH
#else
# define NIC_NAME RTEMS_BSP_NETWORK_DRIVER_NAME
# define NIC_ATTACH RTEMS_BSP_NETWORK_DRIVER_ATTACH
#endif
#endif
#endif /* ifdef MULTI_NETDRIVER */
#endif
#ifdef NIC_NAME
extern int NIC_ATTACH();
#if RTEMS_BSP_NETWORK_DRIVER_ATTACH == BSP_NE2000_NETWORK_DRIVER_ATTACH
static char ethernet_address[6] = { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x34 };
#endif
static struct rtems_bsdnet_ifconfig netdriver_config[1] = {{
NIC_NAME, /* name */
(int (*)(struct rtems_bsdnet_ifconfig*,int))NIC_ATTACH, /* attach function */
0, /* link to next interface */
FIXED_IP_ADDR,
FIXED_NETMASK
#if RTEMS_BSP_NETWORK_DRIVER_ATTACH == BSP_NE2000_NETWORK_DRIVER_ATTACH
,
ethernet_address,
irno:9,
port:0xc100
#endif
}};
#else
#warning "NO KNOWN NETWORK DRIVER FOR THIS BSP -- YOU MAY HAVE TO EDIT networkconfig.h"
#endif
struct rtems_bsdnet_config rtems_bsdnet_config = {
#ifdef NIC_NAME
netdriver_config, /* link to next interface */
RTEMS_DO_BOOTP, /* Use BOOTP to get network configuration */
#else
0,
0,
#endif
NETWORK_TASK_PRIORITY, /* Network task priority */
#if defined(MEMORY_CUSTOM)
MEMORY_CUSTOM,
#elif defined(MEMORY_SCARCE)
100*1024, /* MBUF space */
200*1024, /* MBUF cluster space */
#elif defined(MEMORY_HUGE)
2*1024*1024, /* MBUF space */
5*1024*1024, /* MBUF cluster space */
#else
180*1024, /* MBUF space */
350*1024, /* MBUF cluster space */
#endif
#if (!defined (RTEMS_USE_BOOTP)) && defined(ON_RTEMS_LAB_WINSYSTEMS)
"rtems", /* Host name */
"nodomain.com", /* Domain name */
"192.168.1.14", /* Gateway */
"192.168.1.1", /* Log host */
{"89.212.75.6" }, /* Name server(s) */
{"192.168.1.1" }, /* NTP server(s) */
#else
NULL, /* Host name */
NULL, /* Domain name */
NULL, /* Gateway */
NULL, /* Log host */
{ NULL }, /* Name server(s) */
{ NULL }, /* NTP server(s) */
#endif /* !RTEMS_USE_BOOTP */
0, /* efficiency */
0, /* udp TX buffer */
0, /* udp RX buffer */
0, /* tcp TX buffer */
0, /* tcp RX buffer */
};
#endif /* _RTEMS_NETWORKCONFIG_H_ */

View File

@@ -1,38 +1,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <rtems/rtems_bsdnet.h>
#include <rtems/error.h>
#include "rtemsNetworking.h"
#include <epicsExit.h>
#include <osdTime.h>
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
extern void pvDatabaseAllTests(void);
rtems_task
Init (rtems_task_argument ignored)
int main(int argc, char **argv)
{
rtems_bsdnet_initialize_network ();
//rtems_bsdnet_show_if_stats ();
rtems_time_of_day timeOfDay;
if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&timeOfDay) != RTEMS_SUCCESSFUL) {
timeOfDay.year = 2014;
timeOfDay.month = 1;
timeOfDay.day = 1;
timeOfDay.hour = 0;
timeOfDay.minute = 0;
timeOfDay.second = 0;
timeOfDay.ticks = 0;
rtems_status_code ret = rtems_clock_set(&timeOfDay);
if (ret != RTEMS_SUCCESSFUL) {
printf("**** Can't set time %s\n", rtems_status_text(ret));
}
}
osdTimeRegister();
pvDatabaseAllTests();
epicsExit(0);
return 0;
}

View File

@@ -3,6 +3,12 @@
SRC_DIRS += $(PVDATABASE_TEST)/src
TESTPROD_HOST += testPlugin
testPlugin_SRCS += testPlugin.cpp
testHarness_SRCS += testPlugin.cpp
TESTS += testPlugin
TESTPROD_HOST += testPVCopy
testPVCopy_SRCS += testPVCopy.cpp
testHarness_SRCS += testPVCopy.cpp
@@ -23,7 +29,6 @@ testLocalProvider_SRCS += testLocalProvider.cpp
testHarness_SRCS += testLocalProvider.cpp
TESTS += testLocalProvider
TESTPROD_HOST += testPVAServer
testPVAServer_SRCS += testPVAServer.cpp
testHarness_SRCS += testPVAServer.cpp

View File

@@ -22,17 +22,18 @@
#include <pv/pvTimeStamp.h>
#include <pv/pvAlarm.h>
#include <pv/pvDatabase.h>
#include <pv/pvStructureCopy.h>
#ifdef listenerEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef listenerEpicsExportSharedSymbols
# undef listenerEpicsExportSharedSymbols
#endif
#include <shareLib.h>
//epicsShareFunc epics::pvData::PVStructurePtr createListener();
namespace epics { namespace pvDatabase {
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using namespace std;
@@ -58,7 +59,7 @@ public:
}
virtual void dataPut(PVRecordFieldPtr const & pvRecordField)
{
cout << "Listener::dataPut record " << recordName
cout << "Listener::dataPut record " << recordName
<< " pvRecordField " << pvRecordField->getPVField()->getFullName()
<< endl;
}
@@ -66,7 +67,7 @@ public:
PVRecordStructurePtr const & requested,
PVRecordFieldPtr const & pvRecordField)
{
cout << "Listener::dataPut record " << recordName
cout << "Listener::dataPut record " << recordName
<< " requested " << requested->getPVStructure()->getFullName()
<< " pvRecordField " << pvRecordField->getPVField()->getFullName()
<< endl;
@@ -83,11 +84,11 @@ public:
{
cout << "Listener::unlisten record " << recordName << endl;
}
private:
Listener(PVRecordPtr const & pvRecord)
: pvCopy(
PVCopy::create(
epics::pvCopy::PVCopy::create(
getPVDataCreate()->createPVStructure(
pvRecord->getPVRecordStructure()->getPVStructure()),
CreateRequest::create()->createRequest(""),
@@ -96,7 +97,7 @@ private:
recordName(pvRecord->getRecordName())
{
}
PVCopyPtr pvCopy;
epics::pvCopy::PVCopyPtr pvCopy;
PVStructurePtr pvStructure;
string recordName;
};

View File

@@ -25,14 +25,14 @@
#ifdef powerSupplyEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef powerSupplyEpicsExportSharedSymbols
# undef powerSupplyEpicsExportSharedSymbols
#endif
#include <shareLib.h>
//epicsShareFunc epics::pvData::PVStructurePtr createPowerSupply();
namespace epics { namespace pvDatabase {
namespace epics { namespace pvDatabase {
class PowerSupply;
typedef std::tr1::shared_ptr<PowerSupply> PowerSupplyPtr;
@@ -46,7 +46,6 @@ public:
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure);
virtual ~PowerSupply();
virtual void destroy();
virtual bool init();
virtual void process();
void put(double power,double voltage);
@@ -111,11 +110,6 @@ inline PowerSupply::~PowerSupply()
{
}
inline void PowerSupply::destroy()
{
PVRecord::destroy();
}
inline bool PowerSupply::init()
{
initPVRecord();

View File

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

View File

@@ -68,7 +68,6 @@ static void test()
exampleRecord->unlock();
}
if(debug) {cout << "processed exampleDouble " << endl; }
exampleRecord->destroy();
recordName = "powerSupplyExample";
PowerSupplyPtr psr;
pvStructure = createPowerSupply();
@@ -127,7 +126,6 @@ static void test()
testOk1(psr->getVoltage()==1.0);
testOk1(psr->getPower()==1.0);
testOk1(psr->getCurrent()==1.0);
psr->destroy();
}
MAIN(testExampleRecord)
@@ -136,4 +134,3 @@ MAIN(testExampleRecord)
test();
return 0;
}

View File

@@ -71,7 +71,6 @@ static void test()
pvRecord->unlock();
}
if(debug) {cout << "processed exampleDouble " << endl; }
channelProvider->destroy();
}
MAIN(testLocalProvider)
@@ -80,4 +79,3 @@ MAIN(testLocalProvider)
test();
return 0;
}

View File

@@ -67,7 +67,6 @@ static void test()
ServerContext::shared_pointer ctx =
startPVAServer("local",0,true,true);
testOk1(ctx.get()!=0);
ctx->destroy();
}
MAIN(testPVAServer)
@@ -76,4 +75,3 @@ MAIN(testPVAServer)
test();
return 0;
}

View File

@@ -37,6 +37,7 @@ using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvCopy;
using namespace epics::pvDatabase;
static bool debug = false;
@@ -272,7 +273,34 @@ static void testPVScalarArray(
cout << endl;
}
}
static void testMasterField(PVRecordPtr const& pvRecord)
{
CreateRequest::shared_pointer createRequest = CreateRequest::create();
PVStructurePtr pvRequest = createRequest->createRequest("field(_)");
if(debug) {
cout << "pvRequest" << *pvRequest << endl ;
}
PVStructurePtr pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
PVCopyPtr pvCopy = PVCopy::create(pvStructureRecord,pvRequest,"");
PVStructurePtr pvMasterField = pvCopy->getPVMaster();
if(debug) {
cout << "PV structure from record" << endl << *pvStructureRecord << endl;
cout << "Master PV structure from copy" << endl << *pvMasterField << endl;
cout << "Master PV structure from copy offset " << pvMasterField->getFieldOffset() << endl;
}
testOk1(pvMasterField->getNumberFields() == pvStructureRecord->getNumberFields());
testOk1(pvMasterField->getFieldOffset() == 0);
PVStructurePtr pvStructureCopy = pvCopy->createPVStructure();
BitSetPtr bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
pvCopy->initCopy(pvStructureCopy, bitSet);
if(debug) {
cout << "PV structure from copy" << endl << *pvStructureCopy << endl;
cout << "PV structure from copy offset " << pvStructureCopy->getFieldOffset() << endl;
}
testOk1(pvMasterField->getNumberFields() == pvStructureCopy->getNumberFields());
}
static void scalarTest()
{
if(debug) {cout << endl << endl << "****scalarTest****" << endl;}
@@ -281,7 +309,6 @@ static void scalarTest()
string request;
PVStructurePtr pvRequest;
PVCopyPtr pvCopy;
string builder;
string valueNameRecord;
string valueNameCopy;
@@ -313,7 +340,6 @@ static void scalarTest()
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
valueNameCopy = "value";
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
pvRecord->destroy();
}
static void arrayTest()
@@ -324,7 +350,6 @@ static void arrayTest()
string request;
PVStructurePtr pvRequest;
PVCopyPtr pvCopy;
string builder;
string valueNameRecord;
string valueNameCopy;
@@ -350,7 +375,6 @@ static void arrayTest()
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
valueNameCopy = "value";
testPVScalarArray(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
pvRecord->destroy();
}
static void powerSupplyTest()
@@ -361,7 +385,6 @@ static void powerSupplyTest()
string request;
PVStructurePtr pvRequest;
PVCopyPtr pvCopy;
string builder;
string valueNameRecord;
string valueNameCopy;
@@ -395,15 +418,23 @@ static void powerSupplyTest()
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
valueNameCopy = "power.value";
testPVScalar(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
pvRecord->destroy();
}
static void masterFieldTest()
{
if(debug) {
cout << endl << endl << "****masterFieldTest****" << endl;
}
PVRecordPtr pvRecord = createScalar("doubleRecord",pvDouble,"alarm,timeStamp,display");
testMasterField(pvRecord);
}
MAIN(testPVCopy)
{
testPlan(67);
testPlan(70);
scalarTest();
arrayTest();
powerSupplyTest();
masterFieldTest();
return 0;
}

View File

@@ -28,7 +28,7 @@
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/pvData.h>
#include <pv/pvCopy.h>
#include <pv/pvStructureCopy.h>
#define epicsExportSharedSymbols
#include "powerSupply.h"
@@ -37,6 +37,7 @@ using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvDatabase;
using namespace epics::pvCopy;
using std::string;
static bool debug = false;
@@ -69,7 +70,6 @@ static void scalarTest()
if(pvRecord && debug) {
cout << pvRecord << endl;
}
pvRecord->destroy();
}
static void arrayTest()
@@ -81,7 +81,6 @@ static void arrayTest()
if(pvRecord && debug) {
cout << pvRecord << endl;
}
pvRecord->destroy();
}
static void powerSupplyTest()
@@ -94,7 +93,6 @@ static void powerSupplyTest()
if(pvRecord && debug) {
cout << pvRecord << endl;
}
pvRecord->destroy();
}
MAIN(testPVRecord)
@@ -105,4 +103,3 @@ MAIN(testPVRecord)
powerSupplyTest();
return 0;
}

345
test/src/testPlugin.cpp Normal file
View File

@@ -0,0 +1,345 @@
/*testPluginMain.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
/* Author: Marty Kraimer */
#include <epicsUnitTest.h>
#include <testMain.h>
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/channelProviderLocal.h>
#include <pv/convert.h>
#include <pv/pvStructureCopy.h>
#include <pv/pvDatabase.h>
#define epicsExportSharedSymbols
#include "powerSupply.h"
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvCopy;
using namespace epics::pvDatabase;
static bool debug = true;
static void deadbandTest()
{
if(debug) {cout << endl << endl << "****deadbandTest****" << endl;}
bool result = false;
uint32 nset = 0;
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,""));
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[deadband=abs:1.0]"));
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "initial"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< " pvRecordStructure\n" << pvRecordStructure
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
pvValue->put(.1);
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after pvValue"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< " pvRecordStructure\n" << pvRecordStructure
<< "\n";
}
testOk1(result==false);
testOk1(nset==0);
pvValue->put(1.0);
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after pvValue"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< " pvRecordStructure\n" << pvRecordStructure
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
}
static void arrayTest()
{
if(debug) {cout << endl << endl << "****arrayTest****" << endl;}
bool result = false;
uint32 nset = 0;
size_t n = 10;
shared_vector<double> values(n);
PVStructurePtr pvRecordStructure(getStandardPVField()->scalarArray(pvDouble,""));
PVRecordPtr pvRecord(PVRecord::create("doubleArrayRecord",pvRecordStructure));
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
PVDoubleArrayPtr pvValue(pvRecordStructure->getSubField<PVDoubleArray>("value"));
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "initial"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==false);
testOk1(nset==0);
for(size_t i=0; i<n; i++) values[i] = i + .06;
const shared_vector<const double> yyy(freeze(values));
pvValue->putFrom(yyy);
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after pvValue"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< " pvRecordStructure\n" << pvRecordStructure
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
}
static void unionArrayTest()
{
if(debug) {cout << endl << endl << "****unionArrayTest****" << endl;}
bool result = false;
uint32 nset = 0;
size_t n = 10;
shared_vector<double> values(n);
for(size_t i=0; i<n; i++) values[i] = i + .06;
PVDoubleArrayPtr pvDoubleArray =
static_pointer_cast<PVDoubleArray>(PVDataCreate::getPVDataCreate()->createPVScalarArray(pvDouble));
const shared_vector<const double> yyy(freeze(values));
pvDoubleArray->putFrom(yyy);
StandardFieldPtr standardField = getStandardField();
FieldCreatePtr fieldCreate = getFieldCreate();
StructureConstPtr top = fieldCreate->createFieldBuilder()->
add("value",fieldCreate->createVariantUnion()) ->
add("timeStamp", standardField->timeStamp()) ->
addNestedStructure("subfield") ->
add("value",fieldCreate->createVariantUnion()) ->
endNested()->
createStructure();
PVStructurePtr pvRecordStructure(PVDataCreate::getPVDataCreate()->createPVStructure(top));
PVRecordPtr pvRecord(PVRecord::create("unionArrayRecord",pvRecordStructure));
PVUnionPtr pvUnion = pvRecord->getPVStructure()->getSubField<PVUnion>("value");
pvUnion->set(pvDoubleArray);
pvUnion = pvRecord->getPVStructure()->getSubField<PVUnion>("subfield.value");
pvUnion->set(pvDoubleArray);
if(debug) { cout << "initial\n" << pvRecordStructure << "\n";}
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value[array=1:3]"));
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
PVDoubleArrayPtr pvValue(pvRecordStructure->getSubField<PVDoubleArray>("value"));
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after get value"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
pvRequest = CreateRequest::create()->createRequest("subfield.value[array=1:3]");
pvCopy = PVCopy::create(pvRecordStructure,pvRequest,"");
pvStructureCopy = pvCopy->createPVStructure();
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
pvValue = pvRecordStructure->getSubField<PVDoubleArray>("subfield.value");
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after get subfield.value"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
}
static void timeStampTest()
{
if(debug) {cout << endl << endl << "****timeStampTest****" << endl;}
bool result = false;
uint32 nset = 0;
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,"timeStamp"));
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value,timeStamp[timestamp=current]"));
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
if(debug) {
cout << "initial"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< " pvRecordStructure\n" << pvRecordStructure
<< "\n";
}
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after update"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< " pvRecordStructure\n" << pvRecordStructure
<< "\n";
}
testOk1(result==true);
testOk1(nset==1);
pvRecord->process();
pvValue->put(1.0);
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after pvValue"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< " pvRecordStructure\n" << pvRecordStructure
<< "\n";
}
testOk1(result==true);
testOk1(nset==2);
}
static void ignoreTest()
{
if(debug) {cout << endl << endl << "****ignoreTest****" << endl;}
bool result = false;
uint32 nset = 0;
PVStructurePtr pvRecordStructure(getStandardPVField()->scalar(pvDouble,"alarm,timeStamp"));
PVRecordPtr pvRecord(PVRecord::create("doubleRecord",pvRecordStructure));
PVStructurePtr pvRequest(CreateRequest::create()->createRequest("value,alarm[ignore=true],timeStamp[ignore=true]"));
PVCopyPtr pvCopy(PVCopy::create(pvRecordStructure,pvRequest,""));
PVStructurePtr pvStructureCopy(pvCopy->createPVStructure());
BitSetPtr bitSet(new BitSet(pvStructureCopy->getNumberFields()));
PVDoublePtr pvValue(pvRecordStructure->getSubField<PVDouble>("value"));
PVStringPtr pvMessage(pvRecordStructure->getSubField<PVString>("alarm.message"));
PVIntPtr pvUserTag(pvRecordStructure->getSubField<PVInt>("timeStamp.userTag"));
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "initial"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==false);
testOk1(nset==0);
pvMessage->put("test message");
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after pvMessage"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==false);
testOk1(nset==1);
pvUserTag->put(50);
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after pvMessage"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==false);
testOk1(nset==2);
pvValue->put(1.0);
result = pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
nset = bitSet->cardinality();
if(debug) {
cout << "after pvValue"
<< " result " << (result ? "true" : "false")
<< " nset " << nset
<< " bitSet " << *bitSet
<< " pvStructureCopy\n" << pvStructureCopy
<< "\n";
}
testOk1(result==true);
testOk1(nset==3);
}
MAIN(testPlugin)
{
testPlan(26);
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
deadbandTest();
arrayTest();
unionArrayTest();
timeStampTest();
ignoreTest();
return 0;
}