275 Commits
4.1.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
Andrew Johnson
b26c0ecd71 Use EPICS_BASE_PVA_CORE_LIBS 2017-12-06 22:46:27 -06:00
Andrew Johnson
e06b2b7076 Include <top>/../RELEASE.<host>.local 2017-12-06 20:38:13 -06:00
Andrew Johnson
63214b98f6 Use 'make test-results' in travis-build script 2017-11-30 12:05:58 -06:00
Andrew Johnson
a1714c9aab Unify .gitignore files 2017-11-30 12:05:40 -06:00
Andrew Johnson
64c5fd1e67 Remove ExampleRELEASE.local 2017-11-30 12:04:29 -06:00
Ralph Lange
955947fd0f jenkins: remove microbench option and pvCommon dependency from CB build 2017-11-15 17:18:57 +01:00
Marty Kraimer
c6339f4f1b Merge pull request #31 from mrkraimer/master
PVRecord::process DO NOT set userTag
2017-11-09 09:43:31 -05:00
mrkraimer
ae97789beb PVRecord::process DO NOT set userTag 2017-11-09 09:09:44 -05:00
Marty Kraimer
35d4b5c70e Merge pull request #30 from mrkraimer/master
attempt to fix macos build
2017-10-05 09:07:51 -04:00
mrkraimer
977f078246 attempt to fix macos build 2017-10-05 08:40:37 -04:00
Marty Kraimer
063313f246 Merge pull request #28 from mrkraimer/master
Remove most use of destroy
2017-10-02 16:00:47 -04:00
mrkraimer
cec282f77f Merge https://github.com/epics-base/pvDatabaseCPP 2017-10-02 15:11:37 -04:00
mrkraimer
24cf1d277e remove destroy except PVRecord, which has new semantics 2017-10-02 15:03:16 -04:00
Ralph Lange
1d5e9e7b25 travis-ci: consolidate travis configuration 2017-09-28 15:11:03 +02:00
Ralph Lange
f131f0631c travis-ci: fix requisite build for Base 3.x 2017-09-27 14:45:26 +02:00
Ralph Lange
aa44396a43 travis-ci: update/streamline configuration for EPICS 7 2017-09-27 14:06:46 +02:00
Marty Kraimer
547df7a2cd Merge pull request #27 from mrkraimer/master
create travis files
2017-09-13 10:12:12 -04:00
mrkraimer
be6527b01e another attempt at travis 2017-09-13 07:12:59 -04:00
mrkraimer
d7486622bf create travis files 2017-09-13 05:29:58 -04:00
Marty Kraimer
974bf061a2 Merge pull request #26 from mrkraimer/new-pva-api
add pvAccessIOC to LIBS
2017-07-18 15:38:30 -04:00
mrkraimer
d99087d2f6 add pvAccessIOC to LIBS 2017-07-18 15:36:01 -04:00
Marty Kraimer
8c2926ad92 Merge pull request #25 from mrkraimer/new-pva-api
change version number
2017-07-18 15:02:48 -04:00
mrkraimer
5b60025b76 change version number 2017-07-18 14:50:43 -04:00
Marty Kraimer
d080a073b1 Merge pull request #23 from mrkraimer/new-pva-api
changes for new-pva-api
2017-07-18 13:36:20 -04:00
mrkraimer
ff172cc495 changes for new-pva-api 2017-06-28 10:37:48 -04:00
Marty Kraimer
da00928e7e Merge pull request #22 from mrkraimer/master
monitor change to support filter plugin support
2017-04-07 13:32:50 -04:00
mrkraimer
9dcb68669c monitor change to support filter plugin support 2017-03-30 11:02:17 -04:00
Marty Kraimer
33852c6375 Merge pull request #20 from mrkraimer/master
change SHRLIB_VERSION
2016-07-22 15:10:47 -04:00
mrkraimer
ce9322eb9c change SHRLIB_VERSION 2016-07-22 14:45:02 -04:00
Ralph Lange
a634d53a00 jenkins: fix installE4 logic, add pvCommon dependency 2016-07-22 14:59:12 +02:00
Ralph Lange
515e7926b8 jenkins: use install functions, add BRANCH variable to doc script 2016-07-19 23:07:40 +02:00
Marty Kraimer
6877ec8397 Merge pull request #19 from mrkraimer/master
Documentation Changes
2016-07-19 06:01:59 -04:00
mrkraimer
03fc6f4a63 mainly doc changes 2016-07-18 13:01:35 -04:00
mrkraimer
1d80fbf512 fix LICENSE 2016-07-09 06:54:49 -04:00
mrkraimer
04688b1e1a fix LICENSE 2016-07-09 06:54:48 -04:00
mrkraimer
08751c619b Merge https://github.com/epics-base/pvDatabaseCPP 2016-07-07 09:48:05 -04:00
mrkraimer
0c96300e99 use LICENSE.txt from andrew 2016-07-07 09:41:51 -04:00
Marty Kraimer
e17d8bbd76 Merge pull request #18 from mrkraimer/master
Compatibility with pvDatabaseJava; on-line delete; database termination
2016-07-01 10:36:17 -04:00
mrkraimer
0784cc15d0 make more compatible with pvDatabaseJava; work on on-line delete and also termination 2016-07-01 10:27:04 -04:00
Marty Kraimer
81220c87f8 Merge pull request #17 from mrkraimer/master
on-line delete; notify clients when a PVRecord is deleted
2016-06-24 15:04:44 -04:00
mrkraimer
75849c6676 on-line delete; notify clients when a PVRecord is deleted 2016-06-24 14:51:55 -04:00
Marty Kraimer
5f98b5230a Merge pull request #16 from mrkraimer/master
don't issue maesage when being destroyed is true
2016-06-20 11:03:15 -04:00
mrkraimer
d3bbbdd083 don't issue maesage when being destroyed is true 2016-06-20 09:57:29 -04:00
Marty Kraimer
4197eb9422 Merge pull request #15 from mrkraimer/master
make void test() static
2016-06-15 12:20:10 -04:00
mrkraimer
349f7d0a58 make void test() static 2016-06-15 12:16:12 -04:00
Marty Kraimer
355cb68363 Merge pull request #14 from mrkraimer/master
use correct name in MAIN
2016-06-15 11:00:48 -04:00
mrkraimer
b5e1341736 use correct name in MAIN 2016-06-15 10:50:01 -04:00
Marty Kraimer
570fbf80ae Merge pull request #13 from mrkraimer/master
add removeRecord; other minor changes
2016-06-15 07:52:01 -04:00
mrkraimer
fde7953de0 add removeRecord; more work on termination issues 2016-06-15 07:21:43 -04:00
mrkraimer
e025e542ea work on RAII and memory leaks 2016-06-01 10:10:00 -04:00
Marty Kraimer
f7a3ca2c3c Merge pull request #12 from mrkraimer/master
register LocalChannelProvider; traceRecord consistant with pvDatabase…
2016-04-20 11:13:18 -04:00
mrkraimer
1eea87efc7 register LocalChannelProvider; traceRecord consistant with pvDatabaseJava 2016-04-19 10:14:39 -04:00
Andrew Johnson
15c6d32b61 Change cloudbees_doc script to use Base-3.15.3 2016-04-12 11:50:11 -05:00
Marty Kraimer
db2f528c0a Merge pull request #11 from anjohnson/master
Support for additional Windows targets
2016-04-12 11:50:04 -04:00
Andrew Johnson
351840b490 Use epicsShareFunc, not epicsShareExtern
Also needed on friend declarations.
2016-04-06 14:49:51 -05:00
Marty Kraimer
c36b969da4 Merge pull request #10 from mrkraimer/master
remove unused ContextLocal
2016-03-30 05:28:44 -04:00
mrkraimer
f4c0b54c17 remove unused ContextLocal 2016-03-29 09:39:02 -04:00
Marty Kraimer
0611db9a18 Merge pull request #9 from mrkraimer/master
for installing in include/pv follow  pvaClientCPP
2016-02-04 13:12:15 -05:00
mrkraimer
80ff17cfbc make test/rtemsTestHarness.c the same as epics-base 2016-02-04 08:30:51 -05:00
mrkraimer
1ea3d46baf set CHECK_RELEASE = WARN; remove TODO.html 2016-02-04 08:11:25 -05:00
Andrew Johnson
3babe530ca Fixes for RTEMS - routine name and comment 2016-02-03 11:40:16 -06:00
mrkraimer
6647ab3142 try to make win and rtems build 2016-02-03 07:17:56 -05:00
mrkraimer
0595b5a9d5 for installing in include/pv follow pvaClientCPP 2016-02-02 13:00:51 -05:00
Marty Kraimer
9c93cef34e Merge pull request #8 from mrkraimer/master
test/src/powerSupply.h make all methods inline
2016-01-28 13:31:28 -05:00
mrkraimer
3fc5aad6f5 Merge https://github.com/epics-base/pvDatabaseCPP 2016-01-27 09:49:37 -05:00
mrkraimer
4934e5a8c7 make all methods inline 2016-01-27 09:44:50 -05:00
Marty Kraimer
bb3aca734c Merge pull request #7 from mrkraimer/master
jenkins/cloudbees_build attempt to make vxWorks and RTEMS build
2016-01-27 07:13:59 -05:00
mrkraimer
ce41acd373 add SHRLIB_VERSION 2016-01-27 07:07:52 -05:00
mrkraimer
264100df7c added make runtests 2016-01-26 10:04:36 -05:00
mrkraimer
64909f2152 jenkins/cloudbees_build attempt to make vxWorks and RTEMS build
src/pv/pvDatabase.h attemp t make doc build
src/pvAccess/channelLocal.cpp trap exceptions and turn into Status
2016-01-26 08:33:00 -05:00
Marty Kraimer
f0320e7173 Merge pull request #6 from anjohnson/master
Use epicsGuard and epicsGuardRelease for lock handling
2016-01-25 07:17:19 -05:00
Marty Kraimer
7f15b136b1 Merge pull request #5 from mrkraimer/master
remove examples, make test regression test, update documentation
2016-01-25 07:10:07 -05:00
Andrew Johnson
6c08a05b81 Use epicsGuard and epicsGuardRelease
These objects provide exception-safe locking and unlocking.
2016-01-22 12:05:23 -06:00
mrkraimer
326dc6ca69 fix some errors in documentation/pvDatabaseCPP.html 2016-01-22 10:42:48 -05:00
mrkraimer
751cc8965d forgot to add some files before last commit 2016-01-21 14:57:00 -05:00
mrkraimer
102174913c remove examples (moved to exampleCPP) ; test is now a regresion test (make runtests) 2016-01-21 14:39:23 -05:00
Marty Kraimer
61c41ceb7e Merge pull request #4 from mrkraimer/master
use weak pointer for callbacks
2016-01-21 14:29:07 -05:00
mrkraimer
4ac867ec0f use weak pointer for callbacks 2016-01-07 07:44:08 -05:00
Marty Kraimer
ca3573291a Merge pull request #3 from dhickin/rpc
Add support for Channel RPC
2015-12-09 06:19:44 -05:00
mrkraimer
3764c3ad36 call unlisten before erase 2015-12-08 15:45:54 -05:00
Dave Hickin
0aadb3b0a7 Make ChannelRPCLocal follow pvDatabase conventions
Make ChannelRPCLocal print debug according to TraceLevel. Move function
implementations out of class body. Follow pvDatabase general coding
conventions (variable names, order of declarations, indentation etc.).
2015-12-08 13:40:04 +00:00
Dave Hickin
bc3335d4f9 Add example of record which supports RPC and a client
Record has x and y-coordinate fields and a timestamp and also provides
a service which sets (x,y) to a sequence of values.

An RPC client application (move) sends positions as an array.
2015-12-08 13:38:47 +00:00
Dave Hickin
a99b08fd02 Add support for RPC to pvDatabase
Add a new function to PVRecord which returns a service (from the
pvAccess RPC library) for a supplied pvRequest (defaults to returning
a null pointer).

Add an implementation of ChannelRPC which gets the service from the
record and is used by ChannelLocal.
2015-12-08 10:37:37 +00:00
mrkraimer
c717138c7d get rid of two more references to pvIOC 2015-10-28 07:29:48 -04:00
mrkraimer
e6e7902831 removed all talk about pvIOC 2015-10-27 13:01:03 -04:00
Ralph Lange
d71d3f1862 jenkins: build dependency branches must be empty on master 2015-10-26 14:02:57 +01:00
mrkraimer
77ff6ad6c1 Merge branch 'release/4.1' 2015-10-21 07:17:48 -04:00
mrkraimer
b3b01959e5 mispelled releaase 2015-10-07 10:35:59 -04:00
mrkraimer
9db7ed360b mv documentation/RELEASE_NOTES.md to RELEASE_NOTES.md 2015-10-07 10:29:39 -04:00
mrkraimer
1f7881010e fix doxygen errors 2015-10-03 06:19:15 -04:00
mrkraimer
90a96f4ee4 update documentation; remove recordList 2015-10-02 08:48:30 -04:00
Ralph Lange
34ff6077c7 jenkins: fix CloudBees doc job 2015-09-28 15:28:17 +02:00
Ralph Lange
1050b980ec jenkins: fix CloudBees doc job 2015-09-28 15:27:47 +02:00
Ralph Lange
2bdb012709 jenkins: change doc script to adapt to new CloudBees jobs 2015-09-14 15:02:10 +02:00
Ralph Lange
8a1690f35a jenkins: change doc script to adapt to new CloudBees jobs 2015-09-14 15:00:43 +02:00
Ralph Lange
d578dfbb99 REVERT jenkins: set dependency versions
(reverted from commit e9d14d061e)
2015-09-04 13:01:12 +02:00
Ralph Lange
e9d14d061e jenkins: set dependency versions (part of epics-base/jenkins-jobs#10) 2015-09-04 12:59:57 +02:00
264 changed files with 7800 additions and 35862 deletions

10
.ci/travis-build.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
set -e -x
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make -j2 tapfiles
make -j2 -s test-results
fi

109
.ci/travis-prepare.sh Executable file
View File

@@ -0,0 +1,109 @@
#!/bin/sh
set -e -x
CURDIR="$PWD"
cat << EOF > $CURDIR/configure/RELEASE.local
EPICS_BASE=$HOME/.source/epics-base
EOF
install -d "$HOME/.source"
cd "$HOME/.source"
add_gh_flat() {
MODULE=$1
REPOOWNER=$2
REPONAME=$3
BRANCH=$4
MODULE_UC=$(echo $MODULE | tr 'a-z' 'A-Z')
( git clone --quiet --depth 5 --branch $BRANCH https://github.com/$REPOOWNER/$REPONAME.git $MODULE && \
cd $MODULE && git log -n1 )
cat < $CURDIR/configure/RELEASE.local > $MODULE/configure/RELEASE.local
cat << EOF >> $CURDIR/configure/RELEASE.local
${MODULE_UC}=$HOME/.source/$MODULE
EOF
}
# not recursive
git clone --quiet --depth 5 --branch "$BRBASE" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
(cd epics-base && git log -n1 )
add_gh_flat pvData ${REPOPVD:-epics-base} pvDataCPP ${BRPVD:-master}
add_gh_flat pvAccess ${REPOPVA:-epics-base} pvAccessCPP ${BRPVA:-master}
if [ -e $CURDIR/configure/RELEASE.local ]
then
cat $CURDIR/configure/RELEASE.local
fi
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
# requires wine and g++-mingw-w64-i686
if [ "$WINE" = "32" ]
then
echo "Cross mingw32"
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
CMPLR_PREFIX=i686-w64-mingw32-
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
EOF
fi
if [ "$STATIC" = "YES" ]
then
echo "Build static libraries/executables"
cat << EOF >> epics-base/configure/CONFIG_SITE
SHARED_LIBRARIES=NO
STATIC_BUILD=YES
EOF
fi
case "$CMPLR" in
clang)
echo "Host compiler is clang"
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
GNU = NO
CMPLR_CLASS = clang
CC = clang
CCC = clang++
EOF
# hack
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
clang --version
;;
*)
echo "Host compiler is default"
gcc --version
;;
esac
cat <<EOF >> epics-base/configure/CONFIG_SITE
USR_CPPFLAGS += $USR_CPPFLAGS
USR_CFLAGS += $USR_CFLAGS
USR_CXXFLAGS += $USR_CXXFLAGS
EOF
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
| tar -C / -xmj
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
RTEMS_BASE=$HOME/.rtems
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
EOF
fi
make -j2 -C epics-base $EXTRA
make -j2 -C pvData $EXTRA
make -j2 -C pvAccess $EXTRA

28
.gitignore vendored
View File

@@ -1,13 +1,17 @@
bin/
lib/
doc/
include/
db/
dbd/
documentation/html
documentation/*.tag
/cfg/
/bin/
/lib/
/db/
/dbd/
/html/
/include/
/templates/
/configure/*.local
/documentation/html
/documentation/*.tag
O.*/
/QtC-*
envPaths
configure/*.local
!configure/ExampleRELEASE.local
**/O.*
QtC-*
*.orig
*.log
.*.swp

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

31
.travis.yml Normal file
View File

@@ -0,0 +1,31 @@
sudo: false
dist: trusty
language: c++
compiler:
- gcc
addons:
apt:
packages:
- libreadline6-dev
- libncurses5-dev
- perl
- clang
- g++-mingw-w64-i686
- qemu-system-x86
install:
- ./.ci/travis-prepare.sh
script:
- ./.ci/travis-build.sh
env:
- BRBASE=7.0
- BRBASE=7.0 CMPLR=clang
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++98"
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++11"
- BRBASE=7.0 CMPLR=clang EXTRA="CMD_CXXFLAGS=-std=c++11"
- BRBASE=7.0 WINE=32 TEST=NO STATIC=YES
- BRBASE=7.0 WINE=32 TEST=NO STATIC=NO
- BRBASE=7.0 RTEMS=4.10 TEST=NO
- BRBASE=7.0 RTEMS=4.9 TEST=NO
- BRBASE=3.16
- BRBASE=3.15

389
Doxyfile
View File

@@ -1,4 +1,4 @@
# Doxyfile 1.8.6
# Doxyfile 1.8.10
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -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
@@ -46,10 +46,10 @@ PROJECT_NUMBER =
PROJECT_BRIEF =
# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
# the documentation. The maximum height of the logo should not exceed 55 pixels
# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
# to the output directory.
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
@@ -60,7 +60,7 @@ PROJECT_LOGO =
OUTPUT_DIRECTORY =
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
@@ -70,6 +70,14 @@ OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
# U+3044.
# The default value is: NO.
ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
@@ -85,14 +93,14 @@ CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
@@ -127,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = YES
# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
@@ -197,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
# new page for each member. If set to NO, the documentation of a member will be
# part of the file/class/namespace that contains it.
# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
# page for each member. If set to NO, the documentation of a member will be part
# of the file/class/namespace that contains it.
# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
@@ -261,11 +269,14 @@ OPTIMIZE_OUTPUT_VHDL = NO
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# (default is Fortran), use: inc=Fortran f=C.
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
#
# Note For files without extension you can use no_extension as a placeholder.
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
@@ -284,8 +295,8 @@ MARKDOWN_SUPPORT = YES
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by by putting a % sign in front of the word
# or globally by setting AUTOLINK_SUPPORT to NO.
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
@@ -325,13 +336,20 @@ SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
# If one adds a struct or class to a group and this option is enabled, then also
# any nested class or struct is added to the same group. By default this option
# is disabled and one has to add nested compounds explicitly via \ingroup.
# The default value is: NO.
GROUP_NESTED_COMPOUNDS = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
@@ -390,7 +408,7 @@ LOOKUP_CACHE_SIZE = 0
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -400,35 +418,35 @@ LOOKUP_CACHE_SIZE = 0
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = NO
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
EXTRACT_PACKAGE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
EXTRACT_STATIC = NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO,
# only classes defined in header files are included. Does not have any effect
# for Java sources.
# The default value is: YES.
EXTRACT_LOCAL_CLASSES = NO
# This flag is only useful for Objective-C code. When set to YES local methods,
# This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are
# included in the documentation. If set to NO only methods in the interface are
# included in the documentation. If set to NO, only methods in the interface are
# included.
# The default value is: NO.
@@ -453,21 +471,21 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO these classes will be included in the various overviews. This option has
# no effect if EXTRACT_ALL is enabled.
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO these declarations will be
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
# documentation blocks found inside the body of a function. If set to NO these
# documentation blocks found inside the body of a function. If set to NO, these
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
@@ -481,7 +499,7 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES upper-case letters are also
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
@@ -490,12 +508,19 @@ INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES the
# their full class and namespace scopes in the documentation. If set to YES, the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
# YES the compound reference will be hidden.
# The default value is: NO.
HIDE_COMPOUND_REFERENCE= NO
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
@@ -523,14 +548,14 @@ INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member
# name. If set to NO the members will appear in declaration order.
# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
# name. If set to NO the members will appear in declaration order. Note that
# name. If set to NO, the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
@@ -575,27 +600,25 @@ SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
# todo list. This list is created by putting \todo commands in the
# documentation.
# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
# list. This list is created by putting \todo commands in the documentation.
# The default value is: YES.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
# test list. This list is created by putting \test commands in the
# documentation.
# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
# list. This list is created by putting \test commands in the documentation.
# The default value is: YES.
GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
# list. This list is created by putting \bug commands in the documentation.
# The default value is: YES.
GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
# the deprecated list. This list is created by putting \deprecated commands in
# the documentation.
# The default value is: YES.
@@ -620,8 +643,8 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
# the bottom of the documentation of classes and structs. If set to YES the list
# will mention the files that were used to generate the documentation.
# the bottom of the documentation of classes and structs. If set to YES, the
# list will mention the files that were used to generate the documentation.
# The default value is: YES.
SHOW_USED_FILES = YES
@@ -669,8 +692,7 @@ LAYOUT_FILE =
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. Do not use file names with spaces, bibtex cannot handle them. See
# also \cite for info how to create references.
# search path. See also \cite for info how to create references.
CITE_BIB_FILES =
@@ -686,7 +708,7 @@ CITE_BIB_FILES =
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
# this implies that the warnings are on.
#
# Tip: Turn warnings on while writing the documentation.
@@ -694,7 +716,7 @@ QUIET = NO
WARNINGS = YES
# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
@@ -711,8 +733,8 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO doxygen will only warn about wrong or incomplete parameter
# documentation, but not about the absence of documentation.
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
@@ -740,10 +762,10 @@ WARN_LOGFILE =
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces.
# 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
@@ -756,12 +778,17 @@ INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank the
# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
# *.qsf, *.as and *.js.
# *.h) to filter out the source-files in the directories.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd,
# *.vhdl, *.ucf, *.qsf, *.as and *.js.
FILE_PATTERNS =
@@ -860,7 +887,7 @@ INPUT_FILTER =
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER ) will also be used to filter the input files that are used for
# INPUT_FILTER) will also be used to filter the input files that are used for
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO.
@@ -920,7 +947,7 @@ REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation.
# The default value is: YES.
@@ -997,7 +1024,7 @@ IGNORE_PREFIX =
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = YES
@@ -1008,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).
@@ -1059,13 +1086,15 @@ HTML_FOOTER =
HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
# defined cascading style sheet that is included after the standard style sheets
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
# standard style sheet and is therefor more robust against future updates.
# Doxygen will copy the style sheet file to the output directory. For an example
# see the documentation.
# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@@ -1078,10 +1107,10 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES = documentation/pvDatabaseCPP.html
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the stylesheet and background images according to
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
@@ -1112,8 +1141,9 @@ HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: YES.
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
@@ -1209,28 +1239,29 @@ GENERATE_HTMLHELP = NO
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler ( hhc.exe). If non-empty
# including file name) of the HTML help compiler (hhc.exe). If non-empty,
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated (
# YES) or that it should be included in the master .chm file ( NO).
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated (
# YES) or a normal table of contents ( NO) in the .chm file.
# The BINARY_TOC flag controls whether a binary table of contents is generated
# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1343,7 +1374,7 @@ DISABLE_INDEX = NO
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
@@ -1371,7 +1402,7 @@ ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1400,7 +1431,7 @@ FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using prerendered bitmaps. Use this if you do not have LaTeX
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option.
@@ -1470,11 +1501,11 @@ SEARCHENGINE = NO
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# are two flavours of web server based searching depending on the
# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
# searching and an index file used by the script. When EXTERNAL_SEARCH is
# enabled the indexing and searching needs to be provided by external tools. See
# the section "External Indexing and Searching" for details.
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
# and searching needs to be provided by external tools. See the section
# "External Indexing and Searching" for details.
# The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1486,7 +1517,7 @@ SERVER_BASED_SEARCH = NO
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
# search results.
#
# Doxygen ships with an example indexer ( doxyindexer) and search engine
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/).
#
@@ -1499,7 +1530,7 @@ EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
# which will return the search results when EXTERNAL_SEARCH is enabled.
#
# Doxygen ships with an example indexer ( doxyindexer) and search engine
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/). See the section "External Indexing and
# Searching" for details.
@@ -1537,7 +1568,7 @@ EXTRA_SEARCH_MAPPINGS =
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
@@ -1568,7 +1599,7 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1586,9 +1617,12 @@ COMPACT_LATEX = NO
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
# that should be included in the LaTeX output. To get the times font for
# instance you can specify
# EXTRA_PACKAGES=times
# that should be included in the LaTeX output. The package can be specified just
# by its name or with the correct syntax as to be used with the LaTeX
# \usepackage command. To get the times font for instance you can specify :
# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
# To use the option intlimits with the amsmath package you can specify:
# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1602,23 +1636,36 @@ EXTRA_PACKAGES =
#
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
# replace them by respectively the title of the page, the current date and time,
# only the current date, the version number of doxygen, the project name (see
# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
# string, for the replacement values of the other commands the user is referred
# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last
# chapter. If it is left blank doxygen will generate a standard footer.
# chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer.
#
# Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# LaTeX style sheets that are included after the standard style sheets created
# by doxygen. Using this option one can overrule certain style aspects. Doxygen
# will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list).
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_STYLESHEET =
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or
@@ -1636,8 +1683,8 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = NO
# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES to get a
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1678,11 +1725,19 @@ LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors.
# The default value is: NO.
@@ -1697,7 +1752,7 @@ GENERATE_RTF = NO
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1734,11 +1789,21 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
# classes and files.
# The default value is: NO.
@@ -1762,6 +1827,13 @@ MAN_OUTPUT = man
MAN_EXTENSION = .3
# The MAN_SUBDIR tag determines the name of the directory created within
# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
# MAN_EXTENSION with the initial . removed.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_SUBDIR =
# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
# will generate one additional man file for each entity documented in the real
# man page(s). These additional files only source the real man page, but without
@@ -1775,7 +1847,7 @@ MAN_LINKS = NO
# Configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
@@ -1789,19 +1861,7 @@ GENERATE_XML = NO
XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_SCHEMA =
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size
# of the XML output.
@@ -1814,7 +1874,7 @@ XML_PROGRAMLISTING = YES
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
# that can be used to generate PDF.
# The default value is: NO.
@@ -1828,14 +1888,23 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
# Definitions (see http://autogen.sf.net) file that captures the structure of
# the code including all documentation. Note that this feature is still
# experimental and incomplete at the moment.
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sf.net) file that captures the
# structure of the code including all documentation. Note that this feature is
# still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@@ -1844,7 +1913,7 @@ GENERATE_AUTOGEN_DEF = NO
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
# file that captures the structure of the code including all documentation.
#
# Note that this feature is still experimental and incomplete at the moment.
@@ -1852,7 +1921,7 @@ GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output.
# The default value is: NO.
@@ -1860,9 +1929,9 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
# formatted so it can be parsed by a human reader. This is useful if you want to
# understand what is going on. On the other hand, if this tag is set to NO the
# understand what is going on. On the other hand, if this tag is set to NO, the
# size of the Perl module output will be much smaller and Perl will parse it
# just the same.
# The default value is: YES.
@@ -1882,14 +1951,14 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
# in the source code. If set to NO only conditional compilation will be
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES.
# The default value is: NO.
@@ -1905,7 +1974,7 @@ MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES the includes files in the
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1947,9 +2016,9 @@ PREDEFINED =
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all refrences to function-like macros that are alone on a line, have an
# all uppercase name, and do not end with a semicolon. Such function macros are
# typically used for boiler-plate code, and will confuse the parser if not
# remove all references to function-like macros that are alone on a line, have
# an all uppercase name, and do not end with a semicolon. Such function macros
# are typically used for boiler-plate code, and will confuse the parser if not
# removed.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1969,7 +2038,7 @@ SKIP_FUNCTION_MACROS = YES
# where loc1 and loc2 can be relative or absolute paths or URLs. See the
# section "Linking to external documentation" for more information about the use
# of tag files.
# Note: Each tag file must have an unique name (where the name does NOT include
# Note: Each tag file must have a unique name (where the name does NOT include
# the path). If a tag file is not located in the directory in which doxygen is
# run, you must also specify the path to the tagfile here.
@@ -1981,20 +2050,21 @@ TAGFILES =
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
# class index. If set to NO only the inherited external classes will be listed.
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
# listed.
# The default value is: NO.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
# the modules index. If set to NO, only the current project's groups will be
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
EXTERNAL_GROUPS = YES
# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
# the related pages index. If set to NO, only the current project's pages will
# be listed.
# The default value is: YES.
@@ -2011,7 +2081,7 @@ PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
@@ -2036,7 +2106,7 @@ MSCGEN_PATH =
DIA_PATH =
# If set to YES, the inheritance and collaboration graphs will hide inheritance
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@@ -2061,7 +2131,7 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0
# When you want a differently looking font n the dot files that doxygen
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
@@ -2109,7 +2179,7 @@ COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
# The default value is: NO.
@@ -2161,7 +2231,8 @@ INCLUDED_BY_GRAPH = YES
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected
# functions only using the \callgraph command.
# functions only using the \callgraph command. Disabling a call graph can be
# accomplished by means of the command \hidecallgraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2172,7 +2243,8 @@ CALL_GRAPH = NO
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected
# functions only using the \callergraph command.
# functions only using the \callergraph command. Disabling a caller graph can be
# accomplished by means of the command \hidecallergraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2195,11 +2267,15 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot.
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
# http://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
# Possible values are: png, jpg, gif and svg.
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2242,6 +2318,19 @@ MSCFILE_DIRS =
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
PLANTUML_JAR_PATH =
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
PLANTUML_INCLUDE_PATH =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized
@@ -2278,7 +2367,7 @@ MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default.
@@ -2295,7 +2384,7 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# files that are used to generate the various graphs.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.

75
LICENSE
View File

@@ -1,12 +1,17 @@
Copyright and License Terms
---------------------------
Copyright (c) 2008 Martin R. Kraimer
Copyright (c) 2006 The University of Chicago, as Operator of Argonne
Copyright (c) 2006-2016 Martin R. Kraimer
Copyright (c) 2006-2016 UChicago Argonne LLC, as Operator of Argonne
National Laboratory.
Copyright (c) 2006 Deutsches Elektronen-Synchrotron,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
Copyright (c) 2007 Control System Laboratory,
Copyright (c) 2007-2016 Control System Laboratory,
(COSYLAB) Ljubljana Slovenia
Copyright (c) 2010-2016 Brookhaven Science Associates, as Operator
of Brookhaven National Laboratory
Copyright (c) 2011-2016 Diamond Light Source Limited,
(DLS) Didcot, United Kingdom
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
@@ -31,48 +36,30 @@ OTHER DEALINGS IN THE SOFTWARE.
________________________________________________________________________
This software is in part copyrighted by the University of Chicago (UofC)
Additional Disclaimers
----------------------
In no event shall UofC be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
UofC has been advised of the possibility of such damage.
This software is copyright in part by these institutions:
UofC specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and UofC has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
* Brookhaven Science Associates, as Operator of Brookhaven
National Laboratory, New York, USA
* Control System Laboratory, Ljubljana, Slovenia
* Deutsches Elektronen-Synchroton, Member of the Helmholtz
Association, Hamburg, Germany
* Diamond Light Source Limited, Didcot, United Kingdom
* Helmholtz-Zentrum Berlin fuer Materialien und Energie m.b.H.,
Berlin, Germany.
* UChicage Argonne LLC, as Operator of Argonne National Laboratory,
Illinois, USA
________________________________________________________________________
In no event shall these institutions be liable to any party for direct,
indirect, special, incidental, or consequential damages arising out of
the use of this software, its documentation, or any derivatives thereof,
even if advised of the possibility of such damage.
This software is in part copyrighted by the BERLINER SPEICHERRING
GESELLSCHAFT FUER SYNCHROTRONSTRAHLUNG M.B.H. (BESSY), BERLIN, GERMANY.
These institutions specifically disclaim any warranties, including, but
not limited to, the implied warranties of merchantability, fitness for a
particular purpose, and non-infringement. This software is provided on
an "as is" basis, and these institutions have no obligation to provide
maintenance, support, updates, enhancements, or modifications.
In no event shall BESSY be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
BESSY has been advised of the possibility of such damage.
BESSY specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and BESSY has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
________________________________________________________________________
This software is in part copyrighted by the Deutsches Elektronen-Synchroton,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
In no event shall DESY be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
DESY has been advised of the possibility of such damage.
DESY specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and DESY has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
________________________________________________________________________

View File

@@ -1,27 +1,12 @@
#Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), configure)
DIRS := $(DIRS) $(filter-out $(DIRS), src)
DIRS := $(DIRS) $(filter-out $(DIRS), test)
DIRS := $(DIRS) $(filter-out $(DIRS), arrayPerformance)
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard example*))
DIRS += configure
EMBEDDED_TOPS := $(EMBEDDED_TOPS) $(filter-out $(EMBEDDED_TOPS), test)
EMBEDDED_TOPS := $(EMBEDDED_TOPS) $(filter-out $(EMBEDDED_TOPS), arrayPerformance)
EMBEDDED_TOPS := $(EMBEDDED_TOPS) $(filter-out $(EMBEDDED_TOPS), $(wildcard example*))
DIRS += src
src_DEPEND_DIRS = configure
define DIR_template
$(1)_DEPEND_DIRS = configure
endef
$(foreach dir, $(filter-out configure,$(DIRS)),$(eval $(call DIR_template,$(dir))))
define EMB_template
$(1)_DEPEND_DIRS = src
endef
$(foreach dir, $(EMBEDDED_TOPS),$(eval $(call EMB_template,$(dir))))
#exampleDatabase_DEPEND_DIRS += test
#examplePowerSupply_DEPEND_DIRS += test
DIRS += test
test_DEPEND_DIRS = src
include $(TOP)/configure/RULES_TOP

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
If RELEASE.local does not exist then look at <b>configure/RELEASE</b>
for directions for how to build.
Examples
------------
The examples require the database in pvaDatabaseTestCPP.
For example:
mrk> pwd
/home/epicsv4/pvaDatabaseTestCPP/database/iocBoot/exampleDatabase
mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd
Status
------
* The API is for release 4.5.0-pre1
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

@@ -1,11 +0,0 @@
#Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG
DIRS += configure
DIRS += src
src_DEPEND_DIRS = configure
include $(TOP)/configure/RULES_TOP

View File

@@ -1,29 +0,0 @@
# CONFIG - Load build configuration data
#
# Do not make changes to this file!
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif

View File

@@ -1,39 +0,0 @@
# CONFIG_SITE
# Make any application-specific changes to the EPICS build
# configuration variables in this file.
#
# Host/target specific settings can be specified in files named
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# CHECK_RELEASE controls the consistency checking of the support
# applications pointed to by the RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building anyway if conflicts are found.
#CHECK_RELEASE = YES
# Set this when you only want to compile this application
# for a subset of the cross-compiled target architectures
# that Base is built for.
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</path/name/to/install/top>
# Set this when your IOC and the host use different paths
# to access the application. This will be needed to boot
# from a Microsoft FTP server or with some NFS mounts.
# You must rebuild in the iocBoot directory for this to
# take effect.
#IOCS_APPL_TOP = </IOC/path/to/application/top>
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local

View File

@@ -1,8 +0,0 @@
EPICS_BASE=/home/install/epics/base
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
EPICSV4HOME=/home/hg
PVCOMMON=${EPICSV4HOME}/pvCommonCPP
PVDATA=${EPICSV4HOME}/pvDataCPP
PVACCESS=${EPICSV4HOME}/pvAccessCPP
PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP
PVASRV=${EPICSV4HOME}/pvaSrv

View File

@@ -1,8 +0,0 @@
TOP=..
include $(TOP)/configure/CONFIG
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
include $(TOP)/configure/RULES

View File

@@ -1,40 +0,0 @@
# pvDatabaseCPP/arrayPerformance RELEASE - Location of external support modules
#
# IF YOU CHANGE this file or any file it includes you must
# subsequently do a "gnumake rebuild" in the application's
# top level directory.
#
# The build process does not check dependencies against files
# that are outside this application, thus you should also do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
#
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
# EPICS V4 Developers: Do not edit the locations in this file!
#
# Create a file RELEASE.local pointing to your places
# for the dependencies, e.g.
# PVACCESS = /path/to/epics/pvAccessCPP
# PVDATA = /path/to/epics/pvDataCPP
# PVCOMMON = /path/to/epics/pvCommonCPP
# EPICS_BASE = /path/to/epics/base
# If this example is built in a directory under pvDatabaseCPP,
# use the following definitions:
PVDATABASE = $(TOP)/..
-include $(TOP)/../../RELEASE.local
-include $(TOP)/../configure/RELEASE.local
# If you copied this example from pvDatabaseCPP to be built as a
# standalone TOP, define
# PVDATABASE = /path/to/epics/pvDatabaseCPP
# in the appropriate RELEASE[.local],
# and use the following definitions instead:
#-include $(TOP)/../RELEASE.local
#-include $(TOP)/configure/RELEASE.local

View File

@@ -1,6 +0,0 @@
# RULES
include $(CONFIG)/RULES
# Library should be rebuilt because LIBOBJS may have changed.
$(LIBNAME): ../Makefile

View File

@@ -1,2 +0,0 @@
#RULES.ioc
include $(CONFIG)/RULES.ioc

View File

@@ -1,2 +0,0 @@
#RULES_DIRS
include $(CONFIG)/RULES_DIRS

View File

@@ -1,2 +0,0 @@
#RULES_TOP
include $(CONFIG)/RULES_TOP

View File

@@ -1,45 +0,0 @@
TOP = ..
include $(TOP)/configure/CONFIG
LIBRARY_IOC += pvDatabaseExample
pvDatabaseExample_LIBS += pvDatabase pvAccess pvData Com
pvDatabaseExample_LIBS += $(EPICS_BASE_IOC_LIBS)
INC+= arrayPerformance.h
LIBSRCS += arrayPerformance.cpp
INC+= longArrayMonitor.h
LIBSRCS += longArrayMonitor.cpp
INC+= longArrayGet.h
LIBSRCS += longArrayGet.cpp
INC+= longArrayPut.h
LIBSRCS += longArrayPut.cpp
PROD_HOST += arrayPerformanceMain
arrayPerformanceMain_SRCS += arrayPerformanceMain.cpp
arrayPerformanceMain_LIBS += pvDatabase pvAccess pvData Com
arrayPerformanceMain_LIBS += pvDatabaseExample
PROD_HOST += longArrayMonitorMain
longArrayMonitorMain_SRCS += longArrayMonitorMain.cpp
longArrayMonitorMain_LIBS += pvDatabase pvAccess pvData Com
longArrayMonitorMain_LIBS += pvDatabaseExample
PROD_HOST += longArrayGetMain
longArrayGetMain_SRCS += longArrayGetMain.cpp
longArrayGetMain_LIBS += pvDatabase pvAccess pvData Com
longArrayGetMain_LIBS += pvDatabaseExample
PROD_HOST += longArrayPutMain
longArrayPutMain_SRCS += longArrayPutMain.cpp
longArrayPutMain_LIBS += pvDatabase pvAccess pvData Com
longArrayPutMain_LIBS += pvDatabaseExample
PROD_HOST += vectorPerformanceMain
vectorPerformanceMain_SRCS += vectorPerformanceMain.cpp
vectorPerformanceMain_LIBS += pvDatabase pvAccess pvData Com
vectorPerformanceMain_LIBS += pvDatabaseExample
include $(TOP)/configure/RULES

View File

@@ -1,206 +0,0 @@
/* arrayPerformance.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.08
*/
#include <pv/lock.h>
#define epicsExportSharedSymbols
#include <arrayPerformance.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::cout;
using std::endl;
using std::ostringstream;
ArrayPerformancePtr ArrayPerformance::create(
std::string const & recordName,
size_t size,
double delay)
{
epics::pvData::PVStructurePtr pvStructure =
epics::pvData::getStandardPVField()->scalarArray(epics::pvData::pvLong,"timeStamp,alarm");
ArrayPerformancePtr pvRecord(
new ArrayPerformance(recordName,pvStructure,size,delay));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
ArrayPerformance::ArrayPerformance(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,
size_t size,
double delay)
: PVRecord(recordName,pvStructure),
size(size),
delay(delay),
isDestroyed(false)
{
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
}
ArrayPerformance::~ArrayPerformance()
{
}
bool ArrayPerformance::init()
{
initPVRecord();
PVLongArrayPtr pvLongArray = getPVStructure()->getSubField<PVLongArray>("value");
if(!pvLongArray) return false;
pvValue = pvLongArray;
ArrayPerformancePtr xxx = dynamic_pointer_cast<ArrayPerformance>(getPtrSelf());
arrayPerformanceThread = ArrayPerformanceThreadPtr(new ArrayPerformanceThread(xxx));
arrayPerformanceThread->init();
return true;
}
void ArrayPerformance::start()
{
arrayPerformanceThread->start();
}
void ArrayPerformance::process()
{
timeStamp.getCurrent();
pvTimeStamp.set(timeStamp);
}
void ArrayPerformance::destroy()
{
if(isDestroyed) return;
isDestroyed = true;
arrayPerformanceThread->destroy();
arrayPerformanceThread.reset();
PVRecord::destroy();
}
ArrayPerformanceThread::ArrayPerformanceThread(ArrayPerformancePtr const & arrayPerformance)
:
arrayPerformance(arrayPerformance),
isDestroyed(false),
runReturned(false),
threadName("arrayPerformance"),
value(0)
{}
void ArrayPerformanceThread::init()
{
thread = std::auto_ptr<epicsThread>(new epicsThread(
*this,
threadName.c_str(),
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityHigh));
}
void ArrayPerformanceThread::start()
{
thread->start();
}
void ArrayPerformanceThread::destroy()
{
Lock lock(mutex);
if(isDestroyed) return;
isDestroyed = true;
while(true) {
if(runReturned) break;
lock.unlock();
epicsThreadSleep(.01);
lock.lock();
}
thread->exitWait();
thread.reset();
arrayPerformance.reset();
}
void ArrayPerformanceThread::run()
{
TimeStamp timeStamp;
TimeStamp timeStampLast;
timeStampLast.getCurrent();
int nSinceLastReport = 0;
while(true) {
if(arrayPerformance->delay>0.0) epicsThreadSleep(arrayPerformance->delay);
{
Lock lock(mutex);
if(isDestroyed) {
runReturned = true;
return;
}
}
timeStamp.getCurrent();
double diff = TimeStamp::diff(timeStamp,timeStampLast);
if(diff>=1.0) {
ostringstream out;
out << "arrayPerformance value " << value;
out << " time " << diff ;
double iterations = nSinceLastReport;
iterations /= diff;
if(iterations>10.0e9) {
iterations /= 1e9;
out << " gigaIterations/sec " << iterations;
} else if(iterations>10.0e6) {
iterations /= 1e6;
out << " megaIterations/sec " << iterations;
} else if(iterations>10.0e3) {
iterations /= 1e3;
out << " kiloIterations/sec " << iterations;
} else {
out << " Iterations/sec " << iterations;
}
double elementSize = arrayPerformance->size;
double elementsPerSecond = elementSize*nSinceLastReport;
elementsPerSecond /= diff;
if(elementsPerSecond>10.0e9) {
elementsPerSecond /= 1e9;
out << " gigaElements/sec " << elementsPerSecond;
} else if(elementsPerSecond>10.0e6) {
elementsPerSecond /= 1e6;
out << " megaElements/sec " << elementsPerSecond;
} else if(elementsPerSecond>10.0e3) {
elementsPerSecond /= 1e3;
out << " kiloElements/sec " << elementsPerSecond;
} else {
out << " Elements/sec " << elementsPerSecond;
}
cout << out.str() << endl;
timeStampLast = timeStamp;
nSinceLastReport = 0;
}
++nSinceLastReport;
arrayPerformance->lock();
try {
if(arrayPerformance->getTraceLevel()>1) {
cout << "arrayPerformance size " << arrayPerformance->size;
cout << " value " << value +1 << endl;
}
shared_vector<int64> xxx(arrayPerformance->size,value++);
shared_vector<const int64> data(freeze(xxx));
arrayPerformance->beginGroupPut();
arrayPerformance->pvValue->replace(data);
arrayPerformance->process();
arrayPerformance->endGroupPut();
} catch(...) {
arrayPerformance->unlock();
throw;
}
arrayPerformance->unlock();
}
}
}}

View File

@@ -1,92 +0,0 @@
/* arrayPerformance.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.08
*/
#ifndef ARRAYPERFORMANCE_H
#define ARRAYPERFORMANCE_H
#ifdef epicsExportSharedSymbols
# define arrayperformanceEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <epicsThread.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/pvDatabase.h>
#ifdef arrayperformanceEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef arrayperformanceEpicsExportSharedSymbols
# include <shareLib.h>
#endif
namespace epics { namespace pvDatabase {
class ArrayPerformance;
typedef std::tr1::shared_ptr<ArrayPerformance> ArrayPerformancePtr;
class ArrayPerformanceThread;
typedef std::tr1::shared_ptr<ArrayPerformanceThread> ArrayPerformanceThreadPtr;
class epicsShareClass ArrayPerformance :
public PVRecord
{
public:
POINTER_DEFINITIONS(ArrayPerformance);
static ArrayPerformancePtr create(
std::string const & recordName,
size_t size,
double delay);
virtual ~ArrayPerformance();
virtual bool init();
virtual void start();
virtual void process();
virtual void destroy();
private:
ArrayPerformance(std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,
size_t size,
double delay);
size_t size;
double delay;
bool isDestroyed;
epics::pvData::PVLongArrayPtr pvValue;
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
ArrayPerformanceThreadPtr arrayPerformanceThread;
friend class ArrayPerformanceThread;
};
class epicsShareClass ArrayPerformanceThread :
public epicsThreadRunable
{
public:
ArrayPerformanceThread(ArrayPerformancePtr const & arrayPerformance);
virtual ~ArrayPerformanceThread(){};
void init();
void start();
virtual void run();
void destroy();
private:
ArrayPerformancePtr arrayPerformance;
bool isDestroyed;
bool runReturned;
std::string threadName;
epics::pvData::Mutex mutex;
epics::pvData::int64 value;
std::auto_ptr<epicsThread> thread;
};
}}
#endif /* ARRAYPERFORMANCE_H */

View File

@@ -1,119 +0,0 @@
/*arrayPerformanceMain.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.08
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <vector>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/traceRecord.h>
#include <pv/channelProviderLocal.h>
#include <pv/serverContext.h>
#include <pv/clientFactory.h>
#include <arrayPerformance.h>
#include <longArrayMonitor.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
int main(int argc,char *argv[])
{
bool result(false);
string recordName;
recordName = "arrayPerformance";
size_t size = 10000000;
double delay = .0001;
string providerName("local");
size_t nMonitor = 1;
int queueSize = 2;
double waitTime = 0.0;
if(argc==2 && string(argv[1])==string("-help")) {
cout << "arrayPerformanceMain recordName size";
cout << " delay providerName nMonitor queueSize waitTime" << endl;
cout << "default" << endl;
cout << "arrayPerformance ";
cout << recordName << " ";
cout << size << " ";
cout << delay << " ";
cout << providerName << " ";
cout << nMonitor << " ";
cout << queueSize << " ";
cout << "0.0" << endl;
return 0;
}
if(argc>1) recordName = argv[1];
if(argc>2) size = strtoul(argv[2],0,0);
if(argc>3) delay = atof(argv[3]);
if(argc>4) providerName = argv[4];
if(argc>5) nMonitor = strtoul(argv[5],0,0);
if(argc>6) queueSize = strtol(argv[6],0,0);
if(argc>7) waitTime = atof(argv[7]);
cout << "arrayPerformance ";
cout << recordName << " ";
cout << size << " ";
cout << delay << " ";
cout << providerName << " ";
cout << nMonitor << " ";
cout << queueSize << " ";
cout << waitTime << endl;
ClientFactory::start();
PVDatabasePtr master = PVDatabase::getMaster();
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
PVRecordPtr pvRecord;
pvRecord = ArrayPerformance::create(recordName,size,delay);
result = master->addRecord(pvRecord);
PVRecordPtr arrayPreformance = pvRecord;
arrayPreformance->setTraceLevel(0);
pvRecord = TraceRecord::create("traceRecordPGRPC");
result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
pvRecord.reset();
ServerContext::shared_pointer pvaServer =
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
std::vector<LongArrayMonitorPtr> longArrayMonitor(nMonitor);
for(size_t i=0; i<nMonitor; ++i) {
longArrayMonitor[i]
= LongArrayMonitor::create(providerName,recordName,queueSize,waitTime);
}
epicsThreadSleep(1.0);
for(size_t i=0; i<nMonitor; ++i) longArrayMonitor[i]->start();
cout << "arrayPerformance\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
arrayPreformance.reset();
for(size_t i=0; i<nMonitor; ++i) longArrayMonitor[i]->stop();
for(size_t i=0; i<nMonitor; ++i) longArrayMonitor[i]->destroy();
pvaServer->shutdown();
epicsThreadSleep(1.0);
pvaServer->destroy();
ClientFactory::stop();
epicsThreadSleep(1.0);
channelProvider->destroy();
return 0;
}

View File

@@ -1,543 +0,0 @@
/* longArrayGet.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.09
*/
#include <epicsThread.h>
#include <pv/caProvider.h>
#define epicsExportSharedSymbols
#include <longArrayGet.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using namespace epics::pvAccess;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::cout;
using std::endl;
using std::ostringstream;
using std::string;
static string requesterName("longArrayGet");
static string request("value,timeStamp,alarm");
static epics::pvData::Mutex printMutex;
class LongArrayChannelRequester;
typedef std::tr1::shared_ptr<LongArrayChannelRequester> LongArrayChannelRequesterPtr;
class LongArrayChannelGetRequester;
typedef std::tr1::shared_ptr<LongArrayChannelGetRequester> LongArrayChannelGetRequesterPtr;
class LongArrayChannelRequester :
virtual public ChannelRequester,
public std::tr1::enable_shared_from_this<LongArrayChannelRequester>
{
public:
LongArrayChannelRequester(
LongArrayChannelGetPtr const & longArrayChannelGet)
: longArrayChannelGet(longArrayChannelGet),
isDestroyed(false)
{}
virtual ~LongArrayChannelRequester(){}
virtual void destroy()
{
Lock guard(mutex);
if(isDestroyed) return;
isDestroyed = true;
longArrayChannelGet.reset();
}
virtual string getRequesterName() { return requesterName;}
virtual void message(string const & message, MessageType messageType)
{
Lock guard(printMutex);
cout << requesterName << " message " << message << endl;
}
virtual void channelCreated(
const Status& status,
Channel::shared_pointer const & channel);
virtual void channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState);
private:
LongArrayChannelRequesterPtr getPtrSelf()
{
return shared_from_this();
}
LongArrayChannelGetPtr longArrayChannelGet;
bool isDestroyed;
Mutex mutex;
};
class LongArrayChannelGetRequester :
virtual public ChannelGetRequester,
public std::tr1::enable_shared_from_this<LongArrayChannelGetRequester>
{
public:
LongArrayChannelGetRequester(
LongArrayChannelGetPtr const & longArrayChannelGet)
: longArrayChannelGet(longArrayChannelGet),
isDestroyed(false)
{}
virtual ~LongArrayChannelGetRequester(){}
virtual void destroy()
{
Lock guard(mutex);
if(isDestroyed) return;
isDestroyed = true;
longArrayChannelGet.reset();
}
virtual string getRequesterName() { return requesterName;}
virtual void message(string const & message, MessageType messageType)
{
Lock guard(printMutex);
cout << requesterName << " message " << message << endl;
}
virtual void channelGetConnect(
Status const & status,
ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const &structure);
virtual void getDone(
Status const & status,
ChannelGet::shared_pointer const & channelGet,
PVStructurePtr const &pvStructure,
BitSetPtr const & bitSet);
private:
LongArrayChannelGetRequesterPtr getPtrSelf()
{
return shared_from_this();
}
LongArrayChannelGetPtr longArrayChannelGet;
bool isDestroyed;
Mutex mutex;
};
class LongArrayChannelGet :
public std::tr1::enable_shared_from_this<LongArrayChannelGet>,
public epicsThreadRunable
{
public:
LongArrayChannelGet(
string providerName,
string channelName,
int iterBetweenCreateChannel,
int iterBetweenCreateChannelGet,
double delayTime)
: providerName(providerName),
channelName(channelName),
iterBetweenCreateChannel(iterBetweenCreateChannel),
iterBetweenCreateChannelGet(iterBetweenCreateChannelGet),
delayTime(delayTime),
isDestroyed(false),
runReturned(false),
threadName("longArrayGet")
{}
virtual ~LongArrayChannelGet(){}
bool init();
virtual void destroy();
virtual void run();
void message(string const & message, MessageType messageType)
{
Lock guard(printMutex);
cout << requesterName << " message " << message << endl;
}
virtual void channelCreated(
const Status& status,
Channel::shared_pointer const & channel);
virtual void channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState);
virtual void channelGetConnect(
Status const & status,
ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const &structure);
virtual void getDone(
Status const & status,
ChannelGet::shared_pointer channelGet,
PVStructurePtr const &pvStructure,
BitSetPtr const & bitSet);
private:
LongArrayChannelGetPtr getPtrSelf()
{
return shared_from_this();
}
size_t checkResult();
string providerName;
string channelName;
int iterBetweenCreateChannel;
int iterBetweenCreateChannelGet;
double delayTime;
bool isDestroyed;
bool runReturned;
std::string threadName;
Status status;
Event event;
Mutex mutex;
std::auto_ptr<epicsThread> thread;
Channel::shared_pointer channel;
ChannelGet::shared_pointer channelGet;
PVStructurePtr pvStructure;
BitSetPtr bitSet;
LongArrayChannelRequesterPtr longArrayChannelRequester;
LongArrayChannelGetRequesterPtr longArrayChannelGetRequester;
};
void LongArrayChannelRequester::channelCreated(
const Status& status,
Channel::shared_pointer const & channel)
{
Lock guard(mutex);
if(isDestroyed) return;
longArrayChannelGet->channelCreated(status,channel);
}
void LongArrayChannelRequester::channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState)
{
string mess(Channel::ConnectionStateNames[connectionState]);
message(mess,infoMessage);
Lock guard(mutex);
if(isDestroyed) return;
longArrayChannelGet->channelStateChange(channel,connectionState);
}
void LongArrayChannelGetRequester::channelGetConnect(
Status const & status,
ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const &structure)
{
Lock guard(mutex);
if(isDestroyed) return;
longArrayChannelGet->channelGetConnect(
status,channelGet,structure);
}
void LongArrayChannelGetRequester::getDone(
Status const & status,
ChannelGet::shared_pointer const & channelGet,
PVStructurePtr const &pvStructure,
BitSetPtr const & bitSet)
{
Lock guard(mutex);
if(isDestroyed) return;
longArrayChannelGet->getDone(status,channelGet,pvStructure,bitSet);
}
void LongArrayChannelGet::channelCreated(
const Status& status,
Channel::shared_pointer const & channel)
{
if(!status.isOK()) message(status.getMessage(),errorMessage);
this->status = status;
this->channel = channel;
event.signal();
}
void LongArrayChannelGet::channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState)
{
MessageType messageType =
(connectionState==Channel::CONNECTED ? infoMessage : errorMessage);
message("channelStateChange",messageType);
}
void LongArrayChannelGet::channelGetConnect(
Status const & status,
ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const &structure)
{
this->status = status;
if(!status.isOK()) {
message(status.getMessage(),errorMessage);
event.signal();
return;
}
this->channelGet = channelGet;
bool structureOK(true);
PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure);
PVFieldPtr pvField = pvStructure->getSubField("timeStamp");
if(!pvField) structureOK = false;
pvField = pvStructure->getSubField("value");
if(!pvField) {
structureOK = false;
} else {
FieldConstPtr field = pvField->getField();
if(field->getType()!=scalarArray) {
structureOK = false;
} else {
ScalarArrayConstPtr scalarArray = dynamic_pointer_cast<const ScalarArray>(field);
if(scalarArray->getElementType()!=pvLong) structureOK = false;
}
}
if(!structureOK) {
string mess("channelGetConnect: illegal structure");
message(mess,errorMessage);
this->status = Status(Status::STATUSTYPE_ERROR,mess);
}
event.signal();
}
bool LongArrayChannelGet::init()
{
ChannelProvider::shared_pointer channelProvider =
getChannelProviderRegistry()->getProvider(providerName);
if(!channelProvider) {
cout << "provider " << providerName << " not found" << endl;
return false;
}
longArrayChannelRequester.reset(new LongArrayChannelRequester(getPtrSelf()));
channel = channelProvider->createChannel(
channelName,
longArrayChannelRequester);
event.wait();
channelProvider.reset();
if(!status.isOK()) return false;
CreateRequest::shared_pointer createRequest = CreateRequest::create();
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
cout << "request logic error " << createRequest->getMessage() << endl;
return false;
}
longArrayChannelGetRequester.reset(new LongArrayChannelGetRequester(getPtrSelf()));
channelGet = channel->createChannelGet(
longArrayChannelGetRequester,
pvRequest);
event.wait();
if(!status.isOK()) return false;
thread = std::auto_ptr<epicsThread>(new epicsThread(
*this,
threadName.c_str(),
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityLow));
thread->start();
event.signal();
return true;
}
void LongArrayChannelGet::destroy()
{
if(isDestroyed) return;
isDestroyed = true;
event.signal();
while(true) {
if(runReturned) break;
epicsThreadSleep(.01);
}
if(longArrayChannelRequester) {
longArrayChannelRequester->destroy();
}
if(longArrayChannelGetRequester) {
longArrayChannelGetRequester->destroy();
}
thread->exitWait();
channel->destroy();
channelGet.reset();
channel.reset();
}
void LongArrayChannelGet::run()
{
while(true) {
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
TimeStamp timeStamp;
TimeStamp timeStampLast;
timeStampLast.getCurrent();
int numChannelGet = 0;
int numChannelCreate = 0;
size_t nElements = 0;
while(true) {
channelGet->get();
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
size_t latestSize = checkResult();
nElements += latestSize;
timeStamp.getCurrent();
double diff = TimeStamp::diff(timeStamp,timeStampLast);
if(diff>=1.0) {
ostringstream out;
out << "get";
double elementsPerSec = nElements;
elementsPerSec /= diff;
if(elementsPerSec>10.0e9) {
elementsPerSec /= 1e9;
out << " gigaElements/sec " << elementsPerSec;
} else if(elementsPerSec>10.0e6) {
elementsPerSec /= 1e6;
out << " megaElements/sec " << elementsPerSec;
} else if(elementsPerSec>10.0e3) {
elementsPerSec /= 1e3;
out << " kiloElements/sec " << elementsPerSec;
} else {
out << " Elements/sec " << elementsPerSec;
}
cout << out.str() << endl;
timeStampLast = timeStamp;
nElements = 0;
}
if(delayTime>0.0) epicsThreadSleep(delayTime);
if(isDestroyed) {
runReturned = true;
return;
}
++numChannelCreate;
bool createGet = false;
if(iterBetweenCreateChannel!=0) {
if(numChannelCreate>=iterBetweenCreateChannel) {
longArrayChannelRequester->destroy();
channel->destroy();
ChannelProvider::shared_pointer channelProvider =
getChannelProviderRegistry()->getProvider(providerName);
longArrayChannelRequester.reset(new LongArrayChannelRequester(getPtrSelf()));
channel = channelProvider->createChannel(
channelName,
longArrayChannelRequester);
event.wait();
channelProvider.reset();
if(!status.isOK()) {
message(status.getMessage(),errorMessage);
return;
}
cout<< "createChannel success" << endl;
createGet = true;
numChannelCreate = 0;
}
}
++numChannelGet;
if(iterBetweenCreateChannelGet!=0) {
if(numChannelGet>=iterBetweenCreateChannelGet) createGet = true;
}
if(createGet) {
numChannelGet = 0;
longArrayChannelGetRequester->destroy();
channelGet->destroy();
CreateRequest::shared_pointer createRequest =
CreateRequest::create();
PVStructurePtr pvRequest =
createRequest->createRequest(request);
if(!pvRequest) {
cout << "request logic error " << createRequest->getMessage() << endl;
return ;
}
longArrayChannelGetRequester.reset(new LongArrayChannelGetRequester(getPtrSelf()));
channelGet = channel->createChannelGet(
longArrayChannelGetRequester,
pvRequest);
event.wait();
if(!status.isOK()) {
message(status.getMessage(),errorMessage);
return;
}
cout<< "createChannelGet success" << endl;
}
}
}
}
void LongArrayChannelGet::getDone(
Status const & status,
ChannelGet::shared_pointer channelGet,
PVStructurePtr const &pvStructure,
BitSetPtr const & bitSet)
{
this->pvStructure = pvStructure;
this->bitSet = bitSet;
event.signal();
}
size_t LongArrayChannelGet::checkResult()
{
PVLongArrayPtr pvValue;
if(!status.isOK()) {
message(status.getMessage(),errorMessage);
return 0;
}
pvValue = dynamic_pointer_cast<PVLongArray>(pvStructure->getSubField("value"));
if(!bitSet->get(pvValue->getFieldOffset())) {
return 0;
}
bitSet->clear();
shared_vector<const int64> data = pvValue->view();
if(data.size()>0) {
int64 first = data[0];
int64 last = data[data.size()-1];
if(first!=last) {
cout << "error first=" << first << " last=" << last << endl;
}
}
return data.size();
}
LongArrayGetPtr LongArrayGet::create(
string const &providerName,
string const & channelName,
int iterBetweenCreateChannel,
int iterBetweenCreateChannelGet,
double delayTime)
{
LongArrayGetPtr longArrayGet(
new LongArrayGet(
providerName,
channelName,
iterBetweenCreateChannel,
iterBetweenCreateChannelGet,
delayTime));
if(!longArrayGet->init()) longArrayGet.reset();
return longArrayGet;
}
LongArrayGet::LongArrayGet(
string const &providerName,
string const & channelName,
int iterBetweenCreateChannel,
int iterBetweenCreateChannelGet,
double delayTime)
: providerName(providerName),
channelName(channelName),
iterBetweenCreateChannel(iterBetweenCreateChannel),
iterBetweenCreateChannelGet(iterBetweenCreateChannelGet),
delayTime(delayTime)
{}
LongArrayGet::~LongArrayGet() {}
bool LongArrayGet::init()
{
longArrayChannelGet = LongArrayChannelGetPtr(new LongArrayChannelGet(
providerName,
channelName,
iterBetweenCreateChannel,
iterBetweenCreateChannelGet,
delayTime));
return longArrayChannelGet->init();
}
void LongArrayGet::destroy()
{
longArrayChannelGet->destroy();
longArrayChannelGet.reset();
}
}}

View File

@@ -1,81 +0,0 @@
/* longArrayGet.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.09
*/
#ifndef LONGARRAYGET_H
#define LONGARRAYGET_H
#ifdef epicsExportSharedSymbols
# define longarraygetEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/pvAccess.h>
#ifdef longarraygetEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef longarraygetEpicsExportSharedSymbols
# include <shareLib.h>
#endif
namespace epics { namespace pvDatabase {
class LongArrayGet;
typedef std::tr1::shared_ptr<LongArrayGet> LongArrayGetPtr;
class LongArrayChannelGet;
typedef std::tr1::shared_ptr<LongArrayChannelGet> LongArrayChannelGetPtr;
class epicsShareClass LongArrayGet :
public std::tr1::enable_shared_from_this<LongArrayGet>
{
public:
POINTER_DEFINITIONS(LongArrayGet);
static LongArrayGetPtr create(
std::string const & providerName,
std::string const & channelName,
int iterBetweenCreateChannel = 0,
int iterBetweenCreateChannelGet = 0,
double delayTime = 0.0);
~LongArrayGet();
void destroy();
private:
LongArrayGetPtr getPtrSelf()
{
return shared_from_this();
}
LongArrayGet(
std::string const & providerName,
std::string const & channelName,
int iterBetweenCreateChannel = 0,
int iterBetweenCreateChannelGet = 0,
double delayTime = 0.0);
bool init();
std::string providerName;
std::string channelName;
int iterBetweenCreateChannel;
int iterBetweenCreateChannelGet;
double delayTime;
LongArrayChannelGetPtr longArrayChannelGet;
};
}}
#endif /* LONGARRAYGET_H */

View File

@@ -1,87 +0,0 @@
/*longArrayGetMain.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.10
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <vector>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/traceRecord.h>
#include <pv/channelProviderLocal.h>
#include <pv/serverContext.h>
#include <pv/clientFactory.h>
#include <arrayPerformance.h>
#include <longArrayGet.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
int main(int argc,char *argv[])
{
string channelName("arrayPerformance");
int iterBetweenCreateChannel = 0;
int iterBetweenCreateChannelGet = 0;
double delayTime = 1.0;
if(argc==2 && string(argv[1])==string("-help")) {
cout << "longArrayGetMain channelName ";
cout << "iterBetweenCreateChannel iterBetweenCreateChannelGet delayTime" << endl;
cout << "default" << endl;
cout << "longArrayGetMain " << channelName << " ";
cout << iterBetweenCreateChannel << " ";
cout << iterBetweenCreateChannelGet << " ";
cout << delayTime << endl;
return 0;
}
ClientFactory::start();
if(argc>1) channelName = argv[1];
if(argc>2) iterBetweenCreateChannel = strtol(argv[2],0,0);
if(argc>3) iterBetweenCreateChannelGet = strtol(argv[3],0,0);
if(argc>4) delayTime = atof(argv[4]);
cout << "longArrayGetMain " << channelName << " ";
cout << iterBetweenCreateChannel << " ";
cout << iterBetweenCreateChannelGet << " ";
cout << delayTime << endl;
LongArrayGetPtr longArrayGet
= LongArrayGet::create(
"pvAccess",
channelName,
iterBetweenCreateChannel,
iterBetweenCreateChannelGet,
delayTime);
cout << "longArrayGet\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
longArrayGet->destroy();
longArrayGet.reset();
double xxx = 1.0;
if(xxx<delayTime) xxx = delayTime;
ClientFactory::stop();
epicsThreadSleep(xxx);
return 0;
}

View File

@@ -1,319 +0,0 @@
/* longArrayMonitor.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.09
*/
#include <epicsThread.h>
#include <pv/caProvider.h>
#define epicsExportSharedSymbols
#include <longArrayMonitor.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using namespace epics::pvAccess;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::cout;
using std::endl;
using std::string;
using std::ostringstream;
static string requesterName("longArrayMonitor");
static void messagePvt(string const & message, MessageType messageType)
{
cout << requesterName << " message " << message << endl;
}
class LAMChannelRequester :
public ChannelRequester
{
public:
LAMChannelRequester(LongArrayMonitorPtr const &longArrayMonitor)
: longArrayMonitor(longArrayMonitor)
{}
virtual ~LAMChannelRequester(){}
virtual void destroy(){longArrayMonitor.reset();}
virtual string getRequesterName() { return requesterName;}
virtual void message(string const & message, MessageType messageType)
{ messagePvt(message,messageType);}
virtual void channelCreated(const Status& status, Channel::shared_pointer const & channel);
virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState);
private:
LongArrayMonitorPtr longArrayMonitor;
};
void LAMChannelRequester::channelCreated(const Status& status, Channel::shared_pointer const & channel)
{
if(!status.isOK()) messagePvt(status.getMessage(),errorMessage);
longArrayMonitor->status = status;
longArrayMonitor->channel = channel;
longArrayMonitor->event.signal();
}
void LAMChannelRequester::channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState)
{
MessageType messageType = (connectionState==Channel::CONNECTED ? infoMessage : errorMessage);
messagePvt("channelStateChange",messageType);
}
class LAMMonitorRequester :
public MonitorRequester,
public epicsThreadRunable
{
public:
LAMMonitorRequester(LongArrayMonitorPtr const &longArrayMonitor,double waitTime)
: longArrayMonitor(longArrayMonitor),
waitTime(waitTime),
isDestroyed(false),
runReturned(false),
threadName("longArrayMonitor")
{}
virtual ~LAMMonitorRequester(){}
void init();
virtual void destroy();
virtual void run();
virtual string getRequesterName() { return requesterName;}
virtual void message(string const & message, MessageType messageType)
{ messagePvt(message,messageType);}
virtual void monitorConnect(Status const & status,
MonitorPtr const & monitor, StructureConstPtr const & structure);
virtual void monitorEvent(MonitorPtr const & monitor);
virtual void unlisten(MonitorPtr const & monitor);
private:
LongArrayMonitorPtr longArrayMonitor;
double waitTime;
bool isDestroyed;
bool runReturned;
std::string threadName;
Event event;
Mutex mutex;
std::auto_ptr<epicsThread> thread;
};
void LAMMonitorRequester::init()
{
thread = std::auto_ptr<epicsThread>(new epicsThread(
*this,
threadName.c_str(),
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityLow));
thread->start();
}
void LAMMonitorRequester::destroy()
{
if(isDestroyed) return;
isDestroyed = true;
event.signal();
while(true) {
if(runReturned) break;
epicsThreadSleep(.01);
}
thread->exitWait();
longArrayMonitor.reset();
}
void LAMMonitorRequester::monitorConnect(Status const & status,
MonitorPtr const & monitor, StructureConstPtr const & structure)
{
longArrayMonitor->status = status;
longArrayMonitor->monitor = monitor;
if(!status.isOK()) {
messagePvt(status.getMessage(),errorMessage);
longArrayMonitor->event.signal();
return;
}
bool structureOK(true);
FieldConstPtr field = structure->getField("timeStamp");
if(!field) structureOK = false;
field = structure->getField("value");
if(!field) {
structureOK = false;
} else {
if(field->getType()!=scalarArray) {
structureOK = false;
} else {
ScalarArrayConstPtr scalarArray = dynamic_pointer_cast<const ScalarArray>(field);
if(scalarArray->getElementType()!=pvLong) structureOK = false;
}
}
if(!structureOK) {
string message("monitorConnect: illegal structure");
messagePvt(message,errorMessage);
longArrayMonitor->status = Status(Status::STATUSTYPE_ERROR,message);
}
longArrayMonitor->event.signal();
}
void LAMMonitorRequester::run()
{
PVLongArrayPtr pvValue;
PVTimeStamp pvTimeStamp;
TimeStamp timeStamp;
TimeStamp timeStampLast;
timeStampLast.getCurrent();
size_t nElements = 0;
int nSinceLastReport = 0;
while(true) {
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
while(true) {
MonitorElementPtr monitorElement;
PVStructurePtr pvStructure;
{
Lock xx(mutex);
monitorElement = longArrayMonitor->monitor->poll();
if(monitorElement) pvStructure = monitorElement->pvStructurePtr;
}
if(!monitorElement) break;
if(waitTime>0.0) epicsThreadSleep(waitTime);
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
pvTimeStamp.get(timeStamp);
pvValue = dynamic_pointer_cast<PVLongArray>(pvStructure->getSubField("value"));
shared_vector<const int64> data = pvValue->view();
if(data.size()>0) {
nElements += data.size();
int64 first = data[0];
int64 last = data[data.size()-1];
if(first!=last) {
cout << "error first=" << first << " last=" << last << endl;
}
double diff = TimeStamp::diff(timeStamp,timeStampLast);
if(diff>=1.0) {
ostringstream out;
out << " monitors/sec " << nSinceLastReport << " ";
out << "first " << first << " last " << last ;
BitSetPtr changed = monitorElement->changedBitSet;
BitSetPtr overrun = monitorElement->overrunBitSet;
out << " changed " << *changed;
out << " overrun " << *overrun;
double elementsPerSec = nElements;
elementsPerSec /= diff;
if(elementsPerSec>10.0e9) {
elementsPerSec /= 1e9;
out << " gigaElements/sec " << elementsPerSec;
} else if(elementsPerSec>10.0e6) {
elementsPerSec /= 1e6;
out << " megaElements/sec " << elementsPerSec;
} else if(elementsPerSec>10.0e3) {
elementsPerSec /= 1e3;
out << " kiloElements/sec " << elementsPerSec;
} else {
out << " Elements/sec " << elementsPerSec;
}
cout << out.str() << endl;
timeStampLast = timeStamp;
nSinceLastReport = 0;
nElements = 0;
}
++nSinceLastReport;
} else {
cout << "size = 0" << endl;
}
longArrayMonitor->monitor->release(monitorElement);
}
}
}
void LAMMonitorRequester::monitorEvent(MonitorPtr const & monitor)
{
event.signal();
}
void LAMMonitorRequester::unlisten(MonitorPtr const & monitor)
{
messagePvt("unlisten called",errorMessage);
}
LongArrayMonitorPtr LongArrayMonitor::create(
string const &providerName,
string const & channelName,
int queueSize,
double waitTime)
{
LongArrayMonitorPtr longArrayMonitor(new LongArrayMonitor());
if(!longArrayMonitor->init(providerName,channelName,queueSize,waitTime)) longArrayMonitor.reset();
return longArrayMonitor;
}
LongArrayMonitor::LongArrayMonitor() {}
LongArrayMonitor::~LongArrayMonitor() {}
bool LongArrayMonitor::init(
string const &providerName,
string const &channelName,
int queueSize,
double waitTime)
{
channelRequester = LAMChannelRequesterPtr(new LAMChannelRequester(getPtrSelf()));
monitorRequester = LAMMonitorRequesterPtr(new LAMMonitorRequester(getPtrSelf(),waitTime));
monitorRequester->init();
ChannelProvider::shared_pointer channelProvider =
getChannelProviderRegistry()->getProvider(providerName);
if(!channelProvider) {
cout << "provider " << providerName << " not found" << endl;
return false;
}
channel = channelProvider->createChannel(channelName,channelRequester,0);
event.wait();
if(!status.isOK()) return false;
string request("record[queueSize=");
char buff[20];
sprintf(buff,"%d",queueSize);
request += buff;
request += "]field(value,timeStamp,alarm)";
CreateRequest::shared_pointer createRequest = CreateRequest::create();
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
cout << "request logic error " << createRequest->getMessage() << endl;
return false;
}
monitor = channel->createMonitor(monitorRequester,pvRequest);
event.wait();
if(!status.isOK()) return false;
return true;
}
void LongArrayMonitor::start()
{
monitor->start();
}
void LongArrayMonitor::stop()
{
monitor->stop();
}
void LongArrayMonitor::destroy()
{
monitorRequester->destroy();
monitorRequester.reset();
monitor->destroy();
monitor.reset();
channel->destroy();
channel.reset();
channelRequester->destroy();
channelRequester.reset();
}
}}

View File

@@ -1,85 +0,0 @@
/* longArrayMonitor.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.09
*/
#ifndef LONGARRAYMONITOR_H
#define LONGARRAYMONITOR_H
#ifdef epicsExportSharedSymbols
# define longarraymonitorEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/pvAccess.h>
#ifdef longarraymonitorEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef longarraymonitorEpicsExportSharedSymbols
# include <shareLib.h>
#endif
namespace epics { namespace pvDatabase {
class LongArrayMonitor;
typedef std::tr1::shared_ptr<LongArrayMonitor> LongArrayMonitorPtr;
class LAMChannelRequester;
typedef std::tr1::shared_ptr<LAMChannelRequester> LAMChannelRequesterPtr;
class LAMMonitorRequester;
typedef std::tr1::shared_ptr<LAMMonitorRequester> LAMMonitorRequesterPtr;
class epicsShareClass LongArrayMonitor :
public std::tr1::enable_shared_from_this<LongArrayMonitor>
{
public:
POINTER_DEFINITIONS(LongArrayMonitor);
static LongArrayMonitorPtr create(
std::string const & providerName,
std::string const & channelName,
int queueSize = 1,
double waitTime = 0.0);
~LongArrayMonitor();
void start();
void stop();
void destroy();
private:
static epics::pvData::Mutex printMutex;
bool init(
std::string const & providerName,
std::string const & channelName,
int queueSize,
double waitTime);
LongArrayMonitorPtr getPtrSelf()
{
return shared_from_this();
}
LongArrayMonitor();
LAMChannelRequesterPtr channelRequester;
LAMMonitorRequesterPtr monitorRequester;
epics::pvAccess::Channel::shared_pointer channel;
epics::pvData::Monitor::shared_pointer monitor;
epics::pvData::Event event;
epics::pvData::Status status;
friend class LAMChannelRequester;
friend class LAMMonitorRequester;
};
}}
#endif /* LONGARRAYMONITOR_H */

View File

@@ -1,76 +0,0 @@
/*longArrayMonitorMain.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.10
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <vector>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/traceRecord.h>
#include <pv/channelProviderLocal.h>
#include <pv/serverContext.h>
#include <pv/clientFactory.h>
#include <arrayPerformance.h>
#include <longArrayMonitor.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
int main(int argc,char *argv[])
{
string channelName("arrayPerformance");
int queueSize = 2;
double waitTime = 0.0;
if(argc==2 && string(argv[1])==string("-help")) {
cout << "longArrayMonitorMain channelName queueSize waitTime" << endl;
cout << "default" << endl;
cout << "longArrayMonitorMain " << channelName << " ";
cout << queueSize << " ";
cout << "0.0" << endl;
return 0;
}
ClientFactory::start();
if(argc>1) channelName = argv[1];
if(argc>2) queueSize = strtol(argv[2],0,0);
if(argc>3) waitTime = atof(argv[3]);
cout << "longArrayMonitorMain " << channelName << " ";
cout << queueSize << " ";
cout << waitTime << endl;
LongArrayMonitorPtr longArrayMonitor
= LongArrayMonitor::create("pvAccess",channelName,queueSize,waitTime);
longArrayMonitor->start();
cout << "longArrayMonitor\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
longArrayMonitor->destroy();
longArrayMonitor.reset();
ClientFactory::stop();
epicsThreadSleep(1.0);
return 0;
}

View File

@@ -1,383 +0,0 @@
/* longArrayPut.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.09
*/
#include <epicsThread.h>
#include <pv/caProvider.h>
#define epicsExportSharedSymbols
#include <longArrayPut.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using namespace epics::pvAccess;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::cout;
using std::endl;
using std::ostringstream;
using std::string;
static string requesterName("longArrayPut");
static string request("value");
static epics::pvData::Mutex printMutex;
class LongArrayChannelPut :
virtual public ChannelRequester,
virtual public ChannelPutRequester,
public std::tr1::enable_shared_from_this<LongArrayChannelPut>,
public epicsThreadRunable
{
public:
LongArrayChannelPut(
string providerName,
string channelName,
size_t arraySize,
int iterBetweenCreateChannel,
int iterBetweenCreateChannelPut,
double delayTime)
: providerName(providerName),
channelName(channelName),
arraySize(arraySize),
iterBetweenCreateChannel(iterBetweenCreateChannel),
iterBetweenCreateChannelPut(iterBetweenCreateChannelPut),
delayTime(delayTime),
isDestroyed(false),
runReturned(false),
threadName("longArrayPut")
{}
virtual ~LongArrayChannelPut(){}
bool init();
virtual void destroy();
virtual void run();
virtual string getRequesterName() { return requesterName;}
virtual void message(string const & message, MessageType messageType)
{
Lock guard(printMutex);
cout << requesterName << " message " << message << endl;
}
virtual void channelCreated(
const Status& status,
Channel::shared_pointer const & channel);
virtual void channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState);
virtual void channelPutConnect(
Status const & status,
ChannelPut::shared_pointer const & channelPut,
StructureConstPtr const &structure);
virtual void putDone(
Status const & status,
ChannelPut::shared_pointer const & channelPut);
virtual void getDone(
Status const & status,
ChannelPut::shared_pointer const & channelPut,
PVStructurePtr const &pvStructure,
BitSetPtr const & bitSet){}
private:
LongArrayChannelPutPtr getPtrSelf()
{
return shared_from_this();
}
string providerName;
string channelName;
size_t arraySize;
int iterBetweenCreateChannel;
int iterBetweenCreateChannelPut;
double delayTime;
bool isDestroyed;
bool runReturned;
std::string threadName;
Status status;
Event event;
Mutex mutex;
std::auto_ptr<epicsThread> thread;
Channel::shared_pointer channel;
ChannelPut::shared_pointer channelPut;
PVStructurePtr pvStructure;
PVLongArrayPtr pvLongArray;
BitSetPtr bitSet;
};
bool LongArrayChannelPut::init()
{
ChannelProvider::shared_pointer channelProvider = getChannelProviderRegistry()->getProvider(providerName);
if(!channelProvider) {
cout << "provider " << providerName << " not found" << endl;
return false;
}
channel = channelProvider->createChannel(channelName,getPtrSelf(),0);
event.wait();
if(!status.isOK()) return false;
CreateRequest::shared_pointer createRequest = CreateRequest::create();
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
cout << "request logic error " << createRequest->getMessage() << endl;
return false;
}
channelPut = channel->createChannelPut(getPtrSelf(),pvRequest);
event.wait();
if(!status.isOK()) return false;
thread = std::auto_ptr<epicsThread>(new epicsThread(
*this,
threadName.c_str(),
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityLow));
thread->start();
event.signal();
return true;
}
void LongArrayChannelPut::destroy()
{
if(isDestroyed) return;
isDestroyed = true;
event.signal();
while(true) {
if(runReturned) break;
epicsThreadSleep(.01);
}
thread->exitWait();
channel->destroy();
channelPut.reset();
channel.reset();
}
void LongArrayChannelPut::channelCreated(
const Status& status,
Channel::shared_pointer const & channel)
{
if(!status.isOK()) message(status.getMessage(),errorMessage);
this->status = status;
this->channel = channel;
event.signal();
}
void LongArrayChannelPut::channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState)
{
MessageType messageType =
(connectionState==Channel::CONNECTED ? infoMessage : errorMessage);
message("channelStateChange",messageType);
}
void LongArrayChannelPut::channelPutConnect(
Status const & status,
ChannelPut::shared_pointer const & channelPut,
StructureConstPtr const &structure)
{
this->status = status;
if(!status.isOK()) {
message(status.getMessage(),errorMessage);
event.signal();
return;
}
this->channelPut = channelPut;
pvStructure = getPVDataCreate()->createPVStructure(structure);
bitSet = BitSetPtr(new BitSet(pvStructure->getNumberFields()));
bool structureOK(true);
PVFieldPtr pvField = pvStructure->getSubField("value");
if(!pvField) {
structureOK = false;
} else {
FieldConstPtr field = pvField->getField();
if(field->getType()!=scalarArray) {
structureOK = false;
} else {
ScalarArrayConstPtr scalarArray = dynamic_pointer_cast<const ScalarArray>(field);
if(scalarArray->getElementType()!=pvLong) structureOK = false;
}
}
if(!structureOK) {
string mess("channelPutConnect: illegal structure");
message(mess,errorMessage);
this->status = Status(Status::STATUSTYPE_ERROR,mess);
}
pvLongArray = static_pointer_cast<PVLongArray>(pvField);
event.signal();
}
void LongArrayChannelPut::run()
{
while(true) {
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
TimeStamp timeStamp;
TimeStamp timeStampLast;
timeStampLast.getCurrent();
int numChannelPut = 0;
int numChannelCreate = 0;
size_t nElements = 0;
while(true) {
nElements += sizeof(int64) * arraySize;
shared_vector<int64> xxx(arraySize,numChannelPut);
shared_vector<const int64> data(freeze(xxx));
pvLongArray->replace(data);
bitSet->set(pvLongArray->getFieldOffset());
channelPut->put(pvStructure,bitSet);
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
if(delayTime>0.0) epicsThreadSleep(delayTime);
if(isDestroyed) {
runReturned = true;
return;
}
timeStamp.getCurrent();
double diff = TimeStamp::diff(timeStamp,timeStampLast);
if(diff>=1.0) {
ostringstream out;
out << "put numChannelPut " << numChannelPut;
out << " time " << diff ;
double elementsPerSec = nElements;
elementsPerSec /= diff;
if(elementsPerSec>10.0e9) {
elementsPerSec /= 1e9;
out << " gigaElements/sec " << elementsPerSec;
} else if(elementsPerSec>10.0e6) {
elementsPerSec /= 1e6;
out << " megaElements/sec " << elementsPerSec;
} else if(elementsPerSec>10.0e3) {
elementsPerSec /= 1e3;
out << " kiloElements/sec " << elementsPerSec;
} else {
out << " Elements/sec " << elementsPerSec;
}
cout << out.str() << endl;
timeStampLast = timeStamp;
nElements = 0;
}
++numChannelCreate;
bool createPut = false;
if(iterBetweenCreateChannel!=0) {
if(numChannelCreate>=iterBetweenCreateChannel) {
channel->destroy();
ChannelProvider::shared_pointer channelProvider =
getChannelProviderRegistry()->getProvider(providerName);
channel = channelProvider->createChannel(
channelName,getPtrSelf(),0);
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
if(!status.isOK()) {
message(status.getMessage(),errorMessage);
return;
}
cout<< "createChannel success" << endl;
createPut = true;
numChannelCreate = 0;
}
}
++numChannelPut;
if(iterBetweenCreateChannelPut!=0) {
if(numChannelPut>=iterBetweenCreateChannelPut) createPut = true;
}
if(createPut) {
numChannelPut = 0;
channelPut->destroy();
CreateRequest::shared_pointer createRequest = CreateRequest::create();
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
cout << "request logic error " << createRequest->getMessage() << endl;
return ;
}
channelPut = channel->createChannelPut(getPtrSelf(),pvRequest);
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
if(!status.isOK()) {
message(status.getMessage(),errorMessage);
return;
}
cout<< "createChannelPut success" << endl;
}
}
}
}
void LongArrayChannelPut::putDone(
Status const & status,
ChannelPut::shared_pointer const & channelPut)
{
event.signal();
}
LongArrayPutPtr LongArrayPut::create(
string const &providerName,
string const & channelName,
size_t arraySize,
int iterBetweenCreateChannel,
int iterBetweenCreateChannelPut,
double delayTime)
{
LongArrayPutPtr longArrayPut(
new LongArrayPut(
providerName,
channelName,
arraySize,
iterBetweenCreateChannel,
iterBetweenCreateChannelPut,
delayTime));
if(!longArrayPut->init()) longArrayPut.reset();
return longArrayPut;
}
LongArrayPut::LongArrayPut(
string const &providerName,
string const & channelName,
size_t arraySize,
int iterBetweenCreateChannel,
int iterBetweenCreateChannelPut,
double delayTime)
: providerName(providerName),
channelName(channelName),
arraySize(arraySize),
iterBetweenCreateChannel(iterBetweenCreateChannel),
iterBetweenCreateChannelPut(iterBetweenCreateChannelPut),
delayTime(delayTime)
{}
LongArrayPut::~LongArrayPut() {}
bool LongArrayPut::init()
{
longArrayChannelPut = LongArrayChannelPutPtr(new LongArrayChannelPut(
providerName,
channelName,
arraySize,
iterBetweenCreateChannel,
iterBetweenCreateChannelPut,
delayTime));
return longArrayChannelPut->init();
}
void LongArrayPut::destroy()
{
longArrayChannelPut->destroy();
longArrayChannelPut.reset();
}
}}

View File

@@ -1,84 +0,0 @@
/* longArrayPut.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.09
*/
#ifndef LONGARRAYPUT_H
#define LONGARRAYPUT_H
#ifdef epicsExportSharedSymbols
# define longarrayputEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/pvAccess.h>
#ifdef longarrayputEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef longarrayputEpicsExportSharedSymbols
# include <shareLib.h>
#endif
namespace epics { namespace pvDatabase {
class LongArrayPut;
typedef std::tr1::shared_ptr<LongArrayPut> LongArrayPutPtr;
class LongArrayChannelPut;
typedef std::tr1::shared_ptr<LongArrayChannelPut> LongArrayChannelPutPtr;
class epicsShareClass LongArrayPut :
public std::tr1::enable_shared_from_this<LongArrayPut>
{
public:
POINTER_DEFINITIONS(LongArrayPut);
static LongArrayPutPtr create(
std::string const & providerName,
std::string const & channelName,
size_t arraySize = 100,
int iterBetweenCreateChannel = 0,
int iterBetweenCreateChannelPut = 0,
double delayTime = 0.0);
~LongArrayPut();
void destroy();
private:
LongArrayPutPtr getPtrSelf()
{
return shared_from_this();
}
LongArrayPut(
std::string const & providerName,
std::string const & channelName,
size_t arraySize,
int iterBetweenCreateChannel,
int iterBetweenCreateChannelPut,
double delayTime);
bool init();
std::string providerName;
std::string channelName;
size_t arraySize;
int iterBetweenCreateChannel;
int iterBetweenCreateChannelPut;
double delayTime;
LongArrayChannelPutPtr longArrayChannelPut;
};
}}
#endif /* LONGARRAYPUT_H */

View File

@@ -1,93 +0,0 @@
/*longArrayPutMain.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.08.10
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <vector>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/traceRecord.h>
#include <pv/channelProviderLocal.h>
#include <pv/serverContext.h>
#include <pv/clientFactory.h>
#include <arrayPerformance.h>
#include <longArrayPut.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
int main(int argc,char *argv[])
{
string channelName("arrayPerformance");
size_t arraySize = 10;
int iterBetweenCreateChannel = 0;
int iterBetweenCreateChannelPut = 0;
double delayTime = 1.0;
if(argc==2 && string(argv[1])==string("-help")) {
cout << "longArrayPutMain channelName arraySize ";
cout << "iterBetweenCreateChannel iterBetweenCreateChannelPut delayTime" << endl;
cout << "default" << endl;
cout << "longArrayPutMain " << channelName << " ";
cout << arraySize << " ";
cout << iterBetweenCreateChannel << " ";
cout << iterBetweenCreateChannelPut << " ";
cout << delayTime << endl;
return 0;
}
ClientFactory::start();
if(argc>1) channelName = argv[1];
if(argc>2) arraySize = strtoul(argv[2],0,0);
if(argc>3) iterBetweenCreateChannel = strtol(argv[3],0,0);
if(argc>4) iterBetweenCreateChannelPut = strtol(argv[4],0,0);
if(argc>5) delayTime = atof(argv[5]);
cout << "longArrayPutMain " << channelName << " ";
cout << arraySize << " ";
cout << iterBetweenCreateChannel << " ";
cout << iterBetweenCreateChannelPut << " ";
cout << delayTime << endl;
LongArrayPutPtr longArrayPut
= LongArrayPut::create(
"pvAccess",
channelName,
arraySize,
iterBetweenCreateChannel,
iterBetweenCreateChannelPut,
delayTime);
cout << "longArrayPut\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
longArrayPut->destroy();
longArrayPut.reset();
double xxx = 1.0;
if(xxx<delayTime) xxx = delayTime;
epicsThreadSleep(xxx);
ClientFactory::stop();
epicsThreadSleep(1.0);
return 0;
}

View File

@@ -1,189 +0,0 @@
/*vectorPerformanceMain.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.09.02
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <vector>
#include <epicsThread.h>
#include <pv/timeStamp.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
class VectorPerformanceThread;
typedef std::tr1::shared_ptr<VectorPerformanceThread> VectorPerformanceThreadPtr;
class VectorPerformanceThread :
public epicsThreadRunable
{
public:
VectorPerformanceThread(int threadNumber,size_t size,double delay);
virtual ~VectorPerformanceThread(){};
void init();
void start();
virtual void run();
void destroy();
private:
bool isDestroyed;
bool runReturned;
int threadNumber;
size_t size;
epics::pvData::int64 value;
double delay;
Mutex mutex;
std::vector<int64> vector;
std::auto_ptr<epicsThread> thread;
};
VectorPerformanceThread::VectorPerformanceThread(
int threadNumber,size_t size,double delay)
:
isDestroyed(false),
runReturned(false),
threadNumber(threadNumber),
size(size),
value(0),
delay(delay)
{}
void VectorPerformanceThread::init()
{
vector.resize(size);
thread = std::auto_ptr<epicsThread>(new epicsThread(
*this,
"vectorPerform",
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityHigh));
}
void VectorPerformanceThread::start()
{
thread->start();
}
void VectorPerformanceThread::destroy()
{
Lock lock(mutex);
if(isDestroyed) return;
isDestroyed = true;
while(true) {
if(runReturned) break;
lock.unlock();
epicsThreadSleep(.01);
lock.lock();
}
thread->exitWait();
thread.reset();
}
void VectorPerformanceThread::run()
{
TimeStamp timeStamp;
TimeStamp timeStampLast;
timeStampLast.getCurrent();
int nSinceLastReport = 0;
while(true) {
if(delay>0.0) epicsThreadSleep(delay);
{
Lock lock(mutex);
if(isDestroyed) {
cout << " found isDestroyed " << threadNumber << endl;
runReturned = true;
return;
}
}
timeStamp.getCurrent();
double diff = TimeStamp::diff(timeStamp,timeStampLast);
if(diff>=1.0) {
cout << "thread" << threadNumber;
cout << " value " << value;
cout << " time " << diff;
double iterations = nSinceLastReport;
iterations /= diff;
cout << " iterations/sec " << iterations;
double elementSize = size;
double elementsPerSecond = elementSize*nSinceLastReport;
elementsPerSecond /= diff;
elementsPerSecond /= 1e6;
cout << " elements/sec " << elementsPerSecond << "million" << endl;
cout.flush();
timeStampLast = timeStamp;
nSinceLastReport = 0;
}
++nSinceLastReport;
++value;
for(size_t i=0; i<size; ++i) vector[i] = value;
}
}
int main(int argc,char *argv[])
{
size_t size = 50000000;
double delay = .01;
size_t nThread = 1;
if(argc==2 && string(argv[1])==string("-help")) {
cout << "vectorPerformanceMain size delay nThread" << endl;
cout << "default" << endl;
cout << "vectorPerformance ";
cout << size << " ";
cout << delay << " ";
cout << nThread << " ";
cout << endl;
return 0;
}
if(argc>1) size = strtoul(argv[1],0,0);
if(argc>2) delay = atof(argv[2]);
if(argc>3) nThread = strtoul(argv[3],0,0);
cout << "vectorPerformance ";
cout << size << " ";
cout << delay << " ";
cout << nThread << " ";
cout << endl;
cout << "vectorPerformance\n";
std::vector<VectorPerformanceThreadPtr> threads;
for(size_t i=0; i<nThread; ++i) {
threads.push_back(
VectorPerformanceThreadPtr(
new VectorPerformanceThread(i,size,delay)));
}
epicsThreadSleep(.1);
for(size_t i=0; i<nThread; ++i) {
threads[i]->init();
}
for(size_t i=0; i<nThread; ++i) {
threads[i]->start();
}
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
for(size_t i=0; i<nThread; ++i) {
cout << "" << i << " calling destroy" << endl;
threads[i]->destroy();
threads[i].reset();
}
return 0;
}

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

@@ -14,14 +14,11 @@
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building anyway if conflicts are found.
#CHECK_RELEASE = YES
CHECK_RELEASE = WARN
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</path/name/to/install/top>
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local

View File

@@ -1,8 +0,0 @@
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
EPICS_BASE=/home/install/epics/base
PVCOMMON=/home/hg/pvCommonCPP
PVDATA=/home/hg/pvDataCPP
PVACCESS=/home/hg/pvAccessCPP
PVASRV=/home/hg/pvaSrv

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,28 +1,43 @@
# pvDatabaseCPP RELEASE - Location of external support modules
# RELEASE - Location of external support modules
#
# IF YOU CHANGE this file or any file it includes you must
# subsequently do a "gnumake rebuild" in the application's
# top level directory.
# IF YOU CHANGE ANY PATHS in this file or make API changes to
# any modules it refers to, you should do a "make rebuild" in
# this application's top level directory.
#
# The build process does not check dependencies against files
# that are outside this application, thus you should also do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
# The EPICS build process does not check dependencies against
# any files from outside the application, so it is safest to
# rebuild it completely if any modules it depends on change.
#
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
# EPICS V4 Developers: Do not edit the locations in this file!
#
# Create a file RELEASE.local pointing to your PVASRV, PVACCESS,
# PVDATA, PVCOMMON and EPICS_BASE build directories, e.g.
# PVASRV = /path/to/epics/pvaSrvCPP
# PVACCESS = /path/to/epics/pvAccessCPP
# PVDATA = /path/to/epics/pvDataCPP
# PVCOMMON = /path/to/epics/pvCommonCPP
# EPICS_BASE = /path/to/epics/base
# This file is parsed by both GNUmake and an EPICS Perl script,
# so it may ONLY contain definititions of paths to other support
# modules, variable definitions that are used in module paths,
# and include statements that pull in other RELEASE files.
# Variables may be used before their values have been set.
# Build variables that are NOT used in paths should be set in
# the CONFIG_SITE file.
# Variables and paths to dependent modules:
#MODULES = /path/to/modules
#MYMODULE = $(MODULES)/my-module
# If building the EPICS modules individually, set these:
#EPICS_PVACCESS = $(MODULES)/pvAccess
#EPICS_PVDATA = $(MODULES)/pvData
#EPICS_DATABASE = $(MODULES)/database
#EPICS_CA = $(MODULES)/ca
#EPICS_LIBCOM = $(MODULES)/libcom
#EPICS_BASE = $(MODULES)/core
# Set RULES here if you want to use build rules from elsewhere:
#RULES = $(MODULES)/build-rules
# These allow developers to override the RELEASE variable settings
# without having to modify the configure/RELEASE file itself.
-include $(TOP)/../RELEASE.local
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
-include $(TOP)/configure/RELEASE.local

View File

@@ -1,25 +0,0 @@
<h1>Release 4.0 IN DEVELOPMENT</h1>
<p>The main changes since release 3.0.2 are:</p>
<ul>
<li>array semantics now enforce Copy On Write.</li>
<li>String no longer defined.</li>
<li>toString replaced by stream I/O </li>
<li>union is new type.</li>
<li>copy and monitor use new code in pvDataCPP</li>
</ul>
<h2>New Semantics for Arrays</h2>
<p>pvDatabaseCPP has been changed to use the new array implementation from pvDataCPP.</p>
<h2>String no longer defined</h2>
<p>String is replaced by std::string.</p>
<h2>toString replaced by stream I/O</h2>
<p>All uses of toString have been changed to use the steam I/O that pvDataCPP implements.</p>
<h2>union is a new basic type.</h2>
<p>exampleDatabase now has example records for union and union array.
There are records for regular union and for variant union.</p>
<h2>copy</h2>
<p>The implementation of copy and monitor for pvAccess has been changed
to use the new monitor and copy support from pvDataCPP.</p>
<h2>monitorPlugin</h2>
<p>exampleDatabase now has a example plugin that implements onChange.</p>
<h1>Release 0.9.2</h1>
<p>This was the starting point for RELEASE_NOTES</p>

View File

@@ -1,50 +1,92 @@
Release 4.0 IN DEVELOPMENT
===========
# pvDatabaseCPP Module
The main changes since release 3.0.2 are:
This document summarizes the changes to the module between releases.
* array semantics now enforce Copy On Write.
* String no longer defined.
* toString replaced by stream I/O
* union is new type.
* copy and monitor use new code in pvDataCPP
## Release 4.7.0 (EPICS 7.0.7, Sep 2022)
New Semantics for Arrays
--------
* 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:
pvDatabaseCPP has been changed to use the new array implementation from pvDataCPP.
`field(_[XYZ=A:3;B:uniqueId])`
String no longer defined
---------
where `XYZ` is the name of a specific filter plugin that takes parameters
`A` and `B` with values `3` and `uniqueId` respectively.
String is replaced by std::string.
## 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.
toString replaced by stream I/O
---------
## Release 4.5.0 (EPICS 7.0.3, Jul 2019)
All uses of toString have been changed to use the steam I/O that pvDataCPP implements.
* support is a new feature.
* processRecord is new.
union is a new basic type.
------------
## Release 4.4.2 (EPICS 7.0.2.2, Apr 2019)
exampleDatabase now has example records for union and union array.
There are records for regular union and for variant union.
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
copy
----
## Release 4.4.1 (EPICS 7.0.2.1, Mar 2019)
* Cleaned up some build warnings.
* RTEMS test harness simplified.
The implementation of copy and monitor for pvAccess has been changed
to use the new monitor and copy support from pvDataCPP.
## Release 4.4 (EPICS 7.0.2, Dec 2018)
monitorPlugin
-------------
* pvCopy is now implemented in pvDatabaseCPP. The version in pvDatacPP can be deprecated.
* plugin support is implemented.
exampleDatabase now has a example plugin that implements onChange.
Release 0.9.2
==========
This was the starting point for RELEASE_NOTES
## Release 4.3 (EPICS 7.0.1, Dec 2017)
* Updates for pvAccess API and build system changes.
## Release 4.2 (EPICS V4.6, Aug 2016)
* The examples are moved to exampleCPP
* Support for channelRPC is now available.
* removeRecord and traceRecord are now available.
The test is now a regression test which can be run using:
make runtests
## Release 4.1 (EPICS V4.5, Oct 2015)
This is the first release of pvDatabaseCPP.
It provides functionality equivalent to pvDatabaseJava.

View File

@@ -1,13 +0,0 @@
<h1>TODO</h1>
<h2>recordList</h2>
<p>This is putGet support that provides a list of all the records in an IOC.
Since pvAccess implements pvlist this is no longer needed.
Remove it from pvDatabaseCPP and pvIOCCPP.
Also remove channelList from swtshell.</p>
<h2>monitorPlugin</h2>
<p>A debate is on-going about what semantics should be.</p>
<h2>Must test record delete.</h2>
<p>Must test removing a record from the PVDatabase while a pvAccess client
is attached. Also why do both unlisten and detach exists?</p>
<h2>create more regression tests</h2>
<p>Currently only some simple tests exist. Most of the testing has been via the examples</p>

View File

@@ -1,28 +0,0 @@
TODO
===========
recordList
----------
This is putGet support that provides a list of all the records in an IOC.
Since pvAccess implements pvlist this is no longer needed.
Remove it from pvDatabaseCPP and pvIOCCPP.
Also remove channelList from swtshell.
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>

File diff suppressed because it is too large Load Diff

View File

@@ -1,714 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>pvDatabaseCPP</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div class="head">
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 27-Nov-2012</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
</dd>
<dt>Previous version:</dt>
<dd>None</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
<hr />
</div>
<h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP,
which is a framework for implementing a network accessable database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
The framework must be extended in order to create record instances.
The minimum that an extenson must provide is a top level PVStructure and a process method
but the framework provides for complex extensions.</p>
<p>EPICS version 4 is a set of related products in the EPICS
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumemntsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>
<p>This is the 27-Nov-2012 version of the definition of pvDatabaseCPP.
This is the original version.
</p>
<p>This is the beginning of the implementation of pvDataBaseCPP.
It describes the features that will be provided.
The class definitions for PVRecord and PVDatabase are defined but not implemented.</p>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<h3>Overview</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava.
It extracts the core components required to create a network accessible database of smart
memory resident records.
pvDatabaseCPP does not and will not implement any of the specialized support that pvIOCJava
provides. Instead other projects will implement the specialized support.
It is expected that many services will be created that do not require the full features provided
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
them named pvDatabaseJava.
</p>
<p>A brief description of a pvDatase is that it is a network accessible set of smart memory resident
records. Each record has data composed of a top level PVStructure. Each record has a name which is
the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and
Channel interfaces as defined by pvAccess.
This local provider is accessed by the remote pvAccess server.
A record is smart because code can be attached to a record.</p>
<p>This document describes components that provides the following features:
<dl>
<dt>database<dt>
<dd>This encapsulates the concept of a database of memory resident smart records.
The two main components are:
<dl>
<dt>pvRecord</dt>
<dd>This encapsulates the concept of a smart record. It can be processed.
Changes to field values can be trapped. A record can be locked.</dd>
<dt>pvDatabase<dt>
<dd>This is a database of pvRecords.
Records can be added and removed from a database.</dd>
</dl>
<dt>localChannelProvider</dt>
<dd>This is a complete implementation of ChannelProvider and Channel as defined by pvAccess.
It is used by the server side of pvAccess to attach to pvRecords.
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
</dl>
<p><b>database</b> does not itself implement pvRecord instances.
Instead it provides a base classes that make it easy to create record instances.
What does have to be implemented is a top
level PVStructure and the following two methods:</p>
<dl>
<dt>process</dt>
<dd>This is what makes a record <b>smart</b>.
What process does is up to the implementation except that it must decide if
it's execution model is synchronous or asynchronous.
Synchronous means that when process returns the processing is complete.
Asynchronous means that when process returns the processing is <b>not</b> complete.
Instead process invokes other threads that will complete the processing at a later time.</dd>
<dt>isSynchronous</dt>
<dd>Which execution model is being implemented.</dd>
</dl>
<h3>Example PVRecord Extension</h3>
<p>Directory <b>example/record</b> has an example PVRecord implementation.
It implements a counter.
The top level structure is:</p>
<pre>
structure
long value
</pre>
<p><b>NOTE:</b> The example compiles but does not build because nothing
is implemented.</p>
<h4>exampleRecord.h</h4>
<p>This is the class description.
The example extends PVRecord.</p>
<pre>
class ExampleRecord :
public virtual PVRecord
{
public:
POINTER_DEFINITIONS(ExampleRecord);
static PVRecordPtr create(epics::pvData::String const &amp; recordName);
virtual ~ExampleRecord();
virtual bool isSynchronous();
virtual void process(
epics::pvDatabase::RecordProcessRequesterPtr const &amp;processRequester);
private:
ExampleRecord(epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure,
epics::pvData::PVLongPtr const &amp;pvValue);
epics::pvData::PVLongPtr pvValue;
};
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dd>This is example specific. See the implemention for details.</dd>
<dt>~ExampleRecord<dt>
<dd>The destructor must be declared virtual.</dd>
<dt>isSynchronous<dt>
<dd>The implementation must say if process is synchronous or asynchronous.</dd>
<dt>process<dt>
<dd><b>The</b> implementation.</dd>
<dt>ExampleRecord<dt>
<dd>For the example this is private.</dd>
<dl>
<h4>exampleRecord.cpp</h4>
<p>This is the class implementation.</p>
<pre>
ExampleRecord::~ExampleRecord(){}
PVRecordPtr ExampleRecord::create(String const &amp; recordName)
{
String properties;
PVStructurePtr pvStructure = getStandardPVField()-&gt;scalar(pvLong,properties);
PVLongPtr pvValue = pvStructure-&gt;getLongField("value");
PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
return pvRecord;
}
ExampleRecord::ExampleRecord(
String const &amp; recordName,
PVStructurePtr const &amp; pvStructure,
PVLongPtr const &amp;pvValue)
: PVRecord(recordName,pvStructure),
pvValue(pvValue)
{}
bool ExampleRecord::isSynchronous() {return true;}
void ExampleRecord::process(
RecordProcessRequesterPtr const &amp;processRequester)
{
pvValue-&gt;put(pvValue-&gt;get() + 1);
processRequester-&gt;recordProcessResult(Status::Ok);
processRequester-&gt;recordProcessComplete();
}
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dd>Creates a PVStructure with a single subfield named value.
It gets the interface to the value field.
It then creates an ExampleRecord and returns it.
</dd>
<dt>~ExampleRecord<dt>
<dd>Does not have to do anything because of shared pointers.</dd>
<dt>ExampleRecord<dt>
<dd>Calls the base class constructor and sets pvValue.</dd>
<dt>isSynchronous<dt>
<dd>The example is synchronous.</dd>
<dt>process<dt>
<dd>Gets the curent value, increments it, and puts the new value.
It than calls two processRequester callbacks.</dd>
<dl>
<h4>exampleRecordMain.cpp</h4>
<p>This is a main for creating and running the example.</p>
<pre>
int main(int argc,char *argv[])
{
String recordName("exampleRecord");
PVRecordPtr pvRecord = ExampleRecord::create(recordName);
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
pvDatabase-&gt;addRecord(pvRecord);
cout &lt;&lt; recordName &lt;&lt; "\n";
string str;
while(true) {
cout &lt;&lt; "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
return 0;
}
</pre>
<p>The main program creates an example record and adds it to the database.
It then runs until the process is stopped by typing <b>exit</b>.
<p>Until the process is stopped,
pvAccess clients can put and get the value field.
For example</p>
<pre>
pvget exampleRecord
pvput exampleRecord 5
</pre>
<p>Will both work.</p>
<h3>Phased Development</h3>
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
<dl>
<dt>pvRecord</d>
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
<dt>pvDatabase</d>
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
<dt>Local Channel Provider</dt>
<dd>These two features will be the first phase.
But only synchronous record processing will be supported.</dd>
</dl>
<p>Future phases of pvDatabaseCPP should include:</p>
<dl>
<dt>Install</dt>
<dd>This provides on-line add and delete.</dd>
<dt>Field support</dt>
<dd>Add ability to optionally add support to fields.
In addition some of the basic support defined in pvIOCJava will also be implemented.</dd>
<dt>XML parser</dt>
<dd>This provides the ability to create record instances without writing any code.</dd>
</dl>
<p>The completion of each phase provides useful features that can be used without waiting for the
completion of later phases.
The rest of this document discusses only the first phase.</p>
<h3>Features Required for localChannelProvider</h3>
<dl>
<dt>pvCopy</dt>
<dd>Creates a PVStructure that contains a copy of an arbitary
subset of the fields of another top level PVStructure.
It can copy data between the two and maintains a bitSet that show
which fields are changed.<dd>
<dt>monitor</dt>
<dd>This provides the ability to monitor changes to fields of a record.</dd>
<dt>PVRecord and PVDatabase</dt>
<dd>Defined below.</dd>
<dt>local ChannelProvider</dt>
<dd>This is the pvAccess package in pvIOCJava.
The localChannelProvider will access data from PVRecords.
It will implement all channel methods except channelRPC.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
the process method has to do everything itself without any generic field support.
This will be sufficient for starting to implement services.
The following are the minimium features required</p>
<dl>
<dt>PVDatabase</dt>
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
<dt>PVRecord</dt>
<dd>This, and a set of related interfaces, provide the following:
<dl>
<dt>PVStructure</dt>
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
<dt>Record locking</dt>
<dd>A record can be locked and unlocked.
A record must be locked whenever data in the pvStructure is accessed.</dd>
<dt>Trapping data changes</dt>
<dd>A client can request to be notified when data in the pvStructure is modified.
It can do this on a field by field basis.</dd>
</dl>
</dd>
</dl>
<p>The following sections provide a first attempt to describe the classes required for the first
phase.</p>
<p>The last section gives a brief overview of the features provided by pvIOCJava.</p>
<h2>database</h2>
<p>The classes in <b>pvDatabase.h</b> implement a database of memory resident
smart records. The next subsection has the definitions for all the classes
defined in this header file.
It describes the following classes:</p>
<dl>
<dt>PVRecord</dt>
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
<dt>PVRecordField</dt>
<dt>PVRecordStructure</dt>
<dd>These <b>wrap</b> PVField and PVStructure so that pvCopy and monitor can be implemented.</dd>
<dt>PVListener</dt>
<dd>This is implemented by anything that wants to trap calls to the PVRecord::message.</dd>
<dt>RecordProcessRequester</dt>
<dd>This is implemented by anything that calls PVRecord::queueProcessRequest.</dd>
<dt>PVRecordClient</dt>
<dd>This is called by anything that acceses PVRecord.</dd>
<dt>PVDatabase</dt>
<dd>This is a database of PVRecords.</dd>
</dl>
<p>Each class is described in a separate subsection.</p>
<h3>class PVRecord</h3>
<pre>
class PVRecord
{
public:
POINTER_DEFINITIONS(PVRecord);
PVRecord(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
virtual ~PVRecord();
virtual void process(
RecordProcessRequesterPtr const &amp;recordProcessRequester) = 0;
virtual bool isSynchronous() = 0;
epics::pvData::String getRecordName();
PVRecordStructurePtr getPVRecordStructure();
PVRecordFieldPtr findPVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField);
void lock();
void unlock();
void registerClient(PVRecordClientPtr const &amp; pvRecordClient);
void unregisterClient(PVRecordClientPtr const &amp; pvRecordClient);
void detachClients();
void beginGroupPut();
void endGroupPut();
void registerListener(PVListenerPtr const &amp; pvListener);
void unregisterListener(PVListenerPtr const &amp; pvListener);
void removeEveryListener();
epics::pvData::Status processRequest();
void queueProcessRequest(
RecordProcessRequesterPtr const &amp;recordProcessRequester);
void addRequester(epics::pvData::RequesterPtr const &amp; requester);
void removeRequester(epics::pvData::RequesterPtr const &amp; requester);
void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
epics::pvData::String toString();
epics::pvData::String toString(int indentLevel);
};
</pre>
<p>The methods are:</h3>
<dl>
<dt>PVRecord</dt>
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
<dt>~PVRecord</dt>
<dd>The desctructor which must be virtual. A derived class must also have
a virtual destructor.</dd>
<dt>process</dt>
<dd>Pure virtual method. Derived classes must implement this method.</dd>
<dt>isSynchronous</dt>
<dd>Pure virtual method. Derived classes must implement this method.</dd>
<dt>getRecordName</dt>
<dd>Return the recordName.</dd>
<dt>getPVRecordStructure</dt>
<dd>Get the top level PVStructure.</dd>
<dt>findPVRecordField</dt>
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
<dt>lock</dt>
<dt>unlock</dt>
<dd>Lock and Unlock the record.
Any code accessing the data in the record or calling other PVRecord methods
must have the record locked.</dd>
<dt>registerClient</dt>
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
<dt>unregisterClient</dt>
<dd>Client is no longer accessing the record.</dd>
<dt>detachClients</dt>
<dd>Ask all clients to detach from the record</dd>
<dt>beginGroupPut</dt>
<dd>Begin a group of puts. This results in all registered PVListeners being called</dd>
<dt>endGroupPut</dt>
<dd>End a group of puts. This results in all registered PVListeners being called.</dd>
<dt>registerListener</dt>
<dd>Register a PVListener. This must be called before calling pvRecordField.addListener.</dd>
<dt>unregisterListener</dt>
<dd>Unregister a listener. The listener will also be removed from all fields to which it is attached.</dd>
<dt>removeEveryListener</dt>
<dd>This must be called by any code that is deleting or changing the structure of a record.</dd>
<dt>processRequest</dt>
<dd>This is a convenience method for clients that are willing to block if
process is asynchronous. It implements RecordProcessRequester.
If process is synchronous it just calls process and returns the result
to the caller. If process is asynchronous it calls queueProcessRequest,
and process and waits for completion and then returns the result to the caller.</dd>
<dt>queueProcessRequest</dt>
<dd>Queue a process request.</dd>
<dt>addRequester</dt>
<dd>Add a requester to receive messages.</dd>
<dt>removeRequester</dt>
<dd>Remove a message requester.</dd>
<dt>message</dt>
<dd>Can be called by implementation code.
The message will be sent to every requester.</dd>
</dl>
<h3>class PVRecordField</h3>
<pre>
class PVRecordField {
public:
POINTER_DEFINITIONS(PVRecordField);
PVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField,
PVRecordPtr const &amp; pvRecord);
virtual ~PVRecordField();
PVRecordStructurePtr getParent();
epics::pvData::PVFieldPtr getPVField();
epics::pvData::String getFullFieldName();
epics::pvData::String getFullName();
PVRecordPtr getPVRecord();
bool addListener(PVListenerPtr const &amp; pvListener);
void removeListener(PVListenerPtr const &amp; pvListener);
void postPut();
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
};
</pre>
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordField</dt>
<dd>The constructor.</dd>
<dt>~PVRecordField</dt>
<dd>The destructor.</dd>
<dt>getParent</dt>
<dd>Get the parent PVRecordStructure for this field.</dd>
<dt>getPVField</dt>
<dd>Get the PVField associated with this PVRecordField.</dd>
<dt>getFullFieldName</dt>
<dd>This gets the full name of the field, i.e. field,field,..</dd>
<dt>getFullName</dt>
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
<dt>getPVRecord</dt>
<dd>Returns the PVRecord to which this field belongs.</dd>
<dt>addListener</dt>
<dd>Add A PVListener to this field.
Whenever this field or any subfield if this field is modified the listener will be notified.
PVListener is described below.
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<dt>message</dt>
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
fieldname.</dd>
</dl>
<h3>class PVRecordStructure</h3>
<pre>
class PVRecordStructure : public PVRecordField {
public:
POINTER_DEFINITIONS(PVRecordStructure);
PVRecordStructure(
epics::pvData::PVStructurePtr const &amp; pvStructure,
PVRecordFieldPtrArrayPtr const &amp; pvRecordField);
virtual ~PVRecordStructure();
PVRecordFieldPtrArrayPtr getPVRecordFields();
epics::pvData::PVStructurePtr getPVStructure();
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
};
</pre>
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordStructure</dt>
<dd>The constructor.</dd>
<dt>~PVRecordStructure</dt>
<dd>The destructor.</dd>
<dt>getPVRecordFields</dt>
<dd>Get the PVRecordField array for the subfields</dd>
<dt>getPVStructure</dt>
<dd>Get the PVStructure for this field.</dd>
<dt>message</dt>
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
fieldname.</dd>
</dl>
<h3>class PVListener</h3>
<pre>
class PVListener {
public:
POINTER_DEFINITIONS(PVListener);
virtual ~PVListener();
virtual void dataPut(PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void beginGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void endGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void unlisten(PVRecordPtr const &amp; pvRecord) = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~PVListener</dt>
<dd>The destructor.</dd>
<dt>dataPut(PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
<dt>dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
Requested is the field to which the requester issued a pvField-&amp;addListener.
This is called if the listener has called PVRecordField-&amp;addListener for requested.</dd>
<dt>beginGroupPut</dt>
<dd>A related set of changes is being started.</dd>
<dt>endGroupPut</dt>
<dd>A related set of changes is done.</dd>
<dt>unlisten</dt>
<dd>The PVLister is being removed from the record.
This is called when the record is being destroyed or when the record structure
(not the data values) is being changed.</dd>
</dl>
<h3>class RecordProcessRequester</h3>
<pre>
class RecordProcessRequester :
virtual public epics::pvData::Requester
{
public:
POINTER_DEFINITIONS(RecordProcessRequester);
virtual ~RecordProcessRequester();
virtual void becomeProcessor() = 0;
virtual void recordProcessResult(epics::pvData::Status status) = 0;
virtual void recordProcessComplete() = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~RecordProcessRequester</dt>
<dd>The destructor.</dd>
<dt>becomeProcessor</dt>
<dd>Called as a result of queueRequeProcessst. The requester can the call process.</dd>
<dt>recordProcessResult</dt>
<dd>The results of record processing.
This is called with the record locked so that the process requester
can access data from the record.</dd>
<dt>recordProcessComplete</dt>
<dd>Processing is complete.
This is called with the record unlocked.
If the process requester called process with leaveActive true then the requester
must call setInactive.</dd>
</dl>
<h3>class PVRecordClient</h3>
<pre>
class PVRecordClient {
POINTER_DEFINITIONS(PVRecordClient);
virtual ~PVRecordClient();
virtual void detach(PVRecordPtr const &amp; pvRecord);
};
</pre>
<p>where</p>
<dl>
<dt>~PVRecordClient</dt>
<dd>The destructor.</dd>
<dt>detach</dt>
<dd>The record is being removed from the master database,</dd>
</dl>
<h3>class PVDatabase</h3>
<pre>
class PVDatabase : virtual public epics::pvData::Requester {
public:
POINTER_DEFINITIONS(PVDatabase);
static PVDatabasePtr getMaster();
virtual ~PVDatabase();
PVRecordPtr findRecord(epics::pvData::String const&amp; recordName);
bool addRecord(PVRecordPtr const &amp; record);
bool removeRecord(PVRecordPtr const &amp; record);
private:
PVDatabase();
};
</pre>
<p>where</p>
<dl>
<dt>getMaster</dt>
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
<dt>~PVDatabase</dt>
<dd>The destructor.</dd>
<dt>findRecord</dt>
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
<dt>addRecord</dt>
<dd>Add a record to the database.
If the record already exists it is not modified and false is returned.</dd>
<dt>removeRecord</dt>
<dd>Remove a record from the database.
If the record was not in the database false is returned.</dd>
</dl>
<h2>Local Channel Provider</h2>
<p>Not yet described.</p>
<p>A brief description is that it must implement the following components of pvIOCJava:</p>
<dl>
<dt>pvCopy</dt>
<dt>monitor</dt>
<dt>pvAccess</dt>
<dd>See the next section for a description</dd>
</dl>
<h2>Summary of Packages in pvIOCJAVA</h2>
<p>The following are the direct sub packages of <b>pvIOCJava/src/org/epics/pvioc</b>:</p>
<dl>
<dt>pvCopy</dt>
<dd>This provides a copy of an arbitrary subset of the fields in a PVRecord.
It also provides the ability to detect and report changes to fields.
It is required for pvAccess.</dd>
<dt>monitor</dt>
<dd>This provides the ability to monitor changes to a PVRecord. It is required for pvAccess monitors.</dd>
<dt>pvAccess</dt>
<dd>The local implementation of Channel Provider and Channel.
It is accessed by the remote pvAccess server and can also be accessed by code in the same IOC.</dd>
<dt>database</dt>
<dd>This defines and implements PVRecord, PVDatabase , and PVListener.
It supports the basic feature required the implement a local Channel Provider.</dd>
<dt>support</dt>
<dd>This provides the ability to optionally attach code to any field of a pvRecord.
It and several sub packages provide a set of standard support modules.</dd>
<dt>install</dt>
<dd>This provides the ability to dynamically initialize and add new PVRecords. It also provides
the ability to dynamicall delete PVRecords.</d>
<dt>xml</dt>
<dd>This provides the ability to configure record instances without writing code.</dd>
<dt>util</dt>
<dd>This is misnamed since it is code related to scanning.</dd>
<dt>pdrv</dt>
<dd>This is portDriver, which is a proposed sucessor to the asynManager component of asynDriver.</dd>
<dt>swtshell</dt>
<dd>This is shell that is can either run under the same process as a JavaIOC or as a remote shell.
It is like a version of probe but for pvData/pvAccess.
Almost all of it's features work in either local or remote mode.
With a little more work all or it's features could work remotely.
This should be done and then only remote mode should be supported.
It can then be rewritten in a completely different language and using a complely different GUI
framework.
</dd>
<dt>caV3</dt>
<dd>This has two components:
<dl>
<dt>ClientFactory</dt>
<dd>This is a small wrapper on top of the caV3 client support implemented by pvAccess.
It allows code in the pvIOC to access V3Records via pvAccess.</dd>
<dt>ServerFactory</dt>
<dd>This is a caV3 server that allows a caV3 client to access a PVRecord.
The Java implementation uses CAJ, which does most of the work.
For now it will not be discussed in this document.</dd>
</dl>
</dd>
<dt>v3a</dt>
<dd>I do not know what this is.</dd>
</dl>
<p>In addition there is one class file <b>JavaIOC.java</b>.
This is starting a IOC instance.
This is not required for pvIOCCPP which is either a main or runs as part of a V3 IOC.</p>
</div>
</body>
</html>

View File

@@ -1,874 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>pvDatabaseCPP</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div class="head">
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 11-Dec-2012</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="pvDatabaseCPP_20121127.html">pvDatabaseCPP_20121127.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
<hr />
</div>
<h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP,
which is a framework for implementing a network accessable database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
The framework must be extended in order to create record instances.
The minimum that an extenson must provide is a top level PVStructure and a process method
but the framework provides for complex extensions.</p>
<p>EPICS version 4 is a set of related products in the EPICS
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>
<p>This is the 11-Dec-2012 version of the definition of pvDatabaseCPP.
</p>
<p>This is the beginning of the implementation of pvDataBaseCPP.
It describes the features that will be provided.
The class definitions for PVRecord are implemented.
The class definition for PVDatabase are defined but not implemented.</p>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<h3>Overview</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava.
It extracts the core components required to create a network accessible database of smart
memory resident records.
pvDatabaseCPP does not and will not implement any of the specialized support that pvIOCJava
provides. Instead other projects will implement the specialized support.
It is expected that many services will be created that do not require the full features provided
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
them named pvDatabaseJava.
</p>
<p>A brief description of a pvDatase is that it is a network accessible set of smart memory resident
records. Each record has data composed of a top level PVStructure. Each record has a name which is
the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and
Channel interfaces as defined by pvAccess.
This local provider is accessed by the remote pvAccess server.
A record is smart because code can be attached to a record.</p>
<p>This document describes components that provides the following features:
<dl>
<dt>database<dt>
<dd>This encapsulates the concept of a database of memory resident smart records.
The two main components are:
<dl>
<dt>pvRecord</dt>
<dd>This encapsulates the concept of a smart record. It can be processed.
Changes to field values can be trapped. A record can be locked.</dd>
<dt>pvDatabase<dt>
<dd>This is a database of pvRecords.
Records can be added and removed from a database.</dd>
</dl>
<dt>localChannelProvider</dt>
<dd>This is a complete implementation of ChannelProvider and Channel as defined by pvAccess.
It is used by the server side of pvAccess to attach to pvRecords.
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
</dl>
<p><b>database</b> does not itself implement pvRecord instances.
Instead it provides a base classes that make it easy to create record instances.
What does have to be implemented is a top
level PVStructure and the following two methods:</p>
<dl>
<dt>process</dt>
<dd>This is what makes a record <b>smart</b>.
What process does is up to the implementation except that it must decide if
it's execution model is synchronous or asynchronous.
Synchronous means that when process returns the processing is complete.
Asynchronous means that when process returns the processing is <b>not</b> complete.
Instead process invokes other threads that will complete the processing at a later time.</dd>
<dt>isSynchronous</dt>
<dd>Which execution model is being implemented.</dd>
</dl>
<h3>Example PVRecord Extension</h3>
<p>Directory <b>example/record</b> has an example PVRecord implementation.
It implements a counter.
The top level structure is:</p>
<pre>
structure
long value
</pre>
<p><b>NOTE:</b> The example compiles but does not build because nothing
is implemented.</p>
<h4>exampleRecord.h</h4>
<p>This is the class description.
The example extends PVRecord.</p>
<pre>
class ExampleRecord :
public virtual PVRecord
{
public:
POINTER_DEFINITIONS(ExampleRecord);
static PVRecordPtr create(epics::pvData::String const &amp; recordName);
virtual ~ExampleRecord();
virtual bool isSynchronous();
virtual void process(
epics::pvDatabase::RecordProcessRequesterPtr const &amp;processRequester);
private:
ExampleRecord(epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure,
epics::pvData::PVLongPtr const &amp;pvValue);
epics::pvData::PVLongPtr pvValue;
};
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dd>This is example specific. See the implemention for details.</dd>
<dt>~ExampleRecord<dt>
<dd>The destructor must be declared virtual.</dd>
<dt>isSynchronous<dt>
<dd>The implementation must say if process is synchronous or asynchronous.</dd>
<dt>process<dt>
<dd><b>The</b> implementation.</dd>
<dt>ExampleRecord<dt>
<dd>For the example this is private.</dd>
<dl>
<h4>exampleRecord.cpp</h4>
<p>This is the class implementation.</p>
<pre>
ExampleRecord::~ExampleRecord(){}
PVRecordPtr ExampleRecord::create(String const &amp; recordName)
{
String properties;
PVStructurePtr pvStructure = getStandardPVField()-&gt;scalar(pvLong,properties);
PVLongPtr pvValue = pvStructure-&gt;getLongField("value");
PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
return pvRecord;
}
ExampleRecord::ExampleRecord(
String const &amp; recordName,
PVStructurePtr const &amp; pvStructure,
PVLongPtr const &amp;pvValue)
: PVRecord(recordName,pvStructure),
pvValue(pvValue)
{}
bool ExampleRecord::isSynchronous() {return true;}
void ExampleRecord::process(
RecordProcessRequesterPtr const &amp;processRequester,bool alreadyLocked)
{
if(!alreadyLocked) lock();
pvValue-&gt;put(pvValue-&gt;get() + 1);
processRequester-&gt;recordProcessResult(Status::Ok);
unlock();
processRequester-&gt;recordProcessComplete();
dequeueProcessRequest(processRequester);
}
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dd>Creates a PVStructure with a single subfield named value.
It gets the interface to the value field.
It then creates an ExampleRecord and returns it.
</dd>
<dt>~ExampleRecord<dt>
<dd>Does not have to do anything because of shared pointers.</dd>
<dt>ExampleRecord<dt>
<dd>Calls the base class constructor and sets pvValue.</dd>
<dt>isSynchronous<dt>
<dd>The example is synchronous.</dd>
<dt>process<dt>
<dd>Gets the curent value, increments it, and puts the new value.
It than calls two processRequester callbacks.</dd>
<dl>
<h4>exampleRecordMain.cpp</h4>
<p>This is a main for creating and running the example.</p>
<pre>
int main(int argc,char *argv[])
{
String recordName("exampleRecord");
PVRecordPtr pvRecord = ExampleRecord::create(recordName);
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
pvDatabase-&gt;addRecord(pvRecord);
cout &lt;&lt; recordName &lt;&lt; "\n";
string str;
while(true) {
cout &lt;&lt; "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
return 0;
}
</pre>
<p>The main program creates an example record and adds it to the database.
It then runs until the process is stopped by typing <b>exit</b>.
<p>Until the process is stopped,
pvAccess clients can put and get the value field.
For example</p>
<pre>
pvget exampleRecord
pvput exampleRecord 5
</pre>
<p>Will both work.</p>
<h3>Phased Development</h3>
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
<dl>
<dt>pvRecord</d>
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
<dt>pvDatabase</d>
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
<dt>Local Channel Provider</dt>
<dd>These two features will be the first phase.
But only synchronous record processing will be supported.</dd>
</dl>
<p>Future phases of pvDatabaseCPP should include:</p>
<dl>
<dt>Install</dt>
<dd>This provides on-line add and delete.</dd>
<dt>Field support</dt>
<dd>Add ability to optionally add support to fields.
In addition some of the basic support defined in pvIOCJava will also be implemented.</dd>
<dt>XML parser</dt>
<dd>This provides the ability to create record instances without writing any code.</dd>
</dl>
<p>The completion of each phase provides useful features that can be used without waiting for the
completion of later phases.
The rest of this document discusses only the first phase.</p>
<h3>Features Required for localChannelProvider</h3>
<dl>
<dt>pvCopy</dt>
<dd>Creates a PVStructure that contains a copy of an arbitary
subset of the fields of another top level PVStructure.
It can copy data between the two and maintains a bitSet that show
which fields are changed.<dd>
<dt>monitor</dt>
<dd>This provides the ability to monitor changes to fields of a record.</dd>
<dt>PVRecord and PVDatabase</dt>
<dd>Defined below.</dd>
<dt>local ChannelProvider</dt>
<dd>This is the pvAccess package in pvIOCJava.
The localChannelProvider will access data from PVRecords.
It will implement all channel methods except channelRPC.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
the process method has to do everything itself without any generic field support.
This will be sufficient for starting to implement services.
The following are the minimium features required</p>
<dl>
<dt>PVDatabase</dt>
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
<dt>PVRecord</dt>
<dd>This, and a set of related interfaces, provide the following:
<dl>
<dt>PVStructure</dt>
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
<dt>Record locking</dt>
<dd>A record can be locked and unlocked.
A record must be locked whenever data in the pvStructure is accessed.</dd>
<dt>Trapping data changes</dt>
<dd>A client can request to be notified when data in the pvStructure is modified.
It can do this on a field by field basis.</dd>
</dl>
</dd>
</dl>
<p>The following sections provide a first attempt to describe the classes required for the first
phase.</p>
<p>The last section gives a brief overview of the features provided by pvIOCJava.</p>
<h2>database</h2>
<p>The classes in <b>pvDatabase.h</b> implement a database of memory resident
smart records.
It describes the following classes:</p>
<dl>
<dt>PVRecord</dt>
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
<dt>PVRecordField</dt>
<dt>PVRecordStructure</dt>
<dd>These <b>wrap</b> PVField and PVStructure so that pvCopy and monitor
can be implemented.</dd>
<dt>PVRecordClient</dt>
<dd>This is called by anything that acceses PVRecord.</dd>
<dt>PVListener</dt>
<dd>This is implemented by anything that wants to trap calls to the PVRecord::message.</dd>
<dt>RecordProcessRequester</dt>
<dd>This is implemented by anything that calls PVRecord::queueProcessRequest.</dd>
<dt>RecordPutRequester</dt>
<dd>This is implemented by anything that calls PVRecord::queuePutRequest.</dd>
<dt>PVDatabase</dt>
<dd>This is a database of PVRecords.</dd>
</dl>
<p>Each class is described in a separate subsection.</p>
<h3>C++ namespace and typedefs</h3>
<pre>
namespace epics { namespace pvDatabase {
class PVRecord;
typedef std::tr1::shared_ptr&lt;PVRecord&gt; PVRecordPtr;
class PVRecordField;
typedef std::tr1::shared_ptr&lt;PVRecordField&gt; PVRecordFieldPtr;
typedef std::vector&lt;PVRecordFieldPtr&gt; PVRecordFieldPtrArray;
typedef std::tr1::shared_ptr&lt;PVRecordFieldPtrArray&gt; PVRecordFieldPtrArrayPtr;
class PVRecordStructure;
typedef std::tr1::shared_ptr&lt;PVRecordStructure&gt; PVRecordStructurePtr;
class PVRecordClient;
typedef std::tr1::shared_ptr&lt;PVRecordClient&gt; PVRecordClientPtr;
class PVListener;
typedef std::tr1::shared_ptr&lt;PVListener&gt; PVListenerPtr;
class RecordProcessRequester;
typedef std::tr1::shared_ptr&lt;RecordProcessRequester&gt; RecordProcessRequesterPtr;
class RecordPutRequester;
typedef std::tr1::shared_ptr&lt;RecordPutRequester&gt; RecordPutRequesterPtr;
class PVDatabase;
typedef std::tr1::shared_ptr&lt;PVDatabase&gt; PVDatabasePtr;
</pre>
<h3>class PVRecord</h3>
<p><b>NOTES:</b>
<ul>
<li>This section uses the name record instead of "an instance of PVRecord".</li>
<li>Most clients will access a record via the local channel provider,
i. e. via pvAccess.
Thus this section is mainly of interest to
the local channel provider and record implementers.</li>
</ul>
<hr>PVRecord Methods</h4>
<pre>
class PVRecord
public epics::pvData::Requester,
public std::tr1::enable_shared_from_this&lt;PVRecord&gt;
{
public:
POINTER_DEFINITIONS(PVRecord);
PVRecord(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
virtual ~PVRecord();
virtual void process(
RecordProcessRequesterPtr const &amp;recordProcessRequester,
bool alreadyLocked) = 0;
virtual bool isSynchronous() = 0;
virtual bool requestImmediatePut(epics::pvData::PVFieldPtr const &amp;pvField);
virtual void immediatePutDone();
virtual void destroy();
epics::pvData::String getRecordName();
PVRecordStructurePtr getPVRecordStructure();
PVRecordFieldPtr findPVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField);
bool addRequester(epics::pvData::RequesterPtr const &amp; requester);
bool removeRequester(epics::pvData::RequesterPtr const &amp; requester);
void lock();
void unlock();
bool tryLock();
void lockOtherRecord(PVRecordPtr const &amp; otherRecord);
void addPVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
void removePVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
void detachClients();
void beginGroupPut();
void endGroupPut();
void queueProcessRequest(
RecordProcessRequesterPtr const &amp;recordProcessRequester);
void dequeueProcessRequest(
RecordProcessRequesterPtr const &amp;recordProcessRequester);
void queuePutRequest(
RecordPutRequesterPtr const &amp;recordPutRequester);
void putDone(
RecordPutRequesterPtr const &amp;recordPutRequester);
virtual epics::pvData::String getRequesterName();
void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
void message(
PVRecordFieldPtr const &amp; pvRecordField,
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
void toString(epics::pvData::StringBuilder buf);
void toString(epics::pvData::StringBuilder buf,int indentLevel);
//init MUST be called after derived class is constructed
void init();
};
</pre>
<p>The methods are:</h3>
<dl>
<dt>PVRecord</dt>
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
<dt>~PVRecord</dt>
<dd>The destructor which must be virtual. A derived class must also have
a virtual destructor.</dd>
<dt>process</dt>
<dd>Pure virtual method.
<p>Derived classes must implement this method.</p>
<p>A client <b>must</b> only call this method when
<b>RecordProcessRequester::becomeProcessor</b> is called as a result
of a <b>queueProcessRequest</b>.
A client can either call lock before calling processs
or let process lock the record.
If a client wants to put data into the record it should lock, put, and then call
process.</p>
<p>If the record is synchronous, process will return only when all processing
is complete. If the record is asynchronous then process arranges for some
other thread to do the processing and returns.</p>
<p>When processing is done the record calls two client callbacks:</p>
<dl>
<dt>RecordProcessRequester::recordProcessResult</dt>
<dd>This is called with the record still locked.
The clients can get data from the record.</dd>
<dt>RecordProcessRequester::recordProcessComplete</dt>
<dd>This is called with the record unlocked.
The client can no longer access the record.</dd>
</dl>
</dd>
<dt>isSynchronous</dt>
<dd>Pure virtual method. Derived classes must implement this method.</dd>
<dt>requestImmediatePut</dt>
<dd>This is a virtual method.
<p> The purpose is to allow the implementation to provide fields
that allow a client to abort process.
For example a motor record might provide a field <b>stop</b></p>
<p>The default always returns <b>false</b>.</p>
<p>A record implementation can override the default and return <b>true</b>.
In it does requestImmediatePut it returns with the record locked.</p>
<p>The client can change the value of the associated field and then call
<b>immediatePutDone</b></p>
</dd>
<dt>immediatePutDone</dt>
<dd>This is a virtual method.
<p>The default does nothing.</p>
<p>Must be called by client as a result of a call to <b>requestImmediatePut</b>
that returns <b>true</b>.</p>
</dd>
<dt>destroy</dt>
<dd>This is a virtual method.
<p>The default does nothing.</p>
</dd>
<dt>getRecordName</dt>
<dd>Return the recordName.</dd>
<dt>getPVRecordStructure</dt>
<dd>Get the top level PVStructure.</dd>
<dt>findPVRecordField</dt>
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
<dt>addRequester</dt>
<dd>Add a requester to receive messages.</dd>
<dt>removeRequester</dt>
<dd>Remove a message requester.</dd>
<dt>lock</dt>
<dt>unlock</dt>
<dd>Lock and Unlock the record.
Any code accessing the data in the record or calling other PVRecord methods
must have the record locked.</dd>
<dt>tryLock</dt>
<dd>If <b>true</b> then just like <b>lock</b>.
If <b>false</b>client can not access record.
A client can try to simultaneously hold the lock for more than two records
by calling this method. But must be willing to accept failure.
</dd>
<dt>lockOtherRecord</dt>
<dd>A client that holds the lock for one record can lock one other record.
A client <b>must</b> not call this if the client already has the lock for
more then one record.
</dd>
<dt>addPVRecordClient</dt>
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
<dt>removePVRecordClient</dt>
<dd>Client is no longer accessing the record.</dd>
<dt>detachClients</dt>
<dd>Ask all clients to detach from the record</dd>
<dt>addListener</dt>
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
<dt>removeListener</dt>
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
<dt>beginGroupPut</dt>
<dd>Begin a group of puts.
This results in all registered PVListeners being called</dd>
<dt>endGroupPut</dt>
<dd>End a group of puts.
This results in all registered PVListeners being called.</dd>
<dt>queueProcessRequest</dt>
<dd>Queue a process request.</dd>
<dt>dequeueProcessRequest</dt>
<dd>This <b>must</b> be called by record implementation after it has
completed a process request.
</dd>
<dt>queuePutRequest</dt>
<dd>Queue a put request.
<p>This is for code that wants to change data in a record without processing.
If <b>RecordPutRequester::requestResult</b> is called with result <b>true</b>
then the record is locked and the client can make changes.
When done the client <b>must</b> call <b>putDone</b></p>
</dd>
<dt>putDone</dt>
<dd>Called by <b>RecordPutRequester</b> after changing values in record.
This method unlocks the record</dd>
<dt>getRequesterName</dt>
<dd>virtual method of <b>Requester</b>
</dd>
<dt>message</dt>
<dd>Can be called by implementation code.
The message will be sent to every requester.</dd>
<dt>init</dt>
<dd>This method <b>must</b> be called by derived class
<b>after</b> class is completely constructed.</dd>
</dl>
<h3>class PVRecordField</h3>
<pre>
class PVRecordField {
public virtual epics::pvData::PostHandler,
public std::tr1::enable_shared_from_this&lt;PVRecordField&gt;
public:
POINTER_DEFINITIONS(PVRecordField);
PVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField,
PVRecordStructurePtr const &amp;parent,
PVRecordPtr const &amp; pvRecord);
virtual ~PVRecordField();
PVRecordStructurePtr getParent();
epics::pvData::PVFieldPtr getPVField();
epics::pvData::String getFullFieldName();
epics::pvData::String getFullName();
PVRecordPtr getPVRecord();
bool addListener(PVListenerPtr const &amp; pvListener);
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
};
</pre>
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordField</dt>
<dd>The constructor.</dd>
<dt>~PVRecordField</dt>
<dd>The destructor.</dd>
<dt>getParent</dt>
<dd>Get the parent PVRecordStructure for this field.</dd>
<dt>getPVField</dt>
<dd>Get the PVField associated with this PVRecordField.</dd>
<dt>getFullFieldName</dt>
<dd>This gets the full name of the field, i.e. field,field,..</dd>
<dt>getFullName</dt>
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
<dt>getPVRecord</dt>
<dd>Returns the PVRecord to which this field belongs.</dd>
<dt>addListener</dt>
<dd>Add A PVListener to this field.
Whenever this field or any subfield if this field is modified the listener will be notified.
PVListener is described below.
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<dt>message</dt>
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
fieldname.</dd>
</dl>
<h3>class PVRecordStructure</h3>
<pre>
class PVRecordStructure : public PVRecordField {
public:
POINTER_DEFINITIONS(PVRecordStructure);
PVRecordStructure(
epics::pvData::PVStructurePtr const &amp; pvStructure,
PVRecordFieldPtrArrayPtr const &amp; pvRecordField);
virtual ~PVRecordStructure();
PVRecordFieldPtrArrayPtr getPVRecordFields();
epics::pvData::PVStructurePtr getPVStructure();
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
};
</pre>
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordStructure</dt>
<dd>The constructor.</dd>
<dt>~PVRecordStructure</dt>
<dd>The destructor.</dd>
<dt>getPVRecordFields</dt>
<dd>Get the PVRecordField array for the subfields</dd>
<dt>getPVStructure</dt>
<dd>Get the PVStructure for this field.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<h3>class PVRecordClient</h3>
<pre>
class PVRecordClient {
POINTER_DEFINITIONS(PVRecordClient);
virtual ~PVRecordClient();
virtual void detach(PVRecordPtr const &amp; pvRecord);
};
</pre>
<p>where</p>
<dl>
<dt>~PVRecordClient</dt>
<dd>The destructor.</dd>
<dt>detach</dt>
<dd>The record is being removed from the master database,</dd>
</dl>
</dl>
<h3>class PVListener</h3>
<pre>
class PVListener {
virtual public PVRecordClient
public:
POINTER_DEFINITIONS(PVListener);
virtual ~PVListener();
virtual void dataPut(PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void beginGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void endGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~PVListener</dt>
<dd>The destructor.</dd>
<dt>dataPut(PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
<dt>dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
Requested is the field to which the requester issued a pvField-&amp;addListener.
This is called if the listener has called PVRecordField-&amp;addListener for requested.</dd>
<dt>beginGroupPut</dt>
<dd>A related set of changes is being started.</dd>
<dt>endGroupPut</dt>
<dd>A related set of changes is done.</dd>
</dl>
<h3>class RecordProcessRequester</h3>
<pre>
class RecordProcessRequester :
virtual public PVRecordClient,
virtual public epics::pvData::Requester
{
public:
POINTER_DEFINITIONS(RecordProcessRequester);
virtual ~RecordProcessRequester();
virtual void recordDestroyed() = 0;
virtual void becomeProcessor() = 0;
virtual void recordProcessResult(epics::pvData::Status status) = 0;
virtual void recordProcessComplete() = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~RecordProcessRequester</dt>
<dd>The destructor.</dd>
<dt>recordDestroyed</dt>
<dd>Record is being destroyed.</dd>
<dt>becomeProcessor</dt>
<dd>Called as a result of queueRequeProcessst. The requester can the call process.</dd>
<dt>recordProcessResult</dt>
<dd>The results of record processing.
This is called with the record locked so that the process requester
can access data from the record.</dd>
<dt>recordProcessComplete</dt>
<dd>Processing is complete.
This is called with the record unlocked.
If the process requester called process with leaveActive true then the requester
must call setInactive.</dd>
</dl>
<h3>class RecordPutRequester</h3>
<pre>
class RecordPutRequester :
virtual public PVRecordClient
{
public:
POINTER_DEFINITIONS(RecordPutRequester);
virtual ~RecordPutRequester();
virtual void requestResult(bool result) = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~RecordPutRequester</dt>
<dd>The destructor.</dd>
<dt>requestResult</dt>
<dd>Result of a call to queuePutRequest. If <b>requestResult</b> is <b>false</b>
then the caller can not access the record.
If <b>requestResult</b> is <b>true</b>
then the record is locked and the caller can get and put data in the record.
When done the caller must call <b>PVRecord::putDone</b>, which will unlock the
record.
</dd>
</dl>
<h3>class PVDatabase</h3>
<pre>
class PVDatabase : virtual public epics::pvData::Requester {
public:
POINTER_DEFINITIONS(PVDatabase);
static PVDatabasePtr getMaster();
virtual ~PVDatabase();
PVRecordPtr findRecord(epics::pvData::String const&amp; recordName);
bool addRecord(PVRecordPtr const &amp; record);
bool removeRecord(PVRecordPtr const &amp; record);
private:
PVDatabase();
};
</pre>
<p>where</p>
<dl>
<dt>getMaster</dt>
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
<dt>~PVDatabase</dt>
<dd>The destructor.</dd>
<dt>findRecord</dt>
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
<dt>addRecord</dt>
<dd>Add a record to the database.
If the record already exists it is not modified and false is returned.</dd>
<dt>removeRecord</dt>
<dd>Remove a record from the database.
If the record was not in the database false is returned.</dd>
</dl>
<h2>Local Channel Provider</h2>
<p>Not yet described.</p>
<p>A brief description is that it must implement the following components of pvIOCJava:</p>
<dl>
<dt>pvCopy</dt>
<dt>monitor</dt>
<dt>pvAccess</dt>
<dd>See the next section for a description</dd>
</dl>
<h2>Summary of Packages in pvIOCJAVA</h2>
<p>The following are the direct sub packages of <b>pvIOCJava/src/org/epics/pvioc</b>:</p>
<dl>
<dt>pvCopy</dt>
<dd>This provides a copy of an arbitrary subset of the fields in a PVRecord.
It also provides the ability to detect and report changes to fields.
It is required for pvAccess.</dd>
<dt>monitor</dt>
<dd>This provides the ability to monitor changes to a PVRecord. It is required for pvAccess monitors.</dd>
<dt>pvAccess</dt>
<dd>The local implementation of Channel Provider and Channel.
It is accessed by the remote pvAccess server and can also be accessed by code in the same IOC.</dd>
<dt>database</dt>
<dd>This defines and implements PVRecord, PVDatabase , and PVListener.
It supports the basic feature required the implement a local Channel Provider.</dd>
<dt>support</dt>
<dd>This provides the ability to optionally attach code to any field of a pvRecord.
It and several sub packages provide a set of standard support modules.</dd>
<dt>install</dt>
<dd>This provides the ability to dynamically initialize and add new PVRecords. It also provides
the ability to dynamicall delete PVRecords.</d>
<dt>xml</dt>
<dd>This provides the ability to configure record instances without writing code.</dd>
<dt>util</dt>
<dd>This is misnamed since it is code related to scanning.</dd>
<dt>pdrv</dt>
<dd>This is portDriver, which is a proposed sucessor to the asynManager component of asynDriver.</dd>
<dt>swtshell</dt>
<dd>This is shell that is can either run under the same process as a JavaIOC or as a remote shell.
It is like a version of probe but for pvData/pvAccess.
Almost all of it's features work in either local or remote mode.
With a little more work all or it's features could work remotely.
This should be done and then only remote mode should be supported.
It can then be rewritten in a completely different language and using a complely different GUI
framework.
</dd>
<dt>caV3</dt>
<dd>This has two components:
<dl>
<dt>ClientFactory</dt>
<dd>This is a small wrapper on top of the caV3 client support implemented by pvAccess.
It allows code in the pvIOC to access V3Records via pvAccess.</dd>
<dt>ServerFactory</dt>
<dd>This is a caV3 server that allows a caV3 client to access a PVRecord.
The Java implementation uses CAJ, which does most of the work.
For now it will not be discussed in this document.</dd>
</dl>
</dd>
<dt>v3a</dt>
<dd>I do not know what this is.</dd>
</dl>
<p>In addition there is one class file <b>JavaIOC.java</b>.
This is starting a IOC instance.
This is not required for pvIOCCPP which is either a main or runs as part of a V3 IOC.</p>
</div>
</body>
</html>

View File

@@ -1,870 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>pvDatabaseCPP</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div class="head">
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 17-Apr-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
<hr />
</div>
<h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP,
which is a framework for implementing a network accessable database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
The framework can be extended in order to create record instances that implements services.
The minimum that an extenson must provide is a top level PVStructure and a process method.
</p>
<p>EPICS version 4 is a set of related products in the EPICS
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>
<p>This is the 17-Apr-2013 version of the definition of pvDatabaseCPP.
</p>
<p>The following Channel methods are implemented and working: getField,i
channelProcess, channelGet, channelPut, and channelPutGet.
But lots of work remains:</p>
<dl>
<dt>Other Channel Methods</dt>
<dd>Monitor is next.</dd>
<dt>Memory leaks at exit</dt>
<dd>May need help from Matej.</dd>
<dt>Scalar Arrays</dt>
<dd>Have not been tested. Share has not been implemented.</dd>
<dt>Structure Arrays</dt>
<dd>Has not been implemented</dd>
<dt>Testing</dt>
<dd>Needs lots more testing</dd>
</dl>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<h3>Overview</h3>
<p>A brief description of a pvDatabase is that it is a set of network accessible, smart,
memory resident records.
Each record has data composed of a top level PVStructure.
Each record has a name which is the channelName for pvAccess.
A local Channel Provider implements the complete ChannelProvider and
Channel interfaces as defined by pvAccess.
The local provider provides access to the records in the pvDatabase.
This local provider is accessed by the remote pvAccess server.
A record is smart because code can be attached to a record, which is accessed via a method named process.</p>
<p>This document describes components that provides the following features:
<dl>
<dt>database<dt>
<dd>This encapsulates the concept of a database of memory resident smart records.
The two main components are:
<dl>
<dt>pvRecord</dt>
<dd>This encapsulates the concept of a smart record. It can be processed.
Changes to field values can be trapped. A record can be locked.</dd>
<dt>pvDatabase<dt>
<dd>This is a database of pvRecords.
Records can be added and removed from a database.</dd>
</dl>
<dt>pvAccess</dt>
<dd>This is a complete implementation of ChannelProvider and Channel
as defined by pvAccess.
It is used by the server side of pvAccess to attach to pvRecords.
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
</dl>
<p>database provides base classes that make it easy to create record instances.
The code attached to each record must create the top
level PVStructure and the following two methods:</p>
<dl>
<dt>init</dt>
<dd>This is a method for initializing the support.
It returns true if successful and false otherwise.
</dd>
<dt>process</dt>
<dd>This is what makes a record smart.
</dd>
</dl>
<h3>Relationship with pvIOCJava.</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
which also implements a pvDatabase.
PVDatabaseCPP extracts the core components required to create a network accessible database of smart
memory resident records.
pvDatabaseCPP does not implement any of the specialized support that pvIOCJava
provides.
It is expected that many services will be created that do not require the full features provided
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
them named pvDatabaseJava.</p>
<p>Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing.
For pvDatabaseCPP the process method is allowed to block.
Until a need is demonstrated this will remain true.
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
The server side of remote pvAccess creates two threads for each client and always accesses
a record via these threads.
It is expected that these threads will be sufficient to efficently handle all channel methods except
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
then the scanning facility will have to provide some way of handling process requests that block.</p>
</p>
<h3>Example PVRecord Extension</h3>
<p>The example implements a simple counter.
The example can be run on linux as follows:</p>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP
mrk&gt; bin/linux-x86_64/exampleCounter
</pre>
<p>The example consists of two components:</p>
<dl>
<dt>ExampleCounter.h</dt>
<dd>The source code for the counter.</dd>
<dt>exampleCounterMain.cpp</dt>
<dd>A main program that runs the example so that it can be accessed
by a pvAccess client.</dd>
</dl>
<h4>ExampleCounter.h</h4>
<p>The example resides in src/database.
The complete implementation is in the header file.
A serious implementation would probably break the code into two files:
1) a header, and 2) the implementation. The description consists of</p>
<pre>
class ExampleCounter;
typedef std::tr1::shared_ptr&lt;ExampleCounter&gt; ExampleCounterPtr;
class ExampleCounter :
public PVRecord
{
public:
POINTER_DEFINITIONS(ExampleCounter);
static ExampleCounterPtr create(
epics::pvData::String const &amp; recordName);
virtual ~ExampleCounter();
virtual void destroy();
virtual bool init();
virtual void process();
private:
ExampleCounter(epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
epics::pvData::PVLongPtr pvValue;
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
};
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dd>This is example specific but each support could provide
a similar static method.
</dd>
<dt>~ExampleCounter<dt>
<dd>The destructor must be declared virtual.</dd>
<dt><destroy</dt>
<dd>Called when the record is being destroyed.
This must call the base class destroy method.
<dt>init<dt>
<dd>A method to initialize the support. It returns true
if initialization is successful and false if not.
NOTE that this is a virtual method of PVRecord itself.</dd>
<dt>process<dt>
<dd>
This again is a virtual method of PVRecord.
</dd>
<dt>ExampleCounter<dt>
<dd>For the example this is private.</dd>
<dt>pvValue</dt>
<dd>This is the field of the top level structure that process
accesses.
</dd>
<dl>
<p>The implementation of create method is:</p>
<pre>
ExampleCounterPtr ExampleCounter::create(
epics::pvData::String const &amp; recordName)
{
epics::pvData::PVStructurePtr pvStructure =
epics::pvData::getStandardPVField()-&gt;scalar(
epics::pvData::pvDouble,"timeStamp,alarm"");
ExampleCounterPtr pvRecord(
new ExampleCounter(recordName,pvStructure));
if(!pvRecord-&gt;init()) pvRecord.reset();
return pvRecord;
}
</pre>
This:
<ul>
<li>Creates the top level structure.</li>
<li>Creates a ExampleCounterPtr via the constructor.</li>
<li>Calls init and if it fails resets the shared pointer.</li>
<li>Returns the shared pointer to the newly created record.</li>
</ul>
<p>The private constructor method is:</p>
<pre>
ExampleCounter::ExampleCounter(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure)
: PVRecord(recordName,pvStructure)
{
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
}
</pre>
The example is very simple. It just calls the base class constructor.
<p>The destructor and destroy methods are:</p>
<pre>
ExampleCounter::~ExampleCounter()
{
destroy();
}
void ExampleCounter::destroy()
{
PVRecord::destroy();
}
</pre>
The destructor just calls destroy.
The destroy method, which is virtual, just calls the destroy method of the base class.
A more complicated example can clean up any resources it used but must call the base
class destroy method.
<p>The implementation of init is:</p>
<pre>
bool ExampleCounter::init()
{
initPVRecord();
epics::pvData::PVFieldPtr pvField;
pvValue = getPVStructure()-&gt;getLongField("value");
if(pvValue.get()==NULL) return false;
return true;
}
</pre>
This:
<ul>
<li>Calls initRecord which is implemented by the base class.
It MUST be called.</li>
<li>Calls getLongField to get the interface to the value field,
which must be a scalar with type long.</li>
<li>If a long value field was not found it returns false.</li>
<li>Returns true</li>
</ul>
<p>The implementation of process is:</p>
<pre>
void ExampleCounter::process()
{
pvValue-&gt;put(pvValue-&gt;get() + 1.0);
timeStamp.getCurrent();
pvTimeStamp.set(timeStamp);
}
</pre>
It adds 1.0 to the current value.
It then sets the timeStamp to the current time.
<h4>exampleCounterMain.cpp</h4>
<p>This is in test/server.
The main program is:</p>
<pre>
int main(int argc,char *argv[])
{
PVDatabasePtr master = PVDatabase::getMaster();
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
String recordName("exampleCounter");
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
bool result = master-&gt;addRecord(pvRecord);
cout &lt;&lt; "result of addRecord " &lt;&lt; recordName &lt;&lt; " " &lt;&lt; result &lt;&lt; endl;
pvRecord.reset();
cout &lt;&lt; "exampleServer\n";
string str;
while(true) {
cout &lt;&lt; "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
return 0;
}
</pre>
This:
<ul>
<li>Gets a pointer to the master database.</li>
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
<li>Creates a ExampleCounter record with the name exampleCounter
</li>
<li>Prints exampleCounter on standard out.</li>
<li>Runs forever until the user types exit on standard in.</li>
</ul>
<h3>Phased Development</h3>
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
<dl>
<dt>pvRecord</d>
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
<dt>pvDatabase</d>
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
<dt>Local Channel Provider</dt>
<dd>Complete implementation of ChannelProvider and Channel.
This means that pvCopy and monitor are also implemented.</dd>
</dl>
<p>Future phases of pvDatabaseCPP might include:</p>
<dl>
<dt>Install</dt>
<dd>This provides complete support for on-line add and delete
of sets of records.
With the first phase each "service" is responsible for it's own implementation.
All that is provided is addRecord and removeRecord.
</dd>
<dt>Field support</dt>
<dd>Add the ability to optionally add support to fields.
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
<dt>XML parser</dt>
<dd>This provides the ability to create record instances without writing any code.</dd>
</dl>
<p>The completion of each phase provides useful features that can be used without waiting for the
completion of later phases.
The rest of this document discusses only the first phase.</p>
<h3>Features Required for localChannelProvider</h3>
<dl>
<dt>pvCopy</dt>
<dd>Creates a PVStructure that contains a copy of an arbitary
subset of the fields of another top level PVStructure.
It can copy data between the two and maintains a bitSet that show
which fields are changed.<dd>
<dt>monitor</dt>
<dd>This provides the ability to monitor changes to fields of a record.</dd>
<dt>PVRecord and PVDatabase</dt>
<dd>Defined below.</dd>
<dt>The localChannelProvider itself</dt>
<dd>This is the pvAccess package in pvIOCJava.
The localChannelProvider will access data from PVRecords.
It will implement all channel methods.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
the process method has to do everything itself without any generic field support.
This will be sufficient for starting to implement services.
The following are the minimium features required</p>
<dl>
<dt>PVDatabase</dt>
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
<dt>PVRecord</dt>
<dd>This, and a set of related interfaces, provides the following:
<dl>
<dt>Access to top level PVStructure</dt>
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
<dt>Record locking</dt>
<dd>A record can be locked and unlocked.
A record must be locked whenever data in the pvStructure is accessed.</dd>
<dt>Trapping data changes</dt>
<dd>A client can request to be notified when data in the pvStructure is modified.
It can do this on a field by field basis.</dd>
</dl>
</dd>
</dl>
<p>The following sections describes the classes required for the first phase.</p>
<h2>database</h2>
<p>This directory has the following files:</p>
<dl>
<dt>pvDatabase.h</dt>
<dd>
This is what is described in this section.
</dd>
<dt>pvDatabase.cpp</dt>
<dd>
The implementation of PVDatabase.
</dd>
<dt>pvRecord.cpp</dt>
<dd>
The implementation of the base class for PVREcord.
It can also implement record instances with a process
method does nothing.
This can be used to create a "dumb" record where all changes are
done by clients.
The complete implementation is provided in the header file.
Thus code will be generated only if other code includes the
header file and creates a record instance.
</dd>
<dt>exampleCounter.h</dt>
<dd>
This was described in the introduction.
</dd>
<dt>powerSupplyRecordTest.h</dt>
<dd>
This provides code that simulates a power supply.
It computes the current from the voltage and power.
It is used for testing.
The complete implementation is provided in the header file.
Thus code will be generated only if other code includes the
header file and creates a record instance.
</dd>
</dl>
<p>The classes in pvDatabase.h describe a database of memory resident
smart records.
It describes the following classes:</p>
<dl>
<dt>PVRecord</dt>
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
<dt>PVRecordField</dt>
<dt>PVRecordStructure</dt>
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
can be implemented.</dd>
<dt>PVRecordClient</dt>
<dd>This is called by anything that acceses PVRecord.</dd>
<dt>PVListener</dt>
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
<dt>PVDatabase</dt>
<dd>This is a database of PVRecords.</dd>
</dl>
<p>Each class is described in a separate subsection.</p>
<h3>C++ namespace and typedefs</h3>
<pre>
namespace epics { namespace pvDatabase {
class PVRecord;
typedef std::tr1::shared_ptr&lt;PVRecord&gt; PVRecordPtr;
typedef std::map&lt;epics::pvData::String,PVRecordPtr&gt; PVRecordMap;
class PVRecordField;
typedef std::tr1::shared_ptr&lt;PVRecordField&gt; PVRecordFieldPtr;
typedef std::vector&lt;PVRecordFieldPtr&gt; PVRecordFieldPtrArray;
typedef std::tr1::shared_ptr&lt;PVRecordFieldPtrArray&gt; PVRecordFieldPtrArrayPtr;
class PVRecordStructure;
typedef std::tr1::shared_ptr&lt;PVRecordStructure&gt; PVRecordStructurePtr;
class PVRecordClient;
typedef std::tr1::shared_ptr&lt;PVRecordClient&gt; PVRecordClientPtr;
class PVListener;
typedef std::tr1::shared_ptr&lt;PVListener&gt; PVListenerPtr;
class RecordProcessRequester;
typedef std::tr1::shared_ptr&lt;RecordProcessRequester&gt; RecordProcessRequesterPtr;
class RecordPutRequester;
typedef std::tr1::shared_ptr&lt;RecordPutRequester&gt; RecordPutRequesterPtr;
class PVDatabase;
typedef std::tr1::shared_ptr&lt;PVDatabase&gt; PVDatabasePtr;
</pre>
<h3>class PVRecord</h3>
<p>NOTES:
<ul>
<li>This section uses the name record instead of "an instance of PVRecord".</li>
<li>Most clients will access a record via the local channel provider,
i. e. via pvAccess.
Thus this section is mainly of interest to
the local channel provider and record implementers.</li>
<li>Most readers will not care about most of the PVRecord methods.
Most of the methods are used by the pvAccess code.
Service implementers will mostly be interested in methods init and process.
These are described first.
</ul>
<hr>PVRecord Methods</h4>
<pre>
class PVRecord
public epics::pvData::Requester,
public std::tr1::enable_shared_from_this&lt;PVRecord&gt;
{
public:
POINTER_DEFINITIONS(PVRecord);
virtual bool init() {initPVRecord(); return true;}
virtual void process() {}
static PVRecordPtr create(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
virtual ~PVRecord();
virtual void destroy();
epics::pvData::String getRecordName();
PVRecordStructurePtr getPVRecordStructure();
PVRecordFieldPtr findPVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField);
bool addRequester(epics::pvData::RequesterPtr const &amp; requester);
bool removeRequester(epics::pvData::RequesterPtr const &amp; requester);
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
void lock();
void unlock();
bool tryLock();
void lockOtherRecord(PVRecordPtr const &amp; otherRecord);
bool addPVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
bool removePVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
void detachClients();
bool addListener(PVListenerPtr const &amp; pvListener);
bool removeListener(PVListenerPtr const &amp; pvListener);
void beginGroupPut();
void endGroupPut();
epics::pvData::String getRequesterName() {return getRecordName();}
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
void message(
PVRecordFieldPtr const &amp; pvRecordField,
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
void toString(epics::pvData::StringBuilder buf);
void toString(epics::pvData::StringBuilder buf,int indentLevel);
protected:
PVRecord(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
void initPVRecord();
epics::pvData::PVStructurePtr getPVStructure();
PVRecordPtr getPtrSelf()
{
return shared_from_this();
}
private:
...
}
</pre>
<p>The methods are:</h3>
<dl>
<dt>init</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
This method Must call initPVRecord.</p>
</dd>
<dt>process</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
The base implementation does nothing.</p>
</dd>
<dt>create</dt>
<dd>Static method to create dumb records, i.e. records with a process method
that does nothing.</dd>
<dt>~PVRecord</dt>
<dd>The destructor which must be virtual. A derived class must also have
a virtual destructor.</dd>
<dt>destroy</dt>
<dd>This is a virtual method.
</dd>
<dt>getRecordName</dt>
<dd>Return the recordName.</dd>
<dt>getPVRecordStructure</dt>
<dd>Get the top level PVStructure.</dd>
<dt>findPVRecordField</dt>
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
<dt>addRequester</dt>
<dd>Add a requester to receive messages.</dd>
<dt>removeRequester</dt>
<dd>Remove a message requester.</dd>
<dt>lock_guard</dt>
<dd>This is an inline method that locks the record. The record will automatically
be unlocked when control leaves the block that has the call.
<dt>lock</dt>
<dt>unlock</dt>
<dd>Lock and Unlock the record.
Any code accessing the data in the record or calling other PVRecord methods
must have the record locked.</dd>
<dt>tryLock</dt>
<dd>If true then just like lock.
If falseclient can not access record.
A client can try to simultaneously hold the lock for more than two records
by calling this method. But must be willing to accept failure.
</dd>
<dt>lockOtherRecord</dt>
<dd>A client that holds the lock for one record can lock one other record.
A client must not call this if the client already has the lock for
more then one record.
</dd>
<dt>addPVRecordClient</dt>
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
<dt>removePVRecordClient</dt>
<dd>Client is no longer accessing the record.</dd>
<dt>detachClients</dt>
<dd>Ask all clients to detach from the record</dd>
<dt>addListener</dt>
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
<dt>removeListener</dt>
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
<dt>beginGroupPut</dt>
<dd>Begin a group of puts.
This results in all registered PVListeners being called</dd>
<dt>endGroupPut</dt>
<dd>End a group of puts.
This results in all registered PVListeners being called.</dd>
<dt>getRequesterName</dt>
<dd>virtual method of Requester
</dd>
<dt>message</dt>
<dd>Can be called by implementation code.
The message will be sent to every requester.</dd>
<dt>toString</dt>
<dd>Just calls the top level PVStructure toString method.</dd>
<dt>PVRecord</dt>
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
<dt>initPVRecord</dt>
<dd>This method must be called by derived class.</dd>
<dt>getPVStructure</dt>
<dd>Called by derived class.</dd>
</dl>
<h3>class PVRecordField</h3>
<pre>
class PVRecordField {
public virtual epics::pvData::PostHandler,
public std::tr1::enable_shared_from_this&lt;PVRecordField&gt;
public:
POINTER_DEFINITIONS(PVRecordField);
PVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField,
PVRecordStructurePtr const &amp;parent,
PVRecordPtr const &amp; pvRecord);
virtual ~PVRecordField();
virtual void destroy();
PVRecordStructurePtr getParent();
epics::pvData::PVFieldPtr getPVField();
epics::pvData::String getFullFieldName();
epics::pvData::String getFullName();
PVRecordPtr getPVRecord();
bool addListener(PVListenerPtr const &amp; pvListener);
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
protected:
PVRecordFieldPtr getPtrSelf()
{
return shared_from_this();
}
virtual void init();
private:
...
};
</pre>
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordField</dt>
<dd>The constructor.</dd>
<dt>~PVRecordField</dt>
<dd>The destructor.</dd>
<dt>destroy</dt>
<dd>Called by PVRecordStructure when it's destroy method is called.</dd>
<dt>getParent</dt>
<dd>Get the parent PVRecordStructure for this field.</dd>
<dt>getPVField</dt>
<dd>Get the PVField associated with this PVRecordField.</dd>
<dt>getFullFieldName</dt>
<dd>This gets the full name of the field, i.e. field,field,..</dd>
<dt>getFullName</dt>
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
<dt>getPVRecord</dt>
<dd>Returns the PVRecord to which this field belongs.</dd>
<dt>addListener</dt>
<dd>Add A PVListener to this field.
Whenever this field or any subfield if this field is modified the listener will be notified.
PVListener is described below.
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<dt>message</dt>
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
fieldname.</dd>
</dl>
<h3>class PVRecordStructure</h3>
<pre>
class PVRecordStructure : public PVRecordField {
public:
POINTER_DEFINITIONS(PVRecordStructure);
PVRecordStructure(
epics::pvData::PVStructurePtr const &amp; pvStructure,
PVRecordFieldPtrArrayPtr const &amp; pvRecordField);
virtual ~PVRecordStructure();
virtual void destroy();
PVRecordFieldPtrArrayPtr getPVRecordFields();
epics::pvData::PVStructurePtr getPVStructure();
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
protected:
virtual void init();
private:
...
};
</pre>
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordStructure</dt>
<dd>The constructor.</dd>
<dt>~PVRecordStructure</dt>
<dd>The destructor.</dd>
<dt>getPVRecordFields</dt>
<dd>Get the PVRecordField array for the subfields</dd>
<dt>getPVStructure</dt>
<dd>Get the PVStructure for this field.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<h3>class PVRecordClient</h3>
<pre>
class PVRecordClient {
POINTER_DEFINITIONS(PVRecordClient);
virtual ~PVRecordClient();
virtual void detach(PVRecordPtr const &amp; pvRecord);
};
</pre>
<p>where</p>
<dl>
<dt>~PVRecordClient</dt>
<dd>The destructor.</dd>
<dt>detach</dt>
<dd>The record is being removed from the master database,</dd>
</dl>
</dl>
<h3>class PVListener</h3>
<pre>
class PVListener {
virtual public PVRecordClient
public:
POINTER_DEFINITIONS(PVListener);
virtual ~PVListener();
virtual void dataPut(PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void beginGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void endGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~PVListener</dt>
<dd>The destructor.</dd>
<dt>dataPut(PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
<dt>dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
Requested is the field to which the requester issued a pvField-&amp;addListener.
This is called if the listener has called PVRecordField-&amp;addListener for requested.</dd>
<dt>beginGroupPut</dt>
<dd>A related set of changes is being started.</dd>
<dt>endGroupPut</dt>
<dd>A related set of changes is done.</dd>
</dl>
<h3>class PVDatabase</h3>
<pre>
class PVDatabase : virtual public epics::pvData::Requester {
public:
POINTER_DEFINITIONS(PVDatabase);
static PVDatabasePtr getMaster();
virtual ~PVDatabase();
virtual void destroy();
PVRecordPtr findRecord(epics::pvData::String const&amp; recordName);
bool addRecord(PVRecordPtr const &amp; record);
bool removeRecord(PVRecordPtr const &amp; record);
virtual epics::pvData::String getRequesterName();
virtual void message(
epics::pvData::String const &amp;message,
epics::pvData::MessageType messageType);
private:
PVDatabase();
};
</pre>
<p>where</p>
<dl>
<dt>getMaster</dt>
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
<dt>~PVDatabase</dt>
<dd>The destructor.</dd>
<dt>destroy</dt>
<dd>This is called by remote channelAccess when process exits.
This destroys and removes all records in the PVDatabase.</dd>
<dt>findRecord</dt>
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
<dt>addRecord</dt>
<dd>Add a record to the database.
If the record already exists it is not modified and false is returned.</dd>
<dt>removeRecord</dt>
<dd>Remove a record from the database.
If the record was not in the database false is returned.</dd>
<dt>getRequesterName</dt>
<dd>Virtual method of Requester</dd>
<dt>message</dt>
<dd>Virtual message of Requester.</dd>
</dl>
<h2>pvAccess</h2>
<p>Not yet described.
It is only of interest to someone who wants to understand how it works.
</p>
<p>A brief description is that it implements the following components of pvIOCJava:</p>
<dl>
<dt>pvCopy</dt>
<dt>monitor</dt>
<dt>local ChannelProvider and Channel</dt>
</dl>
</div>
</body>
</html>

View File

@@ -1,876 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>pvDatabaseCPP</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div class="head">
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 16-May-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
<hr />
</div>
<h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP,
which is a framework for implementing a network accessable database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
The framework can be extended in order to create record instances that implements services.
The minimum that an extenson must provide is a top level PVStructure and a process method.
</p>
<p>EPICS version 4 is a set of related products in the EPICS
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>
<p>This is the 16-May-2013 version of the definition of pvDatabaseCPP.
</p>
<p>The following Channel methods are implemented and working: getField,
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
But lots of work remains:</p>
<dl>
<dt>Other Channel Methods</dt>
<dd>ChannelArray is next.</dd>
<dt>Monitor Algorithms</dt>
<dd>Monitor algorithms have no been implemented.
Thus all monitors are onPut.</dd>
<dt>Lifecycle problems</dt>
<dd>Problems when channel clients disconnect.
May need help from Matej</dd>
<dt>Memory leaks at exit</dt>
<dd>May need help from Matej.</dd>
<dt>Scalar Arrays</dt>
<dd>Have not been tested. Share has not been implemented.</dd>
<dt>Structure Arrays</dt>
<dd>Has not been implemented</dd>
<dt>Testing</dt>
<dd>Needs lots more testing</dd>
</dl>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<h3>Overview</h3>
<p>A brief description of a pvDatabase is that it is a set of network accessible, smart,
memory resident records.
Each record has data composed of a top level PVStructure.
Each record has a name which is the channelName for pvAccess.
A local Channel Provider implements the complete ChannelProvider and
Channel interfaces as defined by pvAccess.
The local provider provides access to the records in the pvDatabase.
This local provider is accessed by the remote pvAccess server.
A record is smart because code can be attached to a record, which is accessed via a method named process.</p>
<p>This document describes components that provides the following features:
<dl>
<dt>database<dt>
<dd>This encapsulates the concept of a database of memory resident smart records.
The two main components are:
<dl>
<dt>pvRecord</dt>
<dd>This encapsulates the concept of a smart record. It can be processed.
Changes to field values can be trapped. A record can be locked.</dd>
<dt>pvDatabase<dt>
<dd>This is a database of pvRecords.
Records can be added and removed from a database.</dd>
</dl>
<dt>pvAccess</dt>
<dd>This is a complete implementation of ChannelProvider and Channel
as defined by pvAccess.
It is used by the server side of pvAccess to attach to pvRecords.
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
</dl>
<p>database provides base classes that make it easy to create record instances.
The code attached to each record must create the top
level PVStructure and the following two methods:</p>
<dl>
<dt>init</dt>
<dd>This is a method for initializing the support.
It returns true if successful and false otherwise.
</dd>
<dt>process</dt>
<dd>This is what makes a record smart.
</dd>
</dl>
<h3>Relationship with pvIOCJava.</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
which also implements a pvDatabase.
PVDatabaseCPP extracts the core components required to create a network accessible database of smart
memory resident records.
pvDatabaseCPP does not implement any of the specialized support that pvIOCJava
provides.
It is expected that many services will be created that do not require the full features provided
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
them named pvDatabaseJava.</p>
<p>Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing.
For pvDatabaseCPP the process method is allowed to block.
Until a need is demonstrated this will remain true.
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
The server side of remote pvAccess creates two threads for each client and always accesses
a record via these threads.
It is expected that these threads will be sufficient to efficently handle all channel methods except
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
then the scanning facility will have to provide some way of handling process requests that block.</p>
</p>
<h3>Example PVRecord Extension</h3>
<p>The example implements a simple counter.
The example can be run on linux as follows:</p>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP
mrk&gt; bin/linux-x86_64/exampleCounter
</pre>
<p>The example consists of two components:</p>
<dl>
<dt>ExampleCounter.h</dt>
<dd>The source code for the counter.</dd>
<dt>exampleCounterMain.cpp</dt>
<dd>A main program that runs the example so that it can be accessed
by a pvAccess client.</dd>
</dl>
<h4>ExampleCounter.h</h4>
<p>The example resides in src/database.
The complete implementation is in the header file.
A serious implementation would probably break the code into two files:
1) a header, and 2) the implementation. The description consists of</p>
<pre>
class ExampleCounter;
typedef std::tr1::shared_ptr&lt;ExampleCounter&gt; ExampleCounterPtr;
class ExampleCounter :
public PVRecord
{
public:
POINTER_DEFINITIONS(ExampleCounter);
static ExampleCounterPtr create(
epics::pvData::String const &amp; recordName);
virtual ~ExampleCounter();
virtual void destroy();
virtual bool init();
virtual void process();
private:
ExampleCounter(epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
epics::pvData::PVLongPtr pvValue;
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
};
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dd>This is example specific but each support could provide
a similar static method.
</dd>
<dt>~ExampleCounter<dt>
<dd>The destructor must be declared virtual.</dd>
<dt><destroy</dt>
<dd>Called when the record is being destroyed.
This must call the base class destroy method.
<dt>init<dt>
<dd>A method to initialize the support. It returns true
if initialization is successful and false if not.
NOTE that this is a virtual method of PVRecord itself.</dd>
<dt>process<dt>
<dd>
This again is a virtual method of PVRecord.
</dd>
<dt>ExampleCounter<dt>
<dd>For the example this is private.</dd>
<dt>pvValue</dt>
<dd>This is the field of the top level structure that process
accesses.
</dd>
<dl>
<p>The implementation of create method is:</p>
<pre>
ExampleCounterPtr ExampleCounter::create(
epics::pvData::String const &amp; recordName)
{
epics::pvData::PVStructurePtr pvStructure =
epics::pvData::getStandardPVField()-&gt;scalar(
epics::pvData::pvDouble,"timeStamp,alarm"");
ExampleCounterPtr pvRecord(
new ExampleCounter(recordName,pvStructure));
if(!pvRecord-&gt;init()) pvRecord.reset();
return pvRecord;
}
</pre>
This:
<ul>
<li>Creates the top level structure.</li>
<li>Creates a ExampleCounterPtr via the constructor.</li>
<li>Calls init and if it fails resets the shared pointer.</li>
<li>Returns the shared pointer to the newly created record.</li>
</ul>
<p>The private constructor method is:</p>
<pre>
ExampleCounter::ExampleCounter(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure)
: PVRecord(recordName,pvStructure)
{
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
}
</pre>
The example is very simple. It just calls the base class constructor.
<p>The destructor and destroy methods are:</p>
<pre>
ExampleCounter::~ExampleCounter()
{
destroy();
}
void ExampleCounter::destroy()
{
PVRecord::destroy();
}
</pre>
The destructor just calls destroy.
The destroy method, which is virtual, just calls the destroy method of the base class.
A more complicated example can clean up any resources it used but must call the base
class destroy method.
<p>The implementation of init is:</p>
<pre>
bool ExampleCounter::init()
{
initPVRecord();
epics::pvData::PVFieldPtr pvField;
pvValue = getPVStructure()-&gt;getLongField("value");
if(pvValue.get()==NULL) return false;
return true;
}
</pre>
This:
<ul>
<li>Calls initRecord which is implemented by the base class.
It MUST be called.</li>
<li>Calls getLongField to get the interface to the value field,
which must be a scalar with type long.</li>
<li>If a long value field was not found it returns false.</li>
<li>Returns true</li>
</ul>
<p>The implementation of process is:</p>
<pre>
void ExampleCounter::process()
{
pvValue-&gt;put(pvValue-&gt;get() + 1.0);
timeStamp.getCurrent();
pvTimeStamp.set(timeStamp);
}
</pre>
It adds 1.0 to the current value.
It then sets the timeStamp to the current time.
<h4>exampleCounterMain.cpp</h4>
<p>This is in test/server.
The main program is:</p>
<pre>
int main(int argc,char *argv[])
{
PVDatabasePtr master = PVDatabase::getMaster();
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
String recordName("exampleCounter");
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
bool result = master-&gt;addRecord(pvRecord);
cout &lt;&lt; "result of addRecord " &lt;&lt; recordName &lt;&lt; " " &lt;&lt; result &lt;&lt; endl;
pvRecord.reset();
cout &lt;&lt; "exampleServer\n";
string str;
while(true) {
cout &lt;&lt; "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
return 0;
}
</pre>
This:
<ul>
<li>Gets a pointer to the master database.</li>
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
<li>Creates a ExampleCounter record with the name exampleCounter
</li>
<li>Prints exampleCounter on standard out.</li>
<li>Runs forever until the user types exit on standard in.</li>
</ul>
<h3>Phased Development</h3>
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
<dl>
<dt>pvRecord</d>
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
<dt>pvDatabase</d>
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
<dt>Local Channel Provider</dt>
<dd>Complete implementation of ChannelProvider and Channel.
This means that pvCopy and monitor are also implemented.</dd>
</dl>
<p>Future phases of pvDatabaseCPP might include:</p>
<dl>
<dt>Install</dt>
<dd>This provides complete support for on-line add and delete
of sets of records.
With the first phase each "service" is responsible for it's own implementation.
All that is provided is addRecord and removeRecord.
</dd>
<dt>Field support</dt>
<dd>Add the ability to optionally add support to fields.
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
<dt>XML parser</dt>
<dd>This provides the ability to create record instances without writing any code.</dd>
</dl>
<p>The completion of each phase provides useful features that can be used without waiting for the
completion of later phases.
The rest of this document discusses only the first phase.</p>
<h3>Features Required for localChannelProvider</h3>
<dl>
<dt>pvCopy</dt>
<dd>Creates a PVStructure that contains a copy of an arbitary
subset of the fields of another top level PVStructure.
It can copy data between the two and maintains a bitSet that show
which fields are changed.<dd>
<dt>monitor</dt>
<dd>This provides the ability to monitor changes to fields of a record.</dd>
<dt>PVRecord and PVDatabase</dt>
<dd>Defined below.</dd>
<dt>The localChannelProvider itself</dt>
<dd>This is the pvAccess package in pvIOCJava.
The localChannelProvider will access data from PVRecords.
It will implement all channel methods.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
the process method has to do everything itself without any generic field support.
This will be sufficient for starting to implement services.
The following are the minimium features required</p>
<dl>
<dt>PVDatabase</dt>
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
<dt>PVRecord</dt>
<dd>This, and a set of related interfaces, provides the following:
<dl>
<dt>Access to top level PVStructure</dt>
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
<dt>Record locking</dt>
<dd>A record can be locked and unlocked.
A record must be locked whenever data in the pvStructure is accessed.</dd>
<dt>Trapping data changes</dt>
<dd>A client can request to be notified when data in the pvStructure is modified.
It can do this on a field by field basis.</dd>
</dl>
</dd>
</dl>
<p>The following sections describes the classes required for the first phase.</p>
<h2>database</h2>
<p>This directory has the following files:</p>
<dl>
<dt>pvDatabase.h</dt>
<dd>
This is what is described in this section.
</dd>
<dt>pvDatabase.cpp</dt>
<dd>
The implementation of PVDatabase.
</dd>
<dt>pvRecord.cpp</dt>
<dd>
The implementation of the base class for PVREcord.
It can also implement record instances with a process
method does nothing.
This can be used to create a "dumb" record where all changes are
done by clients.
The complete implementation is provided in the header file.
Thus code will be generated only if other code includes the
header file and creates a record instance.
</dd>
<dt>exampleCounter.h</dt>
<dd>
This was described in the introduction.
</dd>
<dt>powerSupplyRecordTest.h</dt>
<dd>
This provides code that simulates a power supply.
It computes the current from the voltage and power.
It is used for testing.
The complete implementation is provided in the header file.
Thus code will be generated only if other code includes the
header file and creates a record instance.
</dd>
</dl>
<p>The classes in pvDatabase.h describe a database of memory resident
smart records.
It describes the following classes:</p>
<dl>
<dt>PVRecord</dt>
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
<dt>PVRecordField</dt>
<dt>PVRecordStructure</dt>
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
can be implemented.</dd>
<dt>PVRecordClient</dt>
<dd>This is called by anything that acceses PVRecord.</dd>
<dt>PVListener</dt>
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
<dt>PVDatabase</dt>
<dd>This is a database of PVRecords.</dd>
</dl>
<p>Each class is described in a separate subsection.</p>
<h3>C++ namespace and typedefs</h3>
<pre>
namespace epics { namespace pvDatabase {
class PVRecord;
typedef std::tr1::shared_ptr&lt;PVRecord&gt; PVRecordPtr;
typedef std::map&lt;epics::pvData::String,PVRecordPtr&gt; PVRecordMap;
class PVRecordField;
typedef std::tr1::shared_ptr&lt;PVRecordField&gt; PVRecordFieldPtr;
typedef std::vector&lt;PVRecordFieldPtr&gt; PVRecordFieldPtrArray;
typedef std::tr1::shared_ptr&lt;PVRecordFieldPtrArray&gt; PVRecordFieldPtrArrayPtr;
class PVRecordStructure;
typedef std::tr1::shared_ptr&lt;PVRecordStructure&gt; PVRecordStructurePtr;
class PVRecordClient;
typedef std::tr1::shared_ptr&lt;PVRecordClient&gt; PVRecordClientPtr;
class PVListener;
typedef std::tr1::shared_ptr&lt;PVListener&gt; PVListenerPtr;
class RecordProcessRequester;
typedef std::tr1::shared_ptr&lt;RecordProcessRequester&gt; RecordProcessRequesterPtr;
class RecordPutRequester;
typedef std::tr1::shared_ptr&lt;RecordPutRequester&gt; RecordPutRequesterPtr;
class PVDatabase;
typedef std::tr1::shared_ptr&lt;PVDatabase&gt; PVDatabasePtr;
</pre>
<h3>class PVRecord</h3>
<p>NOTES:
<ul>
<li>This section uses the name record instead of "an instance of PVRecord".</li>
<li>Most clients will access a record via the local channel provider,
i. e. via pvAccess.
Thus this section is mainly of interest to
the local channel provider and record implementers.</li>
<li>Most readers will not care about most of the PVRecord methods.
Most of the methods are used by the pvAccess code.
Service implementers will mostly be interested in methods init and process.
These are described first.
</ul>
<hr>PVRecord Methods</h4>
<pre>
class PVRecord
public epics::pvData::Requester,
public std::tr1::enable_shared_from_this&lt;PVRecord&gt;
{
public:
POINTER_DEFINITIONS(PVRecord);
virtual bool init() {initPVRecord(); return true;}
virtual void process() {}
static PVRecordPtr create(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
virtual ~PVRecord();
virtual void destroy();
epics::pvData::String getRecordName();
PVRecordStructurePtr getPVRecordStructure();
PVRecordFieldPtr findPVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField);
bool addRequester(epics::pvData::RequesterPtr const &amp; requester);
bool removeRequester(epics::pvData::RequesterPtr const &amp; requester);
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
void lock();
void unlock();
bool tryLock();
void lockOtherRecord(PVRecordPtr const &amp; otherRecord);
bool addPVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
bool removePVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
void detachClients();
bool addListener(PVListenerPtr const &amp; pvListener);
bool removeListener(PVListenerPtr const &amp; pvListener);
void beginGroupPut();
void endGroupPut();
epics::pvData::String getRequesterName() {return getRecordName();}
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
void message(
PVRecordFieldPtr const &amp; pvRecordField,
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
void toString(epics::pvData::StringBuilder buf);
void toString(epics::pvData::StringBuilder buf,int indentLevel);
protected:
PVRecord(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
void initPVRecord();
epics::pvData::PVStructurePtr getPVStructure();
PVRecordPtr getPtrSelf()
{
return shared_from_this();
}
private:
...
}
</pre>
<p>The methods are:</h3>
<dl>
<dt>init</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
This method Must call initPVRecord.</p>
</dd>
<dt>process</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
The base implementation does nothing.</p>
</dd>
<dt>create</dt>
<dd>Static method to create dumb records, i.e. records with a process method
that does nothing.</dd>
<dt>~PVRecord</dt>
<dd>The destructor which must be virtual. A derived class must also have
a virtual destructor.</dd>
<dt>destroy</dt>
<dd>This is a virtual method.
</dd>
<dt>getRecordName</dt>
<dd>Return the recordName.</dd>
<dt>getPVRecordStructure</dt>
<dd>Get the top level PVStructure.</dd>
<dt>findPVRecordField</dt>
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
<dt>addRequester</dt>
<dd>Add a requester to receive messages.</dd>
<dt>removeRequester</dt>
<dd>Remove a message requester.</dd>
<dt>lock_guard</dt>
<dd>This is an inline method that locks the record. The record will automatically
be unlocked when control leaves the block that has the call.
<dt>lock</dt>
<dt>unlock</dt>
<dd>Lock and Unlock the record.
Any code accessing the data in the record or calling other PVRecord methods
must have the record locked.</dd>
<dt>tryLock</dt>
<dd>If true then just like lock.
If falseclient can not access record.
A client can try to simultaneously hold the lock for more than two records
by calling this method. But must be willing to accept failure.
</dd>
<dt>lockOtherRecord</dt>
<dd>A client that holds the lock for one record can lock one other record.
A client must not call this if the client already has the lock for
more then one record.
</dd>
<dt>addPVRecordClient</dt>
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
<dt>removePVRecordClient</dt>
<dd>Client is no longer accessing the record.</dd>
<dt>detachClients</dt>
<dd>Ask all clients to detach from the record</dd>
<dt>addListener</dt>
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
<dt>removeListener</dt>
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
<dt>beginGroupPut</dt>
<dd>Begin a group of puts.
This results in all registered PVListeners being called</dd>
<dt>endGroupPut</dt>
<dd>End a group of puts.
This results in all registered PVListeners being called.</dd>
<dt>getRequesterName</dt>
<dd>virtual method of Requester
</dd>
<dt>message</dt>
<dd>Can be called by implementation code.
The message will be sent to every requester.</dd>
<dt>toString</dt>
<dd>Just calls the top level PVStructure toString method.</dd>
<dt>PVRecord</dt>
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
<dt>initPVRecord</dt>
<dd>This method must be called by derived class.</dd>
<dt>getPVStructure</dt>
<dd>Called by derived class.</dd>
</dl>
<h3>class PVRecordField</h3>
<pre>
class PVRecordField {
public virtual epics::pvData::PostHandler,
public std::tr1::enable_shared_from_this&lt;PVRecordField&gt;
public:
POINTER_DEFINITIONS(PVRecordField);
PVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField,
PVRecordStructurePtr const &amp;parent,
PVRecordPtr const &amp; pvRecord);
virtual ~PVRecordField();
virtual void destroy();
PVRecordStructurePtr getParent();
epics::pvData::PVFieldPtr getPVField();
epics::pvData::String getFullFieldName();
epics::pvData::String getFullName();
PVRecordPtr getPVRecord();
bool addListener(PVListenerPtr const &amp; pvListener);
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
protected:
PVRecordFieldPtr getPtrSelf()
{
return shared_from_this();
}
virtual void init();
private:
...
};
</pre>
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordField</dt>
<dd>The constructor.</dd>
<dt>~PVRecordField</dt>
<dd>The destructor.</dd>
<dt>destroy</dt>
<dd>Called by PVRecordStructure when it's destroy method is called.</dd>
<dt>getParent</dt>
<dd>Get the parent PVRecordStructure for this field.</dd>
<dt>getPVField</dt>
<dd>Get the PVField associated with this PVRecordField.</dd>
<dt>getFullFieldName</dt>
<dd>This gets the full name of the field, i.e. field,field,..</dd>
<dt>getFullName</dt>
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
<dt>getPVRecord</dt>
<dd>Returns the PVRecord to which this field belongs.</dd>
<dt>addListener</dt>
<dd>Add A PVListener to this field.
Whenever this field or any subfield if this field is modified the listener will be notified.
PVListener is described below.
Before a listener can call addListener it must first call PVRecord.registerListener.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<dt>message</dt>
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
fieldname.</dd>
</dl>
<h3>class PVRecordStructure</h3>
<pre>
class PVRecordStructure : public PVRecordField {
public:
POINTER_DEFINITIONS(PVRecordStructure);
PVRecordStructure(
epics::pvData::PVStructurePtr const &amp; pvStructure,
PVRecordFieldPtrArrayPtr const &amp; pvRecordField);
virtual ~PVRecordStructure();
virtual void destroy();
PVRecordFieldPtrArrayPtr getPVRecordFields();
epics::pvData::PVStructurePtr getPVStructure();
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
protected:
virtual void init();
private:
...
};
</pre>
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordStructure</dt>
<dd>The constructor.</dd>
<dt>~PVRecordStructure</dt>
<dd>The destructor.</dd>
<dt>getPVRecordFields</dt>
<dd>Get the PVRecordField array for the subfields</dd>
<dt>getPVStructure</dt>
<dd>Get the PVStructure for this field.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<h3>class PVRecordClient</h3>
<pre>
class PVRecordClient {
POINTER_DEFINITIONS(PVRecordClient);
virtual ~PVRecordClient();
virtual void detach(PVRecordPtr const &amp; pvRecord);
};
</pre>
<p>where</p>
<dl>
<dt>~PVRecordClient</dt>
<dd>The destructor.</dd>
<dt>detach</dt>
<dd>The record is being removed from the master database,</dd>
</dl>
</dl>
<h3>class PVListener</h3>
<pre>
class PVListener {
virtual public PVRecordClient
public:
POINTER_DEFINITIONS(PVListener);
virtual ~PVListener();
virtual void dataPut(PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void beginGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void endGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~PVListener</dt>
<dd>The destructor.</dd>
<dt>dataPut(PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
<dt>dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
Requested is the field to which the requester issued a pvField-&amp;addListener.
This is called if the listener has called PVRecordField-&amp;addListener for requested.</dd>
<dt>beginGroupPut</dt>
<dd>A related set of changes is being started.</dd>
<dt>endGroupPut</dt>
<dd>A related set of changes is done.</dd>
</dl>
<h3>class PVDatabase</h3>
<pre>
class PVDatabase : virtual public epics::pvData::Requester {
public:
POINTER_DEFINITIONS(PVDatabase);
static PVDatabasePtr getMaster();
virtual ~PVDatabase();
virtual void destroy();
PVRecordPtr findRecord(epics::pvData::String const&amp; recordName);
bool addRecord(PVRecordPtr const &amp; record);
bool removeRecord(PVRecordPtr const &amp; record);
virtual epics::pvData::String getRequesterName();
virtual void message(
epics::pvData::String const &amp;message,
epics::pvData::MessageType messageType);
private:
PVDatabase();
};
</pre>
<p>where</p>
<dl>
<dt>getMaster</dt>
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
<dt>~PVDatabase</dt>
<dd>The destructor.</dd>
<dt>destroy</dt>
<dd>This is called by remote channelAccess when process exits.
This destroys and removes all records in the PVDatabase.</dd>
<dt>findRecord</dt>
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
<dt>addRecord</dt>
<dd>Add a record to the database.
If the record already exists it is not modified and false is returned.</dd>
<dt>removeRecord</dt>
<dd>Remove a record from the database.
If the record was not in the database false is returned.</dd>
<dt>getRequesterName</dt>
<dd>Virtual method of Requester</dd>
<dt>message</dt>
<dd>Virtual message of Requester.</dd>
</dl>
<h2>pvAccess</h2>
<p>Not yet described.
It is only of interest to someone who wants to understand how it works.
</p>
<p>A brief description is that it implements the following components of pvIOCJava:</p>
<dl>
<dt>pvCopy</dt>
<dt>monitor</dt>
<dt>local ChannelProvider and Channel</dt>
</dl>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

@@ -1,19 +0,0 @@
# Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG
DIRS += configure
DIRS += src
src_DEPEND_DIRS = configure
DIRS += ioc
ioc_DEPEND_DIRS = src
DIRS += iocBoot
iocBoot_DEPEND_DIRS = src
include $(TOP)/configure/RULES_TOP

View File

@@ -1,29 +0,0 @@
# CONFIG - Load build configuration data
#
# Do not make changes to this file!
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif

View File

@@ -1,27 +0,0 @@
# CONFIG_SITE
# Make any application-specific changes to the EPICS build
# configuration variables in this file.
#
# Host/target specific settings can be specified in files named
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# CHECK_RELEASE controls the consistency checking of the support
# applications pointed to by the RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building anyway if conflicts are found.
CHECK_RELEASE = WARN
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</path/name/to/install/top>
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local

View File

@@ -1,9 +0,0 @@
EPICS_BASE=/home/install/epics/base
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
EPICSV4HOME=/home/hg
PVCOMMON=${EPICSV4HOME}/pvCommonCPP
PVDATA=${EPICSV4HOME}/pvDataCPP
PVACCESS=${EPICSV4HOME}/pvAccessCPP
PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP
PVDATABASETEST=${EPICSV4HOME}/pvDatabaseCPP/test
PVASRV=${EPICSV4HOME}/pvaSrv

View File

@@ -1,8 +0,0 @@
TOP=..
include $(TOP)/configure/CONFIG
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
include $(TOP)/configure/RULES

View File

@@ -1,43 +0,0 @@
# pvDatabaseCPP/example RELEASE - Location of external support modules
#
# IF YOU CHANGE this file or any file it includes you must
# subsequently do a "gnumake rebuild" in the application's
# top level directory.
#
# The build process does not check dependencies against files
# that are outside this application, thus you should also do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
#
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
# EPICS V4 Developers: Do not edit the locations in this file!
#
# Create a file RELEASE.local pointing to your PVASRV, PVACCESS,
# PVDATA, PVCOMMON and EPICS_BASE build directories, e.g.
# PVASRV = /path/to/epics/pvaSrvCPP
# PVACCESS = /path/to/epics/pvAccessCPP
# PVDATA = /path/to/epics/pvDataCPP
# PVCOMMON = /path/to/epics/pvCommonCPP
# EPICS_BASE = /path/to/epics/base
# If this example is built in a directory under pvDatabaseCPP,
# use the following definitions:
PVDATABASETEST = $(TOP)/../test
PVDATABASE = $(TOP)/..
-include $(TOP)/../configure/RELEASE.local
-include $(TOP)/../../RELEASE.local
# If you copied this example from pvDatabaseCPP to be built as a
# standalone TOP, adjust and use the following definitions:
#PVDATABASETEST = /path/to/epics/pvDatabaseCPP/testTop
#PVDATABASE = /path/to/epics/pvDatabaseCPP
#-include $(TOP)/../RELEASE.local
#-include $(TOP)/configure/RELEASE.local

View File

@@ -1,6 +0,0 @@
# RULES
include $(CONFIG)/RULES
# Library should be rebuilt because LIBOBJS may have changed.
$(LIBNAME): ../Makefile

View File

@@ -1,2 +0,0 @@
#RULES.ioc
include $(CONFIG)/RULES.ioc

View File

@@ -1,2 +0,0 @@
#RULES_DIRS
include $(CONFIG)/RULES_DIRS

View File

@@ -1,3 +0,0 @@
#RULES_TOP
include $(CONFIG)/RULES_TOP

View File

@@ -1,29 +0,0 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#----------------------------------------------------
# Optimization of db files using dbst (DEFAULT: NO)
#DB_OPT = YES
#----------------------------------------------------
# Create and install (or just install)
# databases, templates, substitutions like this
DB += dbScalar.db
DB += dbInteger.db
DB += dbArray.db
DB += dbString.db
DB += dbStringArray.db
DB += dbEnum.db
DB += dbCounter.db
DB += dbDouble.db
#----------------------------------------------------
# If <anyname>.db template is not named <anyname>*.template add
# <anyname>_TEMPLATE = <templatename>
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@@ -1,9 +0,0 @@
record(waveform, "$(name)")
{
field(NELM,"5")
field(NORD,"5")
field(FTVL,"$(type)")
field(EGU, "Counts")
field(HOPR, "10")
field(LOPR, "0")
}

View File

@@ -1,20 +0,0 @@
record(calc, "${name}")
{
field(DESC, "Counter")
field(SCAN,"1 second")
field(CALC, "(A<B)?(A+C):D")
field(INPA, "${name} NPP NMS")
field(INPB, "9")
field(INPC, "1")
field(INPD, "0")
field(EGU, "Counts")
field(HOPR, "10")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}

View File

@@ -1,3 +0,0 @@
record(ao, "$(name)")
{
}

View File

@@ -1,14 +0,0 @@
record(mbbo, "$(name)")
{
field(NOBT,"2")
field(ZRVL,"0")
field(ONVL,"1")
field(TWVL,"2")
field(THVL,"3")
field(ZRST,"zero")
field(ONST,"one")
field(TWST,"two")
field(THST,"three")
field(TWSV,"MINOR")
field(THSV,"MAJOR")
}

View File

@@ -1,16 +0,0 @@
record($(type), "$(name)")
{
field(EGU, "Counts")
field(HOPR, "10")
field(LOPR, "0")
field(DRVH, "9")
field(DRVL, "0")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}

View File

@@ -1,17 +0,0 @@
record($(type), "$(name)")
{
field(PREC, "1")
field(EGU, "Counts")
field(HOPR, "10")
field(LOPR, "0")
field(DRVH, "9.9")
field(DRVL, "-0.1")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}

View File

@@ -1,3 +0,0 @@
record(stringout, "$(name)")
{
}

View File

@@ -1,5 +0,0 @@
record(waveform, "${name}")
{
field(NELM,"5")
field(FTVL,"STRING")
}

View File

@@ -1,8 +0,0 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
include $(TOP)/configure/RULES_DIRS

View File

@@ -1,43 +0,0 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#==================================================
# Build an IOC support library
#
DBD += exampleDatabase.dbd
#=============================
# build an ioc application
PROD_IOC += exampleDatabase
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
exampleDatabase_SRCS += exampleDatabase_registerRecordDeviceDriver.cpp
exampleDatabase_SRCS_DEFAULT += exampleDatabaseMain.cpp
exampleDatabase_SRCS_vxWorks += -nil-
# The following adds support from base/src/vxWorks
exampleDatabase_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
exampleDatabase_LIBS += exampleDatabase
exampleDatabase_LIBS += powerSupply
exampleDatabase_LIBS += pvDatabase
exampleDatabase_LIBS += pvaSrv
exampleDatabase_LIBS += pvAccess
exampleDatabase_LIBS += pvData
exampleDatabase_LIBS += Com
exampleDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@@ -1,6 +0,0 @@
include "base.dbd"
include "PVAServerRegister.dbd"
include "registerChannelProviderLocal.dbd"
include "dbPv.dbd"
include "powerSupplyRegister.dbd"
registrar("exampleDatabaseRegister")

View File

@@ -1,33 +0,0 @@
/*exampleDatabaseMain.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 <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "epicsExit.h"
#include "epicsThread.h"
#include "iocsh.h"
int main(int argc,char *argv[])
{
if(argc>=2) {
iocsh(argv[1]);
epicsThreadSleep(.2);
}
iocsh(NULL);
epicsExit(0);
return(0);
}

View File

@@ -1,7 +0,0 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS += $(wildcard *ioc*)
DIRS += $(wildcard as*)
DIRS += $(wildcard example*)
include $(CONFIG)/RULES_DIRS

View File

@@ -1,5 +0,0 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ARCH = $(EPICS_HOST_ARCH)
TARGETS = envPaths
include $(TOP)/configure/RULES.ioc

View File

@@ -1,29 +0,0 @@
< envPaths
cd ${TOP}
## Register all support components
dbLoadDatabase("dbd/exampleDatabase.dbd")
exampleDatabase_registerRecordDeviceDriver(pdbbase)
## Load record instances
dbLoadRecords("db/dbDouble.db","name=double00")
dbLoadRecords("db/dbDouble.db","name=double01")
dbLoadRecords("db/dbDouble.db","name=double02")
dbLoadRecords("db/dbDouble.db","name=double03")
dbLoadRecords("db/dbDouble.db","name=double04")
dbLoadRecords("db/dbDouble.db","name=double05")
dbLoadRecords("db/dbStringArray.db","name=stringArray01")
dbLoadRecords("db/dbEnum.db","name=enum01")
dbLoadRecords("db/dbCounter.db","name=counter01");
dbLoadRecords("db/dbArray.db","name=doubleArray,type=DOUBLE");
cd ${TOP}/iocBoot/${IOC}
iocInit()
dbl
epicsThreadSleep(2.0)
exampleDatabase
exampleMonitorPlugin
startPVAServer
pvdbl

View File

@@ -1,35 +0,0 @@
TOP=..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
DBD += exampleDatabase.dbd
INC += exampleDatabase.h
LIBRARY += exampleDatabase
exampleDatabase_SRCS += exampleDatabase.cpp
exampleDatabase_SRCS += exampleDatabaseRegister.cpp
exampleDatabase_LIBS += powerSupply
exampleDatabase_LIBS += pvDatabase
exampleDatabase_LIBS += pvAccess
exampleDatabase_LIBS += pvData
exampleDatabase_LIBS += Com
exampleDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
PROD_HOST += exampleDatabaseMain
exampleDatabaseMain_SRCS += exampleDatabaseMain.cpp
exampleDatabaseMain_LIBS += exampleDatabase
exampleDatabaseMain_LIBS += powerSupply
exampleDatabaseMain_LIBS += pvDatabase
exampleDatabaseMain_LIBS += pvAccess
exampleDatabaseMain_LIBS += pvData
exampleDatabaseMain_LIBS += Com
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@@ -1,168 +0,0 @@
/*exampleDatabase.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.07.24
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <vector>
#include <iostream>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/channelProviderLocal.h>
#include <pv/recordList.h>
#include <pv/traceRecord.h>
#include <pv/powerSupply.h>
#define epicsExportSharedSymbols
#include <pv/exampleDatabase.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
static FieldCreatePtr fieldCreate = getFieldCreate();
static StandardFieldPtr standardField = getStandardField();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardPVFieldPtr standardPVField = getStandardPVField();
static void createStructureArrayRecord(
PVDatabasePtr const &master,
string const &recordName)
{
StringArray names(2);
FieldConstPtrArray fields(2);
names[0] = "name";
names[1] = "value";
fields[0] = fieldCreate->createScalar(pvString);
fields[1] = fieldCreate->createScalar(pvString);
StringArray topNames(1);
FieldConstPtrArray topFields(1);
topNames[0] = "value";
topFields[0] = fieldCreate->createStructureArray(
fieldCreate->createStructure(names, fields));
StructureConstPtr top = fieldCreate->createStructure(topNames,topFields);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
bool result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
}
static void createRegularUnionArrayRecord(
PVDatabasePtr const &master,
string const &recordName)
{
StringArray unionNames(2);
FieldConstPtrArray unionFields(2);
unionNames[0] = "string";
unionNames[1] = "stringArray";
unionFields[0] = fieldCreate->createScalar(pvString);
unionFields[1] = fieldCreate->createScalarArray(pvString);
StringArray names(1);
FieldConstPtrArray fields(1);
fields[0] = fieldCreate->createUnionArray(fieldCreate->createUnion(unionNames,unionFields));
names[0] = "value";
StructureConstPtr top = fieldCreate->createStructure(names,fields);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
bool result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
}
static void createVariantUnionArrayRecord(
PVDatabasePtr const &master,
string const &recordName)
{
StringArray names(1);
FieldConstPtrArray fields(1);
fields[0] = fieldCreate->createVariantUnionArray();
names[0] = "value";
StructureConstPtr top = fieldCreate->createStructure(names,fields);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top);
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
bool result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
}
static void createRecords(
PVDatabasePtr const &master,
ScalarType scalarType,
string const &recordNamePrefix,
string const &properties)
{
string recordName = recordNamePrefix;
PVStructurePtr pvStructure = standardPVField->scalar(scalarType,properties);
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
bool result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
recordName += "Array";
pvStructure = standardPVField->scalarArray(scalarType,properties);
pvRecord = PVRecord::create(recordName,pvStructure);
result = master->addRecord(pvRecord);
}
void ExampleDatabase::create()
{
PVDatabasePtr master = PVDatabase::getMaster();
PVRecordPtr pvRecord;
string recordName;
bool result(false);
recordName = "traceRecordPGRPC";
pvRecord = TraceRecord::create(recordName);
result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
string properties;
properties = "alarm,timeStamp";
createRecords(master,pvBoolean,"exampleBoolean",properties);
createRecords(master,pvByte,"exampleByte",properties);
createRecords(master,pvShort,"exampleShort",properties);
createRecords(master,pvInt,"exampleInt",properties);
createRecords(master,pvLong,"exampleLong",properties);
createRecords(master,pvFloat,"exampleFloat",properties);
createRecords(master,pvDouble,"exampleDouble",properties);
createRecords(master,pvDouble,"exampleDouble01",properties);
createRecords(master,pvDouble,"exampleDouble02",properties);
createRecords(master,pvDouble,"exampleDouble03",properties);
createRecords(master,pvDouble,"exampleDouble04",properties);
createRecords(master,pvDouble,"exampleDouble05",properties);
createRecords(master,pvString,"exampleString",properties);
createStructureArrayRecord(master,"exampleStructureArray");
createRegularUnionArrayRecord(master,"exampleRegularUnionArray");
createVariantUnionArrayRecord(master,"exampleVariantUnionArray");
recordName = "examplePowerSupply";
PVStructurePtr pvStructure = createPowerSupply();
PowerSupplyPtr psr = PowerSupply::create(recordName,pvStructure);
if(!psr) {
cout << "PowerSupply::create failed" << endl;
} else {
result = master->addRecord(psr);
if(!result) cout<< "record " << recordName << " not added" << endl;
}
recordName = "laptoprecordListPGRPC";
pvRecord = RecordListRecord::create(recordName);
if(!pvRecord) {
cout << "RecordListRecord::create failed" << endl;
} else {
result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
}
}

View File

@@ -1,38 +0,0 @@
/* exampleDatabase.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.07.24
*/
#ifndef EXAMPLEDATABASE_H
#define EXAMPLEDATABASE_H
#ifdef epicsExportSharedSymbols
# define exampledatabaseEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/pvDatabase.h>
#ifdef exampledatabaseEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef exampledatabaseEpicsExportSharedSymbols
#endif
#include <shareLib.h>
namespace epics { namespace pvDatabase {
class epicsShareClass ExampleDatabase{
public:
static void create();
};
}}
#endif /* EXAMPLEDATABASE_H */

View File

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

View File

@@ -1,36 +0,0 @@
/*exampleDatabaseMain.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 <iostream>
#include <pv/channelProviderLocal.h>
#include <pv/exampleDatabase.h>
using namespace std;
using namespace epics::pvDatabase;
int main(int argc,char *argv[])
{
ExampleDatabase::create();
ContextLocal::shared_pointer contextLocal = ContextLocal::create();
contextLocal->start();
cout << "pvAccess server exampleDatabase running..." << endl;
epics::pvData::PVStringArrayPtr pvNames = PVDatabase::getMaster()->getRecordNames();
cout << "Hosted records: " << endl << *pvNames << endl;
contextLocal->waitForExit();
return 0;
}

View File

@@ -1,63 +0,0 @@
/*exampleDatabase.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.07.24
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <cantProceed.h>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/pvAccess.h>
#include <pv/pvDatabase.h>
#include <epicsExport.h>
#include <pv/exampleDatabase.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
static const iocshArg testArg0 = { "prefix", iocshArgString };
static const iocshArg *testArgs[] = {
&testArg0};
static const iocshFuncDef exampleDatabaseFuncDef = {
"exampleDatabase", 1, testArgs};
static void exampleDatabaseCallFunc(const iocshArgBuf *args)
{
ExampleDatabase::create();
}
static void exampleDatabaseRegister(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&exampleDatabaseFuncDef, exampleDatabaseCallFunc);
}
}
extern "C" {
epicsExportRegistrar(exampleDatabaseRegister);
}

View File

@@ -1,16 +0,0 @@
#Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG
DIRS += configure
DIRS += src
src_DEPEND_DIRS = configure
DIRS += ioc
ioc_DEPEND_DIRS = src
DIRS += iocBoot
include $(TOP)/configure/RULES_TOP

Some files were not shown because too many files have changed in this diff Show More