202 Commits

Author SHA1 Message Date
Andrew Johnson 429c47a34a Update version numbers after tagging 2025-12-15 15:35:55 -06:00
Andrew Johnson 65d2cce753 Final commit for 4.8.1 2025-12-15 14:50:45 -06:00
Andrew Johnson 7535e469e9 Updates to Release Notes 2025-12-15 14:49:21 -06:00
Ralph Lange b3f64a1392 Merge pull request #77 from ralphlange/remove-ci
Remove dysfunctional Travis-CI configuration
2025-02-22 15:33:12 +01:00
Ralph Lange 6ca99ebb92 Merge pull request #76 from anjohnson/master
Fix 10-year old typo in message generation
2025-02-22 15:32:54 +01:00
Ralph Lange 2dbae03028 Remove dysfunctional Travis-CI configuration 2025-02-21 09:46:00 +01:00
Andrew Johnson 09cf317521 Fix 10-year old typo in message generation 2025-02-20 13:14:40 -06:00
Andrew Johnson 8ed07fef96 Set next development version 2021-07-02 15:42:23 -05:00
Andrew Johnson a34876e36a Update version numbers for release 2021-07-02 15:37:45 -05:00
mrkraimer 7105261c90 change location of css scripts 2021-04-08 08:07:59 -04:00
Marty Kraimer a6f5d86162 Merge pull request #73 from epics-base/multichannelmultiprovider
multiChannel now allows an array of provider names
2021-03-30 10:11:32 -04:00
mrkraimer 9e8cc341ea multiChannel now allows an array of provider names 2021-03-23 12:42:58 -04:00
mrkraimer 6eb977ae66 The following changes were made:
1) pvaClientChannel no longer issues an error message on disconnect.
   This should never have been done.
   When pvaClient is used within a database, it caused error mesaage when database exits.
2) pvaClientGet,Monitor,Process,Put,PutGet now let pvaClientChannel handle getRequesterName and message.
   This leads to better error messages.
2021-03-15 06:48:38 -04:00
mrkraimer 3fb934a30b replace boolean by epics::pvData::boolean 2021-03-06 11:17:18 -05:00
Marty Kraimer 2d6f0f1821 Merge pull request #71 from epics-base/pvaClientMultiChannel_changes
Pva client multi channel changes
2021-03-06 09:18:52 -05:00
mrkraimer 8a661bb591 The following changes were made:
1) update documentation.
2) remove some output messages from pvaClientMonitor and pvaClientMultiChannel
3) performance improvement to pvaClientNTMultiPut.
2021-03-01 10:14:05 -05:00
Andrew Johnson efb2631905 Undo random typing... 2021-02-28 21:36:14 -06:00
mrkraimer 1211d01800 The changes:
1) Fix issues #66 and #70
2) All tests in exampleCPP/testMultiplePutGet now work successfully.

I still want to do more testing, especially on connection management.
Also relese notes and documentation needs work.
2021-02-26 12:32:15 -05:00
mrkraimer b665dac669 The following changes were made:
1) PvaClientChannel::channelCreated no longer declares channel connected.
   PvaClientChannel::channelStateChange does this.
2) PvaClientNTMultiData::endDeltaTime no longer calls unionValue[i] = PVUnionPtr()
2021-02-23 09:25:19 -05:00
mrkraimer 65a69a8901 Changes include:
1) Added method PvaClientNTMultiData::getChannelChangeFlags.
2) In pvaClientMultiChannel made methods not intended for client protected.
3) Fixed many connection related problems.
4) Cleaned up doxygen.
2021-02-17 11:10:41 -05:00
Andrew Johnson 7722fdf353 Set next development version 2020-05-28 16:26:01 -05:00
Andrew Johnson bc9ac8422c Update version numbers for release 2020-05-28 15:49:41 -05:00
mrkraimer c3aec4e27b get ready for next epics7 release 2020-05-20 14:01:16 -04:00
Marty Kraimer 0abfeef5ed Merge pull request #65 from dirk-zimoch/CleanupWhitespace
Cleanup whitespace
2020-05-20 08:50:14 -04:00
zimoch 745119cf77 removed empty lines at end of file 2020-04-15 17:51:17 +02:00
zimoch 9f794721ab removed spaces at end of line 2020-04-15 17:49:54 +02:00
zimoch 8f21ac8b9d replaced tabs with spaces 2020-04-15 17:45:02 +02:00
Marty Kraimer 9add9daf85 Merge pull request #64 from epics-base/issue#63
fix issue 63; add PvaClientData::getSinglePVField; simplify getDouble…
2019-12-04 05:46:44 -05:00
mrkraimer aaacadb42d fix issue 63; add PvaClientData::getSinglePVField; simplify getDouble, putDouble, etc 2019-12-02 10:32:48 -05:00
Andrew Johnson 5961c83477 Incr version and set development flag after release 2019-11-01 12:28:27 -05:00
Andrew Johnson b724b72624 Clear development flag for 4.7.0 release 2019-11-01 12:20:59 -05:00
Andrew Johnson fc42cf798e Release notes for 4.7.0 2019-11-01 11:09:28 -05:00
Marty Kraimer 71181afc93 Update .travis.yml 2019-09-13 09:15:35 -04:00
Ralph Lange b92a3ddaa4 rtd-ci: add read-the-docs integration 2019-09-06 14:18:19 +02:00
Andrew Johnson 246cceae3e Update version number to 4.7.0 DEVELOPMENT 2019-08-13 10:46:37 -05:00
mrkraimer 3f4df39ee0 fix issue #62 PvaClientData::parse bug 2019-08-12 06:03:55 -04:00
Marty Kraimer 837924af2e Update RELEASE_NOTES.md 2019-08-02 08:45:10 -04:00
Marty Kraimer 7b0e2b5986 Merge pull request #61 from mrkraimer/master
add JSON support
2019-08-02 08:42:29 -04:00
mrkraimer c84b24bb30 Merge https://github.com/epics-base/pvaClientCPP
merge to get latest hanges from epics-base
2019-08-02 05:44:42 -04:00
Andrew Johnson aba40922e6 Release notes for 4.6.0 2019-07-29 11:47:36 -05:00
Andrew Johnson 2c1cb03cd0 Use new CONFIG_PVACLIENT_VERSION file for SHRLIB_VERSION 2019-07-29 11:46:54 -05:00
mrkraimer f58c5159fc add streamJSON 2019-07-19 09:49:40 -04:00
mrkraimer a91ba8ef9e fixed a bug 2019-07-17 10:43:13 -04:00
mrkraimer ddb36536fe add zeroArrayLength 2019-07-16 10:33:39 -04:00
mrkraimer 9153036ccc added JSON support 2019-07-16 09:42:08 -04:00
Marty Kraimer 4c56116827 Merge pull request #60 from mrkraimer/master
working on issue #56; still problems with monitor
2019-04-26 12:51:02 -04:00
mrkraimer 81f5e25276 working on issue #56; still problems with monitor 2019-04-26 10:09:56 -04:00
Marty Kraimer 703b2224ce Merge pull request #59 from mrkraimer/master
fix issue #57
2019-04-25 05:07:20 -04:00
mrkraimer ed0b1cbf08 fix issue #57 2019-04-24 14:53:18 -04:00
Marty Kraimer 914e382dea Merge pull request #58 from mrkraimer/master
address issue #54
2019-04-24 05:18:19 -04:00
mrkraimer fd77d35b20 address issue #54 2019-04-23 14:04:13 -04:00
Andrew Johnson 428adb270e Update version numbers to 4.5.0 for EPICS 7.0.2.2 release 2019-04-15 11:27:27 -05:00
Marty Kraimer 3111e90de8 Merge pull request #55 from mrkraimer/master
address issue #53 plus more for getDouble, putDouble, getString, putDouble, etc
2019-04-11 14:50:03 -04:00
mrkraimer 365a0b846f update RELEASE_NOTES 2019-04-11 14:13:53 -04:00
mrkraimer 440c8fa496 update RELEASE_NOTES 2019-04-11 14:11:03 -04:00
mrkraimer 150ac45de3 bug in pvaClientData; fix doxygen warning; update doc 2019-04-09 11:15:00 -04:00
mrkraimer fb6f4355f3 getDoubleArray and putDoubleArray now work for all numeric scalar arrays 2019-04-09 06:19:14 -04:00
mrkraimer 0bb17d5b09 make them work if not top level value field 2019-04-08 14:23:58 -04:00
mrkraimer 00103f8207 getStringArray and putStringArray support all numeric array types 2019-04-08 14:11:27 -04:00
mrkraimer 522a050945 add double and string methods to pvaClientChannel 2019-04-07 14:34:56 -04:00
mrkraimer 99a7e3b0b5 more changes 2019-04-06 11:30:10 -04:00
mrkraimer 763c41caa3 setElementData=>setData 2019-04-05 14:37:05 -04:00
mrkraimer 9ffeffd23f mistake 2019-04-04 16:27:53 -04:00
mrkraimer 3f6d93b22f lots of minor changes 2019-04-04 16:02:47 -04:00
mrkraimer d650865a6f address issue #53; reorganize Client*Data 2019-04-03 10:32:45 -04:00
Andrew Johnson b1c101578b Update version numbers and formatting in documentation 2018-12-17 16:17:52 -06:00
Andrew Johnson 8ab4dd1fdb Correct SHRLIB_VERSION 2018-12-17 16:16:59 -06:00
Andrew Johnson 5242540725 Update and unify README.md 2018-12-17 16:16:06 -06:00
Michael Davidsaver a8f296ceb3 update travis-ci 2018-10-29 18:02:20 -07:00
Marty Kraimer 6633d4f21e Merge pull request #52 from mrkraimer/master
with multiple threads callback can occur before create completes
2018-10-06 05:59:14 -04:00
mrkraimer 8745dd03b3 with multithreads callback can occur before create completes 2018-10-05 15:59:59 -04:00
Marty Kraimer cfc3c9b998 Merge pull request #51 from mrkraimer/master
several changes
2018-09-28 07:00:34 -04:00
mrkraimer d57893b566 remove #include <pv/pvCopy.h> 2018-09-27 15:34:02 -04:00
mrkraimer b7ea0fe59a fix bug that causes failure in monotor::stop for privider ca 2018-07-27 05:43:47 -04:00
Marty Kraimer 4e4554af4e Merge pull request #50 from mrkraimer/master
re-implement methods used by pvaPy
2018-01-30 09:11:28 -05:00
mrkraimer d6d5bcf771 merge with epics-base 2018-01-12 15:20:47 -05:00
mrkraimer 6bcc036c71 reimplement methods called by pvaPy
The methods are:
static PvaClientPtr create() EPICS_DEPRECATED;
and
static PvaClientMonitorPtr create(
    PvaClientPtr const &pvaClient,
    std::string const & channelName,
    std::string const & providerName,
    std::string const & request,
    PvaClientChannelStateChangeRequesterPtr const & stateChangeRequester
            = PvaClientChannelStateChangeRequesterPtr(),
    PvaClientMonitorRequesterPtr const & monitorRequester
            = PvaClientMonitorRequesterPtr()
) EPICS_DEPRECATED;
2018-01-12 13:51:13 -05:00
Marty Kraimer a405dd7bdb Merge pull request #49 from epics-base/revert-48-master
Revert "Minor changes"
2018-01-09 15:58:58 -05:00
Marty Kraimer 22e260351c Revert "Minor changes" 2018-01-09 15:14:30 -05:00
Marty Kraimer 5a5b8f809d Merge pull request #48 from mrkraimer/master
Minor changes
2018-01-09 11:16:52 -05:00
mrkraimer 9d5f06c11d pull latest from epics-base 2018-01-08 09:20:13 -05:00
mrkraimer 28a23dc5a8 remove a create method from monitor; remove unused channelStateChange methods 2018-01-05 14:38:42 -05:00
Ralph Lange dcda03c9fc jenkins-ci: fix CloudBees doc job 2017-12-19 09:20:11 +01:00
Andrew Johnson b5291d9619 Update/fix version numbers in documentation 2017-12-14 18:55:23 -06:00
Andrew Johnson 74d381e68c Use EPICS_BASE_PVA_CORE_LIBS 2017-12-06 22:45:00 -06:00
Andrew Johnson c789406f0b Include <top>/../RELEASE.<host>.local 2017-12-06 20:39:49 -06:00
Andrew Johnson a21e5b5913 Use 'make test-results' in travis-build script 2017-11-30 13:06:27 -06:00
Andrew Johnson cb374fcefa Unify .gitignore files 2017-11-30 12:08:10 -06:00
Andrew Johnson 90b2bdc162 Remove ExampleRELEASE.local file 2017-11-30 12:07:52 -06:00
Marty Kraimer ea5809be9b Merge pull request #47 from mrkraimer/master
fix bug in pvaClientNTMultiData that can cause a crash
2017-11-21 05:58:47 -05:00
mrkraimer 0fb4612680 fix bug in pvaClientNTMultiData that can cause a crash 2017-11-21 05:25:51 -05:00
Ralph Lange 5a84b94520 jenkins: remove microbench option and pvCommon dependency from CB build 2017-11-15 17:22:25 +01:00
Marty Kraimer 411560ea8d Merge pull request #46 from mrkraimer/master
ignore mutiple calls to PvaClientMonitor::start
2017-11-10 10:38:20 -05:00
mrkraimer 3e9645c883 Merge https://github.com/epics-base/pvaClientCPP 2017-11-10 09:57:46 -05:00
Andrew Johnson 25b621890b Convert debug into a file static data member
MSVC doesn't seem to be able to provide access to it as a
class static, so this fixes the DLL build errors of exampleCPP
2017-11-06 12:57:21 -06:00
mrkraimer fe15b9dd09 ignore mutiple calls to PvaClientMonitor::start 2017-10-23 10:16:31 -04:00
Ralph Lange 64fc25c240 travis-ci: consolidate travis configuration 2017-09-28 15:10:30 +02:00
Ralph Lange c9e7bc32bd travis-ci: pvaClient does not have unit tests 2017-09-27 15:42:05 +02:00
Ralph Lange ab4c69301f travis-ci: fix requisite build for Base 3.x 2017-09-27 14:46:55 +02:00
Ralph Lange 5b9b84f7d0 travis-ci: update/streamline configuration for EPICS 7 2017-09-27 14:02:33 +02:00
Marty Kraimer dd65681630 Merge pull request #45 from mrkraimer/master
more callbacks for callbacks introduced by pvAccess; doc changes
2017-09-13 10:53:02 -04:00
mrkraimer e11cc25dd7 travis: change required for normativeTypesCPP 2017-09-13 10:24:57 -04:00
mrkraimer 05a454fa69 travis; use pvaSrv as model 2017-09-13 05:07:33 -04:00
mrkraimer b5e9aa6a60 yet more support for noblock; add ci 2017-09-12 14:20:13 -04:00
mrkraimer 4606d84185 add more support for no block; removed extra create methods for put and get 2017-09-08 14:22:50 -04:00
mrkraimer 97d9dc2034 add more calbacks; documentation changes 2017-08-08 06:23:35 -04:00
mrkraimer e1d50000d4 pull from epics-base 2017-07-20 09:52:19 -04:00
Marty Kraimer 878cc27aa7 Merge pull request #44 from mrkraimer/new-pva-api
change version number
2017-07-18 15:02:59 -04:00
mrkraimer 5c99282ee2 change version number 2017-07-18 14:47:44 -04:00
Marty Kraimer 3b344fdb25 Merge pull request #43 from mrkraimer/new-pva-api
New pva api
2017-07-18 13:36:04 -04:00
mrkraimer 932d90ff70 minor changes 2017-07-18 06:01:53 -04:00
mrkraimer d7bf6a8910 add nowait support to pvaClientGet, pvaClientPut, pvaClientMonitor 2017-07-14 15:16:49 -04:00
mrkraimer 9b1539f368 more work on doxygen 2017-07-12 06:38:55 -04:00
mrkraimer 8c7506449b doxygen changes 2017-07-12 06:11:29 -04:00
mrkraimer 609c887c19 replace getChannelProviderRegistry with ChannelProviderRegistry::clients 2017-07-07 10:46:22 -04:00
mrkraimer 8f6cc08f85 MessageType::errorMessage => errorMessage 2017-07-06 15:33:08 -04:00
mrkraimer ae49f8ad99 add PvaClientMonitor::getPvaClientChannel() 2017-07-06 14:04:26 -04:00
mrkraimer 696c251ecc remove some cout messages 2017-07-05 10:08:53 -04:00
mrkraimer 594d8dd19f changes to documentation 2017-06-29 09:47:14 -04:00
mrkraimer d8ab89e96a changes for new-pva-api; improve pvaClientMonitor 2017-06-28 10:36:23 -04:00
mrkraimer 9712f001c8 remove extra print statements 2017-06-26 07:43:12 -04:00
Marty Kraimer 91e6392e77 Merge pull request #1 from epics-base/master
create a branch for changes because of API changes in pvAccessCPP
2017-06-26 07:18:17 -04:00
mrkraimer 094336b5e0 let pvaClientMonitor do what pvaMonitor was doing 2017-06-23 14:45:44 -04:00
mrkraimer f0efef68ea add start and stop methods to PvaMonitor 2017-06-21 15:01:41 -04:00
mrkraimer 0912756a2e back out ChannelProvider change; add PvaMonitor 2017-06-15 14:40:13 -04:00
mrkraimer e071e0f9e3 PvaClientChannel::channelStateChange set state before calling stateChangeRequester 2017-06-14 06:14:47 -04:00
mrkraimer 619bacc0f4 use the new ChannelProviderRegistry methods 2017-06-04 07:58:00 -04:00
Marty Kraimer 7fd5af9e3c Merge pull request #42 from mrkraimer/master
fix issue 41
2017-05-25 06:02:07 -04:00
mrkraimer 6762c54e60 fix issue 41 2017-05-23 07:34:35 -04:00
Marty Kraimer 63947e1c3c Merge pull request #40 from mrkraimer/master
Fix stateChangeRequester and  channelGet
2017-04-07 13:35:06 -04:00
mrkraimer c019b205dd call stateChangeRequester when connecting; ChannelGet.get only does one get 2017-03-30 10:41:10 -04:00
Marty Kraimer 2f75a967de Merge pull request #37 from mrkraimer/master
add request timout to PvaClientRPC
2016-07-22 15:10:08 -04:00
mrkraimer eed64822e0 add request timout to PvaClientRPC 2016-07-22 14:41:21 -04:00
Ralph Lange 6249ae2c44 jenkins: fix installE4 logic, add pvCommon dependency 2016-07-22 14:57:48 +02:00
Marty Kraimer 83a27341cd Merge pull request #36 from mrkraimer/master
fix windows warning about epicsShareClass
2016-07-21 06:24:07 -04:00
mrkraimer 051c924992 fix windows warning about epicsShareClass 2016-07-21 06:14:25 -04:00
Marty Kraimer 261eaf5d9b Merge pull request #35 from mrkraimer/master
another attempt to fix issue 31
2016-07-20 07:08:28 -04:00
mrkraimer 6f18c1febf another attempt to fix issue 31 2016-07-20 06:50:58 -04:00
Ralph Lange 10cfe31653 Add QtC entry to .gitignore 2016-07-19 23:11:48 +02:00
Ralph Lange 22cf65022d jenkins: use install functions, add BRANCH variable to doc script 2016-07-19 23:08:01 +02:00
Marty Kraimer 98b25f6094 Merge pull request #33 from mrkraimer/master
another attempt to fix issue 31
2016-07-19 15:20:10 -04:00
mrkraimer b18fd4b3ae another attempt to fix issue 31 2016-07-19 15:17:25 -04:00
Marty Kraimer dee908b273 Merge pull request #32 from mrkraimer/master
another attempt to fix issue 31
2016-07-19 13:37:50 -04:00
mrkraimer c5c7e19192 another attempt to fix issue 31 2016-07-19 13:30:25 -04:00
Marty Kraimer 852510afe4 Merge pull request #30 from mrkraimer/master
Documentation Changes
2016-07-19 06:02:47 -04:00
mrkraimer b93f466366 attempt to fix issue 31 2016-07-19 05:55:20 -04:00
mrkraimer b5d4d178f5 doc changes; add additional create method for RPC 2016-07-18 13:05:15 -04:00
mrkraimer 348d27b7bb fix LICENSE 2016-07-09 06:48:36 -04:00
mrkraimer bf42a5c22d fix LICENSE 2016-07-09 06:47:42 -04:00
Marty Kraimer 0227872c94 Merge pull request #29 from mrkraimer/master
mostly code cleanup
2016-07-07 08:43:07 -04:00
mrkraimer d890ce28d8 mostly code cleanup 2016-07-06 10:49:22 -04:00
Marty Kraimer de8fc8994b Merge pull request #28 from mrkraimer/master
stateChangeRequester; semantics for unlisten and channelStateChange
2016-06-24 15:23:05 -04:00
mrkraimer fac07c7f3a added stateChangeRequester; improve semantics for unlisten and channelStateChange 2016-06-24 15:03:19 -04:00
Marty Kraimer c06fb08168 Merge pull request #27 from mrkraimer/master
add support for channelRPC
2016-06-22 11:40:56 -04:00
mrkraimer 5398d67e2a add support for channelRPC 2016-06-22 11:33:39 -04:00
Marty Kraimer 46af745a1a Merge pull request #25 from mrkraimer/master
fix pvaClientChannel and pvaClientMonitor bugs
2016-06-20 10:45:01 -04:00
mrkraimer a7fb12a16f pvaClientChannel fix bug if already connected; pvaClientMonitor make reconnection get first event 2016-06-17 12:31:19 -04:00
Marty Kraimer 35458045fa Merge pull request #24 from mrkraimer/master
add another epicsShareClass
2016-06-16 05:30:55 -04:00
mrkraimer 2f013af10d add another epicsShareClass 2016-06-16 05:17:23 -04:00
Marty Kraimer f926282c54 Merge pull request #23 from mrkraimer/master
add epicsShareClass
2016-06-15 10:56:55 -04:00
mrkraimer 4764518bd2 add epicsShareClass 2016-06-15 10:51:35 -04:00
Marty Kraimer 0639d45740 Merge pull request #22 from mrkraimer/master
Minor changes
2016-06-15 07:38:52 -04:00
Marty Kraimer 1c16a72889 Merge pull request #21 from mrkraimer/master
Implement RAII (Resource Acquisition Is Initialization)
2016-06-15 07:27:42 -04:00
mrkraimer ec5d08685c get ready to issue pull request for epics-base 2016-06-15 07:05:52 -04:00
mrkraimer 7a4bd88d8d doc and shared version changes 2016-06-11 12:01:57 -04:00
mrkraimer 32fb16fcf0 fix bug in src/pvaClientMonitor.cpp; other minor changes 2016-06-10 07:48:36 -04:00
mrkraimer 04b5434b69 add some debug messages 2016-06-08 08:34:25 -04:00
mrkraimer 6ff53f4dcb still working on RAII; work on doxygen 2016-05-27 14:20:41 -04:00
mrkraimer 3008825587 still working on RAII 2016-05-24 10:35:10 -04:00
mrkraimer 643fa9b40b still working on RAII 2016-05-20 06:22:13 -04:00
mrkraimer 3920215182 change message for channelStateChange 2016-05-19 12:45:15 -04:00
mrkraimer a0cc581d3f still working on RAII 2016-05-19 12:01:21 -04:00
mrkraimer adc008dee6 handle weak_pointer.lock() properly 2016-05-17 15:04:02 -04:00
mrkraimer 40fb22ebd9 add destroy to pvaClientChannel; in pvaClientGet channel is weak_pointer 2016-05-17 14:26:41 -04:00
mrkraimer cd9bdec84e replace shared_pointer by shared_from_this 2016-05-17 09:24:38 -04:00
mrkraimer 3cc13e2c5a replace destroy by RAII; many implementation changes 2016-05-13 12:50:47 -04:00
Marty Kraimer 9f8073aaa2 Merge pull request #20 from anjohnson/master
Use EPICS_DEPRECATED macro
2016-04-22 06:50:38 -04:00
Andrew Johnson 2b7b38a3c7 Use EPICS_DEPRECATED macro
Don't print error messages when a deprecated function is called,
make it a compile-time warning instead.
2016-04-21 15:52:34 -05:00
Marty Kraimer 899dc4e9be Merge pull request #19 from mrkraimer/master
add PvaClient::get; PvaClient::create deprecated
2016-04-20 11:56:21 -04:00
mrkraimer d2e8fab2b4 add PvaClient::get; PvaClient::create deprecated 2016-04-20 11:03:11 -04:00
Marty Kraimer ff68b01ddf Merge pull request #18 from mrkraimer/master
PvaClientMonitorRequester: add virtual destructor
2016-04-13 07:56:15 -04:00
mrkraimer c258018014 PvaClientMonitorRequester: add virtual destructor 2016-04-13 07:45:00 -04:00
Marty Kraimer 43d13175e5 Merge pull request #16 from mrkraimer/master
fix problems when client uses PvaClientMonitorRequester
2016-04-08 06:41:08 -04:00
mrkraimer bf57c06b06 fix problems when client uses PvaClientMonitorRequester 2016-04-05 15:52:51 -04:00
Marty Kraimer 49f581c4bb Merge pull request #15 from mrkraimer/master
pvaClientChannel.cpp fix possible race conditions; pvaClientNTMultiDa…
2016-03-30 05:28:31 -04:00
mrkraimer c55bf7ec45 pvaClientChannel.cpp fix possible race conditions; pvaClientNTMultiData.cpp fix bug if not all channels connect 2016-03-29 06:39:43 -04:00
Marty Kraimer ec1f6d5eb6 Merge pull request #14 from mrkraimer/master
if channel is connected when channelCreated is called then don't wait…
2016-03-02 07:50:49 -05:00
mrkraimer 56d96716f0 if channel is connected when channelCreated is called then don't wait for channelState change 2016-02-19 09:39:16 -05:00
Ralph Lange 80073054dd jenkins: switch to Base 3.15.3 2016-02-16 10:17:53 +01:00
Michael Davidsaver 9d0069ffe0 set SHRLIB_VERSION 2016-02-09 19:33:35 -05:00
Marty Kraimer 971d35f389 Merge pull request #13 from mdavidsaver/master
move headers to pv/
2016-02-02 11:34:25 -05:00
Michael Davidsaver 9a9bf34f83 update Makefiles 2016-02-01 16:37:41 -05:00
Michael Davidsaver 86a5e037fa move headers to pv/ 2016-02-01 16:37:25 -05:00
Marty Kraimer 434867866b Merge pull request #12 from mrkraimer/master
examples are moved to project exampleCPP; update doc
2016-02-01 07:34:59 -05:00
mrkraimer 0f415a3e39 examples are moved to project exampleCPP; update doc 2016-01-22 11:03:33 -05:00
mrkraimer 9c800f5ebf PvaClientMultiChannel::checkConnected() now throws an exception if connect fails. 2015-12-14 09:57:23 -05:00
Andrew Johnson 7f972fc877 Add libraries needed for static builds 2015-10-29 18:13:46 -05:00
Ralph Lange 1b11e49c2c jenkins: build dependency branches must be empty on master 2015-10-26 14:01:02 +01:00
mrkraimer d456c815e7 merged release/4.1 2015-10-20 14:25:39 -04:00
Matej Sekoranja 698e901b8f added missing nt lib 2015-09-16 22:02:12 +02:00
Matej Sekoranja 78a8f26dd0 win support port 2015-09-16 21:11:05 +02:00
Ralph Lange 3b09ef5c21 jenkins: adapt doc script to new CloudBees jenkins doc job 2015-09-14 16:25:54 +02:00
67 changed files with 5362 additions and 5510 deletions
+16 -11
View File
@@ -1,12 +1,17 @@
bin/ /cfg/
lib/ /bin/
doc/ /lib/
include/ /db/
db/ /dbd/
dbd/ /html/
documentation/html /include/
documentation/*.tag /templates/
/configure/*.local
/documentation/html
/documentation/*.tag
O.*/
/QtC-*
envPaths envPaths
configure/*.local *.orig
!configure/ExampleRELEASE.local *.log
**/O.* .*.swp
+17
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
+245 -155
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 # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project. # doxygen (www.doxygen.org) for a project.
@@ -32,13 +32,13 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places. # title of most generated pages and in a few other places.
# The default value is: My Project. # The default value is: My Project.
PROJECT_NAME = easyPVACPP PROJECT_NAME = pvaClientCPP
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This # The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = PROJECT_NUMBER = 4.8.2-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@@ -46,10 +46,10 @@ PROJECT_NUMBER =
PROJECT_BRIEF = PROJECT_BRIEF =
# With the PROJECT_LOGO tag one can specify an logo or icon that is included in # With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# the documentation. The maximum height of the logo should not exceed 55 pixels # in the documentation. The maximum height of the logo should not exceed 55
# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# to the output directory. # the logo to the output directory.
PROJECT_LOGO = PROJECT_LOGO =
@@ -60,7 +60,7 @@ PROJECT_LOGO =
OUTPUT_DIRECTORY = 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 # directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this # will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where # option can be useful when feeding doxygen a huge amount of source files, where
@@ -70,6 +70,14 @@ OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO 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 # The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this # documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language. # information to generate all constant output in the proper language.
@@ -85,14 +93,14 @@ CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English 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 # descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this. # documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES. # The default value is: YES.
BRIEF_MEMBER_DESC = 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 # 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 # 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 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 # 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 # shortest path that makes the file name unique will be used
# The default value is: YES. # The default value is: YES.
@@ -144,7 +152,7 @@ FULL_PATH_NAMES = YES
# will be relative from the directory where doxygen is started. # will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES. # This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH = STRIP_FROM_PATH = src
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which # path mentioned in the documentation of a class, which tells the reader which
@@ -153,7 +161,7 @@ STRIP_FROM_PATH =
# specify the list of include paths that are normally passed to the compiler # specify the list of include paths that are normally passed to the compiler
# using the -I flag. # using the -I flag.
STRIP_FROM_INC_PATH = STRIP_FROM_INC_PATH = src
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't # less readable) file names. This can be useful is your file systems doesn't
@@ -169,7 +177,7 @@ SHORT_NAMES = NO
# description.) # description.)
# The default value is: NO. # The default value is: NO.
JAVADOC_AUTOBRIEF = YES JAVADOC_AUTOBRIEF = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If # line (until the first dot) of a Qt-style comment as the brief description. If
@@ -197,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
# new page for each member. If set to NO, the documentation of a member will be # page for each member. If set to NO, the documentation of a member will be part
# part of the file/class/namespace that contains it. # of the file/class/namespace that contains it.
# The default value is: NO. # The default value is: NO.
SEPARATE_MEMBER_PAGES = 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 # 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 # 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, # 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 # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# (default is Fortran), use: inc=Fortran f=C. # 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 # Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen. # 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 # When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can # 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 # be prevented in individual cases by putting a % sign in front of the word or
# or globally by setting AUTOLINK_SUPPORT to NO. # globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES. # The default value is: YES.
AUTOLINK_SUPPORT = YES AUTOLINK_SUPPORT = YES
@@ -325,13 +336,20 @@ SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # 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 # member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly. # all members of a group must be documented explicitly.
# The default value is: NO. # The default value is: NO.
DISTRIBUTE_GROUP_DOC = 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 # 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 # (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 # 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 # 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 # documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the # class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -400,35 +418,35 @@ LOOKUP_CACHE_SIZE = 0
EXTRACT_ALL = YES 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. # be included in the documentation.
# The default value is: NO. # The default value is: NO.
EXTRACT_PRIVATE = 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. # scope will be included in the documentation.
# The default value is: NO. # The default value is: NO.
EXTRACT_PACKAGE = 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. # included in the documentation.
# The default value is: NO. # The default value is: NO.
EXTRACT_STATIC = NO EXTRACT_STATIC = NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # 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 # 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 # only classes defined in header files are included. Does not have any effect
# for Java sources. # for Java sources.
# The default value is: YES. # The default value is: YES.
EXTRACT_LOCAL_CLASSES = NO 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 # 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. # included.
# The default value is: NO. # 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 # 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 # 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 # to NO, these classes will be included in the various overviews. This option
# no effect if EXTRACT_ALL is enabled. # has no effect if EXTRACT_ALL is enabled.
# The default value is: NO. # The default value is: NO.
HIDE_UNDOC_CLASSES = NO HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # 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. # included in the documentation.
# The default value is: NO. # The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # 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. # blocks will be appended to the function's detailed documentation block.
# The default value is: NO. # The default value is: NO.
@@ -481,7 +499,7 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # 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 # 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 # in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO. # and Mac users are advised to set this option to NO.
@@ -490,12 +508,19 @@ INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # 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. # scope will be hidden.
# The default value is: NO. # The default value is: NO.
HIDE_SCOPE_NAMES = 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 # 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 files that are included by a file in the documentation of that file.
# The default value is: YES. # 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 # 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 # (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. # The default value is: YES.
SORT_MEMBER_DOCS = YES SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # 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 # 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. # this will also influence the order of the classes in the class list.
# The default value is: NO. # The default value is: NO.
@@ -575,27 +600,25 @@ SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
# todo list. This list is created by putting \todo commands in the # list. This list is created by putting \todo commands in the documentation.
# documentation.
# The default value is: YES. # The default value is: YES.
GENERATE_TODOLIST = YES GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
# test list. This list is created by putting \test commands in the # list. This list is created by putting \test commands in the documentation.
# documentation.
# The default value is: YES. # The default value is: YES.
GENERATE_TESTLIST = 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. # list. This list is created by putting \bug commands in the documentation.
# The default value is: YES. # The default value is: YES.
GENERATE_BUGLIST = 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 deprecated list. This list is created by putting \deprecated commands in
# the documentation. # the documentation.
# The default value is: YES. # The default value is: YES.
@@ -620,8 +643,8 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30 MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # 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 # the bottom of the documentation of classes and structs. If set to YES, the
# will mention the files that were used to generate the documentation. # list will mention the files that were used to generate the documentation.
# The default value is: YES. # The default value is: YES.
SHOW_USED_FILES = 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. # 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 # 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 # 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 # search path. See also \cite for info how to create references.
# also \cite for info how to create references.
CITE_BIB_FILES = CITE_BIB_FILES =
@@ -686,7 +708,7 @@ CITE_BIB_FILES =
QUIET = NO QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are # 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. # this implies that the warnings are on.
# #
# Tip: Turn warnings on while writing the documentation. # Tip: Turn warnings on while writing the documentation.
@@ -694,7 +716,7 @@ QUIET = NO
WARNINGS = YES 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 # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled. # will automatically be disabled.
# The default value is: YES. # 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 # 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 # 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 # value. If set to NO, doxygen will only warn about wrong or incomplete
# documentation, but not about the absence of documentation. # parameter documentation, but not about the absence of documentation.
# The default value is: NO. # The default value is: NO.
WARN_NO_PARAMDOC = NO WARN_NO_PARAMDOC = NO
@@ -740,10 +762,11 @@ WARN_LOGFILE =
# The INPUT tag is used to specify the files and/or directories that contain # 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 # documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with # 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. # Note: If this tag is empty the current directory is searched.
INPUT = include INPUT = src \
src/pv
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -756,12 +779,17 @@ INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the # 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 # 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 # *.h) to filter out the source-files in the directories.
# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, #
# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # Note that for custom extensions or not directly supported extensions you also
# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # need to set EXTENSION_MAPPING for the extension otherwise the files are not
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # read by doxygen.
# *.qsf, *.as and *.js. #
# 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 = FILE_PATTERNS =
@@ -769,7 +797,7 @@ FILE_PATTERNS =
# be searched for input files as well. # be searched for input files as well.
# The default value is: NO. # The default value is: NO.
RECURSIVE = YES RECURSIVE = NO
# The EXCLUDE tag can be used to specify files and/or directories that should be # The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a # excluded from the INPUT source files. This way you can easily exclude a
@@ -860,7 +888,7 @@ INPUT_FILTER =
FILTER_PATTERNS = FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # 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). # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO. # The default value is: NO.
@@ -920,7 +948,7 @@ REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # 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 # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation. # link to the documentation.
# The default value is: YES. # The default value is: YES.
@@ -997,7 +1025,7 @@ IGNORE_PREFIX =
# Configuration options related to the HTML output # 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. # The default value is: YES.
GENERATE_HTML = YES GENERATE_HTML = YES
@@ -1008,7 +1036,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = documentation/html HTML_OUTPUT = html/doxygen
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).
@@ -1059,13 +1087,15 @@ HTML_FOOTER =
HTML_STYLESHEET = HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# defined cascading style sheet that is included after the standard style sheets # cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects. # 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 # This is preferred over using HTML_STYLESHEET since it does not replace the
# standard style sheet and is therefor more robust against future updates. # standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet file to the output directory. For an example # Doxygen will copy the style sheet files to the output directory.
# see the documentation. # 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. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET = HTML_EXTRA_STYLESHEET =
@@ -1078,10 +1108,10 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available. # 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. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES = documentation/overview.html HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # 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 # 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 # 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 # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
@@ -1112,8 +1142,9 @@ HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # 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 # 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. # to YES can help to show when doxygen was last run and thus if the
# The default value is: YES. # documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES HTML_TIMESTAMP = YES
@@ -1209,28 +1240,29 @@ GENERATE_HTMLHELP = NO
CHM_FILE = CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path # 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. # doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path. # The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION = HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated ( # 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). # (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO 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. # and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING = CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated ( # 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. # (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. # The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1343,7 +1375,7 @@ DISABLE_INDEX = NO
# index structure (just like the one that is generated for HTML Help). For this # 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 # 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 # (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 # 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 # 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 # the root of the tree instead of the PROJECT_NAME. Since the tree basically has
@@ -1371,7 +1403,7 @@ ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250 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. # external symbols imported via tag files in a separate window.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1400,7 +1432,7 @@ FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering # 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 # 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 # enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option. # to it using the MATHJAX_RELPATH option.
@@ -1470,11 +1502,11 @@ SEARCHENGINE = NO
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be # 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 # implemented using a web server instead of a web client using Javascript. There
# are two flavours of web server based searching depending on the # are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for # setting. When disabled, doxygen will generate a PHP script for searching and
# searching and an index file used by the script. When EXTERNAL_SEARCH is # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
# enabled the indexing and searching needs to be provided by external tools. See # and searching needs to be provided by external tools. See the section
# the section "External Indexing and Searching" for details. # "External Indexing and Searching" for details.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES. # This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1486,7 +1518,7 @@ SERVER_BASED_SEARCH = NO
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the # external search engine pointed to by the SEARCHENGINE_URL option to obtain the
# search results. # 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 # (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/). # Xapian (see: http://xapian.org/).
# #
@@ -1499,7 +1531,7 @@ EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server # 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. # 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 # (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/). See the section "External Indexing and # Xapian (see: http://xapian.org/). See the section "External Indexing and
# Searching" for details. # Searching" for details.
@@ -1537,7 +1569,7 @@ EXTRA_SEARCH_MAPPINGS =
# Configuration options related to the LaTeX output # 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. # The default value is: YES.
GENERATE_LATEX = NO GENERATE_LATEX = NO
@@ -1568,7 +1600,7 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex 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 # documents. This may be useful for small projects and may help to save some
# trees in general. # trees in general.
# The default value is: NO. # The default value is: NO.
@@ -1586,9 +1618,12 @@ COMPACT_LATEX = NO
PAPER_TYPE = a4wide PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # 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 # that should be included in the LaTeX output. The package can be specified just
# instance you can specify # by its name or with the correct syntax as to be used with the LaTeX
# EXTRA_PACKAGES=times # \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. # If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1602,23 +1637,36 @@ EXTRA_PACKAGES =
# #
# Note: Only use a user-defined header if you know what you are doing! The # 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, # following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will # $datetime, $date, $doxygenversion, $projectname, $projectnumber,
# replace them by respectively the title of the page, the current date and time, # $projectbrief, $projectlogo. Doxygen will replace $title with the empty
# only the current date, the version number of doxygen, the project name (see # string, for the replacement values of the other commands the user is referred
# PROJECT_NAME), or the project number (see PROJECT_NUMBER). # to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER = LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # 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 # 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! # 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. # This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER = 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 # 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 # 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 # directory. Note that the files will be copied as-is; there are no commands or
@@ -1636,8 +1684,8 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = NO PDF_HYPERLINKS = NO
# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate # 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 # the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation. # higher quality PDF documentation.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1678,11 +1726,19 @@ LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain 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 # 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 # RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors. # readers/editors.
# The default value is: NO. # The default value is: NO.
@@ -1697,7 +1753,7 @@ GENERATE_RTF = NO
RTF_OUTPUT = rtf 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 # documents. This may be useful for small projects and may help to save some
# trees in general. # trees in general.
# The default value is: NO. # The default value is: NO.
@@ -1734,11 +1790,21 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_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 # 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. # classes and files.
# The default value is: NO. # The default value is: NO.
@@ -1762,6 +1828,13 @@ MAN_OUTPUT = man
MAN_EXTENSION = .3 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 # 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 # 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 # man page(s). These additional files only source the real man page, but without
@@ -1775,7 +1848,7 @@ MAN_LINKS = NO
# Configuration options related to the XML output # 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. # captures the structure of the code including all documentation.
# The default value is: NO. # The default value is: NO.
@@ -1789,19 +1862,7 @@ GENERATE_XML = NO
XML_OUTPUT = xml XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a # If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
# 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
# listings (including syntax highlighting and cross-referencing information) to # listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size # the XML output. Note that enabling this will significantly increase the size
# of the XML output. # of the XML output.
@@ -1814,7 +1875,7 @@ XML_PROGRAMLISTING = YES
# Configuration options related to the DOCBOOK output # 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. # that can be used to generate PDF.
# The default value is: NO. # The default value is: NO.
@@ -1828,14 +1889,23 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook 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 # Configuration options for the AutoGen Definitions output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# Definitions (see http://autogen.sf.net) file that captures the structure of # AutoGen Definitions (see http://autogen.sf.net) file that captures the
# the code including all documentation. Note that this feature is still # structure of the code including all documentation. Note that this feature is
# experimental and incomplete at the moment. # still experimental and incomplete at the moment.
# The default value is: NO. # The default value is: NO.
GENERATE_AUTOGEN_DEF = NO GENERATE_AUTOGEN_DEF = NO
@@ -1844,7 +1914,7 @@ GENERATE_AUTOGEN_DEF = NO
# Configuration options related to the Perl module output # 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. # file that captures the structure of the code including all documentation.
# #
# Note that this feature is still experimental and incomplete at the moment. # Note that this feature is still experimental and incomplete at the moment.
@@ -1852,7 +1922,7 @@ GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = 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 # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output. # output from the Perl module output.
# The default value is: NO. # The default value is: NO.
@@ -1860,9 +1930,9 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = 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 # 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 # size of the Perl module output will be much smaller and Perl will parse it
# just the same. # just the same.
# The default value is: YES. # The default value is: YES.
@@ -1882,14 +1952,14 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor # 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. # C-preprocessor directives found in the sources and include files.
# The default value is: YES. # The default value is: YES.
ENABLE_PREPROCESSING = YES ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names # 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 # 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 # performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES. # EXPAND_ONLY_PREDEF to YES.
# The default value is: NO. # The default value is: NO.
@@ -1905,7 +1975,7 @@ MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = 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. # INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1947,9 +2017,9 @@ PREDEFINED =
EXPAND_AS_DEFINED = EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # 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 # remove all references to function-like macros that are alone on a line, have
# all uppercase name, and do not end with a semicolon. Such function macros are # an all uppercase name, and do not end with a semicolon. Such function macros
# typically used for boiler-plate code, and will confuse the parser if not # are typically used for boiler-plate code, and will confuse the parser if not
# removed. # removed.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1969,7 +2039,7 @@ SKIP_FUNCTION_MACROS = YES
# where loc1 and loc2 can be relative or absolute paths or URLs. See the # 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 # section "Linking to external documentation" for more information about the use
# of tag files. # 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 # 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. # run, you must also specify the path to the tagfile here.
@@ -1981,20 +2051,21 @@ TAGFILES =
GENERATE_TAGFILE = GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external class will be listed in the # If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# class index. If set to NO only the inherited external classes will be listed. # the class index. If set to NO, only the inherited external classes will be
# listed.
# The default value is: NO. # The default value is: NO.
ALLEXTERNALS = NO ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# the modules index. If set to NO, only the current project's groups will be # in the modules index. If set to NO, only the current project's groups will be
# listed. # listed.
# The default value is: YES. # The default value is: YES.
EXTERNAL_GROUPS = 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 # the related pages index. If set to NO, only the current project's pages will
# be listed. # be listed.
# The default value is: YES. # The default value is: YES.
@@ -2011,7 +2082,7 @@ PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool # 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 # (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 # 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 # disabled, but it is recommended to install and use dot, since it yields more
@@ -2036,7 +2107,7 @@ MSCGEN_PATH =
DIA_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. # and usage relations if the target is undocumented or is not a class.
# The default value is: YES. # The default value is: YES.
@@ -2061,7 +2132,7 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0 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 # 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 # 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 # standard location or by setting the DOTFONTPATH environment variable or by
@@ -2109,7 +2180,7 @@ COLLABORATION_GRAPH = YES
GROUP_GRAPHS = 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 # collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language. # Language.
# The default value is: NO. # The default value is: NO.
@@ -2161,7 +2232,8 @@ INCLUDED_BY_GRAPH = YES
# #
# Note that enabling this option will significantly increase the time of a run. # 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 # 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. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
@@ -2172,7 +2244,8 @@ CALL_GRAPH = NO
# #
# Note that enabling this option will significantly increase the time of a run. # 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 # 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. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
@@ -2195,11 +2268,15 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # 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 # 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 # to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement). # 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. # The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
@@ -2242,6 +2319,19 @@ MSCFILE_DIRS =
DIAFILE_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 # 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 # 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 # larger than this value, doxygen will truncate the graph, which is visualized
@@ -2278,7 +2368,7 @@ MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO 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 # 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 # makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default. # this, this feature is disabled by default.
@@ -2295,7 +2385,7 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES 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. # files that are used to generate the various graphs.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
+31 -44
View File
@@ -1,12 +1,17 @@
Copyright and License Terms
---------------------------
Copyright (c) 2008 Martin R. Kraimer Copyright (c) 2006-2016 Martin R. Kraimer
Copyright (c) 2006 The University of Chicago, as Operator of Argonne Copyright (c) 2006-2016 UChicago Argonne LLC, as Operator of Argonne
National Laboratory. National Laboratory.
Copyright (c) 2006 Deutsches Elektronen-Synchrotron, Copyright (c) 2006 Deutsches Elektronen-Synchrotron,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY. Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
Copyright (c) 2007 Control System Laboratory, Copyright (c) 2007-2016 Control System Laboratory,
(COSYLAB) Ljubljana Slovenia (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 Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation 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, This software is copyright in part by these institutions:
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.
UofC specifically disclaims any warranties, including, but not limited * Brookhaven Science Associates, as Operator of Brookhaven
to, the implied warranties of merchantability, fitness for a particular National Laboratory, New York, USA
purpose, and non-infringement. This software is provided on an "as is" * Control System Laboratory, Ljubljana, Slovenia
basis, and UofC has no obligation to provide maintenance, support, * Deutsches Elektronen-Synchroton, Member of the Helmholtz
updates, enhancements, or modifications. 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 These institutions specifically disclaim any warranties, including, but
GESELLSCHAFT FUER SYNCHROTRONSTRAHLUNG M.B.H. (BESSY), BERLIN, GERMANY. 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.
________________________________________________________________________
+4 -14
View File
@@ -1,20 +1,10 @@
#Makefile at top of application tree #Makefile at top of application tree
TOP = . TOP = .
include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), configure) DIRS += configure
DIRS := $(DIRS) $(filter-out $(DIRS), src)
DIRS := $(DIRS) $(filter-out $(DIRS), example)
EMBEDDED_TOPS := $(EMBEDDED_TOPS) $(filter-out $(EMBEDDED_TOPS), 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))))
include $(TOP)/configure/RULES_TOP include $(TOP)/configure/RULES_TOP
+11 -44
View File
@@ -1,50 +1,17 @@
pvaClientCPP # pvaClientCPP
============
pvaClient is a synchronous client interface to pvAccess, The **pvaClient** API provides a synchronous client interface that was designed to be easier to use than the original basic pvAccess client API.
which is callback based.
pvaClient is thus easier to use than pvAccess itself.
See documentation/pvaClientCPP.html for details. The pvaClientCPP module implements the pvaClient API for C++ client applications.
Building ## Links
--------
If a proper RELEASE.local file exists one directory level above pvaClientCPP - General information about EPICS can be found at the
then just type: [EPICS Controls website](https://epics-controls.org).
- API documentation for this module can be found in its
documentation directory, in particular the file
pvaClientCPP.html
make ## Building
If RELEASE.local does not exist then look at <b>configure/RELEASE</b> This module is included as a submodule of a full EPICS 7 release and will be compiled during builds of that software.
for directions for how to build.
Examples
------------
The examples require the database in pvaClientTestCPP.
For example:
mrk> pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd
Status
------
* The API is for EPICS Version 4 release 4.5.0
* Everything defined in pvaClient.h is ready but see below for remaining work.
* Everything defined in pvaClientMultiChannel.h is ready but see below for remaining work.
pvaClientChannel
---------------
Channel::getField and channelArray are not supported for release 4.5
pvaClientMultiChannel
---------------
For release 4.5 support is available for multiDouble and NTMultiChannel.
In the future additional support should be provided that at least includes NTScalarMultiChannel.
Testing with some channels not connected has not been done.
-11
View File
@@ -1,11 +0,0 @@
Release/4.1
===========
This is for EPICS V4 release 4.5
pvaClient is a synchronous API for pvAccess.
This is the first release of pvaClientCPP.
It provides an API that is similar to pvaClientJava.
+12
View File
@@ -0,0 +1,12 @@
# Version number for the PVA Client API and shared library
EPICS_PVACLIENT_MAJOR_VERSION = 4
EPICS_PVACLIENT_MINOR_VERSION = 8
EPICS_PVACLIENT_MAINTENANCE_VERSION = 2
# Development flag, set to zero for release versions
EPICS_PVACLIENT_DEVELOPMENT_FLAG = 1
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1
-3
View File
@@ -20,8 +20,5 @@
# INSTALL_LOCATION here. # INSTALL_LOCATION here.
#INSTALL_LOCATION=</path/name/to/install/top> #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)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local -include $(TOP)/configure/CONFIG_SITE.local
-9
View File
@@ -1,9 +0,0 @@
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
EPICS_BASE=/home/install/epics/base
V4BASE=/home/epicsv4
PVCOMMON=${V4BASE}/pvCommonCPP
PVDATA=${V4BASE}/pvDataCPP
NORMATIVETYPES=${V4BASE}/normativeTypesCPP
PVACCESS=${V4BASE}/pvAccessCPP
+2
View File
@@ -2,6 +2,8 @@ TOP=..
include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG
CFG += CONFIG_PVACLIENT_VERSION
TARGETS = $(CONFIG_TARGETS) TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
+33 -19
View File
@@ -1,30 +1,44 @@
# easyPVACPP RELEASE - Location of external support modules # RELEASE - Location of external support modules
# #
# IF YOU CHANGE this file or any file it includes you must # IF YOU CHANGE ANY PATHS in this file or make API changes to
# subsequently do a "gnumake rebuild" in the application's # any modules it refers to, you should do a "make rebuild" in
# top level directory. # this application's top level directory.
# #
# The build process does not check dependencies against files # The EPICS build process does not check dependencies against
# that are outside this application, thus you should also do a # any files from outside the application, so it is safest to
# "gnumake rebuild" in the top level directory after EPICS_BASE # rebuild it completely if any modules it depends on change.
# or any other external module pointed to below is rebuilt.
# #
# Host- or target-specific settings can be given in files named # Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common # RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A) # RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A) # RELEASE.$(EPICS_HOST_ARCH).$(T_A)
# EPICS V4 Developers: Do not edit the locations in this file!
# #
# A RELEASE.local must exist that has the following definitions # This file is parsed by both GNUmake and an EPICS Perl script,
# EPICS_BASE=/home/install/epics/base # so it may ONLY contain definititions of paths to other support
# EPICS4_DIR=/home/epicsv4 # modules, variable definitions that are used in module paths,
# PVCOMMON=${EPICS4_DIR}/pvCommonCPP # and include statements that pull in other RELEASE files.
# PVDATA=${EPICS4_DIR}/pvDataCPP # Variables may be used before their values have been set.
# NORMATIVETYPES=${EPICSV4}/normativeTypesCPP # Build variables that are NOT used in paths should be set in
# PVACCESS=${EPICS4_DIR}/pvAccessCPP # the CONFIG_SITE file.
#Either create a RELEASE.local one level above the TOP for this module
#OR copy ExampleRELEASE.local to RELEASE.local and edit it.
# 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_NORMATIVETYPES = $(MODULES)/normativeTypes
#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.local
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
-include $(TOP)/configure/RELEASE.local -include $(TOP)/configure/RELEASE.local
+126
View File
@@ -0,0 +1,126 @@
# pvaClientCPP Module
This document summarizes the changes to the module between releases.
## Release 4.8.1 (EPICS 7.0.10, Dec 2025)
* Fix error message generation code.
## Release 4.8.0 (EPICS 7.0.6 Jul 2021)
* PvaClientNTMultiData::getChannelChangeFlags is a new method. It fixes issue #66.
* Fix for issue #68. Both PvaClientArray and PvaClientField are not longer present. Neither was previously implemented.
* Several public methods are now protected. They were never meant to be called by clients.
* Issue #70 has been fixed.
* Changes was made to increase the performance of pvaMultiChannel.
* doxygen changes were made.
## Release 4.7.1 (EPICS 7.0.3.2 May 2020)
* support access to a union field that is a scalar or scalarArray
* fixed issues #62 and #63
## Release 4.7.0 (EPICS 7.0.3.1, Nov 2019)
* added JSON support for put and putGet
* Fix for
[GitHub issue #62](https://github.com/epics-base/pvaClientCPP/issues/62)
* Doxygen updates and read-the-docs integration.
## Release 4.6.0 (EPICS 7.0.3, Jul 2019)
* pvaClient now handles exceptions from the server properly (issue #54).
* MultiChannel classes now properly handle PV structures that don't have a top-level `value` field (issue #56), and are more tolerant of other missing fields (issue #57).
## Release 4.5.0 (EPICS 7.0.2.2, Apr 2019)
Changes have been made for getDouble, putDouble, getDoubleArray, putDoubleArray, getString, putString, getStringArray, and putStringArray.
1) Previously each only had support for a top level field named value.
Each now allows access to a single sub field that has the correct type.
Thus pvRequest must select a single field. For example
pva->channel("PVRdumbPowerSupply")->putDouble(1.0,"power.value" );
2) PvaChannel now has a method for each of the above.
For example instead of
PvaClientChannelPtr channel = pva->channel("PVRdouble");
PvaClientPutPtr clientPut = channel->put();
PvaClientPutDataPtr putData = clientPut->getData();
putData->putDouble(1.0); clientPut->put();
now it can be
pva->channel("PVRdouble")->putDouble(1.0 );
3) getDoubleArray and putDoubleArray work with any numeric scalar array
4) getStringArray and putStringArray work with any scalar array.
## Release 4.4 (EPICS 7.0.2, Dec 2018)
### API changes to PvaClientMonitor
The create method that had arguments for stateChangeRequester and monitorRequester no longer exists.
### API changes to PvaClientGet, ..., PvaClientMonitor
Previously the pvaClientGet, ..., pvaClientMonitor classes all implemented PvaClientChannelStateChangeRequester(). This method was never called and has been removed.
## Release 4.3 (EPICS 7.0.1, Dec 2017)
### Requires pvDataCPP-7.0 and pvAccessCPP-6.0 versions
This release will not work with older versions of these modules.
### Destroy methods removed
All the destroy() methods have been removed, implementation is RAII compliant.
### API changes to PvaClientMonitor
The second argument of method
static PvaClientMonitorPtr create(
PvaClientPtr const &pvaClient,
epics::pvAccess::Channel::shared_pointer const & channel,
epics::pvData::PVStructurePtr const &pvRequest
);
is now changed to
static PvaClientMonitorPtr create(
PvaClientPtr const &pvaClient,
PvaClientChannelPtr const & pvaClientChannel,
epics::pvData::PVStructurePtr const &pvRequest
);
A new method is also implemented
static PvaClientMonitorPtr create(
PvaClientPtr const &pvaClient,
std::string const & channelName,
std::string const & providerName,
std::string const & request,
PvaClientChannelStateChangeRequesterPtr const & stateChangeRequester,
PvaClientMonitorRequesterPtr const & monitorRequester
);
## Release 4.2 (EPICS V4.6, Aug 2016)
* The examples are moved to exampleCPP.
* Support for channelRPC is now available.
* In PvaClientMultiChannel checkConnected() now throws an exception if connect fails.
## Release 4.1 (EPICS V4.5, Oct 2015)
pvaClient is a synchronous API for pvAccess.
This is the first release of pvaClientCPP.
It provides an API that is similar to pvaClientJava.
+7
View File
@@ -0,0 +1,7 @@
.wy-side-nav-search {
background-color: #18334B;
}
.wy-side-nav-search input[type="text"] {
border-color: #18334b;
}
+80
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',
'pvaClientCPP.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
View File
@@ -0,0 +1,17 @@
pvaClient (C++) Library
========================
.. toctree::
:hidden:
EPICS Website <https://epics-controls.org>
EPICS Documentation Home <https://docs.epics-controls.org>
.. toctree::
:maxdepth: 1
:caption: pvaClientCPP
Reference Manual <https://docs.epics-controls.org/projects/pvaclient-cpp/en/latest/pvaClientCPP.html>
API Documentation <https://docs.epics-controls.org/projects/pvaclient-cpp/en/latest/doxygen>
Source Code Repository on GitHub <https://github.com/epics-base/pvaClientCPP>
+49 -117
View File
@@ -4,11 +4,11 @@
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>EPICS pva</title> <title>EPICS pvaClientCPP</title>
<link rel="stylesheet" type="text/css" <link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" /> href="https://mrkraimer.github.io/website/css/base.css" />
<link rel="stylesheet" type="text/css" <link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" /> href="https://mrkraimer.github.io/website/css/epicsv4.css" />
<style type="text/css"> <style type="text/css">
/*<![CDATA[*/ /*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em} .about { margin-left: 3em; margin-right: 3em; font-size: .83em}
@@ -18,7 +18,7 @@
/*]]>*/</style> /*]]>*/</style>
<!-- Script that generates the Table of Contents --> <!-- Script that generates the Table of Contents -->
<script type="text/javascript" src="http://epics-pvdata.sourceforge.net/script/tocgen.js"></script> <script type="text/javascript" src="https://mrkraimer.github.io/website/css/tocgen.js"></script>
</head> </head>
@@ -26,31 +26,13 @@
<div class="head"> <div class="head">
<h1>EPICS pvaClientCPP</h1> <h1>EPICS pvaClientCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. --> <h2 class="nocount">Release 4.8 - March 2021</h2>
<h2 class="nocount">EPICS V4 Working Group, Working Draft,
02-October-2015</h2>
<dl>
<dt>This version:</dt>
<dd><a
href="pvaClientCPP.html">pvaClientCPP.html
</a> </dd>
<dt>Latest version:</dt>
<dd><a
href="pvaClientCPP_20151002.html">pvaClientCPP_20151002.html
</a> </dd>
<dt>Previous version:</dt>
<dd><a
href="pvaClientCPP_20150803.html">pvaClientCPP_20150803.html
</a> </dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<h2 class="nocount">Abstract</h2> <h2 class="nocount">Abstract</h2>
<p>pvaClient is a software library that provides to an EPICS client programmer, a friendly <p>pvaClient is a software library that provides, to an EPICS client programmer, a friendly
client side programming interface to the data of an EPICS based control system. It is intended client side programming interface to the data of an EPICS based control system. It is intended
for such uses as rapid development of ad hoc programs by controls engineers, or to provide for such uses as rapid development of ad hoc programs by controls engineers, or to provide
scientists a way to directly develop analytical applications.</p> scientists a way to directly develop analytical applications.</p>
<p>Specifically, pvaClient provides a synchronous interface for pvAccess, which is the <p>Specifically, pvaClient provides a synchronous interface for pvAccess, which is the
@@ -59,7 +41,7 @@ pvAccess provides a callback based interface, which can be hard to use.
pvaClient provides an interface that does not require callbacks even for monitors. pvaClient provides an interface that does not require callbacks even for monitors.
</p> </p>
<p> <p>
pvaClientChannel provides many "convenience" methods to directly get and put pvaClientChannel provides many "convenience" methods to directly get and put
scalar and scalarArray data types. scalar and scalarArray data types.
Additional methods provide access to the full features of pvAccess. Additional methods provide access to the full features of pvAccess.
</p> </p>
@@ -78,109 +60,59 @@ The data for the channels is presented via normative type NTMultiChannel.
Control System</a>.</p> Control System</a>.</p>
<h2 class="nocount">Status of this Document and of the pvaClient Software</h2>
<p>pvaClientCPP is ready for use.</p>
</div> <!-- head --> </div> <!-- head -->
<div id="toc"> <div id="contents" class="contents">
<h2 class="nocount">Table of Contents</h2>
</div>
<!-- Place what you would like in the Table of Contents, inside the contents div -->
<div id="contents" class="contents">
<hr /> <hr />
<h2>Overview</h2>
<h2>Introduction</h2>
<p>pvaClient is a synchronous API for accessing PVData via PVAccess. It provides
an interface to many of the features provided by pvData and pvAccess.</p>
<p>This document describes the layout of the source files in this project.</p>
<p> <p>
A user overview is available via Documentation for pvaClientCPP is available at:
<a <a
href="./pvaClientOverview.html">pvaClientOverview.html href="https://mrkraimer.github.io/website/developerGuide/pvaClient/pvaClientCPP.html">
pvaClient
</a> </a>
</p> </p>
<p> <p>
Doxygen documentation is available at pvaClientCPP is one of the components of
<a <a href="https://epics-controls.org/resources-and-support/base/epics-7/">
href="./html/index.html">doxygenDoc EPICS-7
</a> </a>
</p> </p>
<h2>Example Database</h2> <p>This document is only a guide to help locate code and documentation related to pvaClientCPP
<p>The examples require that the database provided by project pvaClientTestCPP
is running.
For example:</p>
<pre>
mrk&gt; pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk&gt; ../../bin/linux-x86_64/exampleDatabase st.cmd
</pre>
<h2>Examples</h2>
<p>Examples are in directory <b>example/src</b>.
An example of how to run them is:</p>
<pre>
mrk&gt; pwd
/home/epicsv4/pvaClientCPP/example
mrk&gt; bin/linux-x86_64/examplePvaClientGet
</pre>
<p>The following is a brief description of each example.
In order to understand each example it
helps to also look at the source for the example.</p>
<h2>examplePvaClientGet</h2>
<p>This has a number of examples:</p>
<dl>
<dt>exampleDouble</dt>
<dd>
This shows two methods for getting data from a channel that has a numeric
scalar value field.
</dd>
<dt>exampleDoubleArray</dt>
<dd>
This shows two methods for getting data from a channel that has a
double array value field.
</dd>
<dt>exampleCADouble</dt>
<dd>
This is like exampleDouble except it uses provider <b>ca</b>.
</dd>
<dt>exampleCADoubleArray</dt>
<dd>
This is like exampleDoubleArray except it uses provider <b>ca</b>.
</dd>
<dt>examplePowerSupply</dt>
<dd>
This is an example of getting data from a channel that does not
have a value field.
</dd>
</dl>
<h2>examplePvaClientMonitor</h2>
<p>This is an example of creating a monitor on a channel.
It monitors a scalar double field.
It also issues puts to the same channel so that it can make the monitors occur.
</p> </p>
<h2>examplePvaClientPut</h2> <p>
<p>This example gets and puts to channels exampleDouble It is intended for developers that want to use pvaClientCPP.
and exampleDoubleArray.</p>
<h2>examplePvaClientProcess</h2>
<p>This example makes a process request to channel exampleDouble.</p>
<h2>helloWorldPutGet</h2>
<p>This is an example of issuing a channelPutGet.</p>
<h2>examplePvaClientMultiDouble</h2>
<p>This is an example of using pvaClientMultiChannel,
pvaClientMultiGetDouble, pvaClientMultiPutDouble, and pvaClientMultiMonitorDouble.
</p> </p>
<h2>examplePvaClientNTMulti</h2> <h2>Developer Guide</h2>
<p>This is an example of using pvaClientMultiChannel, <p>A guide for developers is available at
pvaClientNTMultiGet, pvaClientNTMultiPut, pvaClientNTMultiMonitor, and pvaClientNTMultiData. <a
href="https://mrkraimer.github.io/website/developerGuide/developerGuide.html">
developerGuide
</a>
</p> </p>
<h2>helloWorldRPC</h2> <p>This guide provides an overview of the components that are part of an <b>EPICS V4</b> release.
<p>This is an example of issuing a channelRPC request. Some understanding of the components and how they are related is necessary in order to
It does <b>not</b> use pva.</p> develop code that uses pvaClientCPP.
In particular read everything related to pvaClient.
</p>
<h2>doxygen</h2>
<p>doxygen documentation is available at
<a
href="./html/index.html">doxygen</a>
</p>
<h2>exampleCPP</h2>
<p>Example code is available at
<a
href="https://github.com/epics-base/exampleCPP">
exampleCPP
</a>
</p>
<p>In particular look at exampleClient.
It has many examples of using pvaClientCPP.
</p>
</div> <!-- class="contents" --> </div> <!-- class="contents" -->
</body> </body>
</html> </html>
-199
View File
@@ -1,199 +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>EPICS pva</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 }
body { margin-right: 10% }
/*]]>*/</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>EPICS pvaClientCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS V4 Working Group, Working Draft,
26-June-2015</h2>
<dl>
<dt>This version:</dt>
<dd><a
href="pvaClientCPP.html">pvaClientCPP.html
</a> </dd>
<dt>Latest version:</dt>
<dd><a
href="pvaClientCPP_20150626.html">pvaClientCPP_20150626.html
</a> </dd>
<dt>Previous version:</dt>
<dd><a
href="easyPVA_20150609.html">easyPVA_20150609.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<h2 class="nocount">Abstract</h2>
<p>pvaClient is a software library that provides to an EPICS client programmer, a friendly
client side programming interface to the data of an EPICS based control system. It is intended
for such uses as rapid development of ad hoc programs by controls engineers, or to provide
scientists a way to directly develop analytical applications.</p>
<p>Specifically, pvaClient provides a synchronous interface for pvAccess, which is the
software support for high speed controls network communications used in EPICS version 4.
pvAccess provides a callback based interface, which can be hard to use.
pvaClient provides an interface that does not require callbacks even for monitors.
</p>
pvaClientChannel provides many "convenience" methods to directly get and put
scalar and scalarArray data types.
Additional methods provide access to the full features of pvAccess.
</p>
<p>
pvaClientMultiChannel provides access to data from multiple channels.
It can be used directly by a client or via pvaClientMultiDouble or pvaClientNTMultiChannel.
pvaClientMultiDouble allows the client to get and put data to multiple channels.
But each channel must have a value field that is a numeric scalar.
pvaClientNTMultiChannel allows the client to get and put data to multiple channels.
Each channel must have a value field.
The data for the channels is presented via normative type NTMultiChannel.
</p>
<!-- last para of Abstract is boilerplate reference to EPICS -->
<p>For more information about EPICS generally, please refer to the home page of the <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System</a>.</p>
<h2 class="nocount">Status of this Document and of the pvaClient Software</h2>
<p>pvaClientCPP is ready for use.</p>
</div> <!-- head -->
<div id="toc">
<h2 class="nocount">Table of Contents</h2>
</div>
<!-- Place what you would like in the Table of Contents, inside the contents div -->
<div id="contents" class="contents">
<hr />
<h2>Introduction</h2>
<p>pvaClient is a synchronous API for accessing PVData via PVAccess. It provides
an interface to many of the features provided by pvData and pvAccess.</p>
<p>This document describes the layout of the source files in this project.</p>
<p>
A user overview is available via
<a
href="./pvaClientOverview.html">pvaClientOverview.html
</a>
</p>
<p>
Doxygen documentation is available at
<a
href="./html/index.html">doxygenDoc
</a>
</p>
<h2>Example Database</h2>
<p>The examples require that an example pvAccess server is runnimg.
To get the test database go to:</p>
<a
href="https://github.com/epics_base/pvaClientTestCPP/blob/master/database.zip">pvaClientTestCPP/database.zip
</a>
Then select "raw file" and You will be able to download the zip file.
<p>
When unzipped this is used to create an example IOC database.
</p>
<p>
After unzipping the file:
</p>
<pre>
cd database/configure
cp ExampleRELEASE.local RELEASE.local
edit RELEASE.local
cd ..
make
cd iocBoot/exampleDatabase
../../bin/&lt;arch:&gt;/exampleDatabase st.cmd
</pre>
<h2>Examples</h2>
<p>Examples are in directory <b>example/src</b>.
An example of how to run them is:</p>
<pre>
mrk&gt; pwd
/home/epicsv4/pvaClientCPP/example
mrk&gt; bin/linux-x86_64/examplePvaClientGet
</pre>
<p>The following is a brief description of each example.
In order to understand each example it
helps to also look at the source for the example.</p>
<h2>examplePvaClientGet</h2>
<p>This has a number of examples:</p>
<dl>
<dt>exampleDouble</dt>
<dd>
This shows two methods for getting data from a channel that has a numeric
scalar value field.
</dd>
<dt>exampleDoubleArray</dt>
<dd>
This shows two methods for getting data from a channel that has a
double array value field.
</dd>
<dt>exampleCADouble</dt>
<dd>
This is like exampleDouble except it uses provider <b>ca</b>.
</dd>
<dt>exampleCADoubleArray</dt>
<dd>
This is like exampleDoubleArray except it uses provider <b>ca</b>.
</dd>
<dt>examplePowerSupply</dt>
<dd>
This is an example of getting data from a channel that does not
have a value field.
</dd>
</dl>
<h2>examplePvaClientMonitor</h2>
<p>This is an example of creating a monitor on a channel.
It monitors a channel that models a powerSupply, i. e. it is not a "standard" record.
It does not have a value field.
</p>
<p>After starting the example a change can be made to the powerSupply by issuing:</p>
<pre>
pvput -r "power.value,voltage.value" examplePowerSupply 6 6
</pre>
<h2>examplePvaClientPut</h2>
<p>This example gets and puts to channel exampleDouble.</p>
<h2>examplePvaClientProcess</h2>
<p>This example makes a process request to channel exampleDouble.</p>
<h2>helloWorldPutGet</h2>
<p>This is an example of issuing a channelPutGet.</p>
<h2>examplePvaClientMultiDouble</h2>
<p>This is an example of issuing gets and puts to multiple channels where each
channel has a numeric scalar value field.</p>
<h2>examplePvaClientNTMultiChannel</h2>
<p>This is an example of using NDMultiChannel to obtain data from multiple channels.
</p>
<h2>helloWorldRPC</h2>
<p>This is an example of issuing a channelRPC request.
It does <b>not</b> use pva.</p>
</div> <!-- class="contents" -->
</body>
</html>
-182
View File
@@ -1,182 +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>EPICS pva</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 }
body { margin-right: 10% }
/*]]>*/</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>EPICS pvaClientCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS V4 Working Group, Working Draft,
03-August-2015</h2>
<dl>
<dt>This version:</dt>
<dd><a
href="pvaClientCPP.html">pvaClientCPP.html
</a> </dd>
<dt>Latest version:</dt>
<dd><a
href="pvaClientCPP_20150803.html">pvaClientCPP_20150803.html
</a> </dd>
<dt>Previous version:</dt>
<dd><a
href="pvaClientCPP_20150626.html">pvaClientCPP_20150626.html
</a> </dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<h2 class="nocount">Abstract</h2>
<p>pvaClient is a software library that provides to an EPICS client programmer, a friendly
client side programming interface to the data of an EPICS based control system. It is intended
for such uses as rapid development of ad hoc programs by controls engineers, or to provide
scientists a way to directly develop analytical applications.</p>
<p>Specifically, pvaClient provides a synchronous interface for pvAccess, which is the
software support for high speed controls network communications used in EPICS version 4.
pvAccess provides a callback based interface, which can be hard to use.
pvaClient provides an interface that does not require callbacks even for monitors.
</p>
<p>
pvaClientChannel provides many "convenience" methods to directly get and put
scalar and scalarArray data types.
Additional methods provide access to the full features of pvAccess.
</p>
<p>
pvaClientMultiChannel provides access to data from multiple channels.
It can be used directly by a client or via pvaClientMultiDouble or pvaClientNTMultiChannel.
pvaClientMultiDouble allows the client to get and put data to multiple channels.
But each channel must have a value field that is a numeric scalar.
pvaClientNTMultiChannel allows the client to get and put data to multiple channels.
Each channel must have a value field.
The data for the channels is presented via normative type NTMultiChannel.
</p>
<!-- last para of Abstract is boilerplate reference to EPICS -->
<p>For more information about EPICS generally, please refer to the home page of the <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System</a>.</p>
<h2 class="nocount">Status of this Document and of the pvaClient Software</h2>
<p>pvaClientCPP is ready for use.</p>
</div> <!-- head -->
<div id="toc">
<h2 class="nocount">Table of Contents</h2>
</div>
<!-- Place what you would like in the Table of Contents, inside the contents div -->
<div id="contents" class="contents">
<hr />
<h2>Introduction</h2>
<p>pvaClient is a synchronous API for accessing PVData via PVAccess. It provides
an interface to many of the features provided by pvData and pvAccess.</p>
<p>This document describes the layout of the source files in this project.</p>
<p>
A user overview is available via
<a
href="./pvaClientOverview.html">pvaClientOverview.html
</a>
</p>
<p>
Doxygen documentation is available at
<a
href="./html/index.html">doxygenDoc
</a>
</p>
<h2>Example Database</h2>
<p>The examples require that the database provided by project pvaClientTestCPP
is running.
For example:</p>
<pre>
mrk&gt; pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk&gt; ../../bin/linux-x86_64/exampleDatabase st.cmd
</pre>
<h2>Examples</h2>
<p>Examples are in directory <b>example/src</b>.
An example of how to run them is:</p>
<pre>
mrk&gt; pwd
/home/epicsv4/pvaClientCPP/example
mrk&gt; bin/linux-x86_64/examplePvaClientGet
</pre>
<p>The following is a brief description of each example.
In order to understand each example it
helps to also look at the source for the example.</p>
<h2>examplePvaClientGet</h2>
<p>This has a number of examples:</p>
<dl>
<dt>exampleDouble</dt>
<dd>
This shows two methods for getting data from a channel that has a numeric
scalar value field.
</dd>
<dt>exampleDoubleArray</dt>
<dd>
This shows two methods for getting data from a channel that has a
double array value field.
</dd>
<dt>exampleCADouble</dt>
<dd>
This is like exampleDouble except it uses provider <b>ca</b>.
</dd>
<dt>exampleCADoubleArray</dt>
<dd>
This is like exampleDoubleArray except it uses provider <b>ca</b>.
</dd>
<dt>examplePowerSupply</dt>
<dd>
This is an example of getting data from a channel that does not
have a value field.
</dd>
</dl>
<h2>examplePvaClientMonitor</h2>
<p>This is an example of creating a monitor on a channel.
It monitors a scalar double field.
It also issues puts to the same channel so that it can make the monitors occur.
</p>
<h2>examplePvaClientPut</h2>
<p>This example gets and puts to channels exampleDouble
and exampleDoubleArray.</p>
<h2>examplePvaClientProcess</h2>
<p>This example makes a process request to channel exampleDouble.</p>
<h2>helloWorldPutGet</h2>
<p>This is an example of issuing a channelPutGet.</p>
<h2>examplePvaClientMultiDouble</h2>
<p>This is an example of using pvaClientMultiChannel,
pvaClientMultiGetDouble, pvaClientMultiPutDouble, and pvaClientMultiMonitorDouble.
</p>
<h2>helloWorldRPC</h2>
<p>This is an example of issuing a channelRPC request.
It does <b>not</b> use pva.</p>
</div> <!-- class="contents" -->
</body>
</html>
-186
View File
@@ -1,186 +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>EPICS pva</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 }
body { margin-right: 10% }
/*]]>*/</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>EPICS pvaClientCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS V4 Working Group, Working Draft,
02-October-2015</h2>
<dl>
<dt>This version:</dt>
<dd><a
href="pvaClientCPP.html">pvaClientCPP.html
</a> </dd>
<dt>Latest version:</dt>
<dd><a
href="pvaClientCPP_20151002.html">pvaClientCPP_20151002.html
</a> </dd>
<dt>Previous version:</dt>
<dd><a
href="pvaClientCPP_20150803.html">pvaClientCPP_20150803.html
</a> </dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<h2 class="nocount">Abstract</h2>
<p>pvaClient is a software library that provides to an EPICS client programmer, a friendly
client side programming interface to the data of an EPICS based control system. It is intended
for such uses as rapid development of ad hoc programs by controls engineers, or to provide
scientists a way to directly develop analytical applications.</p>
<p>Specifically, pvaClient provides a synchronous interface for pvAccess, which is the
software support for high speed controls network communications used in EPICS version 4.
pvAccess provides a callback based interface, which can be hard to use.
pvaClient provides an interface that does not require callbacks even for monitors.
</p>
<p>
pvaClientChannel provides many "convenience" methods to directly get and put
scalar and scalarArray data types.
Additional methods provide access to the full features of pvAccess.
</p>
<p>
pvaClientMultiChannel provides access to data from multiple channels.
It can be used directly by a client or via pvaClientMultiDouble or pvaClientNTMultiChannel.
pvaClientMultiDouble allows the client to get and put data to multiple channels.
But each channel must have a value field that is a numeric scalar.
pvaClientNTMultiChannel allows the client to get and put data to multiple channels.
Each channel must have a value field.
The data for the channels is presented via normative type NTMultiChannel.
</p>
<!-- last para of Abstract is boilerplate reference to EPICS -->
<p>For more information about EPICS generally, please refer to the home page of the <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System</a>.</p>
<h2 class="nocount">Status of this Document and of the pvaClient Software</h2>
<p>pvaClientCPP is ready for use.</p>
</div> <!-- head -->
<div id="toc">
<h2 class="nocount">Table of Contents</h2>
</div>
<!-- Place what you would like in the Table of Contents, inside the contents div -->
<div id="contents" class="contents">
<hr />
<h2>Introduction</h2>
<p>pvaClient is a synchronous API for accessing PVData via PVAccess. It provides
an interface to many of the features provided by pvData and pvAccess.</p>
<p>This document describes the layout of the source files in this project.</p>
<p>
A user overview is available via
<a
href="./pvaClientOverview.html">pvaClientOverview.html
</a>
</p>
<p>
Doxygen documentation is available at
<a
href="./html/index.html">doxygenDoc
</a>
</p>
<h2>Example Database</h2>
<p>The examples require that the database provided by project pvaClientTestCPP
is running.
For example:</p>
<pre>
mrk&gt; pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk&gt; ../../bin/linux-x86_64/exampleDatabase st.cmd
</pre>
<h2>Examples</h2>
<p>Examples are in directory <b>example/src</b>.
An example of how to run them is:</p>
<pre>
mrk&gt; pwd
/home/epicsv4/pvaClientCPP/example
mrk&gt; bin/linux-x86_64/examplePvaClientGet
</pre>
<p>The following is a brief description of each example.
In order to understand each example it
helps to also look at the source for the example.</p>
<h2>examplePvaClientGet</h2>
<p>This has a number of examples:</p>
<dl>
<dt>exampleDouble</dt>
<dd>
This shows two methods for getting data from a channel that has a numeric
scalar value field.
</dd>
<dt>exampleDoubleArray</dt>
<dd>
This shows two methods for getting data from a channel that has a
double array value field.
</dd>
<dt>exampleCADouble</dt>
<dd>
This is like exampleDouble except it uses provider <b>ca</b>.
</dd>
<dt>exampleCADoubleArray</dt>
<dd>
This is like exampleDoubleArray except it uses provider <b>ca</b>.
</dd>
<dt>examplePowerSupply</dt>
<dd>
This is an example of getting data from a channel that does not
have a value field.
</dd>
</dl>
<h2>examplePvaClientMonitor</h2>
<p>This is an example of creating a monitor on a channel.
It monitors a scalar double field.
It also issues puts to the same channel so that it can make the monitors occur.
</p>
<h2>examplePvaClientPut</h2>
<p>This example gets and puts to channels exampleDouble
and exampleDoubleArray.</p>
<h2>examplePvaClientProcess</h2>
<p>This example makes a process request to channel exampleDouble.</p>
<h2>helloWorldPutGet</h2>
<p>This is an example of issuing a channelPutGet.</p>
<h2>examplePvaClientMultiDouble</h2>
<p>This is an example of using pvaClientMultiChannel,
pvaClientMultiGetDouble, pvaClientMultiPutDouble, and pvaClientMultiMonitorDouble.
</p>
<h2>examplePvaClientNTMulti</h2>
<p>This is an example of using pvaClientMultiChannel,
pvaClientNTMultiGet, pvaClientNTMultiPut, pvaClientNTMultiMonitor, and pvaClientNTMultiData.
</p>
<h2>helloWorldRPC</h2>
<p>This is an example of issuing a channelRPC request.
It does <b>not</b> use pva.</p>
</div> <!-- class="contents" -->
</body>
</html>
-328
View File
@@ -1,328 +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>pva C++ Overview</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 }
body { margin-right: 10% }
/*]]>*/</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>PvaClient C++ Overview</h1>
</div> <!-- head -->
<div id="toc">
<h2 class="nocount">Table of Contents</h2>
</div>
<!-- Place what you would like in the Table of Contents, inside the contents div -->
<div id="contents" class="contents">
<hr />
<h2>Introduction</h2>
<p>PvaClient is a synchronous API for accessing PVData via PVAccess.
It also provides a number of convenience methods.
It allows the client to request access without checking for failure,
but throws an exception if a request fails.
A client can also check for failues and thus prevent exceptions.</p>
<p>The PvaClient API has the following features:</p>
<ol>
<li>Provides a synchronous API rather than the callback API provided by pvAccess.</li>
<li>Makes common requests pva.</li>
<li>Provides full access to the pvAccess API for more demanding
applications</li>
<li>Allows efficient client side programs.</li>
<li>Takes care of most object resource management problems.</li>
</ol>
<p>Simple examples of using pva:</p>
<pre>
// pvaGet
PvaClientPtr pva = PvaClient::create();
double value = pva-&gt;channel("exampleDouble")-&gt;get()-&gt;getData()-&gt;getDouble();
// pvaPut
PvaClientChannelPtr channel = pva-&gt;channel("exampleDouble");
PvaClientPutPtr put = channel-&gt;put();
PvaClientPutDataPtr putData = put-&gt;getData();
putData-&gt;putDouble(3.0); put-&gt;put();
// pvaMonitor
PvaClientMonitorPtr monitor = pva-&gt;channel("examplePowerSupply")-&gt;monitor("");
PvaClientMonitorDataPtr pvaData = monitor-&gt;getData();
while(true) {
monitor-&gt;waitEvent();
cout &lt;&lt; "changed\n";
pvaData-&gt;showChanged(cout);
cout &lt;&lt; "overrun\n";
pvaData-&gt;showOverrun(cout);
monitor-&gt;releaseEvent();
}
// pvaProcess
PvaClientChannelPtr channel = pva-&gt;channel("exampleDouble");
PvaClientProcessPtr process = channel-&gt;createProcess();
process-&gt;process();
</pre>
<p><b>pvClientCPP/example</b> includes a number of examples.</p>
<p>pvaClient does <b>not</b> provide support for:</p>
<dl>
<dt>ChannelArray</dt>
<dd>TBD</dd>
<dt>ChannelRPC</dt>
<dd>pvAccess itself already provides a synchronous interface.
The examples include helloWorldRPC, which is an example of using channelRP.
</dd>
</dl>
<h2>PvaClient</h2>
<p>An instance of PvaClient is obtained via the call:</p>
<pre>
PvaClientPtr pva = PvaClient::create();
</pre>
<p>PvaClient has methods to create instances of <b>PvaClientChannel</b>.
The client can specify the provider name or use the default provider.
The client can manage it's own channels or can let pvaClient cache channels.
An example of using the cached method is:</p>
<pre>
PvaClientChannelPtr pvaChannel = pva-&gt;channel("exampleDouble");
</pre>
<p>This will attempt to connect to channel exampleDouble.
Since the client did not specify a timeout an exception wll be thrown if
the connection request fails.
The client will block until the connection is made or an exception is thrown.
If the request succeeds, pva caches the pvaChannel so that if the
client makes another request for the same channel the cached object is
returned to the client.
</p>
<p>An example of using a non cached method is:</p>
<pre>
PvaClientChannelPtr pvaChannel = pva-&gt;createChannel("exampleDouble");
</pre>
<p>This will create an PvaClientChannel and return it to the client.
The client must itself connect.
This is useful if the client wants to connect to multiple channels in parallel.
</p>
<h2>PvaClientChannel - Wrapper For Single Channel</h2>
<h3>PvaClientChannel</h3>
<p>This provides methods for connecting to a channel and for creating instances of
PvaClientField, PvaClientProcess, ..., PvaClientPutGet.</p>
<p>Connection must be made before any create method is called or
an exception is raised.
The following is a synchronous connection request:</p>
<pre>
pvaChannel-&gt;connect(5.0); // BLOCKS AND THROWS IF NO CONNECT
</pre>
<p>This blocks until then connection is made or until timout occurs.
An exception is raised if the connection request fails.
</p>
<p>The same request can be made without blocking and without exceptions.</p>
<pre>
pvaChannel-&gt;issueConnect(); // DOES NOT BLOCK
.....
Status status =pvaChannel-&gt;waitConnect(5.0); // BLOCKS DOES NOT THROW
if(!status.isOK()) {
// failure do something
}
</pre>
<p>Once the channel is connected other PvaClient objects can be created.
For example:</p>
<pre>
PvaClientGetPtr pvaGet = pvaChannel-&gt;get(); // DOES BLOCK
</pre>
<p>This is a caching request.
If the client already has made an identical request the client will receive the
cached object.
If a new pvaGet is created than it is connected before it is returned to the client.
</p>
<p>The client can also managed it's own objects:</p>
<pre>
PvaClientGetPtr pvaGet = pvaChannel-&gt;createGet(); // DOES NOT BLOCK
</pre>
<p>The client must connect the pvaGet.</p>
<h3>PvaClientGetData</h3>
<p>This provides the data returned by pvaGet and pvaPutGet.
It is obtained via:</p>
<pre>
PvaClientGetDataPtr pvaData = pvaGet-&gt;getData();
</pre>
<p>It provides methods to get everything returned by channelGet.
In addition there are methods that make it easier to handle a value
field that is a scalar or a scalarArray.
Also for a scalar that is a double or a scalarArray with element type double.
</p>
<p>An example is:</p>
<pre>
double value = pvaData-&gt;getDouble();
</pre>
<p>It also keeps a bitSet showing which fields have changed since the last channelGet or channelPutGet.</p>
<h3>PvaClientMonitorData</h3>
<p>To the client this looks identical to PvaClientGetData except that
it provides two BitSets: changedBitSet and overrrunBitSet.
It is used by pvaMonitor.
</p>
<h3>PvaClientPutData</h3>
<p>This is used to provided data for pvaPut and pvaPutGet.
It has many of the same methods as pvaGetData.
It does not have a bitSet.
It also has put methods like:</p>
<pre>
void pvaData-&gt;putDouble(5.0);
</pre>
<h3>PvaClientGet</h3>
<p>This provides methods to connect to channelGet and to issue get request.
To connect via a single synchronous call:</p>
<pre>
eastGet-&gt;connect(); // BLOCKS AND CAN THROW
</pre>
<p>This can also be done in two steps:</p>
<pre>
pvaGet-&gt;issueConnect(); // DOES NOT BLOCK
...
Status status = pvaGet-&gt;waitConnect(); // BLOCKS AND DOES NOT HROW
</pre>
<p>Once connected gets are issued via either:</p>
<pre>
void pvaGet-&gt;get(); // BLOCKS AND CAN THROW
</pre>
or
<pre>
pvaGet-&gt;issueGet(); // DOES NOT BLOCK
...
Status status = pvaGet-&gt;waitGet(); // BLOCKS AND DOES NOT THROW
</pre>
<h3>PvaClientPut</h3>
<p>This is similar to pvaGet except that it wraps channelPut instead of channelGet.
</p>
<p>Once connected puts are issued via either:</p>
<pre>
void pvaPut-&gt;put(); // BLOCKS AND CAN THROW
</pre>
or
<pre>
pvaPut-&gt;issuePut(); // DOES NOT BLOCK
...
Status status = pvaPut-&gt;waitPut(); // BLOCKS AND DOES NOT THROW
</pre>
<h3>PvaClientMonitor</h3>
<p>Connecting is similar to pvaGet and pvaPut.
The other methods are:</p>
<dl>
<dt>start</dt>
<dd>Starts monitoring</dd>
<dt>stop</dt>
<dd>Stops monitoring</dd>
<dt>poll</dt>
<dd>polls for a monitorEvent.
The data is avalable via pvaMonitorData.
</dd>
<dt>releaseEvent</dt>
<dd>Release the data from the last poll.
Note that this must be called before another poll is requested.
</dd>
<dt>waitEvent</dt>
<dd>Block until a monitorEvent is available.
If true is returned a poll has already been issued.
</dd>
<dt>setRequester</dt>
<dd>A client callback is registered to receive notice of monitorEvents.</dd>
</dl>
<h3>PvaClientProcess</h3>
<p>Connecting is similar to pvaGet.
It has methods:</p>
<dl>
<dt>process</dt>
<dd>call issueProcess and waitProcess.</dd>
<dt>issueProcess</dt>
<dd>call channelProcess-&gt;process() and return immediately.
</dd>
<dt>waitProcess</dt>
<dd>Wait for process to complete.</dd>
</dl>
<h3>PvaClientPutGet</h3>
<p>Connecting is similar to pvaGet.
It has methods:</p>
<dl>
<dt>putGet</dt>
<dd>calls issuePutGet and waitPutGet.
throws an exception if not successfull.
</dd>
<dt>issuePutGet</dt>
<dd>
Calls channel-&gt;putGet() and returns.
</dd>
<dt>waitPutGet</dt>
<dd>
Waits until putGet completes and returns status.
</dd>
<dt>getGet,issueGetGet, and waitGetGet</dt>
<dd>Gets the data for the get part of channelPutGet.</dd>
<dt>getPut,issueGetPut,and waitGetPut</dt>
<dd>Gets the data for the put part of channelPutGet.</dd>
<dt>getPutData</dt>
<dd>
Returns the PvaClientData for the put part of channelPutGet.
</dd>
<dt>getGetData</dt>
<dd>
Returns the PvaClientData for the get part of channelPutGet.
</dd>
</dl>
<p>Look at javaDoc for details.</p>
<h2>PvaClientMultiChannel - Wrapper For Multiple Channels</h2>
<h3>PvaClientMultiChannel</h3>
<p>This provides methods for connecting to multiple channels.
</p>
<h3>PvaClientMultiGetDouble</h3>
<p>This provides support for channelGet to multiple channels where each channel has a value field that is a numeric scalar.
</p>
<h3>PvaClientMultiPutDouble</h3>
<p>This provides support for channelPut to multiple channels where each channel has a value field that is a numeric scalar.
</p>
<h3>PvaClientMultiMonitorDouble</h3>
<p>This provides support for monitoring changes to multiple channels where each channel has a value field that is a numeric scalar.
</p>
<h3>PvaClientNTMultiGet</h3>
<p>This provides support for channelGet to multiple channels where each channel has a value field that has any valid type.
</p>
<h3>PvaClientNTMultiPut</h3>
<p>This provides support for channelPut to multiple channels where each channel has a value
field that has any valid type.
</p>
<h3>PvaClientNTMultiMonitor</h3>
<p>This provides support for monitoring changes to multiple channels where each channel has a
value field that has any valid type.
</p>
<h3>PvaClientNTMultiData</h3>
<p>This provides support for monitoring changes to multiple channels where each channel has a value field that has any valid type.
The client can get the data as normative type NTMultiChannel.
</p>
</div> <!-- class="contents" -->
</body>
</html>
-13
View File
@@ -1,13 +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
-29
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
-27
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
-7
View File
@@ -1,7 +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
EASYPVA==${EPICSV4HOME}/easyPVACPP
-8
View File
@@ -1,8 +0,0 @@
TOP=..
include $(TOP)/configure/CONFIG
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
include $(TOP)/configure/RULES
-41
View File
@@ -1,41 +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:
EASYPVA = $(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:
#EASYPVA = /path/to/epics/easyPVACPP
#-include $(TOP)/../RELEASE.local
#-include $(TOP)/configure/RELEASE.local
-6
View File
@@ -1,6 +0,0 @@
# RULES
include $(CONFIG)/RULES
# Library should be rebuilt because LIBOBJS may have changed.
$(LIBNAME): ../Makefile
-2
View File
@@ -1,2 +0,0 @@
#RULES.ioc
include $(CONFIG)/RULES.ioc
-2
View File
@@ -1,2 +0,0 @@
#RULES_DIRS
include $(CONFIG)/RULES_DIRS
-3
View File
@@ -1,3 +0,0 @@
#RULES_TOP
include $(CONFIG)/RULES_TOP
-71
View File
@@ -1,71 +0,0 @@
TOP=..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
PROD_HOST += examplePvaClientProcess
examplePvaClientProcess_SRCS += examplePvaClientProcess.cpp
examplePvaClientProcess_LIBS += pvaClient
examplePvaClientProcess_LIBS += pvAccess
examplePvaClientProcess_LIBS += pvData
examplePvaClientProcess_LIBS += Com
PROD_HOST += examplePvaClientGet
examplePvaClientGet_SRCS += examplePvaClientGet.cpp
examplePvaClientGet_LIBS += pvaClient
examplePvaClientGet_LIBS += pvAccess
examplePvaClientGet_LIBS += pvData
examplePvaClientGet_LIBS += Com
PROD_HOST += examplePvaClientPut
examplePvaClientPut_SRCS += examplePvaClientPut.cpp
examplePvaClientPut_LIBS += pvaClient
examplePvaClientPut_LIBS += pvAccess
examplePvaClientPut_LIBS += pvData
examplePvaClientPut_LIBS += Com
PROD_HOST += examplePvaClientMonitor
examplePvaClientMonitor_SRCS += examplePvaClientMonitor.cpp
examplePvaClientMonitor_LIBS += pvaClient
examplePvaClientMonitor_LIBS += pvAccess
examplePvaClientMonitor_LIBS += pvData
examplePvaClientMonitor_LIBS += Com
PROD_HOST += examplePvaClientMultiDouble
examplePvaClientMultiDouble_SRCS += examplePvaClientMultiDouble.cpp
examplePvaClientMultiDouble_LIBS += pvaClient
examplePvaClientMultiDouble_LIBS += pvAccess
examplePvaClientMultiDouble_LIBS += pvData
examplePvaClientMultiDouble_LIBS += Com
PROD_HOST += examplePvaClientNTMulti
examplePvaClientNTMulti_SRCS += examplePvaClientNTMulti.cpp
examplePvaClientNTMulti_LIBS += pvaClient
examplePvaClientNTMulti_LIBS += pvAccess
examplePvaClientNTMulti_LIBS += pvData
examplePvaClientNTMulti_LIBS += Com
PROD_HOST += helloWorldRPC
helloWorldRPC_SRCS += helloWorldRPC.cpp
helloWorldRPC_LIBS += pvaClient
helloWorldRPC_LIBS += pvAccess
helloWorldRPC_LIBS += nt
helloWorldRPC_LIBS += pvData
helloWorldRPC_LIBS += Com
PROD_HOST += helloWorldPutGet
helloWorldPutGet_SRCS += helloWorldPutGet.cpp
helloWorldPutGet_LIBS += pvaClient
helloWorldPutGet_LIBS += pvAccess
helloWorldPutGet_LIBS += nt
helloWorldPutGet_LIBS += pvData
helloWorldPutGet_LIBS += Com
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
-146
View File
@@ -1,146 +0,0 @@
/*examplePvaClientGet.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/pvaClient.h>
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static void exampleDouble(PvaClientPtr const &pva)
{
cout << "example double scalar\n";
double value;
try {
cout << "short way\n";
value = pva->channel("exampleDouble")->get()->getData()->getDouble();
cout << "as double " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
cout << "long way\n";
PvaClientChannelPtr pvaChannel = pva->createChannel("exampleDouble");
pvaChannel->issueConnect();
Status status = pvaChannel->waitConnect(2.0);
if(!status.isOK()) {cout << " connect failed\n"; return;}
PvaClientGetPtr pvaGet = pvaChannel->createGet();
pvaGet->issueConnect();
status = pvaGet->waitConnect();
if(!status.isOK()) {cout << " createGet failed\n"; return;}
PvaClientGetDataPtr pvaData = pvaGet->getData();
value = pvaData->getDouble();
cout << "as double " << value << endl;
}
static void exampleDoubleArray(PvaClientPtr const &pva)
{
cout << "example double array\n";
shared_vector<const double> value;
try {
cout << "short way\n";
value = pva->channel("exampleDoubleArray")->get()->getData()->getDoubleArray();
cout << "as doubleArray " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
try {
cout << "long way\n";
PvaClientChannelPtr pvaChannel = pva->createChannel("exampleDoubleArray");
pvaChannel->connect(2.0);
PvaClientGetPtr pvaGet = pvaChannel->createGet();
PvaClientGetDataPtr pvaData = pvaGet->getData();
value = pvaData->getDoubleArray();
cout << "as doubleArray " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
static void examplePowerSupply(PvaClientPtr const &pva)
{
cout << "example powerSupply\n";
PVStructurePtr pvStructure;
try {
cout << "short way\n";
pvStructure = pva->channel("examplePowerSupply")->
get("field()")->getData()->getPVStructure();
cout << pvStructure << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
static void exampleCADouble(PvaClientPtr const &pva)
{
cout << "example double scalar\n";
double value;
try {
cout << "short way\n";
value = pva->channel("double00","ca",5.0)->get()->getData()->getDouble();
cout << "as double " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
cout << "long way\n";
PvaClientChannelPtr pvaChannel = pva->createChannel("double00","ca");
pvaChannel->issueConnect();
Status status = pvaChannel->waitConnect(2.0);
if(!status.isOK()) {cout << " connect failed\n"; return;}
PvaClientGetPtr pvaGet = pvaChannel->createGet();
pvaGet->issueConnect();
status = pvaGet->waitConnect();
if(!status.isOK()) {cout << " createGet failed\n"; return;}
PvaClientGetDataPtr pvaData = pvaGet->getData();
value = pvaData->getDouble();
cout << "as double " << value << endl;
}
static void exampleCADoubleArray(PvaClientPtr const &pva)
{
cout << "example double array\n";
shared_vector<const double> value;
try {
cout << "short way\n";
value = pva->channel("doubleArray","ca",5.0)->get()->getData()->getDoubleArray();
cout << "as doubleArray " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
try {
cout << "long way\n";
PvaClientChannelPtr pvaChannel = pva->createChannel("doubleArray","ca");
pvaChannel->connect(2.0);
PvaClientGetPtr pvaGet = pvaChannel->createGet();
PvaClientGetDataPtr pvaData = pvaGet->getData();
value = pvaData->getDoubleArray();
cout << "as doubleArray " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva= PvaClient::create();
exampleDouble(pva);
exampleDoubleArray(pva);
examplePowerSupply(pva);
exampleCADouble(pva);
exampleCADoubleArray(pva);
cout << "done\n";
return 0;
}
-61
View File
@@ -1,61 +0,0 @@
/*examplePvaClientMonitor.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 <epicsThread.h>
#include <iostream>
#include <pv/pvaClient.h>
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static void exampleMonitor(PvaClientPtr const &pva,string provider)
{
PvaClientMonitorPtr monitor = pva->channel("double00",provider,2.0)->monitor("");
PvaClientMonitorDataPtr monitorData = monitor->getData();
PvaClientPutPtr put = pva->channel("double00",provider,2.0)->put("");
PvaClientPutDataPtr putData = put->getData();
for(size_t ntimes=0; ntimes<5; ++ntimes)
{
double value = ntimes;
cout << "put " << value << endl;
putData->putDouble(value); put->put();
if(!monitor->waitEvent(.1)) {
cout << "waitEvent returned false. Why???";
continue;
} else while(true) {
cout << "monitor " << monitorData->getDouble() << endl;
cout << "changed\n";
monitorData->showChanged(cout);
cout << "overrun\n";
monitorData->showOverrun(cout);
monitor->releaseEvent();
if(!monitor->poll()) break;
}
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
cout << "exampleMonitor pva\n";
exampleMonitor(pva,"pva");
cout << "exampleMonitor ca\n";
exampleMonitor(pva,"ca");
cout << "done\n";
return 0;
}
@@ -1,79 +0,0 @@
/*examplePvaClientMultiDouble.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/pvaClientMultiChannel.h>
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static void example(
PvaClientPtr const &pva,
string provider,
shared_vector<const string> const &channelNames)
{
size_t num = channelNames.size();
cout << "num " << num << " names " << channelNames << endl;
PvaClientMultiChannelPtr multiChannel(
PvaClientMultiChannel::create(pva,channelNames,provider));
PvaClientMultiGetDoublePtr multiGet(multiChannel->createGet());
PvaClientMultiPutDoublePtr multiPut(multiChannel->createPut());
PvaClientMultiMonitorDoublePtr multiMonitor(multiChannel->createMonitor());
shared_vector<double> data(num,0);
for(double value = 0.2; value< 2.3; value+= 1.0) {
try {
for(size_t i=0; i<num; ++i) data[i] = value + i;
cout << "put " << data << endl;
multiPut->put(data);
data = multiGet->get();
cout << "get " << data << endl;
bool result = multiMonitor->waitEvent(.1);
while(result) {
cout << "monitor data " << multiMonitor->get() << endl;
result = multiMonitor->poll();
}
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
size_t num = 5;
shared_vector<string> channelNames(num);
channelNames[0] = "double01";
channelNames[1] = "int01";
channelNames[2] = "double03";
channelNames[3] = "double04";
channelNames[4] = "double05";
cout << "double pva\n";
shared_vector<const string> names(freeze(channelNames));
example(pva,"pva",names);
cout << "double ca\n";
example(pva,"ca",names);
channelNames = shared_vector<string>(num);
channelNames[0] = "exampleDouble01";
channelNames[1] = "exampleInt";
channelNames[2] = "exampleDouble03";
channelNames[3] = "exampleDouble04";
channelNames[4] = "exampleDouble05";
names = freeze(channelNames);
cout << "exampleDouble pva\n";
example(pva,"pva",names);
return 0;
}
-141
View File
@@ -1,141 +0,0 @@
/*examplePvaClientNTMulti.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/pvaClientMultiChannel.h>
#include <pv/convert.h>
using std::tr1::static_pointer_cast;
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static ConvertPtr convert = getConvert();
static void setValue(PVUnionPtr const &pvUnion, double value)
{
UnionConstPtr u = pvUnion->getUnion();
FieldConstPtr field = u->getField(0);
Type type = field->getType();
if(type==scalar) {
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
ScalarType scalarType = scalar->getScalarType();
if(scalarType==pvDouble) {
PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
pvDataCreate->createPVScalar(pvDouble));
pvValue->put(value);
pvUnion->set(0,pvValue);
return;
}
if(scalarType==pvString) {
PVStringPtr pvValue = static_pointer_cast<PVString>(
pvDataCreate->createPVScalar(pvString));
stringstream ss;
ss << "value" << value;
pvValue->put(ss.str());
pvUnion->set(0,pvValue);
return;
}
throw std::runtime_error("only pvDouble and pvString are supported");
}
if(type==scalarArray) {
ScalarArrayConstPtr scalarArray = static_pointer_cast<const ScalarArray>(field);
ScalarType scalarType = scalarArray->getElementType();
if(scalarType==pvDouble) {
size_t num = 5;
PVDoubleArrayPtr pvValue = static_pointer_cast<PVDoubleArray>(
pvDataCreate->createPVScalarArray(pvDouble));
shared_vector<double> data(num);
for(size_t i=0; i<num; ++i) data[i] = value +i;
pvValue->replace(freeze(data));
pvUnion->set(0,pvValue);
return;
}
if(scalarType==pvString) {
size_t num = 5;
PVStringArrayPtr pvValue = static_pointer_cast<PVStringArray>(
pvDataCreate->createPVScalarArray(pvString));
shared_vector<string> data(num);
for(size_t i=0; i<num; ++i) {
stringstream ss;
ss << "value" << value << i;
data[i] = ss.str();
}
pvValue->replace(freeze(data));
pvUnion->set(0,pvValue);
return;
}
throw std::runtime_error("only pvDouble and pvString are supported");
}
throw std::runtime_error("only scalar and scalarArray fields are supported");
}
static void example(
PvaClientPtr const &pva,
string provider,
shared_vector<const string> const &channelNames)
{
size_t num = channelNames.size();
PvaClientMultiChannelPtr multiChannel(
PvaClientMultiChannel::create(pva,channelNames,provider));
PvaClientNTMultiGetPtr multiGet(multiChannel->createNTGet());
PvaClientNTMultiPutPtr multiPut(multiChannel->createNTPut());
PvaClientNTMultiMonitorPtr multiMonitor(multiChannel->createNTMonitor());
shared_vector<epics::pvData::PVUnionPtr> data = multiPut->getValues();
for(double value = 0.0; value< 2.1; value+= 1.0) {
for(size_t i=0; i<num ; ++i) {
PVUnionPtr pvUnion = data[i];
setValue(pvUnion,value);
}
multiPut->put();
multiGet->get();
PvaClientNTMultiDataPtr multiData = multiGet->getData();
PVStructurePtr pvStructure = multiData->getNTMultiChannel()->getPVStructure();
cout << "pvStructure\n" << pvStructure << endl;
bool result = multiMonitor->waitEvent(.1);
while(result) {
multiData = multiMonitor->getData();
pvStructure = multiData->getNTMultiChannel()->getPVStructure();
cout << "monitor pvStructure\n" << pvStructure << endl;
result = multiMonitor->poll();
}
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
size_t num = 4;
shared_vector<string> channelNames(num);
channelNames[0] = "double01";
channelNames[1] = "string01";
channelNames[2] = "doubleArray01";
channelNames[3] = "stringArray01";
cout << "dbRecord pva\n";
shared_vector<const string> names(freeze(channelNames));
example(pva,"pva",names);
cout << "dbRecord ca\n";
example(pva,"ca",names);
channelNames = shared_vector<string>(num);
channelNames[0] = "exampleDouble";
channelNames[1] = "exampleString";
channelNames[2] = "exampleDoubleArray";
channelNames[3] = "exampleStringArray";
names = freeze(channelNames);
cout << "pvRecord pva\n";
example(pva,"pva",names);
return 0;
}
-44
View File
@@ -1,44 +0,0 @@
/*examplePvaClientProcess.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/pvaClient.h>
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static void exampleProcess(PvaClientPtr const &pva)
{
cout << "example process\n";
PvaClientChannelPtr channel = pva->channel("exampleDouble");
PvaClientProcessPtr process = channel->createProcess();
try {
process->process();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
process->process();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
exampleProcess(pva);
return 0;
}
-77
View File
@@ -1,77 +0,0 @@
/*examplePvaClientPut.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/pvaClient.h>
#include <pv/convert.h>
using std::tr1::static_pointer_cast;
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static ConvertPtr convert = getConvert();
static void examplePut(PvaClientPtr const &pva)
{
cout << "example put\n";
PvaClientChannelPtr channel = pva->channel("exampleDouble");
PvaClientPutPtr put = channel->put();
PvaClientPutDataPtr putData = put->getData();
PvaClientMonitorPtr monitor = pva->channel("exampleDouble")->monitor("");
PvaClientMonitorDataPtr monitorData = monitor->getData();
try {
putData->putDouble(3.0); put->put();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
putData->putDouble(4.0); put->put();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
if(!monitor->waitEvent()) {
cout << "waitEvent returned false. Why???";
} else while(true) {
cout << "monitor changed\n" << monitorData->showChanged(cout);
monitor->releaseEvent();
if(!monitor->poll()) break;
}
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
static void examplePVFieldPut(PvaClientPtr const &pva)
{
cout << "example put\n";
PvaClientChannelPtr channel = pva->channel("exampleDouble");
PvaClientPutPtr put = channel->put();
PvaClientPutDataPtr putData = put->getData();
PVFieldPtr pvField = putData->getValue();
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
try {
convert->fromDouble(pvScalar,1.0); put->put();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
convert->fromDouble(pvScalar,2.0); put->put();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
examplePut(pva);
examplePVFieldPut(pva);
return 0;
}
-48
View File
@@ -1,48 +0,0 @@
/*helloWorldPutGet.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/pvaClient.h>
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static void example(PvaClientPtr const &pva)
{
cout << "helloWorldPutGet\n";
try {
PvaClientChannelPtr channel = pva->channel("exampleHello");
PvaClientPutGetPtr putGet = channel->createPutGet();
putGet->connect();
PvaClientPutDataPtr putData = putGet->getPutData();
PVStructurePtr arg = putData->getPVStructure();
PVStringPtr pvValue = arg->getSubField<PVString>("argument.value");
pvValue->put("World");
putGet->putGet();
PvaClientGetDataPtr getData = putGet->getGetData();
cout << getData->getPVStructure() << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
example(pva);
return 0;
}
-77
View File
@@ -1,77 +0,0 @@
/*helloWorldRPC.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/pvData.h>
#include <pv/pvAccess.h>
#include <pv/rpcClient.h>
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static void exampleSimple()
{
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
add("value",pvString)->
createStructure();
PVStructurePtr pvRequest = pvDataCreate->createPVStructure(topStructure);
PVStringPtr pvArgument = pvRequest->getSubField<PVString>("value");
pvArgument->put("World");
cout << "example channeRPC simple\n";
try {
PVStructurePtr pvResult =
RPCClient::sendRequest("exampleHelloRPC", pvRequest);
cout << "result\n" << pvResult << endl;
} catch (RPCRequestException &e) {
cout << e.what() << endl;
}
}
void exampleMore()
{
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
add("value",pvString)->
createStructure();
PVStructurePtr pvRequest = pvDataCreate->createPVStructure(topStructure);
PVStringPtr pvArgument = pvRequest->getSubField<PVString>("value");
pvArgument->put("World");
cout << "example channeRPC more\n";
try {
RPCClient::shared_pointer client = RPCClient::create("exampleHelloRPC");
client->issueConnect();
if (client->waitConnect())
{
client->issueRequest(pvRequest);
PVStructure::shared_pointer result = client->waitResponse();
std::cout << *result << std::endl;
}
else {
cout << "waitConnect timeout\n";
return;
}
} catch (RPCRequestException &e) {
cout << e.what() << endl;
}
}
int main(int argc,char *argv[])
{
exampleSimple();
exampleMore();
return 0;
}
+32 -23
View File
@@ -6,22 +6,37 @@
# #
# Author: Ralph Lange <ralph.lange@gmx.de> # Author: Ralph Lange <ralph.lange@gmx.de>
# Copyright (C) 2013 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH # Copyright (C) 2013 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
# Copyright (C) 2014-2015 ITER Organization. # Copyright (C) 2014-2016 ITER Organization.
# All rights reserved. Use is subject to license terms. # All rights reserved. Use is subject to license terms.
installTool () {
local module=$1
local version=$2
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
}
installE4 () {
local module=$1
local branch=$2
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
tar -xzf ${module}.CB-dist.tar.gz
}
########################################### ###########################################
# Determine EPICS Base version # Defaults for EPICS Base
DEFAULT_BASE=3.14.12.5 DEFAULT_BASE=3.15.4
BASE=${BASE:-${DEFAULT_BASE}}
BASE=${1:-${DEFAULT_BASE}} ###########################################
USE_MB=${2:-"MB_NO"} # Dependent module branches
# Dependent module branches (empty = master) PVDATA_BRANCH="master"
PVCOMMON_BRANCH="Release-4.1-" PVACCESS_BRANCH="master"
PVDATA_BRANCH="Release-5.0-" NORMATIVETYPES_BRANCH="master"
PVACCESS_BRANCH="Release-4.1-"
NORMATIVETYPES_BRANCH="Release-5.0-"
########################################### ###########################################
# Fetch and unpack dependencies # Fetch and unpack dependencies
@@ -32,19 +47,12 @@ rm -fr ${STUFF}
mkdir -p ${STUFF} mkdir -p ${STUFF}
cd ${STUFF} cd ${STUFF}
wget -nv https://openepics.ci.cloudbees.com/job/Base-${BASE}_Build/lastSuccessfulBuild/artifact/base-${BASE}.CB-dist.tar.gz installTool Boost 1.61.0
wget -nv https://openepics.ci.cloudbees.com/job/pvDataCPP_${PVDATA_BRANCH}Build/BASE=${BASE},USE_MB=MB_NO/lastSuccessfulBuild/artifact/pvData.CB-dist.tar.gz installTool Base ${BASE}
wget -nv https://openepics.ci.cloudbees.com/job/pvAccessCPP_${PVACCESS_BRANCH}Build/BASE=${BASE},USE_MB=${USE_MB}/lastSuccessfulBuild/artifact/pvAccess.CB-dist.tar.gz
wget -nv https://openepics.ci.cloudbees.com/job/normativeTypesCPP_${NORMATIVETYPES_BRANCH}Build/BASE=${BASE},USE_MB=MB_NO/lastSuccessfulBuild/artifact/normativeTypes.CB-dist.tar.gz
tar -xzf base-${BASE}.CB-dist.tar.gz
tar -xzf pvData.CB-dist.tar.gz
tar -xzf pvAccess.CB-dist.tar.gz
tar -xzf normativeTypes.CB-dist.tar.gz
if [ "${USE_MB}" = "MB_YES" ]; then installE4 pvData ${PVDATA_BRANCH}
wget -nv https://openepics.ci.cloudbees.com/job/pvCommonCPP_${PVCOMMON_BRANCH}Build/BASE=${BASE},USE_MB=MB_YES/lastSuccessfulBuild/artifact/pvCommon.CB-dist.tar.gz installE4 pvAccess ${PVACCESS_BRANCH}
tar -xzf pvCommon.CB-dist.tar.gz installE4 normativeTypes ${NORMATIVETYPES_BRANCH}
fi
########################################### ###########################################
# Build # Build
@@ -65,7 +73,8 @@ make distclean all
########################################### ###########################################
# Test # Test
make runtests # no regression tests
#make runtests
########################################### ###########################################
# Create distribution # Create distribution
+26 -11
View File
@@ -6,14 +6,32 @@
# #
# Author: Ralph Lange <ralph.lange@gmx.de> # Author: Ralph Lange <ralph.lange@gmx.de>
# Copyright (C) 2013 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH # Copyright (C) 2013 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
# Copyright (C) 2014-2015 ITER Organization. # Copyright (C) 2014-2016 ITER Organization.
# All rights reserved. Use is subject to license terms. # All rights reserved. Use is subject to license terms.
########################################### installTool () {
# Set EPICS Base version and upload target local module=$1
local version=$2
BASE=3.15.2 wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
PUBLISH=${1:-DONT} tar -xzf ${module,,}-${version}.CB-dist.tar.gz
}
installE4 () {
local module=$1
local branch=$2
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
tar -xzf ${module}.CB-dist.tar.gz
}
###########################################
# Defaults for EPICS Base and parameters
BASE=3.15.4
PUBLISH=${PUBLISH:-NO}
BRANCH=${BRANCH:-master}
MB=NO_MICROBENCH
########################################### ###########################################
# Fetch and unpack dependencies # Fetch and unpack dependencies
@@ -24,16 +42,14 @@ rm -fr ${STUFF}
mkdir -p ${STUFF} mkdir -p ${STUFF}
cd ${STUFF} cd ${STUFF}
wget -nv https://openepics.ci.cloudbees.com/job/Doxygen-1.8.3_Build/lastSuccessfulBuild/artifact/doxygen-1.8.3.CB-dist.tar.gz installTool Doxygen 1.8.11
tar -xzf doxygen-1.8.3.CB-dist.tar.gz
########################################### ###########################################
# Generate # Generate
cd ${WORKSPACE} cd ${WORKSPACE}
wget -nv https://openepics.ci.cloudbees.com/job/pvaClientCPP_Build/BASE=${BASE},USE_MB=MB_NO/lastSuccessfulBuild/artifact/pvaClient.CB-dist.tar.gz installE4 pvaClient ${BRANCH}
tar -xzf pvaClient.CB-dist.tar.gz
export PATH=${STUFF}/bin:${PATH} export PATH=${STUFF}/bin:${PATH}
@@ -45,7 +61,6 @@ doxygen
if [ "${PUBLISH}" != "DONT" ]; then if [ "${PUBLISH}" != "DONT" ]; then
# Upload explicit dummy to ensure target directory exists # Upload explicit dummy to ensure target directory exists
echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY
rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvaClientCPP/${PUBLISH}/ rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvaClientCPP/${PUBLISH}/DUMMY
rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvaClientCPP/${PUBLISH}/ rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvaClientCPP/${PUBLISH}/
fi fi
+10 -5
View File
@@ -5,10 +5,14 @@ include $(TOP)/configure/CONFIG
LIBRARY += pvaClient LIBRARY += pvaClient
INC += pvaClient.h # shared library ABI version.
INC += pvaClientMultiChannel.h SHRLIB_VERSION ?= $(EPICS_PVACLIENT_MAJOR_VERSION).$(EPICS_PVACLIENT_MINOR_VERSION).$(EPICS_PVACLIENT_MAINTENANCE_VERSION)
INC += pv/pvaClient.h
INC += pv/pvaClientMultiChannel.h
LIBSRCS += pvaClient.cpp LIBSRCS += pvaClient.cpp
LIBSRCS += pvaClientData.cpp
LIBSRCS += pvaClientPutData.cpp LIBSRCS += pvaClientPutData.cpp
LIBSRCS += pvaClientGetData.cpp LIBSRCS += pvaClientGetData.cpp
LIBSRCS += pvaClientMonitorData.cpp LIBSRCS += pvaClientMonitorData.cpp
@@ -26,9 +30,10 @@ LIBSRCS += pvaClientNTMultiPut.cpp
LIBSRCS += pvaClientNTMultiData.cpp LIBSRCS += pvaClientNTMultiData.cpp
LIBSRCS += pvaClientNTMultiGet.cpp LIBSRCS += pvaClientNTMultiGet.cpp
LIBSRCS += pvaClientNTMultiMonitor.cpp LIBSRCS += pvaClientNTMultiMonitor.cpp
LIBSRCS += pvaClientRPC.cpp
pvaClient_LIBS += pvAccess pvData nt Com pvaClient_LIBS += nt
pvaClient_LIBS += $(EPICS_BASE_IOC_LIBS) pvaClient_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
pvaClient_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES include $(TOP)/configure/RULES
+1805
View File
File diff suppressed because it is too large Load Diff
@@ -12,16 +12,23 @@
#define PVACLIENTMULTICHANNEL_H #define PVACLIENTMULTICHANNEL_H
#ifdef epicsExportSharedSymbols #ifdef epicsExportSharedSymbols
# define pvaClientEpicsExportSharedSymbols # define pvaClientMultiChannelEpicsExportSharedSymbols
# undef epicsExportSharedSymbols # undef epicsExportSharedSymbols
#endif #endif
#include <pv/pvaClient.h>
#include <pv/ntmultiChannel.h> #include <pv/ntmultiChannel.h>
#include <pv/createRequest.h> #include <pv/createRequest.h>
#ifdef pvaClientMultiChannelEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef pvaClientMultiChannelEpicsExportSharedSymbols
#endif
namespace epics { namespace pvaClient {
#include <pv/pvaClient.h>
namespace epics { namespace pvaClient {
class PvaClientMultiChannel; class PvaClientMultiChannel;
@@ -55,135 +62,122 @@ class epicsShareClass PvaClientMultiChannel :
{ {
public: public:
POINTER_DEFINITIONS(PvaClientMultiChannel); POINTER_DEFINITIONS(PvaClientMultiChannel);
/** Create a PvaClientMultiChannel. /** @brief Create a PvaClientMultiChannel.
* @param pvaClient The interface to pvaClient. * @param pvaClient The interface to pvaClient.
* @param channelNames The names of the channel.. * @param channelNames The names of the channel..
* @param providerName The name of the provider. * @param providerName The name of the provider.
* This is also used for the provider for all channels
* with providerNames.size less than channelNames.size()
* @param maxNotConnected The maximum number of channels that can be disconnected. * @param maxNotConnected The maximum number of channels that can be disconnected.
* @param providerNames The providerName for each Channells
* @return The interface to the PvaClientMultiChannel * @return The interface to the PvaClientMultiChannel
*/ */
static PvaClientMultiChannelPtr create( static PvaClientMultiChannelPtr create(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
epics::pvData::shared_vector<const std::string> const & channelNames, epics::pvData::shared_vector<const std::string> const & channelNames,
std::string const & providerName = "pva", std::string const & providerName = "pva",
size_t maxNotConnected=0 size_t maxNotConnected=0,
epics::pvData::shared_vector<const std::string> const & providerNames
= epics::pvData::shared_vector<const std::string>()
); );
/** /**
* Destructor * @brief Destructor
*/ */
~PvaClientMultiChannel(); ~PvaClientMultiChannel();
/** Destroy the pvAccess connections. /** @brief Get the channelNames.
*/
void destroy();
/** Get the channelNames.
* @return The names. * @return The names.
*/ */
epics::pvData::shared_vector<const std::string> getChannelNames(); epics::pvData::shared_vector<const std::string> getChannelNames();
/** Connect to the channels. /** @brief Connect to the channels.
*
* This calls issueConnect and waitConnect. * This calls issueConnect and waitConnect.
* An exception is thrown if connect fails. * An exception is thrown if connect fails.
* @param timeout The time to wait for connecting to the channel. * @param timeout The time to wait for connecting to the channel.
* @return status of request * @return status of request
*/ */
epics::pvData::Status connect(double timeout=5); epics::pvData::Status connect(double timeout=5);
/** Are all channels connected? /** @brief Are all channels connected?
* @return if all are connected. * @return if all are connected.
*/ */
bool allConnected(); bool allConnected();
/** Has a connection state change occured? /** @brief Has a connection state change occured?
* @return (true, false) if (at least one, no) channel has changed state. * @return (true, false) if (at least one, no) channel has changed state.
*/ */
bool connectionChange(); bool connectionChange();
/** Get the connection state of each channel. /** @brief Get the connection state of each channel.
* @return The state of each channel. * @return The state of each channel.
*/ */
epics::pvData::shared_vector<epics::pvData::boolean> getIsConnected(); epics::pvData::shared_vector<epics::pvData::boolean> getIsConnected();
/** Get the pvaClientChannelArray. /** @brief Get the pvaClientChannelArray.
* @return The shared pointer. * @return The shared pointer.
*/ */
PvaClientChannelArray getPvaClientChannelArray(); PvaClientChannelArray getPvaClientChannelArray();
/** Get pvaClient. /** @brief Get pvaClient.
* @return The shared pointer. * @return The shared pointer.
*/ */
PvaClientPtr getPvaClient(); PvaClientPtr getPvaClient();
/** /**
* create a pvaClientMultiGetDouble * @brief create a pvaClientMultiGetDouble
* @return The interface. * @return The interface.
*/ */
PvaClientMultiGetDoublePtr createGet(); PvaClientMultiGetDoublePtr createGet();
/** /**
* create a pvaClientMultiPutDouble * @brief Create a pvaClientMultiPutDouble.
* @return The interface. * @return The interface.
*/ */
PvaClientMultiPutDoublePtr createPut(); PvaClientMultiPutDoublePtr createPut();
/** /**
* Create a pvaClientMultiMonitorDouble. * @brief Create a pvaClientMultiMonitorDouble.
* @return The interface. * @return The interface.
*/ */
PvaClientMultiMonitorDoublePtr createMonitor(); PvaClientMultiMonitorDoublePtr createMonitor();
/** /**
* Create a pvaClientNTMultiPut. * @brief Create a pvaClientNTMultiPut.
* @return The interface. * @return The interface.
*/ */
PvaClientNTMultiPutPtr createNTPut(); PvaClientNTMultiPutPtr createNTPut();
/** /**
* Create a pvaClientNTMultiGet. * @brief Create a pvaClientNTMultiGet;
* This calls the next method with request = "value,alarm,timeStamp"
* @return The interface.
*/
PvaClientNTMultiGetPtr createNTGet();
/**
* Create a pvaClientNTMultiGet;
* @param request The request for each channel. * @param request The request for each channel.
* @return The interface. * @return The interface.
*/ */
PvaClientNTMultiGetPtr createNTGet(std::string const &request); PvaClientNTMultiGetPtr createNTGet(
std::string const &request = "field(value,alarm,timeStamp)");
/** /**
* Create a pvaClientNTMultiMonitor. * @brief Create a pvaClientNTMultiPut.
* This calls the next method with request = "value,alarm,timeStamp"
* @return The interface.
*/
PvaClientNTMultiMonitorPtr createNTMonitor();
/**
* Create a pvaClientNTMultiPut.
* @param request The request for each channel. * @param request The request for each channel.
* @return The interface. * @return The interface.
*/ */
PvaClientNTMultiMonitorPtr createNTMonitor(std::string const &request); PvaClientNTMultiMonitorPtr createNTMonitor(
/** Get the shared pointer to self. std::string const &request= "field(value,alarm,timeStamp)");
* @return The shared pointer.
*/
PvaClientMultiChannelPtr getPtrSelf()
{
return shared_from_this();
}
private: private:
PvaClientMultiChannel( PvaClientMultiChannel(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
epics::pvData::shared_vector<const std::string> const & channelName, epics::pvData::shared_vector<const std::string> const & channelNames,
std::string const & providerName, std::string const & providerName,
size_t maxNotConnected); size_t maxNotConnected,
epics::pvData::shared_vector<const std::string> const & providerNames);
void checkConnected(); void checkConnected();
PvaClientPtr pvaClient; PvaClientPtr pvaClient;
epics::pvData::shared_vector<const std::string> channelName; epics::pvData::shared_vector<const std::string> channelNames;
std::string providerName; std::string providerName;
size_t maxNotConnected; size_t maxNotConnected;
epics::pvData::shared_vector<const std::string> const & providerNames;
size_t numChannel; size_t numChannel;
size_t numProviderNames;
epics::pvData::Mutex mutex; epics::pvData::Mutex mutex;
size_t numConnected; size_t numConnected;
bool firstConnect;
PvaClientChannelArray pvaClientChannelArray; PvaClientChannelArray pvaClientChannelArray;
epics::pvData::shared_vector<epics::pvData::boolean> isConnected; epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
epics::pvData::CreateRequest::shared_pointer createRequest; epics::pvData::CreateRequest::shared_pointer createRequest;
bool isDestroyed;
}; };
/** /**
* This provides channelGet to multiple channels where each channel has a numeric scalar value field. * @brief Provides channelGet to multiple channels where each channel has a numeric scalar value field.
*/ */
class epicsShareClass PvaClientMultiGetDouble : class epicsShareClass PvaClientMultiGetDouble :
public std::tr1::enable_shared_from_this<PvaClientMultiGetDouble> public std::tr1::enable_shared_from_this<PvaClientMultiGetDouble>
@@ -191,38 +185,25 @@ class epicsShareClass PvaClientMultiGetDouble :
public: public:
POINTER_DEFINITIONS(PvaClientMultiGetDouble); POINTER_DEFINITIONS(PvaClientMultiGetDouble);
protected:
/**
* Factory method that creates a PvaClientMultiGetDouble.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
static PvaClientMultiGetDoublePtr create( static PvaClientMultiGetDoublePtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray); PvaClientChannelArray const &pvaClientChannelArray);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~PvaClientMultiGetDouble(); ~PvaClientMultiGetDouble();
/** Destroy the pvAccess connection.
*/
void destroy();
/** /**
* Create a channelGet for each channel. * @brief Create a channelGet for each channel.
*/ */
void connect(); void connect();
/** /**
* get the data. * @brief Get the data.
* @return The double[] where each element is the value field of the corresponding channel. * @return The double[] where each element is the value field of the corresponding channel.
*/ */
epics::pvData::shared_vector<double> get(); epics::pvData::shared_vector<double> get();
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientMultiGetDoublePtr getPtrSelf()
{
return shared_from_this();
}
private: private:
PvaClientMultiGetDouble( PvaClientMultiGetDouble(
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -232,15 +213,14 @@ private:
PvaClientChannelArray pvaClientChannelArray; PvaClientChannelArray pvaClientChannelArray;
size_t nchannel; size_t nchannel;
epics::pvData::Mutex mutex; epics::pvData::Mutex mutex;
epics::pvData::shared_vector<double> doubleValue; epics::pvData::shared_vector<double> doubleValue;
std::vector<PvaClientGetPtr> pvaClientGet; std::vector<PvaClientGetPtr> pvaClientGet;
bool isGetConnected; bool isGetConnected;
bool isDestroyed;
}; };
/** /**
* This provides channelPut to multiple channels where each channel has a numeric scalar value field. * @brief Provides channelPut to multiple channels where each channel has a numeric scalar value field.
*/ */
class epicsShareClass PvaClientMultiPutDouble : class epicsShareClass PvaClientMultiPutDouble :
public std::tr1::enable_shared_from_this<PvaClientMultiPutDouble> public std::tr1::enable_shared_from_this<PvaClientMultiPutDouble>
@@ -248,36 +228,25 @@ class epicsShareClass PvaClientMultiPutDouble :
public: public:
POINTER_DEFINITIONS(PvaClientMultiPutDouble); POINTER_DEFINITIONS(PvaClientMultiPutDouble);
protected:
/**
* Factory method that creates a PvaClientMultiPutDouble.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
static PvaClientMultiPutDoublePtr create( static PvaClientMultiPutDoublePtr create(
PvaClientMultiChannelPtr const &pvaMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray); PvaClientChannelArray const &pvaClientChannelArray);
~PvaClientMultiPutDouble(); friend class PvaClientMultiChannel;
public:
/** Destroy the pvAccess connection. /**
* @brief Destructor
*/ */
void destroy(); ~PvaClientMultiPutDouble();
/** /**
* Create a channelPut for each channel. * @brief Create a channelPut for each channel.
*/ */
void connect(); void connect();
/** put data to each channel as a double /** @brief put data to each channel as a double
* @param data The array of data for each channel. * @param data The array of data for each channel.
*/ */
void put(epics::pvData::shared_vector<double> const &data); void put(epics::pvData::shared_vector<double> const &data);
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientMultiPutDoublePtr getPtrSelf()
{
return shared_from_this();
}
private: private:
PvaClientMultiPutDouble( PvaClientMultiPutDouble(
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -290,11 +259,10 @@ private:
std::vector<PvaClientPutPtr> pvaClientPut; std::vector<PvaClientPutPtr> pvaClientPut;
bool isPutConnected; bool isPutConnected;
bool isDestroyed;
}; };
/** /**
* This provides a monitor to multiple channels where each channel has a numeric scalar value field. * @brief Provides a monitor to multiple channels where each channel has a numeric scalar value field.
*/ */
class epicsShareClass PvaClientMultiMonitorDouble : class epicsShareClass PvaClientMultiMonitorDouble :
public std::tr1::enable_shared_from_this<PvaClientMultiMonitorDouble> public std::tr1::enable_shared_from_this<PvaClientMultiMonitorDouble>
@@ -302,50 +270,40 @@ class epicsShareClass PvaClientMultiMonitorDouble :
public: public:
POINTER_DEFINITIONS(PvaClientMultiMonitorDouble); POINTER_DEFINITIONS(PvaClientMultiMonitorDouble);
protected:
/**
* Factory method that creates a PvaClientMultiMonitorDouble.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
static PvaClientMultiMonitorDoublePtr create( static PvaClientMultiMonitorDoublePtr create(
PvaClientMultiChannelPtr const &pvaMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray); PvaClientChannelArray const &pvaClientChannelArray);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~PvaClientMultiMonitorDouble(); ~PvaClientMultiMonitorDouble();
/** Destroy the pvAccess connection.
*/
void destroy();
/** /**
* Create a channel monitor for each channel. * @brief Connect a channel monitor for each channel.
*/ */
void connect(); void connect();
/** /**
* poll each channel. * @brief Poll each channel.
*
* If any has new data it is used to update the double[]. * If any has new data it is used to update the double[].
* @return (false,true) if (no, at least one) value was updated. * @return (false,true) if (no, at least one) value was updated.
*/ */
bool poll(); bool poll();
/** /**
* Wait until poll returns true. * @brief Wait until poll returns true.
* @param waitForEvent The time to keep trying. * @param secondsToWait The time to keep trying.
* A thread sleep of .1 seconds occurs between each call to poll. * A thread sleep of .1 seconds occurs between each call to poll.
* @return (false,true) if (timeOut, poll returned true). * @return (false,true) if (timeOut, poll returned true).
*/ */
bool waitEvent(double waitForEvent); bool waitEvent(double secondsToWait);
/** /**
* get the data. * get the data.
* @return The double[] where each element is the value field of the corresponding channel. * @return The double[] where each element is the value field of the corresponding channel.
*/ */
epics::pvData::shared_vector<double> get(); epics::pvData::shared_vector<double> get();
/** Monitor the shared pointer to self.
* @return The shared pointer.
*/
PvaClientMultiMonitorDoublePtr getPtrSelf()
{
return shared_from_this();
}
private: private:
PvaClientMultiMonitorDouble( PvaClientMultiMonitorDouble(
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -359,11 +317,10 @@ private:
epics::pvData::shared_vector<double> doubleValue; epics::pvData::shared_vector<double> doubleValue;
std::vector<PvaClientMonitorPtr> pvaClientMonitor; std::vector<PvaClientMonitorPtr> pvaClientMonitor;
bool isMonitorConnected; bool isMonitorConnected;
bool isDestroyed;
}; };
/** /**
* This provides channelGet to multiple channels where the value field of each channel is presented as a union. * @brief Provides channelGet to multiple channels where the value field of each channel is presented as a union.
*/ */
class epicsShareClass PvaClientNTMultiGet : class epicsShareClass PvaClientNTMultiGet :
public std::tr1::enable_shared_from_this<PvaClientNTMultiGet> public std::tr1::enable_shared_from_this<PvaClientNTMultiGet>
@@ -371,43 +328,33 @@ class epicsShareClass PvaClientNTMultiGet :
public: public:
POINTER_DEFINITIONS(PvaClientNTMultiGet); POINTER_DEFINITIONS(PvaClientNTMultiGet);
/** protected:
* Factory method that creates a PvaClientNTMultiGet.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @param pvRequest The pvRequest for each channel.
* @return The interface.
*/
static PvaClientNTMultiGetPtr create( static PvaClientNTMultiGetPtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest); epics::pvData::PVStructurePtr const & pvRequest);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~PvaClientNTMultiGet(); ~PvaClientNTMultiGet();
/** Destroy the pvAccess connection.
*/
void destroy();
/** /**
* Create a channelGet for each channel. * @brief Connect a channelGet for each channel.
*/ */
void connect(); void connect();
/** /**
* get data for each channel. * @brief Get each channel.
*
* @param valueOnly use only value for union.
*/ */
void get(); void get(bool valueOnly = true);
/** /**
* get the data. * @brief Get the data from the last get.
* @return the pvaClientNTMultiData. * @return the pvaClientNTMultiData.
*/ */
PvaClientNTMultiDataPtr getData(); PvaClientNTMultiDataPtr getData();
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiGetPtr getPtrSelf()
{
return shared_from_this();
}
private: private:
PvaClientNTMultiGet( PvaClientNTMultiGet(
epics::pvData::UnionConstPtr const & u, epics::pvData::UnionConstPtr const & u,
@@ -420,16 +367,14 @@ private:
epics::pvData::PVStructurePtr pvRequest; epics::pvData::PVStructurePtr pvRequest;
size_t nchannel; size_t nchannel;
epics::pvData::Mutex mutex; epics::pvData::Mutex mutex;
PvaClientNTMultiDataPtr pvaClientNTMultiData; PvaClientNTMultiDataPtr pvaClientNTMultiData;
std::vector<PvaClientGetPtr> pvaClientGet; std::vector<PvaClientGetPtr> pvaClientGet;
bool isConnected; bool isConnected;
bool isDestroyed;
}; };
/** /**
* This provides channelPut to multiple channels where the value field of each channel is presented as a union. * @brief Provides channelPut to multiple channels where the value field of each channel is presented as a union.
*/ */
class epicsShareClass PvaClientNTMultiPut : class epicsShareClass PvaClientNTMultiPut :
public std::tr1::enable_shared_from_this<PvaClientNTMultiPut> public std::tr1::enable_shared_from_this<PvaClientNTMultiPut>
@@ -437,40 +382,30 @@ class epicsShareClass PvaClientNTMultiPut :
public: public:
POINTER_DEFINITIONS(PvaClientNTMultiPut); POINTER_DEFINITIONS(PvaClientNTMultiPut);
/** protected:
* Factory method that creates a PvaClientNTMultiPut.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
static PvaClientNTMultiPutPtr create( static PvaClientNTMultiPutPtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray); PvaClientChannelArray const &pvaClientChannelArray);
~PvaClientNTMultiPut(); friend class PvaClientMultiChannel;
public:
/** Destroy the pvAccess connection. /**
* @brief Destructor
*/ */
void destroy(); ~PvaClientNTMultiPut();
/** /**
* Create a channelPut for each channel. * @brief Connect a channelPut for each channel.
*/ */
void connect(); void connect();
/** /**
* get the value field of each channel as a union. * @brief Get the value field of each channel as a union.
* @return A shared vector of union. * @return A shared vector of union.
*/ */
epics::pvData::shared_vector<epics::pvData::PVUnionPtr> getValues(); epics::pvData::shared_vector<epics::pvData::PVUnionPtr> getValues();
/** /**
* put the data to each channel. * @brief Issue a put for each channel.
' */
void put();
/** Get the shared pointer to self.
* @return The shared pointer.
*/ */
PvaClientNTMultiPutPtr getPtrSelf() void put();
{
return shared_from_this();
}
private: private:
PvaClientNTMultiPut( PvaClientNTMultiPut(
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -485,11 +420,10 @@ private:
epics::pvData::shared_vector<epics::pvData::PVFieldPtr> value; epics::pvData::shared_vector<epics::pvData::PVFieldPtr> value;
std::vector<PvaClientPutPtr> pvaClientPut; std::vector<PvaClientPutPtr> pvaClientPut;
bool isConnected; bool isConnected;
bool isDestroyed;
}; };
/** /**
* This provides channel monitor to multiple channels where the value field of each channel is presented as a union. * @brief Provides channel monitor to multiple channels where the value field of each channel is presented as a union.
*/ */
class epicsShareClass PvaClientNTMultiMonitor : class epicsShareClass PvaClientNTMultiMonitor :
public std::tr1::enable_shared_from_this<PvaClientNTMultiMonitor> public std::tr1::enable_shared_from_this<PvaClientNTMultiMonitor>
@@ -497,51 +431,42 @@ class epicsShareClass PvaClientNTMultiMonitor :
public: public:
POINTER_DEFINITIONS(PvaClientNTMultiMonitor); POINTER_DEFINITIONS(PvaClientNTMultiMonitor);
/** protected:
* Factory method that creates a PvaClientNTMultiMonitor.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @param pvRequest The pvRequest for each channel.
* @return The interface.
*/
static PvaClientNTMultiMonitorPtr create( static PvaClientNTMultiMonitorPtr create(
PvaClientMultiChannelPtr const &pvaNTMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest); epics::pvData::PVStructurePtr const & pvRequest);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~PvaClientNTMultiMonitor(); ~PvaClientNTMultiMonitor();
/** Destroy the pvAccess connection.
*/
void destroy();
/** /**
* Create a channel monitor for each channel. * @brief Connect to a channel monitor for each channel.
*/ */
void connect(); void connect();
/** /**
* poll each channel. * @brief Poll each channel.
*
* @param valueOnly use only value for union.
* If any has new data it is used to update the double[]. * If any has new data it is used to update the double[].
* @return (false,true) if (no, at least one) value was updated. * @return (false,true) if (no, at least one) value was updated.
*/ */
bool poll(); bool poll(bool valueOnly = true);
/** /**
* Wait until poll returns true. * @brief Wait until poll returns true.
* @param waitForEvent The time to keep trying. * @param secondsToWait The time to keep trying.
* A thread sleep of .1 seconds occurs between each call to poll. * A thread sleep of .1 seconds occurs between each call to poll.
* @return (false,true) if (timeOut, poll returned true). * @return (false,true) if (timeOut, poll returned true).
*/ */
bool waitEvent(double waitForEvent); bool waitEvent(double secondsToWait);
/** /**
* get the data. * @brief Get the data for the last successfull poll.
* @return the pvaClientNTMultiData. * @return the pvaClientNTMultiData.
*/ */
PvaClientNTMultiDataPtr getData(); PvaClientNTMultiDataPtr getData();
/** Monitor the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiMonitorPtr getPtrSelf()
{
return shared_from_this();
}
private: private:
PvaClientNTMultiMonitor( PvaClientNTMultiMonitor(
epics::pvData::UnionConstPtr const & u, epics::pvData::UnionConstPtr const & u,
@@ -557,11 +482,10 @@ private:
PvaClientNTMultiDataPtr pvaClientNTMultiData; PvaClientNTMultiDataPtr pvaClientNTMultiData;
std::vector<PvaClientMonitorPtr> pvaClientMonitor; std::vector<PvaClientMonitorPtr> pvaClientMonitor;
bool isConnected; bool isConnected;
bool isDestroyed;
}; };
/** /**
* This provides NTMultiChannel data for both PvaClientNTMultiGet and PvaClientNTMultiMonitor. * @brief Provides NTMultiChannel data for both PvaClientNTMultiGet and PvaClientNTMultiMonitor.
*/ */
class epicsShareClass PvaClientNTMultiData : class epicsShareClass PvaClientNTMultiData :
public std::tr1::enable_shared_from_this<PvaClientNTMultiData> public std::tr1::enable_shared_from_this<PvaClientNTMultiData>
@@ -569,64 +493,43 @@ class epicsShareClass PvaClientNTMultiData :
public: public:
POINTER_DEFINITIONS(PvaClientNTMultiData); POINTER_DEFINITIONS(PvaClientNTMultiData);
/**
* Factory method that creates a PvaClientNTMultiData.
* Normally only called by PvaClientNTMultiGet and PvaClientNTMultiMonitor.
* @param u The union interface for the value field of each channel.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @param pvRequest The pvRequest for each channel.
*/
static PvaClientNTMultiDataPtr create(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaNTMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
~PvaClientNTMultiData(); ~PvaClientNTMultiData();
/** Destroy the pvAccess connection. /**
*/ * @brief Get the number of channels.
void destroy();
/**
* Get the number of channels.
* @return The number of channels. * @return The number of channels.
*/ */
size_t getNumber(); size_t getNumber();
/**
/** * @brief Get the time when the last get was made.
* Set the timeStamp base for computing deltaTimes.
*/
void startDeltaTime();
/**
* Update NTMultiChannel fields.
*/
void endDeltaTime();
/**
* Get the time when the last get was made.
* @return The timeStamp. * @return The timeStamp.
*/ */
epics::pvData::TimeStamp getTimeStamp(); epics::pvData::TimeStamp getTimeStamp();
/** /**
* Get the NTMultiChannel. * @brief Get the NTMultiChannel.
* @return The value. * @return The value.
*/ */
epics::nt::NTMultiChannelPtr getNTMultiChannel(); epics::nt::NTMultiChannelPtr getNTMultiChannel();
/** Get the shared pointer to self. /**
* @return The shared pointer. * @brief Get channel change flags.
* @return Array of boolean fields that are set to true if corresponding channel changed
*/ */
PvaClientNTMultiDataPtr getPtrSelf() epics::pvData::shared_vector<epics::pvData::boolean> getChannelChangeFlags();
{ protected:
return shared_from_this(); static PvaClientNTMultiDataPtr create(
} epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
void startDeltaTime();
void endDeltaTime(bool valueOnly = true);
friend class PvaClientNTMultiGet;
friend class PvaClientNTMultiMonitor;
private: private:
PvaClientNTMultiData( PvaClientNTMultiData(
epics::pvData::UnionConstPtr const & u, epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaNTMultiChannel, PvaClientMultiChannelPtr const &pvaNTMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest); epics::pvData::PVStructurePtr const & pvRequest);
void setStructure(epics::pvData::StructureConstPtr const & structure,size_t index);
void setPVStructure( void setPVStructure(
epics::pvData::PVStructurePtr const &pvStructure,size_t index); epics::pvData::PVStructurePtr const &pvStructure,size_t index);
@@ -638,8 +541,8 @@ private:
std::vector<epics::pvData::PVStructurePtr> topPVStructure; std::vector<epics::pvData::PVStructurePtr> topPVStructure;
bool gotAlarm; bool gotAlarm;
bool gotTimeStamp; bool gotTimeStamp;
bool isDestroyed;
epics::pvData::shared_vector<epics::pvData::boolean> changeFlags;
epics::pvData::StructureConstPtr ntMultiChannelStructure; epics::pvData::StructureConstPtr ntMultiChannelStructure;
epics::pvData::shared_vector<epics::pvData::PVUnionPtr> unionValue; epics::pvData::shared_vector<epics::pvData::PVUnionPtr> unionValue;
epics::pvData::shared_vector<epics::pvData::int32> severity; epics::pvData::shared_vector<epics::pvData::int32> severity;
@@ -651,19 +554,9 @@ private:
epics::pvData::Alarm alarm; epics::pvData::Alarm alarm;
epics::pvData::TimeStamp timeStamp;; epics::pvData::TimeStamp timeStamp;;
epics::pvData::PVTimeStamp pvTimeStamp; epics::pvData::PVTimeStamp pvTimeStamp;
friend class PvaClientNTMultiGet;
friend class PvaClientNTMultiPut;
friend class PvaClientNTMultiMonitor;
}; };
}} }}
#endif /* PVACLIENTMULTICHANNEL_H */ #endif /* PVACLIENTMULTICHANNEL_H */
/** @page Overview Documentation
*
* <a href = "../pvaClientOverview.html">pvaClientOverview.html</a>
*
*/
+88 -91
View File
@@ -9,86 +9,40 @@
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <map> #include <map>
#include <pv/pvaClient.h>
#include <pv/createRequest.h> #include <pv/createRequest.h>
#include <pv/clientFactory.h> #include <pv/clientFactory.h>
#include <pv/caProvider.h> #include <pv/caProvider.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::pvAccess::ca; using namespace epics::pvAccess::ca;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static FieldCreatePtr fieldCreate = getFieldCreate();
static const string pvaClientName = "pvaClient";
static const string defaultProvider = "pva";
static UnionConstPtr variantUnion = fieldCreate->createVariantUnion();
namespace pvaClientPvt { class epicsShareClass PvaClientChannelCache
static size_t numberPvaClient = 0;
static bool firstTime = true;
static Mutex mutex;
class StartStopClientFactory {
public:
static void PvaClientBeingConstructed()
{
bool saveFirst = false;
{
Lock xx(mutex);
++numberPvaClient;
saveFirst = firstTime;
firstTime = false;
}
if(saveFirst) {
ClientFactory::start();
CAClientFactory::start();
}
}
static void PvaClientBeingDestroyed() {
size_t numLeft = 0;
{
Lock xx(mutex);
--numberPvaClient;
numLeft = numberPvaClient;
}
if(numLeft<=0) {
ClientFactory::stop();
CAClientFactory::stop();
}
}
};
} // namespace pvaClientPvt
class PvaClientChannelCache
{ {
public: public:
PvaClientChannelCache(){} PvaClientChannelCache(){}
~PvaClientChannelCache(){ ~PvaClientChannelCache(){
destroy(); if(PvaClient::getDebug()) cout << "PvaClientChannelCache::~PvaClientChannelCache\n";
} }
void destroy() {
pvaClientChannelMap.clear();
}
PvaClientChannelPtr getChannel( PvaClientChannelPtr getChannel(
string const & channelName, string const & channelName,
string const & providerName); string const & providerName);
void addChannel(PvaClientChannelPtr const & pvaClientChannel); void addChannel(PvaClientChannelPtr const & pvaClientChannel);
void removeChannel(string const & channelName,string const & providerName);
void showCache(); void showCache();
size_t cacheSize(); size_t cacheSize();
private: private:
map<string,PvaClientChannelPtr> pvaClientChannelMap; map<string,PvaClientChannelPtr> pvaClientChannelMap;
}; };
PvaClientChannelPtr PvaClientChannelCache::getChannel( PvaClientChannelPtr PvaClientChannelCache::getChannel(
string const & channelName, string const & channelName,
string const & providerName) string const & providerName)
@@ -104,17 +58,12 @@ void PvaClientChannelCache::addChannel(PvaClientChannelPtr const & pvaClientChan
Channel::shared_pointer channel = pvaClientChannel->getChannel(); Channel::shared_pointer channel = pvaClientChannel->getChannel();
string name = channel->getChannelName() string name = channel->getChannelName()
+ channel->getProvider()->getProviderName(); + channel->getProvider()->getProviderName();
pvaClientChannelMap.insert(std::pair<string,PvaClientChannelPtr>(
name,pvaClientChannel));
}
void PvaClientChannelCache::removeChannel(
string const & channelName,
string const & providerName)
{
string name = channelName + providerName;
map<string,PvaClientChannelPtr>::iterator iter = pvaClientChannelMap.find(name); map<string,PvaClientChannelPtr>::iterator iter = pvaClientChannelMap.find(name);
if(iter!=pvaClientChannelMap.end()) pvaClientChannelMap.erase(iter); if(iter!=pvaClientChannelMap.end()) {
throw std::runtime_error("pvaClientChannelCache::addChannel channel already cached");
}
pvaClientChannelMap.insert(std::pair<string,PvaClientChannelPtr>(
name,pvaClientChannel));
} }
void PvaClientChannelCache::showCache() void PvaClientChannelCache::showCache()
@@ -127,10 +76,8 @@ void PvaClientChannelCache::showCache()
string channelName = channel->getChannelName(); string channelName = channel->getChannelName();
string providerName = channel->getProvider()->getProviderName(); string providerName = channel->getProvider()->getProviderName();
cout << "channel " << channelName << " provider " << providerName << endl; cout << "channel " << channelName << " provider " << providerName << endl;
cout << " get and put cacheSize " << pvaChannel->cacheSize() << endl;
pvaChannel->showCache(); pvaChannel->showCache();
} }
} }
size_t PvaClientChannelCache::cacheSize() size_t PvaClientChannelCache::cacheSize()
@@ -139,35 +86,82 @@ size_t PvaClientChannelCache::cacheSize()
} }
using namespace epics::pvaClient::pvaClientPvt; // MSVC doesn't like making this a class static data member:
static bool debug = 0;
PvaClientPtr PvaClient::create() void PvaClient::setDebug(bool value)
{ {
PvaClientPtr xx(new PvaClient()); debug = value;
StartStopClientFactory::PvaClientBeingConstructed();
return xx;
} }
bool PvaClient::getDebug()
PvaClient::PvaClient()
: pvaClientChannelCache(new PvaClientChannelCache()),
isDestroyed(false)
{ {
return debug;
}
PvaClientPtr PvaClient::get(std::string const & providerNames)
{
static PvaClientPtr master;
static Mutex mutex;
Lock xx(mutex);
if(!master) {
master = PvaClientPtr(new PvaClient(providerNames));
}
return master;
}
PvaClientPtr PvaClient::create() {return get();}
PvaClient::PvaClient(std::string const & providerNames)
: pvaClientChannelCache(new PvaClientChannelCache()),
pvaStarted(false),
caStarted(false),
channelRegistry(ChannelProviderRegistry::clients())
{
stringstream ss(providerNames);
string providerName;
if(getDebug()) {
cout<< "PvaClient::PvaClient()\n";
}
while (getline(ss, providerName, ' '))
{
if(providerName=="pva") {
if(getDebug()) {
cout<< "calling ClientFactory::start()\n";
}
ClientFactory::start();
pvaStarted = true;
} else if(providerName=="ca") {
if(getDebug()) {
cout<< "calling CAClientFactory::start()\n";
}
CAClientFactory::start();
caStarted = true;
} else {
if(!channelRegistry->getProvider(providerName)) {
cerr << "PvaClient::get provider " << providerName << " not known" << endl;
}
}
}
} }
PvaClient::~PvaClient() { PvaClient::~PvaClient() {
destroy(); if(getDebug()) {
} cout<< "PvaClient::~PvaClient()\n"
<< "pvaChannel cache:\n";
void PvaClient::destroy() showCache();
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
} }
pvaClientChannelCache.reset(); if(pvaStarted){
StartStopClientFactory::PvaClientBeingDestroyed(); if(getDebug()) cout<< "calling ClientFactory::stop()\n";
ClientFactory::stop();
if(getDebug()) cout<< "after calling ClientFactory::stop()\n";
}
if(caStarted) {
if(getDebug()) cout<< "calling CAClientFactory::stop()\n";
CAClientFactory::stop();
if(getDebug()) cout<< "after calling CAClientFactory::stop()\n";
}
channelRegistry.reset();
} }
string PvaClient:: getRequesterName() string PvaClient:: getRequesterName()
@@ -197,7 +191,7 @@ PvaClientChannelPtr PvaClient::channel(
std::string const & providerName, std::string const & providerName,
double timeOut) double timeOut)
{ {
PvaClientChannelPtr pvaClientChannel = PvaClientChannelPtr pvaClientChannel =
pvaClientChannelCache->getChannel(channelName,providerName); pvaClientChannelCache->getChannel(channelName,providerName);
if(pvaClientChannel) return pvaClientChannel; if(pvaClientChannel) return pvaClientChannel;
pvaClientChannel = createChannel(channelName,providerName); pvaClientChannel = createChannel(channelName,providerName);
@@ -208,7 +202,7 @@ PvaClientChannelPtr PvaClient::channel(
PvaClientChannelPtr PvaClient::createChannel(string const & channelName, string const & providerName) PvaClientChannelPtr PvaClient::createChannel(string const & channelName, string const & providerName)
{ {
return PvaClientChannel::create(getPtrSelf(),channelName,providerName); return PvaClientChannel::create(shared_from_this(),channelName,providerName);
} }
void PvaClient::setRequester(RequesterPtr const & requester) void PvaClient::setRequester(RequesterPtr const & requester)
@@ -218,12 +212,16 @@ void PvaClient::setRequester(RequesterPtr const & requester)
void PvaClient::clearRequester() void PvaClient::clearRequester()
{ {
requester = Requester::weak_pointer(); requester.reset();
} }
void PvaClient::showCache() void PvaClient::showCache()
{ {
pvaClientChannelCache->showCache(); if(pvaClientChannelCache->cacheSize()>=1) {
pvaClientChannelCache->showCache();
} else {
cout << "pvaClientChannelCache is empty\n";
}
} }
@@ -233,4 +231,3 @@ size_t PvaClient::cacheSize()
} }
}} }}
-1348
View File
File diff suppressed because it is too large Load Diff
+254 -191
View File
@@ -8,16 +8,16 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <map> #include <map>
#include <pv/event.h> #include <pv/event.h>
#include <pv/lock.h> #include <pv/lock.h>
#include <pv/pvaClient.h>
#include <pv/createRequest.h> #include <pv/createRequest.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
@@ -25,13 +25,13 @@ using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
class PvaClientGetCache class epicsShareClass PvaClientGetCache
{ {
public: public:
PvaClientGetCache(){} PvaClientGetCache(){}
~PvaClientGetCache(); ~PvaClientGetCache()
void destroy() { {
pvaClientGetMap.clear(); if(PvaClient::getDebug()) cout << "PvaClientGetCache::~PvaClientGetCache\n";
} }
PvaClientGetPtr getGet(string const & request); PvaClientGetPtr getGet(string const & request);
void addGet(string const & request,PvaClientGetPtr const & pvaClientGet); void addGet(string const & request,PvaClientGetPtr const & pvaClientGet);
@@ -41,11 +41,6 @@ private:
map<string,PvaClientGetPtr> pvaClientGetMap; map<string,PvaClientGetPtr> pvaClientGetMap;
}; };
PvaClientGetCache::~PvaClientGetCache()
{
destroy();
}
PvaClientGetPtr PvaClientGetCache::getGet(string const & request) PvaClientGetPtr PvaClientGetCache::getGet(string const & request)
{ {
map<string,PvaClientGetPtr>::iterator iter = pvaClientGetMap.find(request); map<string,PvaClientGetPtr>::iterator iter = pvaClientGetMap.find(request);
@@ -55,8 +50,11 @@ PvaClientGetPtr PvaClientGetCache::getGet(string const & request)
void PvaClientGetCache::addGet(string const & request,PvaClientGetPtr const & pvaClientGet) void PvaClientGetCache::addGet(string const & request,PvaClientGetPtr const & pvaClientGet)
{ {
pvaClientGetMap.insert(std::pair<string,PvaClientGetPtr>( map<string,PvaClientGetPtr>::iterator iter = pvaClientGetMap.find(request);
request,pvaClientGet)); if(iter!=pvaClientGetMap.end()) {
throw std::runtime_error("pvaClientGetCache::addGet pvaClientGet already cached");
}
pvaClientGetMap.insert(std::pair<string,PvaClientGetPtr>(request,pvaClientGet));
} }
void PvaClientGetCache::showCache() void PvaClientGetCache::showCache()
@@ -74,13 +72,13 @@ size_t PvaClientGetCache::cacheSize()
} }
class PvaClientPutCache class epicsShareClass PvaClientPutCache
{ {
public: public:
PvaClientPutCache(){} PvaClientPutCache(){}
~PvaClientPutCache(); ~PvaClientPutCache()
void destroy() { {
pvaClientPutMap.clear(); if(PvaClient::getDebug()) cout << "PvaClientPutCache::~PvaClientPutCache\n";
} }
PvaClientPutPtr getPut(string const & request); PvaClientPutPtr getPut(string const & request);
void addPut(string const & request,PvaClientPutPtr const & pvaClientPut); void addPut(string const & request,PvaClientPutPtr const & pvaClientPut);
@@ -90,10 +88,6 @@ private:
map<string,PvaClientPutPtr> pvaClientPutMap; map<string,PvaClientPutPtr> pvaClientPutMap;
}; };
PvaClientPutCache::~PvaClientPutCache()
{
destroy();
}
PvaClientPutPtr PvaClientPutCache::getPut(string const & request) PvaClientPutPtr PvaClientPutCache::getPut(string const & request)
{ {
@@ -104,6 +98,10 @@ PvaClientPutPtr PvaClientPutCache::getPut(string const & request)
void PvaClientPutCache::addPut(string const & request,PvaClientPutPtr const & pvaClientPut) void PvaClientPutCache::addPut(string const & request,PvaClientPutPtr const & pvaClientPut)
{ {
map<string,PvaClientPutPtr>::iterator iter = pvaClientPutMap.find(request);
if(iter!=pvaClientPutMap.end()) {
throw std::runtime_error("pvaClientPutCache::addPut pvaClientPut already cached");
}
pvaClientPutMap.insert(std::pair<string,PvaClientPutPtr>( pvaClientPutMap.insert(std::pair<string,PvaClientPutPtr>(
request,pvaClientPut)); request,pvaClientPut));
} }
@@ -123,29 +121,14 @@ size_t PvaClientPutCache::cacheSize()
} }
class ChannelRequesterImpl : public ChannelRequester PvaClientChannelPtr PvaClientChannel::create(
PvaClientPtr const &pvaClient,
string const & channelName,
string const & providerName)
{ {
PvaClientChannel *pvaClientChannel; PvaClientChannelPtr channel(new PvaClientChannel(pvaClient,channelName,providerName));
public: return channel;
ChannelRequesterImpl(PvaClientChannel *pvaClientChannel) }
: pvaClientChannel(pvaClientChannel) {}
void channelCreated(
const Status& status,
Channel::shared_pointer const & channel)
{ pvaClientChannel->channelCreated(status,channel); }
void channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState)
{pvaClientChannel->channelStateChange(channel,connectionState);}
tr1::shared_ptr<Channel> getChannel() {return pvaClientChannel->getChannel();}
string getRequesterName()
{return pvaClientChannel->getRequesterName();}
void message(
string const & message,
MessageType messageType)
{ pvaClientChannel->message(message,messageType); }
void destroy() {pvaClientChannel->destroy();}
};
PvaClientChannel::PvaClientChannel( PvaClientChannel::PvaClientChannel(
@@ -156,52 +139,87 @@ PvaClientChannel::PvaClientChannel(
channelName(channelName), channelName(channelName),
providerName(providerName), providerName(providerName),
connectState(connectIdle), connectState(connectIdle),
isDestroyed(false),
createRequest(CreateRequest::create()), createRequest(CreateRequest::create()),
pvaClientGetCache(new PvaClientGetCache()), pvaClientGetCache(new PvaClientGetCache()),
pvaClientPutCache(new PvaClientPutCache()) pvaClientPutCache(new PvaClientPutCache())
{} {
if(PvaClient::getDebug()) {
cout << "PvaClientChannel::PvaClientChannel channelName " << channelName << endl;
}
}
PvaClientChannel::~PvaClientChannel() PvaClientChannel::~PvaClientChannel()
{ {
destroy(); if(PvaClient::getDebug()) {
cout << "PvaClientChannel::~PvaClientChannel() "
<< " channelName " << channelName
<< endl;
}
if(PvaClient::getDebug()) showCache();
} }
void PvaClientChannel::channelCreated(const Status& status, Channel::shared_pointer const & channel) void PvaClientChannel::channelCreated(const Status& status, Channel::shared_pointer const & channel)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed"); if(PvaClient::getDebug()) {
if(status.isOK()) { cout << "PvaClientChannel::channelCreated"
this->channel = channel; << " channelName " << channelName
return; << " connectState " << connectState
<< " isConnected " << (channel->isConnected() ? "true" : "false")
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
Lock xx(mutex);
this->channel = channel;
if(connectState==connected) return;
if(connectState!=connectActive) {
string message("PvaClientChannel::channelCreated");
message += " channel " + channelName
+ " why was this called when connectState!=ConnectState.connectActive";
throw std::runtime_error(message);
}
if(!status.isOK()) {
string message("PvaClientChannel::channelCreated");
message += " channel " + channelName
+ " status " + status.getMessage() + " why??";
throw std::runtime_error(message);
} }
cout << "PvaClientChannel::channelCreated status " << status.getMessage() << " why??\n";
} }
void PvaClientChannel::channelStateChange( void PvaClientChannel::channelStateChange(
Channel::shared_pointer const & channel, Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState) Channel::ConnectionState connectionState)
{ {
Lock xx(mutex); if(PvaClient::getDebug()) {
if(isDestroyed) return; cout << " PvaClientChannel::channelStateChange "
<< " channelName " << channelName
<< " " << Channel::ConnectionStateNames[connectionState]
<< endl;
}
bool waitingForConnect = false; bool waitingForConnect = false;
if(connectState==connectActive) waitingForConnect = true; if(connectState==connectActive) waitingForConnect = true;
if(connectionState!=Channel::CONNECTED) { if(connectionState!=Channel::CONNECTED) {
string mess(channelName + Lock xx(mutex);
" connection state " + Channel::ConnectionStateNames[connectionState]); connectState = notConnected;
message(mess,errorMessage);
channelConnectStatus = Status(Status::STATUSTYPE_ERROR,mess);
connectState = notConnected;
} else { } else {
connectState = connected; Lock xx(mutex);
channelConnectStatus = Status::Ok; this->channel = channel;
connectState = connected;
}
if(waitingForConnect) {
Lock xx(mutex);
waitForConnect.signal();
}
PvaClientChannelStateChangeRequesterPtr req(stateChangeRequester.lock());
if(req) {
bool value = (connectionState==Channel::CONNECTED ? true : false);
req->channelStateChange(shared_from_this(),value);
} }
if(waitingForConnect) waitForConnect.signal();
} }
string PvaClientChannel::getRequesterName() string PvaClientChannel::getRequesterName()
{ {
PvaClientPtr yyy = pvaClient.lock(); PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed"); if(!yyy) return string("PvaClientChannel::getRequesterName() PvaClient isDestroyed");
return yyy->getRequesterName(); return yyy->getRequesterName();
} }
@@ -209,99 +227,97 @@ void PvaClientChannel::message(
string const & message, string const & message,
MessageType messageType) MessageType messageType)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
PvaClientPtr yyy = pvaClient.lock(); PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed"); if(!yyy) return;
yyy->message(channelName + " " + message, messageType); yyy->message(channelName + " " + message, messageType);
} }
void PvaClientChannel::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
if(channel) channel->destroy();
channel.reset();
pvaClientGetCache.reset();
pvaClientPutCache.reset();
}
string PvaClientChannel::getChannelName() string PvaClientChannel::getChannelName()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
return channelName; return channelName;
} }
Channel::shared_pointer PvaClientChannel::getChannel() Channel::shared_pointer PvaClientChannel::getChannel()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
return channel; return channel;
} }
void PvaClientChannel::setStateChangeRequester(
PvaClientChannelStateChangeRequesterPtr const & stateChangeRequester)
{
this->stateChangeRequester = stateChangeRequester;
bool isConnected = false;
if(channel) isConnected = channel->isConnected();
stateChangeRequester->channelStateChange(shared_from_this(),isConnected);
}
void PvaClientChannel::connect(double timeout) void PvaClientChannel::connect(double timeout)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientChannel::connect"
<< " channelName " << channelName << endl;
}
issueConnect(); issueConnect();
Status status = waitConnect(timeout); Status status = waitConnect(timeout);
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + getChannelName() if(PvaClient::getDebug()) cout << "PvaClientChannel::connect waitConnect failed\n";
string message = string("channel ") + channelName
+ " PvaClientChannel::connect " + status.getMessage(); + " PvaClientChannel::connect " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientChannel::issueConnect() void PvaClientChannel::issueConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=connectIdle) { cout << "PvaClientChannel::issueConnect"
throw std::runtime_error("pvaClientChannel already connected"); << " channelName " << channelName << endl;
} }
channelRequester = ChannelRequester::shared_pointer(new ChannelRequesterImpl(this)); {
Lock xx(mutex);
channelConnectStatus = Status( if(connectState==connected) return;
Status::STATUSTYPE_ERROR, if(connectState!=connectIdle) {
getChannelName() + " createChannel failed"); throw std::runtime_error("pvaClientChannel already connected");
connectState = connectActive; }
ChannelProviderRegistry::shared_pointer reg = getChannelProviderRegistry(); connectState = connectActive;
ChannelProvider::shared_pointer provider = reg->getProvider(providerName);
if(!provider) {
throw std::runtime_error(getChannelName() + " provider " + providerName + " not registered");
} }
channel = provider->createChannel(channelName,channelRequester,ChannelProvider::PRIORITY_DEFAULT); ChannelProviderRegistry::shared_pointer reg(ChannelProviderRegistry::clients());
channelProvider = reg->getProvider(providerName);
if(!channelProvider) {
throw std::runtime_error(channelName + " provider " + providerName + " not registered");
}
if(PvaClient::getDebug()) cout << "PvaClientChannel::issueConnect calling provider->createChannel\n";
channel = channelProvider->createChannel(channelName,shared_from_this(),ChannelProvider::PRIORITY_DEFAULT);
if(!channel) { if(!channel) {
throw std::runtime_error(getChannelName() + " channelCreate failed "); throw std::runtime_error(channelName + " channelCreate failed ");
} }
} }
Status PvaClientChannel::waitConnect(double timeout) Status PvaClientChannel::waitConnect(double timeout)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed"); if(PvaClient::getDebug()) {
waitForConnect.wait(timeout); cout << "PvaClientChannel::waitConnect"
return channelConnectStatus; << " channelName " << channelName << endl;
} }
{
PvaClientFieldPtr PvaClientChannel::createField() Lock xx(mutex);
{ if(!channel) return Status(Status::STATUSTYPE_ERROR,"");
return createField(""); if(channel->isConnected()) return Status::Ok;
} }
if(timeout>0.0) {
PvaClientFieldPtr PvaClientChannel::createField(string const & subField) waitForConnect.wait(timeout);
{ } else {
if(connectState!=connected) connect(5.0); waitForConnect.wait();
throw std::runtime_error("PvaClientChannel::createField not implemented"); }
} if(!channel) return Status(Status::STATUSTYPE_ERROR,"pvaClientChannel::waitConnect channel is null");
if(channel->isConnected()) return Status::Ok;
PvaClientProcessPtr PvaClientChannel::createProcess() return Status(Status::STATUSTYPE_ERROR," not connected");
{
return createProcess("");
} }
PvaClientProcessPtr PvaClientChannel::createProcess(string const & request) PvaClientProcessPtr PvaClientChannel::createProcess(string const & request)
{ {
PVStructurePtr pvRequest = createRequest->createRequest(request); PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) { if(!pvRequest) {
string message = string("channel ") + getChannelName() string message = string("channel ") + channelName
+ " PvaClientChannel::createProcess invalid pvRequest: " + " PvaClientChannel::createProcess invalid pvRequest: "
+ createRequest->getMessage(); + createRequest->getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
@@ -314,31 +330,28 @@ PvaClientProcessPtr PvaClientChannel::createProcess(PVStructurePtr const & pvRe
if(connectState!=connected) connect(5.0); if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock(); PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed"); if(!yyy) throw std::runtime_error("PvaClient was destroyed");
return PvaClientProcess::create(yyy,channel,pvRequest); return PvaClientProcess::create(yyy,shared_from_this(),pvRequest);
} }
PvaClientGetPtr PvaClientChannel::get() {return get("value,alarm,timeStamp");}
PvaClientGetPtr PvaClientChannel::get(string const & request) PvaClientGetPtr PvaClientChannel::get(string const & request)
{ {
PvaClientGetPtr pvaClientGet = pvaClientGetCache->getGet(request); PvaClientGetPtr pvaClientGet = pvaClientGetCache->getGet(request);
if(pvaClientGet) return pvaClientGet; if(!pvaClientGet) {
pvaClientGet = createGet(request); pvaClientGet = createGet(request);
pvaClientGet->connect(); pvaClientGet->connect();
pvaClientGetCache->addGet(request,pvaClientGet); pvaClientGetCache->addGet(request,pvaClientGet);
}
pvaClientGet->get();
return pvaClientGet; return pvaClientGet;
} }
PvaClientGetPtr PvaClientChannel::createGet()
{
return PvaClientChannel::createGet("value,alarm,timeStamp");
}
PvaClientGetPtr PvaClientChannel::createGet(string const & request) PvaClientGetPtr PvaClientChannel::createGet(string const & request)
{ {
PVStructurePtr pvRequest = createRequest->createRequest(request); PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) { if(!pvRequest) {
string message = string("channel ") + getChannelName() string message = string("channel ") + channelName
+ " PvaClientChannel::createGet invalid pvRequest: " + " PvaClientChannel::createGet invalid pvRequest: "
+ createRequest->getMessage(); + createRequest->getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
@@ -351,32 +364,49 @@ PvaClientGetPtr PvaClientChannel::createGet(PVStructurePtr const & pvRequest)
if(connectState!=connected) connect(5.0); if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock(); PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed"); if(!yyy) throw std::runtime_error("PvaClient was destroyed");
return PvaClientGet::create(yyy,channel,pvRequest); return PvaClientGet::create(yyy,shared_from_this(),pvRequest);
}
double PvaClientChannel::getDouble(string const & request)
{
return get(request)->getData()->getDouble();
}
string PvaClientChannel::getString(string const & request)
{
return get(request)->getData()->getString();
}
shared_vector<const double> PvaClientChannel::getDoubleArray(string const & request)
{
return get(request)->getData()->getDoubleArray();
}
shared_vector<const std::string> PvaClientChannel::getStringArray(string const & request)
{
return get(request)->getData()->getStringArray();
} }
PvaClientPutPtr PvaClientChannel::put() {return put("value");}
PvaClientPutPtr PvaClientChannel::put(string const & request) PvaClientPutPtr PvaClientChannel::put(string const & request)
{ {
PvaClientPutPtr pvaClientPut = pvaClientPutCache->getPut(request); PvaClientPutPtr pvaClientPut = pvaClientPutCache->getPut(request);
if(pvaClientPut) return pvaClientPut; if(pvaClientPut) return pvaClientPut;
pvaClientPut = createPut(request); if(!pvaClientPut) {
pvaClientPut->connect(); pvaClientPut = createPut(request);
pvaClientPut->get(); pvaClientPut->connect();
pvaClientPutCache->addPut(request,pvaClientPut); pvaClientPut->get();
pvaClientPutCache->addPut(request,pvaClientPut);
}
return pvaClientPut; return pvaClientPut;
} }
PvaClientPutPtr PvaClientChannel::createPut()
{
return createPut("value");
}
PvaClientPutPtr PvaClientChannel::createPut(string const & request) PvaClientPutPtr PvaClientChannel::createPut(string const & request)
{ {
PVStructurePtr pvRequest = createRequest->createRequest(request); PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) { if(!pvRequest) {
string message = string("channel ") + getChannelName() string message = string("channel ") + channelName
+ " PvaClientChannel::createPut invalid pvRequest: " + " PvaClientChannel::createPut invalid pvRequest: "
+ createRequest->getMessage(); + createRequest->getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
@@ -389,19 +419,52 @@ PvaClientPutPtr PvaClientChannel::createPut(PVStructurePtr const & pvRequest)
if(connectState!=connected) connect(5.0); if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock(); PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed"); if(!yyy) throw std::runtime_error("PvaClient was destroyed");
return PvaClientPut::create(yyy,channel,pvRequest); return PvaClientPut::create(yyy,shared_from_this(),pvRequest);
} }
PvaClientPutGetPtr PvaClientChannel::createPutGet() void PvaClientChannel::putDouble(double value,string const & request)
{ {
return createPutGet("putField(argument)getField(result)"); PvaClientPutPtr clientPut = put(request);
PvaClientPutDataPtr putData = clientPut->getData();
putData->putDouble(value); clientPut->put();
}
void PvaClientChannel::putString(std::string const & value,string const & request)
{
PvaClientPutPtr clientPut = put(request);
PvaClientPutDataPtr putData = clientPut->getData();
putData->putString(value); clientPut->put();
}
void PvaClientChannel::putDoubleArray(
shared_vector<const double> const & value,
string const & request)
{
PvaClientPutPtr clientPut = put(request);
PvaClientPutDataPtr putData = clientPut->getData();
size_t n = value.size();
shared_vector<double> valueArray(n);
for(size_t i=0; i<n; ++i) valueArray[i] = value[i];
putData->putDoubleArray(freeze(valueArray)); clientPut->put();
}
void PvaClientChannel::putStringArray(
shared_vector<const string> const & value,
string const & request)
{
PvaClientPutPtr clientPut = put(request);
PvaClientPutDataPtr putData = clientPut->getData();
size_t n = value.size();
shared_vector<string> valueArray(n);
for(size_t i=0; i<n; ++i) valueArray[i] = value[i];
putData->putStringArray(freeze(valueArray)); clientPut->put();
} }
PvaClientPutGetPtr PvaClientChannel::createPutGet(string const & request) PvaClientPutGetPtr PvaClientChannel::createPutGet(string const & request)
{ {
PVStructurePtr pvRequest = createRequest->createRequest(request); PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) { if(!pvRequest) {
string message = string("channel ") + getChannelName() string message = string("channel ") + channelName
+ " PvaClientChannel::createPutGet invalid pvRequest: " + " PvaClientChannel::createPutGet invalid pvRequest: "
+ createRequest->getMessage(); + createRequest->getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
@@ -414,36 +477,9 @@ PvaClientPutGetPtr PvaClientChannel::createPutGet(PVStructurePtr const & pvReque
if(connectState!=connected) connect(5.0); if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock(); PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed"); if(!yyy) throw std::runtime_error("PvaClient was destroyed");
return PvaClientPutGet::create(yyy,channel,pvRequest); return PvaClientPutGet::create(yyy,shared_from_this(),pvRequest);
} }
PvaClientArrayPtr PvaClientChannel::createArray()
{
return createArray("value");
}
PvaClientArrayPtr PvaClientChannel::createArray(string const & request)
{
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
string message = string("channel ") + getChannelName()
+ " PvaClientChannel::createArray invalid pvRequest: "
+ createRequest->getMessage();
throw std::runtime_error(message);
}
return createArray(pvRequest);
}
PvaClientArrayPtr PvaClientChannel::createArray(PVStructurePtr const & pvRequest)
{
if(connectState!=connected) connect(5.0);
throw std::runtime_error("PvaClientChannel::createArray not implemented");
}
PvaClientMonitorPtr PvaClientChannel::monitor() {return monitor("value,alarm,timeStamp");}
PvaClientMonitorPtr PvaClientChannel::monitor(string const & request) PvaClientMonitorPtr PvaClientChannel::monitor(string const & request)
{ {
PvaClientMonitorPtr pvaClientMonitor = createMonitor(request); PvaClientMonitorPtr pvaClientMonitor = createMonitor(request);
@@ -454,7 +490,7 @@ PvaClientMonitorPtr PvaClientChannel::monitor(string const & request)
PvaClientMonitorPtr PvaClientChannel::monitor(PvaClientMonitorRequesterPtr const & pvaClientMonitorRequester) PvaClientMonitorPtr PvaClientChannel::monitor(PvaClientMonitorRequesterPtr const & pvaClientMonitorRequester)
{ {
return monitor("value,alarm,timeStamp",pvaClientMonitorRequester); return monitor("field(value,alarm,timeStamp)",pvaClientMonitorRequester);
} }
PvaClientMonitorPtr PvaClientChannel::monitor(string const & request, PvaClientMonitorPtr PvaClientChannel::monitor(string const & request,
@@ -467,16 +503,11 @@ PvaClientMonitorPtr PvaClientChannel::monitor(string const & request,
return pvaClientMonitor; return pvaClientMonitor;
} }
PvaClientMonitorPtr PvaClientChannel::createMonitor()
{
return createMonitor("value,alarm,timeStamp");
}
PvaClientMonitorPtr PvaClientChannel::createMonitor(string const & request) PvaClientMonitorPtr PvaClientChannel::createMonitor(string const & request)
{ {
PVStructurePtr pvRequest = createRequest->createRequest(request); PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) { if(!pvRequest) {
string message = string("channel ") + getChannelName() string message = string("channel ") + channelName
+ " PvaClientChannel::createMonitor invalid pvRequest: " + " PvaClientChannel::createMonitor invalid pvRequest: "
+ createRequest->getMessage(); + createRequest->getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
@@ -489,15 +520,55 @@ PvaClientMonitorPtr PvaClientChannel::createMonitor(PVStructurePtr const & pvR
if(connectState!=connected) connect(5.0); if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock(); PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed"); if(!yyy) throw std::runtime_error("PvaClient was destroyed");
return PvaClientMonitor::create(yyy,channel,pvRequest); return PvaClientMonitor::create(yyy,shared_from_this(),pvRequest);
}
PVStructurePtr PvaClientChannel::rpc(
PVStructurePtr const & pvRequest,
PVStructurePtr const & pvArgument)
{
PvaClientRPCPtr rpc = createRPC(pvRequest);
return rpc->request(pvArgument);
}
PVStructurePtr PvaClientChannel::rpc(
PVStructurePtr const & pvArgument)
{
PvaClientRPCPtr rpc = createRPC();
return rpc->request(pvArgument);
}
PvaClientRPCPtr PvaClientChannel::createRPC()
{
if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed");
return PvaClientRPC::create(yyy,channel);
}
PvaClientRPCPtr PvaClientChannel::createRPC(PVStructurePtr const & pvRequest)
{
if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed");
return PvaClientRPC::create(yyy,channel,pvRequest);
} }
void PvaClientChannel::showCache() void PvaClientChannel::showCache()
{ {
cout << " pvaClientGet" << endl; if(pvaClientGetCache->cacheSize()>=1) {
pvaClientGetCache->showCache(); cout << " pvaClientGet cache" << endl;
cout << " pvaClientPut" << endl; pvaClientGetCache->showCache();
pvaClientPutCache->showCache(); } else {
cout << " pvaClientGet cache is empty\n";
}
if(pvaClientPutCache->cacheSize()>=1) {
cout << " pvaClientPut cache" << endl;
pvaClientPutCache->showCache();
} else {
cout << " pvaClientPut cache is empty\n";
}
} }
size_t PvaClientChannel::cacheSize() size_t PvaClientChannel::cacheSize()
@@ -506,13 +577,5 @@ size_t PvaClientChannel::cacheSize()
} }
PvaClientChannelPtr PvaClientChannel::create(
PvaClientPtr const &pvaClient,
string const & channelName,
string const & providerName)
{
PvaClientChannelPtr channel(new PvaClientChannel(pvaClient,channelName,providerName));
return channel;
}
}} }}
+440
View File
@@ -0,0 +1,440 @@
/* pvaClientData.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.04
*/
#include <typeinfo>
#include <sstream>
#include <istream>
#include <ostream>
#include <pv/createRequest.h>
#include <pv/convert.h>
#include <pv/pvEnumerated.h>
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
# include <pv/json.h>
# define USE_JSON
#endif
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvaClient {
typedef std::tr1::shared_ptr<PVArray> PVArrayPtr;
static ConvertPtr convert = getConvert();
static string noStructure("no pvStructure ");
static string noValue("no value field");
static string noScalar("value is not a scalar");
static string noArray("value is not an array");
static string noScalarArray("value is not a scalarArray");
static string noAlarm("no alarm");
static string noTimeStamp("no timeStamp");
PvaClientDataPtr PvaClientData::create(StructureConstPtr const & structure)
{
if(PvaClient::getDebug()) cout << "PvaClientData::create\n";
PvaClientDataPtr epv(new PvaClientData(structure));
return epv;
}
PvaClientData::PvaClientData(StructureConstPtr const & structure)
: structure(structure)
{
}
PVFieldPtr PvaClientData::getSinglePVField()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getSinglePVField\n";
PVStructurePtr pvStructure = getPVStructure();
while(true) {
const PVFieldPtrArray fieldPtrArray(pvStructure->getPVFields());
if(fieldPtrArray.size()==0) {
throw std::logic_error("PvaClientData::getSinglePVField() pvRequest for empty structure");
}
if(fieldPtrArray.size()!=1) {
PVFieldPtr pvValue = pvStructure->getSubField("value");
if(pvValue) {
Type type = pvValue->getField()->getType();
if(type!=epics::pvData::structure) return pvValue;
}
throw std::logic_error("PvaClientData::getSinglePVField() pvRequest for multiple fields");
}
PVFieldPtr pvField(fieldPtrArray[0]);
Type type = pvField->getField()->getType();
if(type!=epics::pvData::structure) return pvField;
pvStructure = static_pointer_cast<PVStructure>(pvField);
}
}
void PvaClientData::checkValue()
{
if(PvaClient::getDebug()) cout << "PvaClientData::checkValue\n";
if(pvValue) return;
throw std::runtime_error(messagePrefix + noValue);
}
void PvaClientData::setMessagePrefix(std::string const & value)
{
messagePrefix = value + " ";
}
StructureConstPtr PvaClientData::getStructure()
{
return structure;
}
PVStructurePtr PvaClientData::getPVStructure()
{
if(pvStructure) return pvStructure;
throw std::runtime_error(messagePrefix + noStructure);
}
BitSetPtr PvaClientData::getChangedBitSet()
{
if(bitSet)return bitSet;
throw std::runtime_error(messagePrefix + noStructure);
}
std::ostream & PvaClientData::showChanged(std::ostream & out)
{
if(!bitSet) throw std::runtime_error(messagePrefix + noStructure);
size_t nextSet = bitSet->nextSetBit(0);
PVFieldPtr pvField;
while(nextSet!=string::npos) {
if(nextSet==0) {
pvField = pvStructure;
} else {
pvField = pvStructure->getSubField(nextSet);
}
string name = pvField->getFullName();
out << name << " = " << pvField << endl;
nextSet = bitSet->nextSetBit(nextSet+1);
}
return out;
}
void PvaClientData::setData(
PVStructurePtr const & pvStructureFrom,
BitSetPtr const & bitSetFrom)
{
if(PvaClient::getDebug()) cout << "PvaClientData::setData\n";
pvStructure = pvStructureFrom;
bitSet = bitSetFrom;
pvValue = pvStructure->getSubField("value");
}
bool PvaClientData::hasValue()
{
if(PvaClient::getDebug()) cout << "PvaClientData::hasValue\n";
if(!pvValue) return false;
return true;
}
bool PvaClientData::isValueScalar()
{
if(PvaClient::getDebug()) cout << "PvaClientData::isValueScalar\n";
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalar) return true;
return false;
}
bool PvaClientData::isValueScalarArray()
{
if(PvaClient::getDebug()) cout << "PvaClientData::isValueScalarArray\n";
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalarArray) return true;
return false;
}
PVFieldPtr PvaClientData::getValue()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getValue\n";
checkValue();
return pvValue;
}
PVScalarPtr PvaClientData::getScalarValue()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getScalarValue\n";
checkValue();
if(pvValue->getField()->getType()!=scalar) {
throw std::runtime_error(messagePrefix + noScalar);
}
return pvStructure->getSubField<PVScalar>("value");
}
PVArrayPtr PvaClientData::getArrayValue()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getArrayValue\n";
checkValue();
Type type = pvValue->getField()->getType();
if(type!=scalarArray && type!=structureArray && type!=unionArray) {
throw std::runtime_error(messagePrefix + noArray);
}
return pvStructure->getSubField<PVArray>("value");
}
PVScalarArrayPtr PvaClientData::getScalarArrayValue()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getScalarArrayValue\n";
checkValue();
Type type = pvValue->getField()->getType();
if(type!=scalarArray) {
throw std::runtime_error(messagePrefix + noScalarArray);
}
return pvStructure->getSubField<PVScalarArray>("value");
}
double PvaClientData::getDouble()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getDouble\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
if(type!=scalar) {
throw std::logic_error("PvaClientData::getDouble() did not find a scalar field");
}
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
ScalarType scalarType = pvScalar->getScalar()->getScalarType();
if(scalarType==pvDouble) {
PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar);
return pvDouble->get();
}
if(!ScalarTypeFunc::isNumeric(scalarType)) {
throw std::logic_error(
"PvaClientData::getDouble() did not find a numeric scalar field");
}
return convert->toDouble(pvScalar);
}
string PvaClientData::getString()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getString\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
if(type!=scalar) {
throw std::logic_error("PvaClientData::getString() did not find a scalar field");
}
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
return convert->toString(pvScalar);
}
shared_vector<const double> PvaClientData::getDoubleArray()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getDoubleArray\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
if(type!=scalarArray) {
throw std::logic_error("PvaClientData::getDoubleArray() did not find a scalarArray field");
}
PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
ScalarType scalarType = pvScalarArray->getScalarArray()->getElementType();
if(!ScalarTypeFunc::isNumeric(scalarType)) {
throw std::logic_error(
"PvaClientData::getDoubleArray() did not find a numeric scalarArray field");
}
shared_vector<const double> retValue;
pvScalarArray->getAs<const double>(retValue);
return retValue;
}
shared_vector<const string> PvaClientData::getStringArray()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getStringArray\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
if(type!=scalarArray) {
throw std::logic_error("PvaClientData::getStringArray() did not find a scalarArray field");
}
PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
shared_vector<const string> retValue;
pvScalarArray->getAs<const string>(retValue);
return retValue;
}
Alarm PvaClientData::getAlarm()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getAlarm\n";
if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("alarm");
if(!pvs) throw std::runtime_error(messagePrefix + noAlarm);
pvAlarm.attach(pvs);
if(pvAlarm.isAttached()) {
Alarm alarm;
pvAlarm.get(alarm);
pvAlarm.detach();
return alarm;
}
throw std::runtime_error(messagePrefix + noAlarm);
}
TimeStamp PvaClientData::getTimeStamp()
{
if(PvaClient::getDebug()) cout << "PvaClientData::getTimeStamp\n";
if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("timeStamp");
if(!pvs) throw std::runtime_error(messagePrefix + noTimeStamp);
pvTimeStamp.attach(pvs);
if(pvTimeStamp.isAttached()) {
TimeStamp timeStamp;
pvTimeStamp.get(timeStamp);
pvTimeStamp.detach();
return timeStamp;
}
throw std::runtime_error(messagePrefix + noTimeStamp);
}
void PvaClientData::zeroArrayLength()
{
if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
zeroArrayLength(pvStructure);
}
void PvaClientData::parse(
const std::string &arg,const PVFieldPtr &dest,BitSetPtr & bitSet)
{
#ifdef USE_JSON
std::istringstream strm(arg);
parseJSON(strm, dest,&(*bitSet));
#else
throw std::runtime_error("JSON support not built");
#endif
}
void PvaClientData::parse(
const std::string &arg,const PVUnionPtr &pvUnion)
{
if(pvUnion->getUnion()->isVariant()) {
throw std::runtime_error(messagePrefix + "varient union not implemented");
}
size_t iequals = arg.find_first_of('=');
string field;
string rest;
if(iequals==std::string::npos) {
string mess(arg);
mess += " was expected to start with field=";
throw std::runtime_error(messagePrefix + mess);
}
field = arg.substr(0,iequals);
rest = arg.substr(iequals+1);
PVFieldPtr pvField(pvUnion->select(field));
if(pvField->getField()->getType()==epics::pvData::union_) {
PVUnionPtr pvu = static_pointer_cast<PVUnion>(pvField);
parse(rest,pvu);
return;
}
BitSetPtr bs;
parse(rest,pvField,bs);
return;
}
void PvaClientData::parse(const std::vector<std::string> &args)
{
if(!pvStructure) throw std::runtime_error(messagePrefix + noStructure);
if(!bitSet) throw std::runtime_error(messagePrefix + noStructure);
size_t num = args.size();
if(num<1) throw std::runtime_error(messagePrefix + " no arguments");
for(size_t i=0; i<num; ++i)
{
string val = args[i];
size_t iequals = val.find_first_of('=');
string field;
string rest(val);
if(iequals==std::string::npos) {
parse(rest,pvStructure,bitSet);
continue;
}
field = val.substr(0,iequals);
rest = val.substr(iequals+1);
if(field.size()==std::string::npos) {
parse(rest,pvStructure,bitSet);
continue;
}
PVFieldPtr pvField(pvStructure->getSubField(field));
if(!pvField) throw std::runtime_error(messagePrefix + field +" does not exist");
// look for enumerated structure
PVEnumerated pvEnumerated;
bool result = pvEnumerated.attach(pvField);
if(result) {
PVStringArray::const_svector choices(pvEnumerated.getChoices());
for(size_t i=0; i<choices.size(); ++i) {
if(choices[i]==rest) {
pvEnumerated.setIndex(i);
return;
}
}
}
// look for union
PVUnionPtr pvUnion(pvStructure->getSubField<PVUnion>(field));
if(pvUnion) {
parse(rest,pvUnion);
bitSet->set(pvUnion->getFieldOffset());
return;
}
parse(rest,pvField,bitSet);
}
}
void PvaClientData::streamJSON(
std::ostream& strm,
bool ignoreUnprintable,
bool multiLine)
{
#ifdef USE_JSON
JSONPrintOptions opts;
opts.ignoreUnprintable = ignoreUnprintable;
opts.multiLine = multiLine;
printJSON(strm,*pvStructure,*bitSet,opts);
#else
throw std::runtime_error("JSON support not built");
#endif
}
void PvaClientData::zeroArrayLength(const PVStructurePtr &pvStructure)
{
const PVFieldPtrArray pvFields(pvStructure->getPVFields());
for(size_t i=0; i<pvFields.size(); ++i) {
PVFieldPtr pvField = pvFields[i];
Type type(pvField->getField()->getType());
switch(type) {
case scalarArray:
{
PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
pvScalarArray->setLength(0);
}
break;
case structureArray:
{
PVStructureArrayPtr pvStructureArray = static_pointer_cast<PVStructureArray>(pvField);
pvStructureArray->setLength(0);
}
break;
case epics::pvData::structure:
{
PVStructurePtr pvStructure = static_pointer_cast<PVStructure>(pvField);
zeroArrayLength(pvStructure);
}
break;
default:
break;
}
}
}
}}
+174 -90
View File
@@ -8,81 +8,140 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <pv/event.h> #include <pv/event.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h> #include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
class ChannelGetRequesterImpl : public ChannelGetRequester class ChannelGetRequesterImpl : public ChannelGetRequester
{ {
PvaClientGet * pvaClientGet; PvaClientGet::weak_pointer pvaClientGet;
PvaClient::weak_pointer pvaClient;
public: public:
ChannelGetRequesterImpl(PvaClientGet * pvaClientGet) ChannelGetRequesterImpl(
: pvaClientGet(pvaClientGet) {} PvaClientGetPtr const & pvaClientGet,
string getRequesterName() PvaClientPtr const &pvaClient)
{return pvaClientGet->getRequesterName();} : pvaClientGet(pvaClientGet),
void message(string const & message,MessageType messageType) pvaClient(pvaClient)
{pvaClientGet->message(message,messageType);} {}
void channelGetConnect( virtual ~ChannelGetRequesterImpl() {
if(PvaClient::getDebug()) std::cout << "~ChannelGetRequesterImpl" << std::endl;
}
virtual std::string getRequesterName() {
PvaClientGetPtr clientGet(pvaClientGet.lock());
if(!clientGet) return string("clientGet is null");
return clientGet->getRequesterName();
}
virtual void message(std::string const & message, MessageType messageType) {
PvaClientGetPtr clientGet(pvaClientGet.lock());
if(!clientGet) return;
clientGet->message(message,messageType);
}
virtual void channelGetConnect(
const Status& status, const Status& status,
ChannelGet::shared_pointer const & channelGet, ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const & structure) Structure::const_shared_pointer const & structure)
{pvaClientGet->channelGetConnect(status,channelGet,structure);} {
void getDone( PvaClientGetPtr clientGet(pvaClientGet.lock());
if(!clientGet) return;
clientGet->channelGetConnect(status,channelGet,structure);
}
virtual void getDone(
const Status& status, const Status& status,
ChannelGet::shared_pointer const & channelGet, ChannelGet::shared_pointer const & channelGet,
PVStructurePtr const & pvStructure, PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet) BitSet::shared_pointer const & bitSet)
{pvaClientGet->getDone(status,channelGet,pvStructure,bitSet);} {
PvaClientGetPtr clientGet(pvaClientGet.lock());
if(!clientGet) return;
clientGet->getDone(status,channelGet,pvStructure,bitSet);
}
}; };
PvaClientGetPtr PvaClientGet::create(
PvaClientPtr const &pvaClient,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientGet::create(pvaClient,channelName,pvRequest)\n"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " pvRequest " << pvRequest
<< endl;
}
PvaClientGetPtr clientGet(new PvaClientGet(pvaClient,pvaClientChannel,pvRequest));
clientGet->channelGetRequester = ChannelGetRequesterImplPtr(
new ChannelGetRequesterImpl(clientGet,pvaClient));
return clientGet;
}
PvaClientGet::PvaClientGet( PvaClientGet::PvaClientGet(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel, PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest) PVStructurePtr const &pvRequest)
: pvaClient(pvaClient), : pvaClient(pvaClient),
channel(channel), pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest), pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle), connectState(connectIdle),
getState(getIdle) getState(getIdle)
{ {
if(PvaClient::getDebug()) {
cout << "PvaClientGet::PvaClientGet channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
} }
PvaClientGet::~PvaClientGet() PvaClientGet::~PvaClientGet()
{ {
destroy(); if(PvaClient::getDebug()) {
cout<< "PvaClientGet::~PvaClientGet channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
} }
void PvaClientGet::checkGetState()
void PvaClientGet::checkConnectState()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
if(connectState==connectIdle) connect(); cout << "PvaClientGet::checkConnectState channelName "
if(getState==getIdle) get(); << pvaClientChannel->getChannel()->getChannelName() << "\n";
}
if(!pvaClientChannel->getChannel()->isConnected()) {
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientGet::checkConnectState channel not connected ";
throw std::runtime_error(message);
}
if(connectState==connectIdle) {
connect();
}
if(connectState==connectActive){
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " "
+ channelGetConnectStatus.getMessage();
throw std::runtime_error(message);
}
} }
// from ChannelGetRequester
string PvaClientGet::getRequesterName() string PvaClientGet::getRequesterName()
{ {
PvaClientPtr yyy = pvaClient.lock(); return pvaClientChannel->getRequesterName();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
} }
void PvaClientGet::message(string const & message,MessageType messageType) void PvaClientGet::message(string const & message,MessageType messageType)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); pvaClientChannel->message(message,messageType);
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
} }
void PvaClientGet::channelGetConnect( void PvaClientGet::channelGetConnect(
@@ -90,16 +149,27 @@ void PvaClientGet::channelGetConnect(
ChannelGet::shared_pointer const & channelGet, ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const & structure) StructureConstPtr const & structure)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
channelGetConnectStatus = status; cout << "PvaClientGet::channelGetConnect channelName "
this->channelGet = channelGet; << pvaClientChannel->getChannel()->getChannelName()
if(status.isOK()) { << " status.isOK " << (status.isOK() ? "true" : "false")
pvaClientData = PvaClientGetData::create(structure); << "\n";
pvaClientData->setMessagePrefix(channel->getChannelName());
connectState = connected;
} }
waitForConnect.signal(); {
Lock xx(mutex);
channelGetConnectStatus = status;
if(status.isOK()) {
this->channelGet = channelGet;
connectState = connected;
pvaClientData = PvaClientGetData::create(structure);
pvaClientData->setMessagePrefix(channelGet->getChannel()->getChannelName());
}
waitForConnect.signal();
}
PvaClientGetRequesterPtr req(pvaClientGetRequester.lock());
if(req) {
req->channelGetConnect(status,shared_from_this());
}
} }
void PvaClientGet::getDone( void PvaClientGet::getDone(
@@ -108,82 +178,90 @@ void PvaClientGet::getDone(
PVStructurePtr const & pvStructure, PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet) BitSetPtr const & bitSet)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
channelGetStatus = status; cout << "PvaClientGet::getDone channelName "
if(status.isOK()) { << pvaClientChannel->getChannel()->getChannelName()
pvaClientData->setData(pvStructure,bitSet); << " status.isOK " << (status.isOK() ? "true" : "false")
<< "\n";
} }
waitForGet.signal();
}
// from PvaClientGet
void PvaClientGet::destroy()
{
{ {
Lock xx(mutex); Lock xx(mutex);
if(isDestroyed) return; channelGetStatus = status;
isDestroyed = true; if(status.isOK()) {
pvaClientData->setData(pvStructure,bitSet);
}
getState = getComplete;
waitForGet.signal();
}
PvaClientGetRequesterPtr req(pvaClientGetRequester.lock());
if(req) {
req->getDone(status,shared_from_this());
} }
if(channelGet) channelGet->destroy();
channelGet.reset();
} }
void PvaClientGet::connect() void PvaClientGet::connect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientGet::connect channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
issueConnect(); issueConnect();
Status status = waitConnect(); Status status = waitConnect();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientGet::connect " + status.getMessage(); + " PvaClientGet::connect " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientGet::issueConnect() void PvaClientGet::issueConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientGet::issueConnect channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
if(connectState!=connectIdle) { if(connectState!=connectIdle) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientGet already connected "; + " pvaClientGet already connected ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
getRequester = ChannelGetRequester::shared_pointer(new ChannelGetRequesterImpl(this));
connectState = connectActive; connectState = connectActive;
channelGet = channel->createChannelGet(getRequester,pvRequest); channelGetConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelGet = pvaClientChannel->getChannel()->createChannelGet(channelGetRequester,pvRequest);
} }
Status PvaClientGet::waitConnect() Status PvaClientGet::waitConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
if(connectState==connected) return channelGetConnectStatus; cout << "PvaClientGet::waitConnect channelName "
if(connectState!=connectActive) { << pvaClientChannel->getChannel()->getChannelName() << "\n";
string message = string("channel ") + channel->getChannelName()
+ " pvaClientGet illegal connect state ";
throw std::runtime_error(message);
} }
waitForConnect.wait(); waitForConnect.wait();
connectState = channelGetConnectStatus.isOK() ? connected : connectIdle;
return channelGetConnectStatus; return channelGetConnectStatus;
} }
void PvaClientGet::get() void PvaClientGet::get()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientGet::get channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
issueGet(); issueGet();
Status status = waitGet(); Status status = waitGet();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientGet::get " + status.getMessage(); + " PvaClientGet::get " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientGet::issueGet() void PvaClientGet::issueGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientGet::issueGet channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(getState!=getIdle) { if(getState==getActive) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientGet::issueGet get aleady active "; + " PvaClientGet::issueGet get aleady active ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
@@ -193,32 +271,38 @@ void PvaClientGet::issueGet()
Status PvaClientGet::waitGet() Status PvaClientGet::waitGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed"); if(PvaClient::getDebug()) {
if(getState!=getActive){ cout << "PvaClientGet::waitGet channelName "
string message = string("channel ") + channel->getChannelName() << pvaClientChannel->getChannel()->getChannelName() << "\n";
+ " PvaClientGet::waitGet llegal get state";
throw std::runtime_error(message);
} }
waitForGet.wait(); waitForGet.wait();
getState = getIdle;
if(channelGetStatus.isOK()) {
return Status::Ok;
}
return channelGetStatus; return channelGetStatus;
} }
PvaClientGetDataPtr PvaClientGet::getData() PvaClientGetDataPtr PvaClientGet::getData()
{ {
checkGetState(); if(PvaClient::getDebug()) {
cout<< "PvaClientGet::getData channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
checkConnectState();
if(getState==getIdle) get();
return pvaClientData; return pvaClientData;
} }
PvaClientGetPtr PvaClientGet::create( void PvaClientGet::setRequester(PvaClientGetRequesterPtr const & pvaClientGetRequester)
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
{ {
PvaClientGetPtr epv(new PvaClientGet(pvaClient,channel,pvRequest)); if(PvaClient::getDebug()) {
return epv; cout << "PvaClientGet::setRequester channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
this->pvaClientGetRequester = pvaClientGetRequester;
} }
PvaClientChannelPtr PvaClientGet::getPvaClientChannel()
{
return pvaClientChannel;
}
}} }}
+7 -191
View File
@@ -8,17 +8,17 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <typeinfo> #include <typeinfo>
#include <sstream> #include <sstream>
#include <pv/pvaClient.h>
#include <pv/createRequest.h> #include <pv/createRequest.h>
#include <pv/convert.h> #include <pv/convert.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
@@ -26,199 +26,15 @@ using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
typedef std::tr1::shared_ptr<PVArray> PVArrayPtr;
static ConvertPtr convert = getConvert();
static string noStructure("no pvStructure ");
static string noValue("no value field");
static string noScalar("value is not a scalar");
static string notCompatibleScalar("value is not a compatible scalar");
static string noArray("value is not an array");
static string noScalarArray("value is not a scalarArray");
static string notDoubleArray("value is not a doubleArray");
static string notStringArray("value is not a stringArray");
static string noAlarm("no alarm");
static string noTimeStamp("no timeStamp");
PvaClientGetDataPtr PvaClientGetData::create(StructureConstPtr const & structure) PvaClientGetDataPtr PvaClientGetData::create(StructureConstPtr const & structure)
{ {
if(PvaClient::getDebug()) cout << "PvaClientGetData::create\n";
PvaClientGetDataPtr epv(new PvaClientGetData(structure)); PvaClientGetDataPtr epv(new PvaClientGetData(structure));
return epv; return epv;
} }
PvaClientGetData::PvaClientGetData(StructureConstPtr const & structure) PvaClientGetData::PvaClientGetData(StructureConstPtr const & structure)
: structure(structure) : PvaClientData(structure)
{ {}
messagePrefix = "";
}
void PvaClientGetData::checkValue()
{
if(pvValue) return;
throw std::runtime_error(messagePrefix + noValue);
}
void PvaClientGetData::setMessagePrefix(std::string const & value)
{
messagePrefix = value + " ";
}
StructureConstPtr PvaClientGetData::getStructure()
{return structure;}
PVStructurePtr PvaClientGetData::getPVStructure()
{
if(pvStructure) return pvStructure;
throw std::runtime_error(messagePrefix + noStructure);
}
BitSetPtr PvaClientGetData::getChangedBitSet()
{
if(bitSet)return bitSet;
throw std::runtime_error(messagePrefix + noStructure);
}
std::ostream & PvaClientGetData::showChanged(std::ostream & out)
{
if(!bitSet) throw std::runtime_error(messagePrefix + noStructure);
size_t nextSet = bitSet->nextSetBit(0);
PVFieldPtr pvField;
while(nextSet!=string::npos) {
if(nextSet==0) {
pvField = pvStructure;
} else {
pvField = pvStructure->getSubField(nextSet);
}
string name = pvField->getFullName();
out << name << " = " << pvField << endl;
nextSet = bitSet->nextSetBit(nextSet+1);
}
return out;
}
void PvaClientGetData::setData(
PVStructurePtr const & pvStructureFrom,
BitSetPtr const & bitSetFrom)
{
pvStructure = pvStructureFrom;
bitSet = bitSetFrom;
pvValue = pvStructure->getSubField("value");
}
bool PvaClientGetData::hasValue()
{
if(!pvValue) return false;
return true;
}
bool PvaClientGetData::isValueScalar()
{
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalar) return true;
return false;
}
bool PvaClientGetData::isValueScalarArray()
{
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalarArray) return true;
return false;
}
PVFieldPtr PvaClientGetData::getValue()
{
checkValue();
return pvValue;
}
PVScalarPtr PvaClientGetData::getScalarValue()
{
checkValue();
PVScalarPtr pv = pvStructure->getSubField<PVScalar>("value");
if(!pv) throw std::runtime_error(messagePrefix + noScalar);
return pv;
}
PVArrayPtr PvaClientGetData::getArrayValue()
{
checkValue();
PVArrayPtr pv = pvStructure->getSubField<PVArray>("value");
if(!pv) throw std::runtime_error(messagePrefix + noArray);
return pv;
}
PVScalarArrayPtr PvaClientGetData::getScalarArrayValue()
{
checkValue();
PVScalarArrayPtr pv = pvStructure->getSubField<PVScalarArray>("value");
if(!pv) throw std::runtime_error(messagePrefix + noScalarArray);
return pv;
}
double PvaClientGetData::getDouble()
{
PVScalarPtr pvScalar = getScalarValue();
ScalarType scalarType = pvScalar->getScalar()->getScalarType();
if(scalarType==pvDouble) {
PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar);
return pvDouble->get();
}
if(!ScalarTypeFunc::isNumeric(scalarType)) {
throw std::runtime_error(messagePrefix + notCompatibleScalar);
}
return convert->toDouble(pvScalar);
}
string PvaClientGetData::getString()
{
PVScalarPtr pvScalar = getScalarValue();
return convert->toString(pvScalar);
}
shared_vector<const double> PvaClientGetData::getDoubleArray()
{
checkValue();
PVDoubleArrayPtr pv = pvStructure->getSubField<PVDoubleArray>("value");
if(!pv) throw std::runtime_error(messagePrefix + notDoubleArray);
return pv->view();
}
shared_vector<const string> PvaClientGetData::getStringArray()
{
checkValue();
PVStringArrayPtr pv = pvStructure->getSubField<PVStringArray>("value");
if(!pv) throw std::runtime_error(messagePrefix + notStringArray);
return pv->view();
}
Alarm PvaClientGetData::getAlarm()
{
if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("alarm");
if(!pvs) throw std::runtime_error(messagePrefix + noAlarm);
pvAlarm.attach(pvs);
if(pvAlarm.isAttached()) {
Alarm alarm;
pvAlarm.get(alarm);
pvAlarm.detach();
return alarm;
}
throw std::runtime_error(messagePrefix + noAlarm);
}
TimeStamp PvaClientGetData::getTimeStamp()
{
if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("timeStamp");
if(!pvs) throw std::runtime_error(messagePrefix + noTimeStamp);
pvTimeStamp.attach(pvs);
if(pvTimeStamp.isAttached()) {
TimeStamp timeStamp;
pvTimeStamp.get(timeStamp);
pvTimeStamp.detach();
return timeStamp;
}
throw std::runtime_error(messagePrefix + noTimeStamp);
}
}} }}
+342 -97
View File
@@ -8,84 +8,205 @@
* @author mrk * @author mrk
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <sstream> #include <sstream>
#include <pv/event.h> #include <pv/event.h>
#include <pv/pvaClient.h>
#include <pv/bitSetUtil.h> #include <pv/bitSetUtil.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
class MonitorRequesterImpl : public MonitorRequester
class ChannelMonitorRequester : public MonitorRequester
{ {
PvaClientMonitor * pvaClientMonitor; PvaClientMonitor::weak_pointer pvaClientMonitor;
PvaClient::weak_pointer pvaClient;
public: public:
ChannelMonitorRequester(PvaClientMonitor * pvaClientMonitor) MonitorRequesterImpl(
: pvaClientMonitor(pvaClientMonitor) {} PvaClientMonitorPtr const & pvaClientMonitor,
string getRequesterName() PvaClientPtr const &pvaClient)
{return pvaClientMonitor->getRequesterName();} : pvaClientMonitor(pvaClientMonitor),
void message(string const & message,MessageType messageType) pvaClient(pvaClient)
{pvaClientMonitor->message(message,messageType);} {}
void monitorConnect( virtual ~MonitorRequesterImpl() {
if(PvaClient::getDebug()) std::cout << "~MonitorRequesterImpl" << std::endl;
}
virtual std::string getRequesterName() {
PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
if(!clientMonitor) return string("pvaClientMonitor is null");
return clientMonitor->getRequesterName();
}
virtual void message(std::string const & message, MessageType messageType) {
PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
if(!clientMonitor) return;
clientMonitor->message(message,messageType);
}
virtual void monitorConnect(
const Status& status, const Status& status,
Monitor::shared_pointer const & monitor, Monitor::shared_pointer const & monitor,
StructureConstPtr const & structure) Structure::const_shared_pointer const & structure)
{pvaClientMonitor->monitorConnect(status,monitor,structure);}
void monitorEvent(MonitorPtr const & monitor)
{ {
pvaClientMonitor->monitorEvent(monitor); PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
if(!clientMonitor) return;
clientMonitor->monitorConnect(status,monitor,structure);
}
virtual void unlisten(MonitorPtr const & monitor)
{
PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
if(!clientMonitor) return;
clientMonitor->unlisten(monitor);
}
virtual void monitorEvent(MonitorPtr const & monitor)
{
PvaClientMonitorPtr clientMonitor(pvaClientMonitor.lock());
if(!clientMonitor) return;
clientMonitor->monitorEvent(monitor);
} }
void unlisten(MonitorPtr const & monitor)
{pvaClientMonitor->unlisten();}
}; };
PvaClientMonitorPtr PvaClientMonitor::create(
PvaClientPtr const &pvaClient,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
{
PvaClientMonitorPtr clientMonitor(new PvaClientMonitor(pvaClient,pvaClientChannel,pvRequest));
clientMonitor->monitorRequester = MonitorRequesterImplPtr(
new MonitorRequesterImpl(clientMonitor,pvaClient));
return clientMonitor;
}
PvaClientMonitorPtr PvaClientMonitor::create(
PvaClientPtr const &pvaClient,
std::string const & channelName,
std::string const & providerName,
std::string const & request,
PvaClientChannelStateChangeRequesterPtr const & stateChangeRequester,
PvaClientMonitorRequesterPtr const & monitorRequester)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientMonitor::create(pvaClient,channelName,providerName,request,stateChangeRequester,monitorRequester)\n"
<< " channelName " << channelName
<< " providerName " << providerName
<< " request " << request
<< endl;
}
CreateRequest::shared_pointer createRequest(CreateRequest::create());
PVStructurePtr pvRequest(createRequest->createRequest(request));
if(!pvRequest) throw std::runtime_error(createRequest->getMessage());
PvaClientChannelPtr pvaClientChannel = pvaClient->createChannel(channelName,providerName);
PvaClientMonitorPtr clientMonitor(new PvaClientMonitor(pvaClient,pvaClientChannel,pvRequest));
clientMonitor->monitorRequester = MonitorRequesterImplPtr(
new MonitorRequesterImpl(clientMonitor,pvaClient));
if(stateChangeRequester) clientMonitor->pvaClientChannelStateChangeRequester = stateChangeRequester;
if(monitorRequester) clientMonitor->pvaClientMonitorRequester = monitorRequester;
pvaClientChannel->setStateChangeRequester(clientMonitor);
pvaClientChannel->issueConnect();
return clientMonitor;
}
PvaClientMonitor::PvaClientMonitor( PvaClientMonitor::PvaClientMonitor(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel, PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest) PVStructurePtr const &pvRequest)
: pvaClient(pvaClient), : pvaClient(pvaClient),
channel(channel), pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest), pvRequest(pvRequest),
isDestroyed(false), isStarted(false),
connectState(connectIdle), connectState(connectIdle),
userPoll(false), userPoll(false),
userWait(false) userWait(false)
{ {
if(PvaClient::getDebug()) {
cout<< "PvaClientMonitor::PvaClientMonitor\n"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
} }
PvaClientMonitor::~PvaClientMonitor() PvaClientMonitor::~PvaClientMonitor()
{ {
destroy(); if(PvaClient::getDebug()) {
cout<< "PvaClientMonitor::~PvaClientMonitor"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(monitor) {
if(isStarted) monitor->stop();
}
}
void PvaClientMonitor::channelStateChange(PvaClientChannelPtr const & channel, bool isConnected)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientMonitor::channelStateChange"
<< " channelName " << channel->getChannelName()
<< " isConnected " << (isConnected ? "true" : "false")
<< endl;
}
if(isConnected&&!monitor)
{
connectState = connectActive;
monitor = pvaClientChannel->getChannel()->createMonitor(monitorRequester,pvRequest);
}
PvaClientChannelStateChangeRequesterPtr req(pvaClientChannelStateChangeRequester.lock());
if(req) {
req->channelStateChange(channel,isConnected);
}
}
void PvaClientMonitor::event(PvaClientMonitorPtr const & monitor)
{
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::event"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
if(req) req->event(monitor);
} }
void PvaClientMonitor::checkMonitorState() void PvaClientMonitor::checkMonitorState()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
if(connectState==connectIdle) connect(); cout << "PvaClientMonitor::checkMonitorState"
if(connectState==connected) start(); << " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " connectState " << connectState
<< endl;
}
if(connectState==connectIdle) {
connect();
if(!isStarted) start();
return;
}
if(connectState==connectActive){
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " "
+ monitorConnectStatus.getMessage();
throw std::runtime_error(message);
}
} }
// from MonitorRequester
string PvaClientMonitor::getRequesterName() string PvaClientMonitor::getRequesterName()
{ {
PvaClientPtr yyy = pvaClient.lock(); return pvaClientChannel->getRequesterName();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
} }
void PvaClientMonitor::message(string const & message,MessageType messageType) void PvaClientMonitor::message(string const & message,MessageType messageType)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); pvaClientChannel->message(message,messageType);
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
} }
void PvaClientMonitor::monitorConnect( void PvaClientMonitor::monitorConnect(
@@ -93,119 +214,234 @@ void PvaClientMonitor::monitorConnect(
Monitor::shared_pointer const & monitor, Monitor::shared_pointer const & monitor,
StructureConstPtr const & structure) StructureConstPtr const & structure)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
connectStatus = status; cout << "PvaClientMonitor::monitorConnect"
this->monitor = monitor; << " channelName " << pvaClientChannel->getChannel()->getChannelName()
if(status.isOK()) { << " status.isOK " << (status.isOK() ? "true" : "false")
pvaClientData = PvaClientMonitorData::create(structure); << endl;
pvaClientData->setMessagePrefix(channel->getChannelName());
} }
waitForConnect.signal(); {
Lock xx(mutex);
monitorConnectStatus = status;
if(status.isOK()) {
this->monitor = monitor;
} else {
stringstream ss;
ss << pvRequest;
string message = string("\nPvaClientMonitor::monitorConnect)")
+ "\nchannelName=" + pvaClientChannel->getChannel()->getChannelName()
+ "\npvRequest\n" + ss.str()
+ "\nerror\n" + status.getMessage();
monitorConnectStatus = Status(Status::STATUSTYPE_ERROR,message);
waitForConnect.signal();
PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
if(req) req->monitorConnect(status,shared_from_this(),structure);
return;
}
}
bool signal = (connectState==connectWait) ? true : false;
connectState = connected;
if(isStarted) {
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::monitorConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " is already started "
<< endl;
}
waitForConnect.signal();
PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
if(req) req->monitorConnect(status,shared_from_this(),structure);
return;
}
pvaClientData = PvaClientMonitorData::create(structure);
pvaClientData->setMessagePrefix(pvaClientChannel->getChannel()->getChannelName());
if(signal) {
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::monitorConnect calling waitForConnect.signal\n";
}
waitForConnect.signal();
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::monitorConnect calling start\n";
}
start();
} else {
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::monitorConnect calling start\n";
}
start();
}
PvaClientMonitorRequesterPtr req(pvaClientMonitorRequester.lock());
if(req) req->monitorConnect(status,shared_from_this(),structure);
} }
void PvaClientMonitor::monitorEvent(MonitorPtr const & monitor) void PvaClientMonitor::monitorEvent(MonitorPtr const & monitor)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::monitorEvent"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock(); PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock();
if(req) req->event(getPtrSelf()); if(req) req->event(shared_from_this());
if(userWait) waitForEvent.signal(); if(userWait) waitForEvent.signal();
} }
void PvaClientMonitor::unlisten() void PvaClientMonitor::unlisten(MonitorPtr const & monitor)
{ {
destroy(); if(PvaClient::getDebug()) cout << "PvaClientMonitor::unlisten\n";
PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock();
if(req) {
req->unlisten();
}
} }
void PvaClientMonitor::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
if(monitor) monitor->destroy();
monitor.reset();
monitorElement.reset();
}
void PvaClientMonitor::connect() void PvaClientMonitor::connect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) cout << "PvaClientMonitor::connect\n";
issueConnect(); issueConnect();
Status status = waitConnect(); Status status = waitConnect();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientMonitor::connect " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientMonitor::connect "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientMonitor::issueConnect() void PvaClientMonitor::issueConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) cout << "PvaClientMonitor::issueConnect\n";
if(connectState!=connectIdle) { if(connectState!=connectIdle) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientMonitor already connected "; + " pvaClientMonitor already connected ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
monitorRequester = ChannelMonitorRequester::shared_pointer(new ChannelMonitorRequester(this)); connectState = connectWait;
connectState = connectActive; monitor = pvaClientChannel->getChannel()->createMonitor(monitorRequester,pvRequest);
monitor = channel->createMonitor(monitorRequester,pvRequest);
} }
Status PvaClientMonitor::waitConnect() Status PvaClientMonitor::waitConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=connectActive) { cout << "PvaClientMonitor::waitConnect "
string message = string("channel ") + channel->getChannelName() << pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientMonitor illegal connect state "; << endl;
throw std::runtime_error(message);
} }
waitForConnect.wait(); waitForConnect.wait();
connectState = connectStatus.isOK() ? connected : connectIdle; if(PvaClient::getDebug()) {
return connectStatus; cout << "PvaClientMonitor::waitConnect"
<< " monitorConnectStatus " << (monitorConnectStatus.isOK() ? "connected" : "not connected")
<< endl;
}
return monitorConnectStatus;
} }
void PvaClientMonitor::setRequester(PvaClientMonitorRequesterPtr const & pvaClientMonitorrRequester) void PvaClientMonitor::setRequester(PvaClientMonitorRequesterPtr const & pvaClientMonitorRequester)
{ {
this->pvaClientMonitorRequester = pvaClientMonitorrRequester; if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::setRequester"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
this->pvaClientMonitorRequester = pvaClientMonitorRequester;
} }
void PvaClientMonitor::start() void PvaClientMonitor::start()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
if(connectState==monitorStarted) return; cout << "PvaClientMonitor::start"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " connectState " << connectState
<< endl;
}
if(isStarted) {
return;
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(connectState!=connected) throw std::runtime_error("PvaClientMonitor::start illegal state"); if(connectState!=connected) {
connectState = monitorStarted; string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientMonitor::start illegal state ";
throw std::runtime_error(message);
}
isStarted = true;
monitor->start(); monitor->start();
} }
void PvaClientMonitor::start(string const & request)
{
if(PvaClient::getDebug()) {
cout<< "PvaMonitor::start(request)"
<< " request " << request
<< endl;
}
PvaClientPtr client(pvaClient.lock());
if(!client) throw std::runtime_error("pvaClient was deleted");
if(!pvaClientChannel->getChannel()->isConnected()) {
client->message(
"PvaClientMonitor::start(request) but not connected",
errorMessage);
return;
}
CreateRequest::shared_pointer createRequest(CreateRequest::create());
PVStructurePtr pvr(createRequest->createRequest(request));
if(!pvr) throw std::runtime_error(createRequest->getMessage());
if(monitor) {
if(isStarted) monitor->stop();
}
monitorRequester.reset();
monitor.reset();
isStarted = false;
connectState = connectIdle;
userPoll = false;
userWait = false;
monitorRequester = MonitorRequesterImplPtr(
new MonitorRequesterImpl(shared_from_this(),client));
pvRequest = pvr;
connect();
}
void PvaClientMonitor::stop() void PvaClientMonitor::stop()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=monitorStarted) return; cout << "PvaClientMonitor::stop"
connectState = connected; << " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(!isStarted) return;
isStarted = false;
monitor->stop(); monitor->stop();
} }
bool PvaClientMonitor::poll() bool PvaClientMonitor::poll()
{ {
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::poll"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkMonitorState(); checkMonitorState();
if(connectState!=monitorStarted) throw std::runtime_error("PvaClientMonitor::poll illegal state");
if(userPoll) throw std::runtime_error("PvaClientMonitor::poll did not release last");
monitorElement = monitor->poll(); monitorElement = monitor->poll();
if(!monitorElement) return false; if(!monitorElement) return false;
userPoll = true; userPoll = true;
pvaClientData->setData(monitorElement); pvaClientData->setData(monitorElement);
return true; return true;
} }
bool PvaClientMonitor::waitEvent(double secondsToWait) bool PvaClientMonitor::waitEvent(double secondsToWait)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=monitorStarted) throw std::runtime_error("PvaClientMonitor::waitEvent illegal state"); cout << "PvaClientMonitor::waitEvent"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(!isStarted) {
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientMonitor::waitEvent illegal state ";
throw std::runtime_error(message);
}
if(poll()) return true; if(poll()) return true;
userWait = true; userWait = true;
if(secondsToWait==0.0) { if(secondsToWait==0.0) {
@@ -219,26 +455,35 @@ bool PvaClientMonitor::waitEvent(double secondsToWait)
void PvaClientMonitor::releaseEvent() void PvaClientMonitor::releaseEvent()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=monitorStarted) throw std::runtime_error("PvaClientMonitor::poll illegal state"); cout << "PvaClientMonitor::releaseEvent"
if(!userPoll) throw std::runtime_error("PvaClientMonitor::releaseEvent did not call poll"); << " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(!userPoll) {
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientMonitor::releaseEvent did not call poll";
throw std::runtime_error(message);
}
userPoll = false; userPoll = false;
monitor->release(monitorElement); monitor->release(monitorElement);
} }
PvaClientChannelPtr PvaClientMonitor::getPvaClientChannel()
{
return pvaClientChannel;
}
PvaClientMonitorDataPtr PvaClientMonitor::getData() PvaClientMonitorDataPtr PvaClientMonitor::getData()
{ {
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::getData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkMonitorState(); checkMonitorState();
return pvaClientData; return pvaClientData;
} }
PvaClientMonitorPtr PvaClientMonitor::create(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
{
PvaClientMonitorPtr epv(new PvaClientMonitor(pvaClient,channel,pvRequest));
return epv;
}
}} }}
+10 -186
View File
@@ -8,17 +8,17 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <typeinfo> #include <typeinfo>
#include <sstream> #include <sstream>
#include <pv/pvaClient.h>
#include <pv/createRequest.h> #include <pv/createRequest.h>
#include <pv/convert.h> #include <pv/convert.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
@@ -52,43 +52,16 @@ PvaClientMonitorDataPtr PvaClientMonitorData::create(StructureConstPtr const & s
} }
PvaClientMonitorData::PvaClientMonitorData(StructureConstPtr const & structure) PvaClientMonitorData::PvaClientMonitorData(StructureConstPtr const & structure)
: structure(structure) : PvaClientData(structure)
{ {
messagePrefix = "";
} }
void PvaClientMonitorData::setData(MonitorElementPtr const & monitorElement) void PvaClientMonitorData::setData(MonitorElementPtr const & monitorElement)
{ {
pvStructure = monitorElement->pvStructurePtr; PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
changedBitSet = monitorElement->changedBitSet; BitSetPtr changedBitSet = monitorElement->changedBitSet;
PvaClientData::setData(pvStructure,changedBitSet);
overrunBitSet = monitorElement->overrunBitSet; overrunBitSet = monitorElement->overrunBitSet;
pvValue = pvStructure->getSubField("value");
}
void PvaClientMonitorData::checkValue()
{
if(pvValue) return;
throw std::runtime_error(messagePrefix + noValue);
}
void PvaClientMonitorData::setMessagePrefix(std::string const & value)
{
messagePrefix = value + " ";
}
StructureConstPtr PvaClientMonitorData::getStructure()
{return structure;}
PVStructurePtr PvaClientMonitorData::getPVStructure()
{
if(pvStructure) return pvStructure;
throw std::runtime_error(messagePrefix + noStructure);
}
BitSetPtr PvaClientMonitorData::getChangedBitSet()
{
if(!changedBitSet) throw std::runtime_error(messagePrefix + noStructure);
return changedBitSet;
} }
BitSetPtr PvaClientMonitorData::getOverrunBitSet() BitSetPtr PvaClientMonitorData::getOverrunBitSet()
@@ -97,24 +70,6 @@ BitSetPtr PvaClientMonitorData::getOverrunBitSet()
return overrunBitSet; return overrunBitSet;
} }
std::ostream & PvaClientMonitorData::showChanged(std::ostream & out)
{
if(!changedBitSet) throw std::runtime_error(messagePrefix + noStructure);
size_t nextSet = changedBitSet->nextSetBit(0);
PVFieldPtr pvField;
while(nextSet!=string::npos) {
if(nextSet==0) {
pvField = pvStructure;
} else {
pvField = pvStructure->getSubField(nextSet);
}
string name = pvField->getFullName();
out << name << " = " << pvField << endl;
nextSet = changedBitSet->nextSetBit(nextSet+1);
}
return out;
}
std::ostream & PvaClientMonitorData::showOverrun(std::ostream & out) std::ostream & PvaClientMonitorData::showOverrun(std::ostream & out)
{ {
if(!overrunBitSet) throw std::runtime_error(messagePrefix + noStructure); if(!overrunBitSet) throw std::runtime_error(messagePrefix + noStructure);
@@ -122,9 +77,9 @@ std::ostream & PvaClientMonitorData::showOverrun(std::ostream & out)
PVFieldPtr pvField; PVFieldPtr pvField;
while(nextSet!=string::npos) { while(nextSet!=string::npos) {
if(nextSet==0) { if(nextSet==0) {
pvField = pvStructure; pvField = getPVStructure();
} else { } else {
pvField = pvStructure->getSubField(nextSet); pvField = getPVStructure()->getSubField(nextSet);
} }
string name = pvField->getFullName(); string name = pvField->getFullName();
out << name << " = " << pvField << endl; out << name << " = " << pvField << endl;
@@ -133,135 +88,4 @@ std::ostream & PvaClientMonitorData::showOverrun(std::ostream & out)
return out; return out;
} }
bool PvaClientMonitorData::hasValue()
{
if(!pvValue) return false;
return true;
}
bool PvaClientMonitorData::isValueScalar()
{
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalar) return true;
return false;
}
bool PvaClientMonitorData::isValueScalarArray()
{
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalarArray) return true;
return false;
}
PVFieldPtr PvaClientMonitorData::getValue()
{
checkValue();
return pvValue;
}
PVScalarPtr PvaClientMonitorData::getScalarValue()
{
checkValue();
PVScalarPtr pv = pvStructure->getSubField<PVScalar>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + noScalar);
}
return pv;
}
PVArrayPtr PvaClientMonitorData::getArrayValue()
{
checkValue();
PVArrayPtr pv = pvStructure->getSubField<PVArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + noArray);
}
return pv;
}
PVScalarArrayPtr PvaClientMonitorData::getScalarArrayValue()
{
checkValue();
PVScalarArrayPtr pv = pvStructure->getSubField<PVScalarArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + noScalarArray);
}
return pv;
}
double PvaClientMonitorData::getDouble()
{
PVScalarPtr pvScalar = getScalarValue();
ScalarType scalarType = pvScalar->getScalar()->getScalarType();
if(scalarType==pvDouble) {
PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar);
return pvDouble->get();
}
if(!ScalarTypeFunc::isNumeric(scalarType)) {
throw std::runtime_error(messagePrefix + notCompatibleScalar);
}
return convert->toDouble(pvScalar);
}
string PvaClientMonitorData::getString()
{
PVScalarPtr pvScalar = getScalarValue();
return convert->toString(pvScalar);
}
shared_vector<const double> PvaClientMonitorData::getDoubleArray()
{
checkValue();
PVDoubleArrayPtr pv = pvStructure->getSubField<PVDoubleArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + notDoubleArray);
}
return pv->view();
}
shared_vector<const string> PvaClientMonitorData::getStringArray()
{
checkValue();
PVStringArrayPtr pv = pvStructure->getSubField<PVStringArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + notStringArray);
}
return pv->view();
}
Alarm PvaClientMonitorData::getAlarm()
{
if(!pvStructure) {
throw std::runtime_error(messagePrefix + noAlarm);
}
PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("alarm");
if(!pvs) throw std::runtime_error(messagePrefix + noAlarm);
pvAlarm.attach(pvs);
if(pvAlarm.isAttached()) {
Alarm alarm;
pvAlarm.get(alarm);
pvAlarm.detach();
return alarm;
}
throw std::runtime_error(messagePrefix + noAlarm);
}
TimeStamp PvaClientMonitorData::getTimeStamp()
{
if(!pvStructure) {
throw std::runtime_error(messagePrefix + noTimeStamp);
}
PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("timeStamp");
if(!pvs) throw std::runtime_error(messagePrefix + noTimeStamp);
pvTimeStamp.attach(pvs);
if(pvTimeStamp.isAttached()) {
TimeStamp timeStamp;
pvTimeStamp.get(timeStamp);
pvTimeStamp.detach();
return timeStamp;
}
throw std::runtime_error(messagePrefix + noTimeStamp);
}
}} }}
+44 -59
View File
@@ -8,16 +8,15 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <map> #include <map>
#include <pv/event.h> #include <pv/event.h>
#include <pv/lock.h> #include <pv/lock.h>
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h> #include <pv/pvaClientMultiChannel.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
@@ -29,71 +28,74 @@ static CreateRequest::shared_pointer createRequestPvt = CreateRequest::create()
PvaClientMultiChannelPtr PvaClientMultiChannel::create( PvaClientMultiChannelPtr PvaClientMultiChannel::create(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
epics::pvData::shared_vector<const string> const & channelNames, shared_vector<const string> const & channelNames,
string const & providerName, string const & providerName,
size_t maxNotConnected) size_t maxNotConnected,
shared_vector<const string> const & providerNames)
{ {
return PvaClientMultiChannelPtr( return PvaClientMultiChannelPtr(
new PvaClientMultiChannel(pvaClient,channelNames,providerName,maxNotConnected)); new PvaClientMultiChannel(
pvaClient,channelNames,providerName,maxNotConnected,providerNames));
} }
PvaClientMultiChannel::PvaClientMultiChannel( PvaClientMultiChannel::PvaClientMultiChannel(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
epics::pvData::shared_vector<const string> const & channelName, shared_vector<const string> const & channelNames,
string const & providerName, string const & providerName,
size_t maxNotConnected) size_t maxNotConnected,
shared_vector<const string> const & providerNames)
: pvaClient(pvaClient), : pvaClient(pvaClient),
channelName(channelName), channelNames(channelNames),
providerName(providerName), providerName(providerName),
maxNotConnected(maxNotConnected), maxNotConnected(maxNotConnected),
numChannel(channelName.size()), providerNames(providerNames),
numChannel(channelNames.size()),
numProviderNames(providerNames.size()),
numConnected(0), numConnected(0),
firstConnect(true),
pvaClientChannelArray(PvaClientChannelArray(numChannel,PvaClientChannelPtr())), pvaClientChannelArray(PvaClientChannelArray(numChannel,PvaClientChannelPtr())),
isConnected(shared_vector<epics::pvData::boolean>(numChannel,false)), isConnected(shared_vector<epics::pvData::boolean>(numChannel,false)),
createRequest(CreateRequest::create()), createRequest(CreateRequest::create())
isDestroyed(false)
{ {
if(PvaClient::getDebug()) cout<< "PvaClientMultiChannel::PvaClientMultiChannel()\n";
} }
PvaClientMultiChannel::~PvaClientMultiChannel() PvaClientMultiChannel::~PvaClientMultiChannel()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientMultiChannel::~PvaClientMultiChannel()\n";
}
void PvaClientMultiChannel::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
} }
void PvaClientMultiChannel::checkConnected() void PvaClientMultiChannel::checkConnected()
{ {
if(numConnected==0) connect(3.0); if(firstConnect) {
connect();
firstConnect = false;
}
} }
epics::pvData::shared_vector<const string> PvaClientMultiChannel::getChannelNames() shared_vector<const string> PvaClientMultiChannel::getChannelNames()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); return channelNames;
return channelName;
} }
Status PvaClientMultiChannel::connect(double timeout) Status PvaClientMultiChannel::connect(double timeout)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); if(!firstConnect) return Status::Ok;
firstConnect = false;
for(size_t i=0; i< numChannel; ++i) { for(size_t i=0; i< numChannel; ++i) {
pvaClientChannelArray[i] = pvaClient->createChannel(channelName[i],providerName); if(numProviderNames<=i) {
pvaClientChannelArray[i] = pvaClient->createChannel(channelNames[i],providerName);
} else {
pvaClientChannelArray[i] = pvaClient->createChannel(channelNames[i],providerNames[i]);
}
pvaClientChannelArray[i]->issueConnect(); pvaClientChannelArray[i]->issueConnect();
} }
Status returnStatus = Status::Ok; Status returnStatus = Status::Ok;
Status status = Status::Ok; Status status = Status::Ok;
size_t numBad = 0; size_t numBad = 0;
for(size_t i=0; i< numChannel; ++i) { for(size_t i=0; i< numChannel; ++i) {
if(numBad==0) { if(numBad==0) {
status = pvaClientChannelArray[i]->waitConnect(timeout); status = pvaClientChannelArray[i]->waitConnect(timeout);
} else { } else {
status = pvaClientChannelArray[i]->waitConnect(.001); status = pvaClientChannelArray[i]->waitConnect(.001);
@@ -101,11 +103,10 @@ Status PvaClientMultiChannel::connect(double timeout)
if(status.isOK()) { if(status.isOK()) {
++numConnected; ++numConnected;
isConnected[i] = true; isConnected[i] = true;
continue; } else {
if(returnStatus.isOK()) returnStatus = status;
++numBad;
} }
if(returnStatus.isOK()) returnStatus = status;
++numBad;
if(numBad>maxNotConnected) break;
} }
return numBad>maxNotConnected ? returnStatus : Status::Ok; return numBad>maxNotConnected ? returnStatus : Status::Ok;
} }
@@ -113,13 +114,11 @@ Status PvaClientMultiChannel::connect(double timeout)
bool PvaClientMultiChannel::allConnected() bool PvaClientMultiChannel::allConnected()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
return (numConnected==numChannel) ? true : false; return (numConnected==numChannel) ? true : false;
} }
bool PvaClientMultiChannel::connectionChange() bool PvaClientMultiChannel::connectionChange()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
for(size_t i=0; i<numChannel; ++i) { for(size_t i=0; i<numChannel; ++i) {
PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i]; PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i];
Channel::shared_pointer channel = pvaClientChannel->getChannel(); Channel::shared_pointer channel = pvaClientChannel->getChannel();
@@ -130,9 +129,8 @@ bool PvaClientMultiChannel::connectionChange()
return false; return false;
} }
epics::pvData::shared_vector<epics::pvData::boolean> PvaClientMultiChannel::getIsConnected() shared_vector<epics::pvData::boolean> PvaClientMultiChannel::getIsConnected()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
for(size_t i=0; i<numChannel; ++i) { for(size_t i=0; i<numChannel; ++i) {
PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i]; PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i];
if(!pvaClientChannel) { if(!pvaClientChannel) {
@@ -148,50 +146,43 @@ epics::pvData::shared_vector<epics::pvData::boolean> PvaClientMultiChannel::get
PvaClientChannelArray PvaClientMultiChannel::getPvaClientChannelArray() PvaClientChannelArray PvaClientMultiChannel::getPvaClientChannelArray()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
return pvaClientChannelArray; return pvaClientChannelArray;
} }
PvaClientPtr PvaClientMultiChannel::getPvaClient() PvaClientPtr PvaClientMultiChannel::getPvaClient()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
return pvaClient; return pvaClient;
} }
PvaClientMultiGetDoublePtr PvaClientMultiChannel::createGet() PvaClientMultiGetDoublePtr PvaClientMultiChannel::createGet()
{ {
checkConnected(); checkConnected();
return PvaClientMultiGetDouble::create(getPtrSelf(),pvaClientChannelArray); return PvaClientMultiGetDouble::create(shared_from_this(),pvaClientChannelArray);
} }
PvaClientMultiPutDoublePtr PvaClientMultiChannel::createPut() PvaClientMultiPutDoublePtr PvaClientMultiChannel::createPut()
{ {
checkConnected(); checkConnected();
return PvaClientMultiPutDouble::create(getPtrSelf(),pvaClientChannelArray); return PvaClientMultiPutDouble::create(shared_from_this(),pvaClientChannelArray);
} }
PvaClientMultiMonitorDoublePtr PvaClientMultiChannel::createMonitor() PvaClientMultiMonitorDoublePtr PvaClientMultiChannel::createMonitor()
{ {
checkConnected(); checkConnected();
return PvaClientMultiMonitorDouble::create(getPtrSelf(), pvaClientChannelArray); return PvaClientMultiMonitorDouble::create(shared_from_this(), pvaClientChannelArray);
} }
PvaClientNTMultiPutPtr PvaClientMultiChannel::createNTPut() PvaClientNTMultiPutPtr PvaClientMultiChannel::createNTPut()
{ {
checkConnected(); checkConnected();
return PvaClientNTMultiPut::create(getPtrSelf(), pvaClientChannelArray); return PvaClientNTMultiPut::create(shared_from_this(), pvaClientChannelArray);
} }
PvaClientNTMultiGetPtr PvaClientMultiChannel::createNTGet()
{
return createNTGet("value,alarm,timeStamp");
}
PvaClientNTMultiGetPtr PvaClientMultiChannel::createNTGet(std::string const &request) PvaClientNTMultiGetPtr PvaClientMultiChannel::createNTGet(std::string const &request)
{ {
checkConnected(); checkConnected();
@@ -201,13 +192,7 @@ PvaClientNTMultiGetPtr PvaClientMultiChannel::createNTGet(std::string const &req
+ createRequest->getMessage(); + createRequest->getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
return PvaClientNTMultiGet::create(getPtrSelf(), pvaClientChannelArray,pvRequest); return PvaClientNTMultiGet::create(shared_from_this(), pvaClientChannelArray,pvRequest);
}
PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor()
{
return createNTMonitor("value,alarm,timeStamp");
} }
PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor(std::string const &request) PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor(std::string const &request)
@@ -219,7 +204,7 @@ PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor(std::string co
+ createRequest->getMessage(); + createRequest->getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
return PvaClientNTMultiMonitor::create(getPtrSelf(), pvaClientChannelArray,pvRequest); return PvaClientNTMultiMonitor::create(shared_from_this(), pvaClientChannelArray,pvRequest);
} }
+23 -29
View File
@@ -9,24 +9,19 @@
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <epicsMath.h> #include <epicsMath.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::nt; using namespace epics::nt;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
PvaClientMultiGetDoublePtr PvaClientMultiGetDouble::create( PvaClientMultiGetDoublePtr PvaClientMultiGetDouble::create(
@@ -44,31 +39,21 @@ PvaClientMultiGetDouble::PvaClientMultiGetDouble(
: pvaClientMultiChannel(pvaClientMultiChannel), : pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray), pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()), nchannel(pvaClientChannelArray.size()),
doubleValue(shared_vector<double>(nchannel)), doubleValue( shared_vector<double>(nchannel)),
pvaClientGet(std::vector<PvaClientGetPtr>(nchannel,PvaClientGetPtr())), pvaClientGet(std::vector<PvaClientGetPtr>(nchannel,PvaClientGetPtr())),
isGetConnected(false), isGetConnected(false)
isDestroyed(false)
{ {
if(PvaClient::getDebug()) cout<< "PvaClientMultiGetDouble::PvaClientMultiGetDouble()\n";
} }
PvaClientMultiGetDouble::~PvaClientMultiGetDouble() PvaClientMultiGetDouble::~PvaClientMultiGetDouble()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientMultiGetDouble::~PvaClientMultiGetDouble()\n";
}
void PvaClientMultiGetDouble::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
} }
void PvaClientMultiGetDouble::connect() void PvaClientMultiGetDouble::connect()
{ {
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean>isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value"; string request = "value";
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
@@ -90,14 +75,14 @@ void PvaClientMultiGetDouble::connect()
isGetConnected = true; isGetConnected = true;
} }
epics::pvData::shared_vector<double> PvaClientMultiGetDouble::get() shared_vector<double> PvaClientMultiGetDouble::get()
{ {
if(!isGetConnected) connect(); if(!isGetConnected) connect();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
if(!pvaClientGet[i]) pvaClientGet[i]=pvaClientChannelArray[i]->createGet("value");
pvaClientGet[i]->issueGet(); pvaClientGet[i]->issueGet();
} }
} }
@@ -111,13 +96,22 @@ epics::pvData::shared_vector<double> PvaClientMultiGetDouble::get()
throw std::runtime_error(message); throw std::runtime_error(message);
} }
} }
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) if(isConnected[i])
{ {
PVStructurePtr pvStructure = pvaClientGet[i]->getData()->getPVStructure(); PVStructurePtr pvStructure = pvaClientGet[i]->getData()->getPVStructure();
doubleValue[i] = convert->toDouble(pvStructure->getSubField<PVScalar>("value")); PVScalarPtr pvScalar(pvStructure->getSubField<PVScalar>("value"));
if(pvScalar) {
ScalarType scalarType = pvScalar->getScalar()->getScalarType();
if(ScalarTypeFunc::isNumeric(scalarType)) {
doubleValue[i] = getConvert()->toDouble(pvScalar);
} else {
doubleValue[i] = epicsNAN;
}
} else {
doubleValue[i] = epicsNAN;
}
} else { } else {
doubleValue[i] = epicsNAN; doubleValue[i] = epicsNAN;
} }
+21 -26
View File
@@ -9,25 +9,19 @@
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <epicsThread.h> #include <epicsThread.h>
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h> #include <epicsMath.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::nt; using namespace epics::nt;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
PvaClientMultiMonitorDoublePtr PvaClientMultiMonitorDouble::create( PvaClientMultiMonitorDoublePtr PvaClientMultiMonitorDouble::create(
@@ -47,24 +41,14 @@ PvaClientMultiMonitorDouble::PvaClientMultiMonitorDouble(
nchannel(pvaClientChannelArray.size()), nchannel(pvaClientChannelArray.size()),
doubleValue(shared_vector<double>(nchannel,epicsNAN)), doubleValue(shared_vector<double>(nchannel,epicsNAN)),
pvaClientMonitor(std::vector<PvaClientMonitorPtr>(nchannel,PvaClientMonitorPtr())), pvaClientMonitor(std::vector<PvaClientMonitorPtr>(nchannel,PvaClientMonitorPtr())),
isMonitorConnected(false), isMonitorConnected(false)
isDestroyed(false)
{ {
if(PvaClient::getDebug()) cout<< "PvaClientMultiMonitorDouble::PvaClientMultiMonitorDouble()\n";
} }
PvaClientMultiMonitorDouble::~PvaClientMultiMonitorDouble() PvaClientMultiMonitorDouble::~PvaClientMultiMonitorDouble()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientMultiMonitorDouble::~PvaClientMultiMonitorDouble()\n";
}
void PvaClientMultiMonitorDouble::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
} }
void PvaClientMultiMonitorDouble::connect() void PvaClientMultiMonitorDouble::connect()
@@ -99,13 +83,24 @@ bool PvaClientMultiMonitorDouble::poll()
{ {
if(!isMonitorConnected){ if(!isMonitorConnected){
connect(); connect();
epicsThreadSleep(.01); epicsThreadSleep(.1);
} }
bool result = false; bool result = false;
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
if(!pvaClientMonitor[i]){
pvaClientMonitor[i] = pvaClientChannelArray[i]->createMonitor("value");
pvaClientMonitor[i]->issueConnect();
Status status = pvaClientMonitor[i]->waitConnect();
if(!status.isOK()) {
string message = string("channel ") + pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelMonitor::waitConnect " + status.getMessage();
throw std::runtime_error(message);
}
pvaClientMonitor[i]->start();
}
if(pvaClientMonitor[i]->poll()) { if(pvaClientMonitor[i]->poll()) {
doubleValue[i] = pvaClientMonitor[i]->getData()->getDouble(); doubleValue[i] = pvaClientMonitor[i]->getData()->getDouble();
pvaClientMonitor[i]->releaseEvent(); pvaClientMonitor[i]->releaseEvent();
@@ -132,7 +127,7 @@ bool PvaClientMultiMonitorDouble::waitEvent(double waitForEvent)
return false; return false;
} }
epics::pvData::shared_vector<double> PvaClientMultiMonitorDouble::get() shared_vector<double> PvaClientMultiMonitorDouble::get()
{ {
return doubleValue; return doubleValue;
} }
+20 -27
View File
@@ -9,25 +9,19 @@
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <epicsMath.h> #include <epicsMath.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::nt; using namespace epics::nt;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
static CreateRequest::shared_pointer createRequest = CreateRequest::create();
PvaClientMultiPutDoublePtr PvaClientMultiPutDouble::create( PvaClientMultiPutDoublePtr PvaClientMultiPutDouble::create(
@@ -46,27 +40,18 @@ PvaClientMultiPutDouble::PvaClientMultiPutDouble(
pvaClientChannelArray(pvaClientChannelArray), pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()), nchannel(pvaClientChannelArray.size()),
pvaClientPut(std::vector<PvaClientPutPtr>(nchannel,PvaClientPutPtr())), pvaClientPut(std::vector<PvaClientPutPtr>(nchannel,PvaClientPutPtr())),
isPutConnected(false), isPutConnected(false)
isDestroyed(false)
{ {
if(PvaClient::getDebug()) cout<< "PvaClientMultiPutDouble::PvaClientMultiPutDouble()\n";
} }
PvaClientMultiPutDouble::~PvaClientMultiPutDouble() PvaClientMultiPutDouble::~PvaClientMultiPutDouble()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientMultiPutDouble::~PvaClientMultiPutDouble()\n";
} }
void PvaClientMultiPutDouble::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
}
void PvaClientMultiPutDouble::connect() void PvaClientMultiPutDouble::connect()
{ {
@@ -91,7 +76,7 @@ void PvaClientMultiPutDouble::connect()
isPutConnected = true; isPutConnected = true;
} }
void PvaClientMultiPutDouble::put(epics::pvData::shared_vector<double> const &data) void PvaClientMultiPutDouble::put(shared_vector<double> const &data)
{ {
if(!isPutConnected) connect(); if(!isPutConnected) connect();
if(data.size()!=nchannel) { if(data.size()!=nchannel) {
@@ -101,10 +86,18 @@ void PvaClientMultiPutDouble::put(epics::pvData::shared_vector<double> const &da
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
if(!pvaClientPut[i]) pvaClientPut[i]=pvaClientChannelArray[i]->createPut("value");
PVStructurePtr pvTop = pvaClientPut[i]->getData()->getPVStructure(); PVStructurePtr pvTop = pvaClientPut[i]->getData()->getPVStructure();
PVScalarPtr pvValue = pvTop->getSubField<PVScalar>("value"); PVScalarPtr pvScalar= pvTop->getSubField<PVScalar>("value");
convert->fromDouble(pvValue,data[i]); if(pvScalar && ScalarTypeFunc::isNumeric(pvScalar->getScalar()->getScalarType())) {
pvaClientPut[i]->issuePut(); getConvert()->fromDouble(pvScalar,data[i]);
pvaClientPut[i]->issuePut();
} else {
string message = string("channel ")
+ pvaClientChannelArray[i]->getChannelName()
+ " is not a numeric scalar";
throw std::runtime_error(message);
}
} }
if(isConnected[i]) { if(isConnected[i]) {
Status status = pvaClientPut[i]->waitPut(); Status status = pvaClientPut[i]->waitPut();
+62 -59
View File
@@ -9,23 +9,21 @@
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <epicsMath.h> #include <epicsMath.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::nt; using namespace epics::nt;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
PvaClientNTMultiDataPtr PvaClientNTMultiData::create( PvaClientNTMultiDataPtr PvaClientNTMultiData::create(
epics::pvData::UnionConstPtr const & u, UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaMultiChannel, PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest) PVStructurePtr const & pvRequest)
@@ -35,23 +33,23 @@ PvaClientNTMultiDataPtr PvaClientNTMultiData::create(
} }
PvaClientNTMultiData::PvaClientNTMultiData( PvaClientNTMultiData::PvaClientNTMultiData(
epics::pvData::UnionConstPtr const & u, UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest) PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel), : pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray), pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()), nchannel(pvaClientChannelArray.size()),
gotAlarm(false), gotAlarm(false),
gotTimeStamp(false), gotTimeStamp(false)
isDestroyed(false)
{ {
PVFieldPtr pvValue = pvRequest->getSubField("field.value"); if(PvaClient::getDebug()) cout<< "PvaClientNTMultiData::PvaClientNTMultiData()\n";
if(!pvValue) { changeFlags = shared_vector<epics::pvData::boolean>(nchannel);
throw std::runtime_error("pvRequest did not specify value");
}
topPVStructure.resize(nchannel); topPVStructure.resize(nchannel);
unionValue.resize(nchannel); unionValue.resize(nchannel);
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i< nchannel; ++i) { for(size_t i=0; i< nchannel; ++i) {
topPVStructure[i] = PVStructurePtr(); topPVStructure[i] = PVStructurePtr();
unionValue[i] = pvDataCreate->createPVUnion(u); unionValue[i] = pvDataCreate->createPVUnion(u);
@@ -68,7 +66,7 @@ PvaClientNTMultiData::PvaClientNTMultiData(
severity.resize(nchannel); severity.resize(nchannel);
status.resize(nchannel); status.resize(nchannel);
message.resize(nchannel); message.resize(nchannel);
} }
if(pvRequest->getSubField("field.timeStamp")) { if(pvRequest->getSubField("field.timeStamp")) {
gotTimeStamp = true; gotTimeStamp = true;
@@ -86,28 +84,7 @@ PvaClientNTMultiData::PvaClientNTMultiData(
PvaClientNTMultiData::~PvaClientNTMultiData() PvaClientNTMultiData::~PvaClientNTMultiData()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientNTMultiData::~PvaClientNTMultiData()\n";
}
void PvaClientNTMultiData::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
}
void PvaClientNTMultiData::setStructure(StructureConstPtr const & structure,size_t index)
{
FieldConstPtr field = structure->getField("value");
if(!field) {
string message = "channel "
+ pvaClientChannelArray[index]->getChannel()->getChannelName()
+ " does not have top level value field";
throw std::runtime_error(message);
}
} }
void PvaClientNTMultiData::setPVStructure( void PvaClientNTMultiData::setPVStructure(
@@ -116,12 +93,18 @@ void PvaClientNTMultiData::setPVStructure(
topPVStructure[index] = pvStructure; topPVStructure[index] = pvStructure;
} }
shared_vector<epics::pvData::boolean> PvaClientNTMultiData::getChannelChangeFlags()
{
return changeFlags;
}
size_t PvaClientNTMultiData::getNumber() size_t PvaClientNTMultiData::getNumber()
{ {
return nchannel; return nchannel;
} }
void PvaClientNTMultiData::startDeltaTime() void PvaClientNTMultiData::startDeltaTime()
{ {
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
@@ -147,29 +130,49 @@ void PvaClientNTMultiData::startDeltaTime()
} }
void PvaClientNTMultiData::endDeltaTime() void PvaClientNTMultiData::endDeltaTime(bool valueOnly)
{ {
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
PVStructurePtr pvst = topPVStructure[i]; PVStructurePtr pvst = topPVStructure[i];
if(!pvst) { changeFlags[i] = false;
unionValue[i] = PVUnionPtr(); if(pvst&&unionValue[i]) {
} else { changeFlags[i] = true;
unionValue[i]->set(pvst->getSubField("value")); if(valueOnly) {
PVFieldPtr pvValue = pvst->getSubField("value");
if(pvValue) {
unionValue[i]->set(pvst->getSubField("value"));
}
} else {
unionValue[i]->set(pvst);
}
if(gotAlarm)
{
PVIntPtr pvSeverity = pvst->getSubField<PVInt>("alarm.severity");
PVIntPtr pvStatus = pvst->getSubField<PVInt>("alarm.status");
PVStringPtr pvMessage = pvst->getSubField<PVString>("alarm.message");
if(pvSeverity&&pvStatus&&pvMessage) {
severity[i] = pvSeverity->get();
status[i] = pvStatus->get();
message[i] = pvMessage->get();
} else {
severity[i] = undefinedAlarm;
status[i] = undefinedStatus;
message[i] = "no alarm field";
}
}
if(gotTimeStamp)
{
PVLongPtr pvEpoch = pvst->getSubField<PVLong>("timeStamp.secondsPastEpoch");
PVIntPtr pvNano = pvst->getSubField<PVInt>("timeStamp.nanoseconds");
PVIntPtr pvTag = pvst->getSubField<PVInt>("timeStamp.userTag");
if(pvEpoch&&pvNano&&pvTag) {
secondsPastEpoch[i] = pvEpoch->get();
nanoseconds[i] = pvNano->get();
userTag[i] = pvTag->get();
}
}
} }
if(gotAlarm)
{
severity[i] = pvst->getSubField<PVInt>("alarm.severity")->get();
status[i] = pvst->getSubField<PVInt>("alarm.status")->get();
message[i] = pvst->getSubField<PVString>("alarm.message")->get();
}
if(gotTimeStamp)
{
secondsPastEpoch[i] = pvst->getSubField<PVLong>("timeStamp.secondsPastEpoch")->get();
nanoseconds[i] = pvst->getSubField<PVInt>("timeStamp.nanoseconds")->get();
userTag[i] = pvst->getSubField<PVInt>("timeStamp.userTag")->get();
}
} }
} }
@@ -181,10 +184,10 @@ TimeStamp PvaClientNTMultiData::getTimeStamp()
NTMultiChannelPtr PvaClientNTMultiData::getNTMultiChannel() NTMultiChannelPtr PvaClientNTMultiData::getNTMultiChannel()
{ {
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(ntMultiChannelStructure); PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(ntMultiChannelStructure);
NTMultiChannelPtr ntMultiChannel = NTMultiChannel::wrap(pvStructure); NTMultiChannelPtr ntMultiChannel = NTMultiChannel::wrap(pvStructure);
ntMultiChannel->getChannelName()->replace(pvaClientMultiChannel->getChannelNames()); ntMultiChannel->getChannelName()->replace(pvaClientMultiChannel->getChannelNames());
shared_vector<epics::pvData::PVUnionPtr> val(nchannel); shared_vector<PVUnionPtr> val(nchannel);
for(size_t i=0; i<nchannel; ++i) val[i] = unionValue[i]; for(size_t i=0; i<nchannel; ++i) val[i] = unionValue[i];
ntMultiChannel->getValue()->replace(freeze(val)); ntMultiChannel->getValue()->replace(freeze(val));
shared_vector<epics::pvData::boolean> connected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean> connected = pvaClientMultiChannel->getIsConnected();
+20 -35
View File
@@ -9,24 +9,18 @@
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h> #include <epicsMath.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::nt; using namespace epics::nt;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
PvaClientNTMultiGetPtr PvaClientNTMultiGet::create( PvaClientNTMultiGetPtr PvaClientNTMultiGet::create(
@@ -34,7 +28,7 @@ PvaClientNTMultiGetPtr PvaClientNTMultiGet::create(
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest) PVStructurePtr const & pvRequest)
{ {
UnionConstPtr u = fieldCreate->createVariantUnion(); UnionConstPtr u = getFieldCreate()->createVariantUnion();
PvaClientNTMultiGetPtr pvaClientNTMultiGet( PvaClientNTMultiGetPtr pvaClientNTMultiGet(
new PvaClientNTMultiGet(u,pvaMultiChannel,pvaClientChannelArray,pvRequest)); new PvaClientNTMultiGet(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiGet; return pvaClientNTMultiGet;
@@ -44,7 +38,7 @@ PvaClientNTMultiGet::PvaClientNTMultiGet(
UnionConstPtr const & u, UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel, PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest) PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel), : pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray), pvaClientChannelArray(pvaClientChannelArray),
pvRequest(pvRequest), pvRequest(pvRequest),
@@ -55,37 +49,24 @@ PvaClientNTMultiGet::PvaClientNTMultiGet(
pvaClientMultiChannel, pvaClientMultiChannel,
pvaClientChannelArray, pvaClientChannelArray,
pvRequest)), pvRequest)),
isConnected(false), isConnected(false)
isDestroyed(false)
{ {
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiGet::PvaClientNTMultiGet()\n";
} }
PvaClientNTMultiGet::~PvaClientNTMultiGet() PvaClientNTMultiGet::~PvaClientNTMultiGet()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientNTMultiGet::~PvaClientNTMultiGet()\n";
}
void PvaClientNTMultiGet::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
} }
void PvaClientNTMultiGet::connect() void PvaClientNTMultiGet::connect()
{ {
pvaClientGet.resize(nchannel); pvaClientGet.resize(nchannel);
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
if(pvRequest->getSubField("field.alarm")) request += ",alarm";
if(pvRequest->getSubField("field.timeStamp")) request += ",timeStamp";
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
pvaClientGet[i] = pvaClientChannelArray[i]->createGet(request); pvaClientGet[i] = pvaClientChannelArray[i]->createGet(pvRequest);
pvaClientGet[i]->issueConnect(); pvaClientGet[i]->issueConnect();
} }
} }
@@ -94,7 +75,7 @@ void PvaClientNTMultiGet::connect()
if(isConnected[i]) { if(isConnected[i]) {
Status status = pvaClientGet[i]->waitConnect(); Status status = pvaClientGet[i]->waitConnect();
if(status.isOK()) continue; if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName() string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelGet::waitConnect " + status.getMessage(); + " PvaChannelGet::waitConnect " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
@@ -102,14 +83,18 @@ void PvaClientNTMultiGet::connect()
this->isConnected = true; this->isConnected = true;
} }
void PvaClientNTMultiGet::get() void PvaClientNTMultiGet::get(bool valueOnly)
{ {
if(!isConnected) connect(); if(!isConnected) connect();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
if(!pvaClientGet[i]){
pvaClientGet[i]=pvaClientChannelArray[i]->createGet(pvRequest);
pvaClientGet[i]->connect();
}
pvaClientGet[i]->issueGet(); pvaClientGet[i]->issueGet();
} }
} }
@@ -118,7 +103,7 @@ void PvaClientNTMultiGet::get()
if(isConnected[i]) { if(isConnected[i]) {
Status status = pvaClientGet[i]->waitGet(); Status status = pvaClientGet[i]->waitGet();
if(status.isOK()) continue; if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName() string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelGet::waitGet " + status.getMessage(); + " PvaChannelGet::waitGet " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
@@ -130,7 +115,7 @@ void PvaClientNTMultiGet::get()
pvaClientNTMultiData->setPVStructure(pvaClientGet[i]->getData()->getPVStructure(),i); pvaClientNTMultiData->setPVStructure(pvaClientGet[i]->getData()->getPVStructure(),i);
} }
} }
pvaClientNTMultiData->endDeltaTime(); pvaClientNTMultiData->endDeltaTime(valueOnly);
} }
PvaClientNTMultiDataPtr PvaClientNTMultiGet::getData() PvaClientNTMultiDataPtr PvaClientNTMultiGet::getData()
+24 -33
View File
@@ -9,29 +9,28 @@
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <epicsThread.h> #include <epicsThread.h>
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h> #include <pv/standardField.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <epicsMath.h> #include <epicsMath.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::nt; using namespace epics::nt;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static FieldCreatePtr fieldCreate = getFieldCreate();
PvaClientNTMultiMonitorPtr PvaClientNTMultiMonitor::create( PvaClientNTMultiMonitorPtr PvaClientNTMultiMonitor::create(
PvaClientMultiChannelPtr const &pvaMultiChannel, PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray, PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest) PVStructurePtr const & pvRequest)
{ {
UnionConstPtr u = fieldCreate->createVariantUnion(); UnionConstPtr u = getFieldCreate()->createVariantUnion();
PvaClientNTMultiMonitorPtr pvaClientNTMultiMonitor( PvaClientNTMultiMonitorPtr pvaClientNTMultiMonitor(
new PvaClientNTMultiMonitor(u,pvaMultiChannel,pvaClientChannelArray,pvRequest)); new PvaClientNTMultiMonitor(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiMonitor; return pvaClientNTMultiMonitor;
@@ -52,25 +51,15 @@ PvaClientNTMultiMonitor::PvaClientNTMultiMonitor(
pvaClientMultiChannel, pvaClientMultiChannel,
pvaClientChannelArray, pvaClientChannelArray,
pvRequest)), pvRequest)),
isConnected(false), isConnected(false)
isDestroyed(false)
{ {
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiMonitor::PvaClientNTMultiMonitor()\n";
} }
PvaClientNTMultiMonitor::~PvaClientNTMultiMonitor() PvaClientNTMultiMonitor::~PvaClientNTMultiMonitor()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientNTMultiMonitor::~PvaClientNTMultiMonitor()\n";
}
void PvaClientNTMultiMonitor::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
} }
@@ -78,13 +67,10 @@ void PvaClientNTMultiMonitor::connect()
{ {
pvaClientMonitor.resize(nchannel); pvaClientMonitor.resize(nchannel);
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
if(pvRequest->getSubField("field.alarm")) request += ",alarm";
if(pvRequest->getSubField("field.timeStamp")) request += ",timeStamp";
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
pvaClientMonitor[i] = pvaClientChannelArray[i]->createMonitor(request); pvaClientMonitor[i] = pvaClientChannelArray[i]->createMonitor(pvRequest);
pvaClientMonitor[i]->issueConnect(); pvaClientMonitor[i]->issueConnect();
} }
} }
@@ -93,7 +79,7 @@ void PvaClientNTMultiMonitor::connect()
if(isConnected[i]) { if(isConnected[i]) {
Status status = pvaClientMonitor[i]->waitConnect(); Status status = pvaClientMonitor[i]->waitConnect();
if(status.isOK()) continue; if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName() string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelMonitor::waitConnect " + status.getMessage(); + " PvaChannelMonitor::waitConnect " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
@@ -105,24 +91,29 @@ void PvaClientNTMultiMonitor::connect()
this->isConnected = true; this->isConnected = true;
} }
bool PvaClientNTMultiMonitor::poll() bool PvaClientNTMultiMonitor::poll(bool valueOnly)
{ {
if(!isConnected) connect(); if(!isConnected) connect();
bool result = false; bool result = false;
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected(); shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
pvaClientNTMultiData->startDeltaTime(); pvaClientNTMultiData->startDeltaTime();
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
if(pvaClientMonitor[i]->poll()) { if(!pvaClientMonitor[i]){
pvaClientMonitor[i]=pvaClientChannelArray[i]->createMonitor(pvRequest);
pvaClientMonitor[i]->connect();
pvaClientMonitor[i]->start();
}
if(pvaClientMonitor[i]->poll()) {
pvaClientNTMultiData->setPVStructure( pvaClientNTMultiData->setPVStructure(
pvaClientMonitor[i]->getData()->getPVStructure(),i); pvaClientMonitor[i]->getData()->getPVStructure(),i);
pvaClientMonitor[i]->releaseEvent(); pvaClientMonitor[i]->releaseEvent();
result = true; result = true;
} }
} }
} }
if(result) pvaClientNTMultiData->endDeltaTime(); if(result) pvaClientNTMultiData->endDeltaTime(valueOnly);
return result; return result;
} }
+52 -32
View File
@@ -9,23 +9,20 @@
* @date 2015.03 * @date 2015.03
*/ */
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h> #include <pv/standardField.h>
#include <pv/convert.h> #include <pv/convert.h>
#include <epicsMath.h> #include <epicsMath.h>
using std::tr1::static_pointer_cast; #define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace epics::nt; using namespace epics::nt;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
PvaClientNTMultiPutPtr PvaClientNTMultiPut::create( PvaClientNTMultiPutPtr PvaClientNTMultiPut::create(
PvaClientMultiChannelPtr const &pvaMultiChannel, PvaClientMultiChannelPtr const &pvaMultiChannel,
@@ -41,27 +38,17 @@ PvaClientNTMultiPut::PvaClientNTMultiPut(
: pvaClientMultiChannel(pvaClientMultiChannel), : pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray), pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()), nchannel(pvaClientChannelArray.size()),
unionValue(shared_vector<epics::pvData::PVUnionPtr>(nchannel,PVUnionPtr())), unionValue(shared_vector<PVUnionPtr>(nchannel,PVUnionPtr())),
value(shared_vector<epics::pvData::PVFieldPtr>(nchannel,PVFieldPtr())), value(shared_vector<PVFieldPtr>(nchannel,PVFieldPtr())),
isConnected(false), isConnected(false)
isDestroyed(false)
{ {
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiPut::PvaClientNTMultiPut()\n";
} }
PvaClientNTMultiPut::~PvaClientNTMultiPut() PvaClientNTMultiPut::~PvaClientNTMultiPut()
{ {
destroy(); if(PvaClient::getDebug()) cout<< "PvaClientNTMultiPut::~PvaClientNTMultiPut()\n";
}
void PvaClientNTMultiPut::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
} }
void PvaClientNTMultiPut::connect() void PvaClientNTMultiPut::connect()
@@ -80,7 +67,7 @@ void PvaClientNTMultiPut::connect()
if(isConnected[i]) { if(isConnected[i]) {
Status status = pvaClientPut[i]->waitConnect(); Status status = pvaClientPut[i]->waitConnect();
if(status.isOK()) continue; if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName() string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelPut::waitConnect " + status.getMessage(); + " PvaChannelPut::waitConnect " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
@@ -96,11 +83,13 @@ void PvaClientNTMultiPut::connect()
if(isConnected[i]) { if(isConnected[i]) {
Status status = pvaClientPut[i]->waitGet(); Status status = pvaClientPut[i]->waitGet();
if(status.isOK()) continue; if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName() string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelPut::waitGet " + status.getMessage(); + " PvaChannelPut::waitGet " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
} }
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
@@ -113,9 +102,26 @@ void PvaClientNTMultiPut::connect()
this->isConnected = true; this->isConnected = true;
} }
shared_vector<epics::pvData::PVUnionPtr> PvaClientNTMultiPut::getValues() shared_vector<PVUnionPtr> PvaClientNTMultiPut::getValues()
{ {
if(!isConnected) connect(); if(!isConnected) connect();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
if(!pvaClientPut[i]){
pvaClientPut[i] = pvaClientChannelArray[i]->createPut();
pvaClientPut[i]->connect();
pvaClientPut[i]->get();
value[i] = pvaClientPut[i]->getData()->getValue();
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
FieldBuilderPtr builder = fieldCreate->createFieldBuilder();
builder->add("value",value[i]->getField());
unionValue[i] = pvDataCreate->createPVUnion(builder->createUnion());
}
}
}
return unionValue; return unionValue;
} }
@@ -126,15 +132,29 @@ void PvaClientNTMultiPut::put()
for(size_t i=0; i<nchannel; ++i) for(size_t i=0; i<nchannel; ++i)
{ {
if(isConnected[i]) { if(isConnected[i]) {
if(!pvaClientPut[i]){
pvaClientPut[i] = pvaClientChannelArray[i]->createPut();
pvaClientPut[i]->connect();
pvaClientPut[i]->get();
value[i] = pvaClientPut[i]->getData()->getValue();
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
FieldBuilderPtr builder = fieldCreate->createFieldBuilder();
builder->add("value",value[i]->getField());
unionValue[i] = pvDataCreate->createPVUnion(builder->createUnion());
}
value[i]->copy(*unionValue[i]->get()); value[i]->copy(*unionValue[i]->get());
pvaClientPut[i]->issuePut(); pvaClientPut[i]->issuePut();
} }
if(isConnected[i]) { }
Status status = pvaClientPut[i]->waitPut(); for(size_t i=0; i<nchannel; ++i)
if(status.isOK()) continue; {
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName() if(isConnected[i]) {
+ " PvaChannelPut::waitPut " + status.getMessage(); Status status = pvaClientPut[i]->waitPut();
throw std::runtime_error(message); if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelPut::waitPut " + status.getMessage();
throw std::runtime_error(message);
} }
} }
} }
+154 -74
View File
@@ -8,160 +8,234 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <pv/event.h> #include <pv/event.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h> #include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
class ChannelProcessRequesterImpl : public ChannelProcessRequester class ChannelProcessRequesterImpl : public ChannelProcessRequester
{ {
PvaClientProcess * pvaClientProcess; PvaClientProcess::weak_pointer pvaClientProcess;
PvaClient::weak_pointer pvaClient;
public: public:
ChannelProcessRequesterImpl(PvaClientProcess * pvaClientProcess) ChannelProcessRequesterImpl(
: pvaClientProcess(pvaClientProcess) {} PvaClientProcessPtr const & pvaClientProcess,
string getRequesterName() PvaClientPtr const &pvaClient)
{return pvaClientProcess->getRequesterName();} : pvaClientProcess(pvaClientProcess),
void message(string const & message,MessageType messageType) pvaClient(pvaClient)
{pvaClientProcess->message(message,messageType);} {}
void channelProcessConnect( virtual ~ChannelProcessRequesterImpl() {
if(PvaClient::getDebug()) std::cout << "~ChannelProcessRequesterImpl" << std::endl;
}
virtual std::string getRequesterName() {
PvaClientProcessPtr clientProcess(pvaClientProcess.lock());
if(!clientProcess) return string("clientProcess is null");
return clientProcess->getRequesterName();
}
virtual void message(std::string const & message, MessageType messageType) {
PvaClientProcessPtr clientProcess(pvaClientProcess.lock());
if(!clientProcess) return;
clientProcess->message(message,messageType);
}
virtual void channelProcessConnect(
const Status& status, const Status& status,
ChannelProcess::shared_pointer const & channelProcess) ChannelProcess::shared_pointer const & channelProcess)
{pvaClientProcess->channelProcessConnect(status,channelProcess);} {
void processDone( PvaClientProcessPtr clientProcess(pvaClientProcess.lock());
if(!clientProcess) return;
clientProcess->channelProcessConnect(status,channelProcess);
}
virtual void processDone(
const Status& status, const Status& status,
ChannelProcess::shared_pointer const & channelProcess) ChannelProcess::shared_pointer const & ChannelProcess)
{pvaClientProcess->processDone(status,channelProcess);} {
PvaClientProcessPtr clientProcess(pvaClientProcess.lock());
if(!clientProcess) return;
clientProcess->processDone(status,ChannelProcess);
}
}; };
PvaClientProcessPtr PvaClientProcess::create(
PvaClientPtr const &pvaClient,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientProcess::create(pvaClient,channelName,pvRequest)\n"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " pvRequest " << pvRequest
<< endl;
}
PvaClientProcessPtr channelProcess(new PvaClientProcess(pvaClient,pvaClientChannel,pvRequest));
channelProcess->channelProcessRequester = ChannelProcessRequesterImplPtr(
new ChannelProcessRequesterImpl(channelProcess,pvaClient));
return channelProcess;
}
PvaClientProcess::PvaClientProcess( PvaClientProcess::PvaClientProcess(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel, PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest) PVStructurePtr const &pvRequest)
: pvaClient(pvaClient), : pvaClient(pvaClient),
channel(channel), pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest), pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle), connectState(connectIdle),
processState(processIdle) processState(processIdle)
{ {
if(PvaClient::getDebug()) {
cout<< "PvaClientProcess::PvaClientProcess()"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
} }
PvaClientProcess::~PvaClientProcess() PvaClientProcess::~PvaClientProcess()
{ {
destroy(); if(PvaClient::getDebug()) {
cout<< "PvaClientProcess::~PvaClientProcess()"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
} }
// from ChannelProcessRequester
string PvaClientProcess::getRequesterName() string PvaClientProcess::getRequesterName()
{ {
PvaClientPtr yyy = pvaClient.lock(); return pvaClientChannel->getRequesterName();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
} }
void PvaClientProcess::message(string const & message,MessageType messageType) void PvaClientProcess::message(string const & message,MessageType messageType)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed"); pvaClientChannel->message(message,messageType);
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
} }
void PvaClientProcess::channelProcessConnect( void PvaClientProcess::channelProcessConnect(
const Status& status, const Status& status,
ChannelProcess::shared_pointer const & channelProcess) ChannelProcess::shared_pointer const & channelProcess)
{ {
if(isDestroyed) return; if(PvaClient::getDebug()) {
channelProcessConnectStatus = status; cout << "PvaClientProcess::channelProcessConnect"
this->channelProcess = channelProcess; << " channelName " << pvaClientChannel->getChannel()->getChannelName()
waitForConnect.signal(); << " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
Lock xx(mutex);
channelProcessConnectStatus = status;
if(status.isOK()) {
this->channelProcess = channelProcess;
connectState = connected;
}
waitForConnect.signal();
}
PvaClientProcessRequesterPtr req(pvaClientProcessRequester.lock());
if(req) {
req->channelProcessConnect(status,shared_from_this());
}
} }
void PvaClientProcess::processDone( void PvaClientProcess::processDone(
const Status& status, const Status& status,
ChannelProcess::shared_pointer const & channelProcess) ChannelProcess::shared_pointer const & channelProcess)
{ {
if(isDestroyed) return; if(PvaClient::getDebug()) {
channelProcessStatus = status; cout << "PvaClientProcess::processDone"
waitForProcess.signal(); << " channelName " << pvaClientChannel->getChannel()->getChannelName()
} << " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
// from PvaClientProcess
void PvaClientProcess::destroy()
{
{ {
Lock xx(mutex); Lock xx(mutex);
if(isDestroyed) return; channelProcessStatus = status;
isDestroyed = true; processState = processComplete;
waitForProcess.signal();
}
PvaClientProcessRequesterPtr req(pvaClientProcessRequester.lock());
if(req) {
req->processDone(status,shared_from_this());
} }
if(channelProcess) channelProcess->destroy();
channelProcess.reset();
} }
void PvaClientProcess::connect() void PvaClientProcess::connect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientProcess::connect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueConnect(); issueConnect();
Status status = waitConnect(); Status status = waitConnect();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientProcess::connect " + status.getMessage(); + " PvaClientProcess::connect " + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientProcess::issueConnect() void PvaClientProcess::issueConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientProcess::issueConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState!=connectIdle) { if(connectState!=connectIdle) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientProcess already connected "; + " pvaClientProcess already connected ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
processRequester = ChannelProcessRequester::shared_pointer(new ChannelProcessRequesterImpl(this));
connectState = connectActive; connectState = connectActive;
channelProcess = channel->createChannelProcess(processRequester,pvRequest); channelProcessConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelProcess = pvaClientChannel->getChannel()->createChannelProcess(channelProcessRequester,pvRequest);
} }
Status PvaClientProcess::waitConnect() Status PvaClientProcess::waitConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=connectActive) { cout << "PvaClientProcess::waitConnect"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientProcess illegal connect state "; << endl;
throw std::runtime_error(message);
} }
waitForConnect.wait(); waitForConnect.wait();
connectState = channelProcessConnectStatus.isOK() ? connected : connectIdle;
return channelProcessConnectStatus; return channelProcessConnectStatus;
} }
void PvaClientProcess::process() void PvaClientProcess::process()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientProcess::process"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueProcess(); issueProcess();
Status status = waitProcess(); Status status = waitProcess();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientProcess::process" + status.getMessage(); + " PvaClientProcess::process" + status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientProcess::issueProcess() void PvaClientProcess::issueProcess()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientProcess::issueProcess"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(processState!=processIdle) { if(processState==processActive) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientProcess::issueProcess process aleady active "; + " PvaClientProcess::issueProcess process aleady active ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
@@ -171,24 +245,30 @@ void PvaClientProcess::issueProcess()
Status PvaClientProcess::waitProcess() Status PvaClientProcess::waitProcess()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed"); if(PvaClient::getDebug()) {
if(processState!=processActive){ cout << "PvaClientProcess::waitProcess"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientProcess::waitProcess llegal process state"; << endl;
throw std::runtime_error(message);
} }
waitForProcess.wait(); waitForProcess.wait();
processState = processIdle; processState = processComplete;
return channelProcessStatus; return channelProcessStatus;
} }
PvaClientProcessPtr PvaClientProcess::create( void PvaClientProcess::setRequester(PvaClientProcessRequesterPtr const & pvaClientProcessRequester)
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
{ {
PvaClientProcessPtr epv(new PvaClientProcess(pvaClient,channel,pvRequest)); if(PvaClient::getDebug()) {
return epv; cout << "PvaClientProcess::setRequester"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
this->pvaClientProcessRequester = pvaClientProcessRequester;
} }
PvaClientChannelPtr PvaClientProcess::getPvaClientChannel()
{
return pvaClientChannel;
}
}} }}
+233 -113
View File
@@ -8,12 +8,13 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <pv/event.h> #include <pv/event.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h> #include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
@@ -22,72 +23,127 @@ namespace epics { namespace pvaClient {
class ChannelPutRequesterImpl : public ChannelPutRequester class ChannelPutRequesterImpl : public ChannelPutRequester
{ {
PvaClientPut * pvaClientPut; PvaClientPut::weak_pointer pvaClientPut;
PvaClient::weak_pointer pvaClient;
public: public:
ChannelPutRequesterImpl(PvaClientPut * pvaClientPut) ChannelPutRequesterImpl(
: pvaClientPut(pvaClientPut) {} PvaClientPutPtr const & pvaClientPut,
string getRequesterName() PvaClientPtr const &pvaClient)
{return pvaClientPut->getRequesterName();} : pvaClientPut(pvaClientPut),
void message(string const & message,MessageType messageType) pvaClient(pvaClient)
{pvaClientPut->message(message,messageType);} {}
void channelPutConnect( virtual ~ChannelPutRequesterImpl() {
if(PvaClient::getDebug()) std::cout << "~ChannelPutRequesterImpl" << std::endl;
}
virtual std::string getRequesterName() {
PvaClientPutPtr clientPut(pvaClientPut.lock());
if(!clientPut) return string("clientPut is null");
return clientPut->getRequesterName();
}
virtual void message(std::string const & message, MessageType messageType) {
PvaClientPutPtr clientPut(pvaClientPut.lock());
if(!clientPut) return;
clientPut->message(message,messageType);
}
virtual void channelPutConnect(
const Status& status, const Status& status,
ChannelPut::shared_pointer const & channelPut, ChannelPut::shared_pointer const & channelPut,
StructureConstPtr const & structure) Structure::const_shared_pointer const & structure)
{pvaClientPut->channelPutConnect(status,channelPut,structure);} {
void getDone( PvaClientPutPtr clientPut(pvaClientPut.lock());
if(!clientPut) return;
clientPut->channelPutConnect(status,channelPut,structure);
}
virtual void getDone(
const Status& status, const Status& status,
ChannelPut::shared_pointer const & channelPut, ChannelPut::shared_pointer const & channelPut,
PVStructurePtr const & pvStructure, PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet) BitSet::shared_pointer const & bitSet)
{pvaClientPut->getDone(status,channelPut,pvStructure,bitSet);} {
void putDone( PvaClientPutPtr clientPut(pvaClientPut.lock());
if(!clientPut) return;
clientPut->getDone(status,channelPut,pvStructure,bitSet);
}
virtual void putDone(
const Status& status, const Status& status,
ChannelPut::shared_pointer const & channelPut) ChannelPut::shared_pointer const & channelPut)
{pvaClientPut->putDone(status,channelPut);} {
PvaClientPutPtr clientPut(pvaClientPut.lock());
if(!clientPut) return;
clientPut->putDone(status,channelPut);
}
}; };
PvaClientPutPtr PvaClientPut::create(
PvaClientPtr const &pvaClient,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
{
PvaClientPutPtr clientPut(new PvaClientPut(pvaClient,pvaClientChannel,pvRequest));
clientPut->channelPutRequester = ChannelPutRequesterImplPtr(
new ChannelPutRequesterImpl(clientPut,pvaClient));
return clientPut;
}
PvaClientPut::PvaClientPut( PvaClientPut::PvaClientPut(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel, PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest) PVStructurePtr const &pvRequest)
: pvaClient(pvaClient), : pvaClient(pvaClient),
channel(channel), pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest), pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle), connectState(connectIdle),
putState(putIdle) putState(putIdle)
{ {
if(PvaClient::getDebug()) {
cout<< "PvaClientPut::PvaClientPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
} }
PvaClientPut::~PvaClientPut() PvaClientPut::~PvaClientPut()
{ {
destroy(); if(PvaClient::getDebug()) {
} cout<< "PvaClientPut::~PvaClientPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
void PvaClientPut::checkPutState() << endl;
{ }
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); }
if(connectState==connectIdle){
connect();
get(); void PvaClientPut::checkConnectState()
{
if(PvaClient::getDebug()) {
cout << "PvaClientPut::checkConnectState"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState==connectIdle){
connect();
}
if(connectState==connectActive){
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " "
+ channelPutConnectStatus.getMessage();
throw std::runtime_error(message);
} }
} }
// from ChannelPutRequester
string PvaClientPut::getRequesterName() string PvaClientPut::getRequesterName()
{ {
PvaClientPtr yyy = pvaClient.lock(); return pvaClientChannel->getRequesterName();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
} }
void PvaClientPut::message(string const & message,MessageType messageType) void PvaClientPut::message(string const & message,MessageType messageType)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); pvaClientChannel->message(message,messageType);
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
} }
void PvaClientPut::channelPutConnect( void PvaClientPut::channelPutConnect(
@@ -95,15 +151,27 @@ void PvaClientPut::channelPutConnect(
ChannelPut::shared_pointer const & channelPut, ChannelPut::shared_pointer const & channelPut,
StructureConstPtr const & structure) StructureConstPtr const & structure)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
channelPutConnectStatus = status; cout << "PvaClientPut::channelPutConnect"
this->channelPut = channelPut; << " channelName " << pvaClientChannel->getChannel()->getChannelName()
if(status.isOK()) { << " status.isOK " << (status.isOK() ? "true" : "false")
pvaClientData = PvaClientPutData::create(structure); << endl;
pvaClientData->setMessagePrefix(channel->getChannelName()); }
{
Lock xx(mutex);
channelPutConnectStatus = status;
if(status.isOK()) {
this->channelPut = channelPut;
connectState = connected;
pvaClientData = PvaClientPutData::create(structure);
pvaClientData->setMessagePrefix(channelPut->getChannel()->getChannelName());
}
waitForConnect.signal();
}
PvaClientPutRequesterPtr req(pvaClientPutRequester.lock());
if(req) {
req->channelPutConnect(status,shared_from_this());
} }
waitForConnect.signal();
} }
void PvaClientPut::getDone( void PvaClientPut::getDone(
@@ -112,133 +180,175 @@ void PvaClientPut::getDone(
PVStructurePtr const & pvStructure, PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet) BitSetPtr const & bitSet)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
channelGetPutStatus = status; cout << "PvaClientPut::getDone"
if(status.isOK()) { << " channelName " << pvaClientChannel->getChannel()->getChannelName()
PVStructurePtr pvs = pvaClientData->getPVStructure(); << " status.isOK " << (status.isOK() ? "true" : "false")
pvs->copyUnchecked(*pvStructure,*bitSet); << endl;
BitSetPtr bs = pvaClientData->getChangedBitSet(); }
bs->clear(); {
*bs |= *bitSet; Lock xx(mutex);
channelGetPutStatus = status;
if(status.isOK()) {
PVStructurePtr pvs = pvaClientData->getPVStructure();
pvs->copyUnchecked(*pvStructure,*bitSet);
BitSetPtr bs = pvaClientData->getChangedBitSet();
bs->clear();
*bs |= *bitSet;
}
putState = putComplete;
waitForGetPut.signal();
}
PvaClientPutRequesterPtr req(pvaClientPutRequester.lock());
if(req) {
req->getDone(status,shared_from_this());
} }
waitForGetPut.signal();
} }
void PvaClientPut::putDone( void PvaClientPut::putDone(
const Status& status, const Status& status,
ChannelPut::shared_pointer const & channelPut) ChannelPut::shared_pointer const & channelPut)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
channelGetPutStatus = status; cout << "PvaClientPut::putDone"
waitForGetPut.signal(); << " channelName " << pvaClientChannel->getChannel()->getChannelName()
} << " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
// from PvaClientPut
void PvaClientPut::destroy()
{
{ {
Lock xx(mutex); Lock xx(mutex);
if(isDestroyed) return; channelGetPutStatus = status;
isDestroyed = true; putState = putComplete;
waitForGetPut.signal();
} }
if(channelPut) channelPut->destroy(); PvaClientPutRequesterPtr req(pvaClientPutRequester.lock());
channelPut.reset(); if(req) { req->putDone(status,shared_from_this());}
} }
void PvaClientPut::connect() void PvaClientPut::connect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPut::connect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueConnect(); issueConnect();
Status status = waitConnect(); Status status = waitConnect();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPut::connect " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::connect "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientPut::issueConnect() void PvaClientPut::issueConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPut::issueConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState!=connectIdle) { if(connectState!=connectIdle) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientPut already connected "; + " pvaClientPut already connected ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
putRequester = ChannelPutRequester::shared_pointer(new ChannelPutRequesterImpl(this));
connectState = connectActive; connectState = connectActive;
channelPut = channel->createChannelPut(putRequester,pvRequest); channelPutConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelPut = pvaClientChannel->getChannel()->createChannelPut(channelPutRequester,pvRequest);
} }
Status PvaClientPut::waitConnect() Status PvaClientPut::waitConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=connectActive) { cout << "PvaClientPut::waitConnect"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientPut illegal connect state "; << endl;
throw std::runtime_error(message);
} }
waitForConnect.wait(); waitForConnect.wait();
connectState = channelPutConnectStatus.isOK() ? connected : connectIdle;
return channelPutConnectStatus; return channelPutConnectStatus;
} }
void PvaClientPut::get() void PvaClientPut::get()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPut::get"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueGet(); issueGet();
Status status = waitGet(); Status status = waitGet();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPut::get " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::get "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientPut::issueGet() void PvaClientPut::issueGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPut::issueGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(putState!=putIdle) { if(putState==getActive || putState==putActive) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ "PvaClientPut::issueGet get or put aleady active "; + "PvaClientPut::issueGet get or put aleady active ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
putState = getActive; putState = getActive;
pvaClientData->getChangedBitSet()->clear();
channelPut->get(); channelPut->get();
} }
Status PvaClientPut::waitGet() Status PvaClientPut::waitGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
if(putState!=getActive){ cout << "PvaClientPut::waitGet"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::waitGet llegal put state"; << endl;
throw std::runtime_error(message);
} }
waitForGetPut.wait(); waitForGetPut.wait();
putState = putIdle; putState = putComplete;
return channelGetPutStatus; return channelGetPutStatus;
} }
void PvaClientPut::put() void PvaClientPut::put()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPut::put"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issuePut(); issuePut();
Status status = waitPut(); Status status = waitPut();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPut::put " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::put "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientPut::issuePut() void PvaClientPut::issuePut()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPut::issuePut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " pvStructure\n" << pvaClientData->getPVStructure()
<< " bitSet " << *pvaClientData->getChangedBitSet() << endl
<< endl;
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(putState!=putIdle) { if(putState==getActive || putState==putActive) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ "PvaClientPut::issueGet get or put aleady active "; + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::issuePut get or put aleady active ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
putState = putActive; putState = putActive;
@@ -247,32 +357,42 @@ void PvaClientPut::issuePut()
Status PvaClientPut::waitPut() Status PvaClientPut::waitPut()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed"); if(PvaClient::getDebug()) {
if(putState!=putActive){ cout << "PvaClientPut::waitPut"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::waitPut llegal put state"; << endl;
throw std::runtime_error(message);
} }
waitForGetPut.wait(); waitForGetPut.wait();
putState = putIdle; putState = putComplete;
if(channelGetPutStatus.isOK()) pvaClientData->getChangedBitSet()->clear(); if(channelGetPutStatus.isOK()) pvaClientData->getChangedBitSet()->clear();
return channelGetPutStatus; return channelGetPutStatus;
} }
PvaClientPutDataPtr PvaClientPut::getData() PvaClientPutDataPtr PvaClientPut::getData()
{ {
checkPutState(); if(PvaClient::getDebug()) {
cout<< "PvaClientPut::getData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkConnectState();
if(putState==putIdle) get();
return pvaClientData; return pvaClientData;
} }
PvaClientPutPtr PvaClientPut::create( void PvaClientPut::setRequester(PvaClientPutRequesterPtr const & pvaClientPutRequester)
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
{ {
PvaClientPutPtr epv(new PvaClientPut(pvaClient,channel,pvRequest)); if(PvaClient::getDebug()) {
return epv; cout << "PvaClientPut::setRequester"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
this->pvaClientPutRequester = pvaClientPutRequester;
} }
PvaClientChannelPtr PvaClientPut::getPvaClientChannel()
{
return pvaClientChannel;
}
}} }}
+70 -179
View File
@@ -8,15 +8,16 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#define epicsExportSharedSymbols
#include <typeinfo> #include <typeinfo>
#include <sstream> #include <sstream>
#include <pv/pvaClient.h>
#include <pv/createRequest.h> #include <pv/createRequest.h>
#include <pv/convert.h> #include <pv/convert.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast; using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
@@ -24,40 +25,36 @@ using namespace epics::pvAccess;
using namespace std; using namespace std;
namespace epics { namespace pvaClient { namespace epics { namespace pvaClient {
class PvaClientPostHandlerPvt: public PostHandler
{
PvaClientPutData * easyData;
size_t fieldNumber;
public:
PvaClientPostHandlerPvt(PvaClientPutData *easyData,size_t fieldNumber)
: easyData(easyData),fieldNumber(fieldNumber){}
void postPut() { easyData->postPut(fieldNumber);}
};
typedef std::tr1::shared_ptr<PVArray> PVArrayPtr;
static ConvertPtr convert = getConvert(); static ConvertPtr convert = getConvert();
static string noValue("no value field");
static string notScalar("value is not a scalar");
static string notCompatibleScalar("value is not a compatible scalar"); static string notCompatibleScalar("value is not a compatible scalar");
static string notArray("value is not an array");
static string notScalarArray("value is not a scalarArray");
static string notDoubleArray("value is not a doubleArray"); static string notDoubleArray("value is not a doubleArray");
static string notStringArray("value is not a stringArray"); static string notStringArray("value is not a stringArray");
class PvaClientPostHandlerPvt: public PostHandler
{
PvaClientPutData * putData;
size_t fieldNumber;
public:
PvaClientPostHandlerPvt(PvaClientPutData *putData,size_t fieldNumber)
: putData(putData),fieldNumber(fieldNumber){}
void postPut() { putData->postPut(fieldNumber);}
};
PvaClientPutDataPtr PvaClientPutData::create(StructureConstPtr const & structure) PvaClientPutDataPtr PvaClientPutData::create(StructureConstPtr const & structure)
{ {
if(PvaClient::getDebug()) cout << "PvaClientPutData::create\n";
PvaClientPutDataPtr epv(new PvaClientPutData(structure)); PvaClientPutDataPtr epv(new PvaClientPutData(structure));
return epv; return epv;
} }
PvaClientPutData::PvaClientPutData(StructureConstPtr const & structure) PvaClientPutData::PvaClientPutData(StructureConstPtr const & structure)
: structure(structure), : PvaClientData(structure)
pvStructure(getPVDataCreate()->createPVStructure(structure)),
bitSet(BitSetPtr(new BitSet(pvStructure->getNumberFields())))
{ {
messagePrefix = ""; if(PvaClient::getDebug()) cout << "PvaClientPutData::PvaClientPutData\n";
PVStructurePtr pvStructure(getPVDataCreate()->createPVStructure(structure));
BitSetPtr bitSet(BitSetPtr(new BitSet(pvStructure->getNumberFields())));
setData(pvStructure,bitSet);
size_t nfields = pvStructure->getNumberFields(); size_t nfields = pvStructure->getNumberFields();
postHandler.resize(nfields); postHandler.resize(nfields);
PVFieldPtr pvField; PVFieldPtr pvField;
@@ -71,145 +68,18 @@ PvaClientPutData::PvaClientPutData(StructureConstPtr const & structure)
} }
pvField->setPostHandler(postHandler[i]); pvField->setPostHandler(postHandler[i]);
} }
pvValue = pvStructure->getSubField("value");
} }
void PvaClientPutData::checkValue()
{
if(pvValue) return;
throw std::runtime_error(messagePrefix + noValue);
}
void PvaClientPutData::postPut(size_t fieldNumber)
{
bitSet->set(fieldNumber);
}
void PvaClientPutData::setMessagePrefix(std::string const & value)
{
messagePrefix = value + " ";
}
StructureConstPtr PvaClientPutData::getStructure()
{return structure;}
PVStructurePtr PvaClientPutData::getPVStructure()
{return pvStructure;}
BitSetPtr PvaClientPutData::getChangedBitSet()
{return bitSet;}
std::ostream & PvaClientPutData::showChanged(std::ostream & out)
{
size_t nextSet = bitSet->nextSetBit(0);
PVFieldPtr pvField;
while(nextSet!=string::npos) {
if(nextSet==0) {
pvField = pvStructure;
} else {
pvField = pvStructure->getSubField(nextSet);
}
string name = pvField->getFullName();
out << name << " = " << pvField << endl;
nextSet = bitSet->nextSetBit(nextSet+1);
}
return out;
}
bool PvaClientPutData::hasValue()
{
if(!pvValue) return false;
return true;
}
bool PvaClientPutData::isValueScalar()
{
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalar) return true;
return false;
}
bool PvaClientPutData::isValueScalarArray()
{
if(!pvValue) return false;
if(pvValue->getField()->getType()==scalarArray) return true;
return false;
}
PVFieldPtr PvaClientPutData::getValue()
{
checkValue();
return pvValue;
}
PVScalarPtr PvaClientPutData::getScalarValue()
{
checkValue();
PVScalarPtr pv = pvStructure->getSubField<PVScalar>("value");
if(!pv) throw std::runtime_error(messagePrefix + notScalar);
return pv;
}
PVArrayPtr PvaClientPutData::getArrayValue()
{
checkValue();
PVArrayPtr pv = pvStructure->getSubField<PVArray>("value");
if(!pv) throw std::runtime_error(messagePrefix + notArray);
return pv;
}
PVScalarArrayPtr PvaClientPutData::getScalarArrayValue()
{
checkValue();
PVScalarArrayPtr pv = pvStructure->getSubField<PVScalarArray>("value");
if(!pv) throw std::runtime_error(messagePrefix + notScalarArray);
return pv;
}
double PvaClientPutData::getDouble()
{
PVScalarPtr pvScalar = getScalarValue();
ScalarType scalarType = pvScalar->getScalar()->getScalarType();
if(scalarType==pvDouble) {
PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar);
return pvDouble->get();
}
if(!ScalarTypeFunc::isNumeric(scalarType)) {
throw std::runtime_error(messagePrefix + notCompatibleScalar);
}
return convert->toDouble(pvScalar);
}
string PvaClientPutData::getString()
{
PVScalarPtr pvScalar = getScalarValue();
return convert->toString(pvScalar);
}
shared_vector<const double> PvaClientPutData::getDoubleArray()
{
checkValue();
PVDoubleArrayPtr pv = pvStructure->getSubField<PVDoubleArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + notDoubleArray);
}
return pv->view();
}
shared_vector<const string> PvaClientPutData::getStringArray()
{
checkValue();
PVStringArrayPtr pv = pvStructure->getSubField<PVStringArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + notStringArray);
}
return pv->view();
}
void PvaClientPutData::putDouble(double value) void PvaClientPutData::putDouble(double value)
{ {
PVScalarPtr pvScalar = getScalarValue(); if(PvaClient::getDebug()) cout << "PvaClientPutData::putDouble\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
if(type!=scalar) {
throw std::logic_error("PvaClientData::putDouble() did not find a scalar field");
}
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
ScalarType scalarType = pvScalar->getScalar()->getScalarType(); ScalarType scalarType = pvScalar->getScalar()->getScalarType();
if(scalarType==pvDouble) { if(scalarType==pvDouble) {
PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar); PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar);
@@ -217,47 +87,68 @@ void PvaClientPutData::putDouble(double value)
return; return;
} }
if(!ScalarTypeFunc::isNumeric(scalarType)) { if(!ScalarTypeFunc::isNumeric(scalarType)) {
throw std::runtime_error(messagePrefix + notCompatibleScalar); throw std::logic_error(
"PvaClientData::putDouble() did not find a numeric scalar field");
} }
convert->fromDouble(pvScalar,value); convert->fromDouble(pvScalar,value);
} }
void PvaClientPutData::putString(std::string const & value) void PvaClientPutData::putString(std::string const & value)
{ {
PVScalarPtr pvScalar = getScalarValue(); if(PvaClient::getDebug()) cout << "PvaClientPutData::putString\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
if(type!=scalar) {
throw std::logic_error("PvaClientData::putString() did not find a scalar field");
}
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
convert->fromString(pvScalar,value); convert->fromString(pvScalar,value);
} }
void PvaClientPutData::putDoubleArray(shared_vector<const double> const & value) void PvaClientPutData::putDoubleArray(shared_vector<const double> const & value)
{ {
checkValue(); if(PvaClient::getDebug()) cout << "PvaClientPutData::putDoubleArray\n";
PVDoubleArrayPtr pv = pvStructure->getSubField<PVDoubleArray>("value"); PVFieldPtr pvField = getSinglePVField();
if(!pv) { Type type = pvField->getField()->getType();
throw std::runtime_error(messagePrefix + notDoubleArray); if(type!=scalarArray) {
throw std::logic_error("PvaClientData::putDoubleArray() did not find a scalarArray field");
} }
pv->replace(value); PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
ScalarType scalarType = pvScalarArray->getScalarArray()->getElementType();
if(!ScalarTypeFunc::isNumeric(scalarType)) {
throw std::logic_error(
"PvaClientData::putDoubleArray() did not find a numeric scalarArray field");
}
pvScalarArray->putFrom<const double>(value);
} }
void PvaClientPutData::putStringArray(shared_vector<const std::string> const & value) void PvaClientPutData::putStringArray(shared_vector<const std::string> const & value)
{ {
checkValue(); if(PvaClient::getDebug()) cout << "PvaClientPutData::putStringArray\n";
PVStringArrayPtr pv = pvStructure->getSubField<PVStringArray>("value"); PVFieldPtr pvField = getSinglePVField();
if(!pv) { Type type = pvField->getField()->getType();
throw std::runtime_error(messagePrefix + notStringArray); if(type!=scalarArray) {
throw std::logic_error("PvaClientData::putStringArray() did not find a scalarArray field");
} }
pv->replace(value); PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
pvScalarArray->putFrom<const string>(value);
return;
} }
void PvaClientPutData::putStringArray(std::vector<std::string> const & value) void PvaClientPutData::putStringArray(std::vector<string> const & value)
{ {
checkValue(); size_t length = value.size();
PVScalarArrayPtr pv = pvStructure->getSubField<PVScalarArray>("value"); shared_vector<string> val(length);
if(!pv) { for(size_t i=0; i < length; ++i) val[i] = value[i];
throw std::runtime_error(messagePrefix + notScalarArray); putStringArray(freeze(val));
} return;
convert->fromStringArray(pv,0,value.size(),value,0);
} }
void PvaClientPutData::postPut(size_t fieldNumber)
{
if(PvaClient::getDebug()) cout << "PvaClientPutData::postPut\n";
getChangedBitSet()->set(fieldNumber);
}
}} }}
+298 -149
View File
@@ -8,12 +8,12 @@
* @author mrk * @author mrk
* @date 2015.02 * @date 2015.02
*/ */
#include <pv/event.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/event.h>
#include <pv/pvaClient.h> #include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
using namespace std; using namespace std;
@@ -22,89 +22,140 @@ namespace epics { namespace pvaClient {
class ChannelPutGetRequesterImpl : public ChannelPutGetRequester class ChannelPutGetRequesterImpl : public ChannelPutGetRequester
{ {
PvaClientPutGet * pvaClientPutGet; PvaClientPutGet::weak_pointer pvaClientPutGet;
PvaClient::weak_pointer pvaClient;
public: public:
ChannelPutGetRequesterImpl(PvaClientPutGet * pvaClientPutGet) ChannelPutGetRequesterImpl(
: pvaClientPutGet(pvaClientPutGet) {} PvaClientPutGetPtr const & pvaClientPutGet,
string getRequesterName() PvaClientPtr const &pvaClient)
{return pvaClientPutGet->getRequesterName();} : pvaClientPutGet(pvaClientPutGet),
void message(string const & message,MessageType messageType) pvaClient(pvaClient)
{pvaClientPutGet->message(message,messageType);} {}
void channelPutGetConnect( virtual ~ChannelPutGetRequesterImpl() {
const epics::pvData::Status& status, if(PvaClient::getDebug()) std::cout << "~ChannelPutGetRequesterImpl" << std::endl;
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet,
epics::pvData::StructureConstPtr const & putStructure,
epics::pvData::StructureConstPtr const & getStructure)
{
pvaClientPutGet->channelPutGetConnect(status,channelPutGet,putStructure,getStructure);
} }
void putGetDone(
const epics::pvData::Status& status, virtual std::string getRequesterName() {
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
epics::pvData::PVStructurePtr const & getPVStructure, if(!clientPutGet) return string("clientPutGet is null");
epics::pvData::BitSetPtr const & getChangedBitSet) return clientPutGet->getRequesterName();
{
pvaClientPutGet->putGetDone(status,channelPutGet,getPVStructure,getChangedBitSet);
} }
void getPutDone(
const epics::pvData::Status& status, virtual void message(std::string const & message, MessageType messageType) {
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
epics::pvData::PVStructurePtr const & putPVStructure, if(!clientPutGet) return;
epics::pvData::BitSet::shared_pointer const & putBitSet) clientPutGet->message(message,messageType);
{
pvaClientPutGet->getPutDone(status,channelPutGet,putPVStructure,putBitSet);
} }
void getGetDone(
const epics::pvData::Status& status, virtual void channelPutGetConnect(
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet, const Status& status,
epics::pvData::PVStructurePtr const & getPVStructure, ChannelPutGet::shared_pointer const & channelPutGet,
epics::pvData::BitSet::shared_pointer const & getChangedBitSet) Structure::const_shared_pointer const & putStructure,
Structure::const_shared_pointer const & getStructure)
{ {
pvaClientPutGet->getGetDone(status,channelPutGet,getPVStructure,getChangedBitSet); PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
if(!clientPutGet) return;
clientPutGet->channelPutGetConnect(status,channelPutGet,putStructure,getStructure);
}
virtual void putGetDone(
const Status& status,
ChannelPutGet::shared_pointer const & channelPutGet,
PVStructurePtr const & getPVStructure,
BitSet::shared_pointer const & getBitSet)
{
PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
if(!clientPutGet) return;
clientPutGet->putGetDone(status,channelPutGet,getPVStructure,getBitSet);
}
virtual void getPutDone(
const Status& status,
ChannelPutGet::shared_pointer const & channelPutGet,
PVStructurePtr const & putPVStructure,
BitSet::shared_pointer const & putBitSet)
{
PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
if(!clientPutGet) return;
clientPutGet->getPutDone(status,channelPutGet,putPVStructure,putBitSet);
}
virtual void getGetDone(
const Status& status,
ChannelPutGet::shared_pointer const & channelPutGet,
PVStructurePtr const & getPVStructure,
BitSet::shared_pointer const & getBitSet)
{
PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
if(!clientPutGet) return;
clientPutGet->getGetDone(status,channelPutGet,getPVStructure,getBitSet);
} }
}; };
PvaClientPutGetPtr PvaClientPutGet::create(
PvaClientPtr const &pvaClient,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
{
PvaClientPutGetPtr clientPutGet(new PvaClientPutGet(pvaClient,pvaClientChannel,pvRequest));
clientPutGet->channelPutGetRequester = ChannelPutGetRequesterImplPtr(
new ChannelPutGetRequesterImpl(clientPutGet,pvaClient));
return clientPutGet;
}
PvaClientPutGet::PvaClientPutGet( PvaClientPutGet::PvaClientPutGet(
PvaClientPtr const &pvaClient, PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel, PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest) PVStructurePtr const &pvRequest)
: pvaClient(pvaClient), : pvaClient(pvaClient),
channel(channel), pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest), pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle), connectState(connectIdle),
putGetState(putGetIdle) putGetState(putGetIdle)
{ {
if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::PvaClientPutGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
} }
PvaClientPutGet::~PvaClientPutGet() PvaClientPutGet::~PvaClientPutGet()
{ {
destroy(); if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::~PvaClientPutGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
} }
void PvaClientPutGet::checkPutGetState() void PvaClientPutGet::checkPutGetState()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::checkPutGetState"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState==connectIdle){ if(connectState==connectIdle){
connect(); connect();
getPut(); }
if(connectState==connectActive){
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " "
+ channelPutGetConnectStatus.getMessage();
throw std::runtime_error(message);
} }
} }
// from ChannelPutGetRequester
string PvaClientPutGet::getRequesterName() string PvaClientPutGet::getRequesterName()
{ {
PvaClientPtr yyy = pvaClient.lock(); return pvaClientChannel->getRequesterName();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
} }
void PvaClientPutGet::message(string const & message,MessageType messageType) void PvaClientPutGet::message(string const & message,MessageType messageType)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); pvaClientChannel->message(message,messageType);
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
} }
void PvaClientPutGet::channelPutGetConnect( void PvaClientPutGet::channelPutGetConnect(
@@ -113,17 +164,29 @@ void PvaClientPutGet::channelPutGetConnect(
StructureConstPtr const & putStructure, StructureConstPtr const & putStructure,
StructureConstPtr const & getStructure) StructureConstPtr const & getStructure)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
channelPutGetConnectStatus = status; cout << "PvaClientPutGet::channelPutGetConnect"
this->channelPutGet = channelPutGet; << " channelName " << pvaClientChannel->getChannel()->getChannelName()
if(status.isOK()) { << " status.isOK " << (status.isOK() ? "true" : "false")
pvaClientPutData = PvaClientPutData::create(putStructure); << endl;
pvaClientPutData->setMessagePrefix(channel->getChannelName()); }
pvaClientGetData = PvaClientGetData::create(getStructure); {
pvaClientGetData->setMessagePrefix(channel->getChannelName()); Lock xx(mutex);
channelPutGetConnectStatus = status;
if(status.isOK()) {
this->channelPutGet = channelPutGet;
connectState = connected;
pvaClientPutData = PvaClientPutData::create(putStructure);
pvaClientPutData->setMessagePrefix(channelPutGet->getChannel()->getChannelName());
pvaClientGetData = PvaClientGetData::create(getStructure);
pvaClientGetData->setMessagePrefix(channelPutGet->getChannel()->getChannelName());
}
waitForConnect.signal();
}
PvaClientPutGetRequesterPtr req(pvaClientPutGetRequester.lock());
if(req) {
req->channelPutGetConnect(status,shared_from_this());
} }
waitForConnect.signal();
} }
void PvaClientPutGet::putGetDone( void PvaClientPutGet::putGetDone(
@@ -132,12 +195,25 @@ void PvaClientPutGet::putGetDone(
PVStructurePtr const & getPVStructure, PVStructurePtr const & getPVStructure,
BitSetPtr const & getChangedBitSet) BitSetPtr const & getChangedBitSet)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
channelPutGetStatus = status; cout << "PvaClientPutGet::putGetDone"
if(status.isOK()) { << " channelName " << pvaClientChannel->getChannel()->getChannelName()
pvaClientGetData->setData(getPVStructure,getChangedBitSet); << " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
Lock xx(mutex);
channelPutGetStatus = status;
if(status.isOK()) {
pvaClientGetData->setData(getPVStructure,getChangedBitSet);
}
putGetState = putGetComplete;
waitForPutGet.signal();
}
PvaClientPutGetRequesterPtr req(pvaClientPutGetRequester.lock());
if(req) {
req->putGetDone(status,shared_from_this());
} }
waitForPutGet.signal();
} }
void PvaClientPutGet::getPutDone( void PvaClientPutGet::getPutDone(
@@ -146,16 +222,29 @@ void PvaClientPutGet::getPutDone(
PVStructurePtr const & putPVStructure, PVStructurePtr const & putPVStructure,
BitSetPtr const & putBitSet) BitSetPtr const & putBitSet)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
channelPutGetStatus = status; cout << "PvaClientPutGet::getPutDone"
if(status.isOK()) { << " channelName " << pvaClientChannel->getChannel()->getChannelName()
PVStructurePtr pvs = pvaClientPutData->getPVStructure(); << " status.isOK " << (status.isOK() ? "true" : "false")
pvs->copyUnchecked(*putPVStructure,*putBitSet); << endl;
BitSetPtr bs = pvaClientPutData->getChangedBitSet(); }
bs->clear(); {
*bs |= *putBitSet; Lock xx(mutex);
channelPutGetStatus = status;
if(status.isOK()) {
PVStructurePtr pvs = pvaClientPutData->getPVStructure();
pvs->copyUnchecked(*putPVStructure,*putBitSet);
BitSetPtr bs = pvaClientPutData->getChangedBitSet();
bs->clear();
*bs |= *putBitSet;
}
putGetState = putGetComplete;
waitForPutGet.signal();
}
PvaClientPutGetRequesterPtr req(pvaClientPutGetRequester.lock());
if(req) {
req->getPutDone(status,shared_from_this());
} }
waitForPutGet.signal();
} }
void PvaClientPutGet::getGetDone( void PvaClientPutGet::getGetDone(
@@ -164,84 +253,103 @@ void PvaClientPutGet::getGetDone(
PVStructurePtr const & getPVStructure, PVStructurePtr const & getPVStructure,
BitSetPtr const & getChangedBitSet) BitSetPtr const & getChangedBitSet)
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
channelPutGetStatus = status; cout << "PvaClientPutGet::getGetDone"
if(status.isOK()) { << " channelName " << pvaClientChannel->getChannel()->getChannelName()
pvaClientGetData->setData(getPVStructure,getChangedBitSet); << " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
} }
waitForPutGet.signal();
}
// from PvaClientPutGet
void PvaClientPutGet::destroy()
{
{ {
Lock xx(mutex); Lock xx(mutex);
if(isDestroyed) return; channelPutGetStatus = status;
isDestroyed = true; if(status.isOK()) {
pvaClientGetData->setData(getPVStructure,getChangedBitSet);
}
putGetState = putGetComplete;
waitForPutGet.signal();
}
PvaClientPutGetRequesterPtr req(pvaClientPutGetRequester.lock());
if(req) {
req->getGetDone(status,shared_from_this());
} }
if(channelPutGet) channelPutGet->destroy();
channelPutGet.reset();
} }
void PvaClientPutGet::connect() void PvaClientPutGet::connect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::connect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueConnect(); issueConnect();
Status status = waitConnect(); Status status = waitConnect();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPutGet::connect " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::connect "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientPutGet::issueConnect() void PvaClientPutGet::issueConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::issueConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState!=connectIdle) { if(connectState!=connectIdle) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientPutGet already connected "; + " pvaClientPutGet already connected ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
putGetRequester = ChannelPutGetRequester::shared_pointer(new ChannelPutGetRequesterImpl(this));
connectState = connectActive; connectState = connectActive;
channelPutGet = channel->createChannelPutGet(putGetRequester,pvRequest); channelPutGetConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelPutGet = pvaClientChannel->getChannel()->createChannelPutGet(channelPutGetRequester,pvRequest);
} }
Status PvaClientPutGet::waitConnect() Status PvaClientPutGet::waitConnect()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
if(connectState!=connectActive) { cout << "PvaClientPutGet::waitConnect"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientPutGet illegal connect state "; << endl;
throw std::runtime_error(message);
} }
waitForConnect.wait(); waitForConnect.wait();
connectState = channelPutGetConnectStatus.isOK() ? connected : connectIdle;
return channelPutGetConnectStatus; return channelPutGetConnectStatus;
} }
void PvaClientPutGet::putGet() void PvaClientPutGet::putGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::putGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issuePutGet(); issuePutGet();
Status status = waitPutGet(); Status status = waitPutGet();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPutGet::putGet " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::putGet "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientPutGet::issuePutGet() void PvaClientPutGet::issuePutGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::issuePutGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(putGetState!=putGetIdle) { if(putGetState==putGetActive) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPutGet::issueGet get or put aleady active "; + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::issuePutGet get or put aleady active ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
putGetState = putGetActive; putGetState = putGetActive;
@@ -251,35 +359,45 @@ void PvaClientPutGet::issuePutGet()
Status PvaClientPutGet::waitPutGet() Status PvaClientPutGet::waitPutGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
if(putGetState!=putGetActive){ cout << "PvaClientPutGet::waitPutGet"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::waitPutGet llegal put state"; << endl;
throw std::runtime_error(message);
} }
waitForPutGet.wait(); waitForPutGet.wait();
putGetState = putGetIdle; if(channelPutGetStatus.isOK()) pvaClientPutData->getChangedBitSet()->clear();
return channelPutGetStatus; return channelPutGetStatus;
} }
void PvaClientPutGet::getGet() void PvaClientPutGet::getGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::getGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueGetGet(); issueGetGet();
Status status = waitGetGet(); Status status = waitGetGet();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPutGet::getGet " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::getGet "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientPutGet::issueGetGet() void PvaClientPutGet::issueGetGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::issueGetGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(putGetState!=putGetIdle) { if(putGetState==putGetActive) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPutGet::issueGetGet aleady active "; + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::issueGetGet get or put aleady active ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
putGetState = putGetActive; putGetState = putGetActive;
@@ -288,35 +406,44 @@ void PvaClientPutGet::issueGetGet()
Status PvaClientPutGet::waitGetGet() Status PvaClientPutGet::waitGetGet()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
if(putGetState!=putGetActive){ cout << "PvaClientPutGet::waitGetGet"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::waitGetGet illegal state"; << endl;
throw std::runtime_error(message);
} }
waitForPutGet.wait(); waitForPutGet.wait();
putGetState = putGetIdle;
return channelPutGetStatus; return channelPutGetStatus;
} }
void PvaClientPutGet::getPut() void PvaClientPutGet::getPut()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::getGetPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueGetPut(); issueGetPut();
Status status = waitGetPut(); Status status = waitGetPut();
if(status.isOK()) return; if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPutGet::getPut " + status.getMessage(); + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::getPut "
+ status.getMessage();
throw std::runtime_error(message); throw std::runtime_error(message);
} }
void PvaClientPutGet::issueGetPut() void PvaClientPutGet::issueGetPut()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::issueGetPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(connectState==connectIdle) connect(); if(connectState==connectIdle) connect();
if(putGetState!=putGetIdle) { if(putGetState==putGetActive) {
string message = string("channel ") + channel->getChannelName() string message = string("channel ")
+ " PvaClientPutGet::issueGetPut aleady active "; + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::issueGetPut get or put aleady active ";
throw std::runtime_error(message); throw std::runtime_error(message);
} }
putGetState = putGetActive; putGetState = putGetActive;
@@ -325,37 +452,59 @@ void PvaClientPutGet::issueGetPut()
Status PvaClientPutGet::waitGetPut() Status PvaClientPutGet::waitGetPut()
{ {
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed"); if(PvaClient::getDebug()) {
if(putGetState!=putGetActive){ cout << "PvaClientPutGet::waitGetPut"
string message = string("channel ") + channel->getChannelName() << " channelName " << pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::waitGetPut illegal state"; << endl;
throw std::runtime_error(message);
} }
waitForPutGet.wait(); waitForPutGet.wait();
putGetState = putGetIdle;
return channelPutGetStatus; return channelPutGetStatus;
} }
PvaClientGetDataPtr PvaClientPutGet::getGetData() PvaClientGetDataPtr PvaClientPutGet::getGetData()
{ {
if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::getGetData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkPutGetState(); checkPutGetState();
if(putGetState==putGetIdle){
getGet();
getPut();
}
return pvaClientGetData; return pvaClientGetData;
} }
PvaClientPutDataPtr PvaClientPutGet::getPutData() PvaClientPutDataPtr PvaClientPutGet::getPutData()
{ {
if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::getPutData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkPutGetState(); checkPutGetState();
if(putGetState==putGetIdle){
getGet();
getPut();
}
return pvaClientPutData; return pvaClientPutData;
} }
PvaClientPutGetPtr PvaClientPutGet::create( void PvaClientPutGet::setRequester(PvaClientPutGetRequesterPtr const & pvaClientPutGetRequester)
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
{ {
PvaClientPutGetPtr epv(new PvaClientPutGet(pvaClient,channel,pvRequest)); if(PvaClient::getDebug()) {
return epv; cout << "PvaClientPutGet::setRequester"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
this->pvaClientPutGetRequester = pvaClientPutGetRequester;
} }
PvaClientChannelPtr PvaClientPutGet::getPvaClientChannel()
{
return pvaClientChannel;
}
}} }}
+352
View File
@@ -0,0 +1,352 @@
/* pvaClientRPC.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 2015.03
*/
#include <sstream>
#include <pv/event.h>
#include <pv/bitSetUtil.h>
#include <pv/rpcService.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvaClient {
class RPCRequesterImpl : public ChannelRPCRequester
{
PvaClientRPC::weak_pointer pvaClientRPC;
PvaClient::weak_pointer pvaClient;
public:
RPCRequesterImpl(
PvaClientRPCPtr const & pvaClientRPC,
PvaClientPtr const &pvaClient)
: pvaClientRPC(pvaClientRPC),
pvaClient(pvaClient)
{}
virtual ~RPCRequesterImpl() {
if(PvaClient::getDebug()) std::cout << "~RPCRequesterImpl" << std::endl;
}
virtual std::string getRequesterName() {
PvaClientRPCPtr clientRPC(pvaClientRPC.lock());
if(!clientRPC) return string("pvaClientRPC is null");
return clientRPC->getRequesterName();
}
virtual void message(std::string const & message, MessageType messageType) {
PvaClientRPCPtr clientRPC(pvaClientRPC.lock());
if(!clientRPC) return;
clientRPC->message(message,messageType);
}
virtual void channelRPCConnect(
const Status& status,
ChannelRPC::shared_pointer const & channelRPC)
{
PvaClientRPCPtr clientRPC(pvaClientRPC.lock());
if(!clientRPC) return;
clientRPC->rpcConnect(status,channelRPC);
}
virtual void requestDone(
const Status& status,
ChannelRPC::shared_pointer const & channelRPC,
PVStructure::shared_pointer const & pvResponse)
{
PvaClientRPCPtr clientRPC(pvaClientRPC.lock());
if(!clientRPC) return;
clientRPC->requestDone(status,channelRPC,pvResponse);
}
};
PvaClientRPCPtr PvaClientRPC::create(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel)
{
StructureConstPtr structure(getFieldCreate()->createStructure());
PVStructurePtr pvRequest(getPVDataCreate()->createPVStructure(structure));
return create(pvaClient,channel,pvRequest);
}
PvaClientRPCPtr PvaClientRPC::create(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
{
PvaClientRPCPtr epv(new PvaClientRPC(pvaClient,channel,pvRequest));
epv->rpcRequester = RPCRequesterImplPtr(
new RPCRequesterImpl(epv,pvaClient));
return epv;
}
PvaClientRPC::PvaClientRPC(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
:
connectState(connectIdle),
pvaClient(pvaClient),
channel(channel),
pvRequest(pvRequest),
rpcState(rpcIdle),
responseTimeout(0.0)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientRPC::PvaClientRPC()"
<< " channelName " << channel->getChannelName()
<< endl;
}
}
PvaClientRPC::~PvaClientRPC()
{
if(PvaClient::getDebug()) {
string channelName("disconnected");
Channel::shared_pointer chan(channel.lock());
if(chan) channelName = chan->getChannelName();
cout<< "PvaClientRPC::~PvaClientRPC"
<< " channelName " << channelName
<< endl;
}
}
void PvaClientRPC::checkRPCState()
{
if(PvaClient::getDebug()) {
string channelName("disconnected");
Channel::shared_pointer chan(channel.lock());
if(chan) channelName = chan->getChannelName();
cout << "PvaClientRPC::checkRPCState"
<< " channelName " << channelName
<< " connectState " << connectState
<< endl;
}
if(connectState==connectIdle) connect();
}
string PvaClientRPC::getRequesterName()
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) return string("PvaClientRPC::getRequesterName() PvaClient isDestroyed");
return yyy->getRequesterName();
}
void PvaClientRPC::message(string const & message,MessageType messageType)
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) return;
yyy->message(message, messageType);
}
void PvaClientRPC::rpcConnect(
const Status& status,
ChannelRPC::shared_pointer const & channelRPC)
{
Channel::shared_pointer chan(channel.lock());
if(PvaClient::getDebug()) {
string channelName("disconnected");
Channel::shared_pointer chan(channel.lock());
if(chan) channelName = chan->getChannelName();
cout << "PvaClientRPC::rpcConnect"
<< " channelName " << channelName
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
if(!chan) return;
connectStatus = status;
connectState = connected;
if(PvaClient::getDebug()) {
cout << "PvaClientRPC::rpcConnect calling waitForConnect.signal\n";
}
waitForConnect.signal();
}
void PvaClientRPC::requestDone(
const Status& status,
ChannelRPC::shared_pointer const & channelRPC,
PVStructure::shared_pointer const & pvResponse)
{
PvaClientRPCRequesterPtr req = pvaClientRPCRequester.lock();
{
Lock xx(mutex);
requestStatus = status;
if(PvaClient::getDebug()) {
string channelName("disconnected");
Channel::shared_pointer chan(channel.lock());
if(chan) channelName = chan->getChannelName();
cout << "PvaClientRPC::requestDone"
<< " channelName " << channelName
<< endl;
}
if(rpcState!=rpcActive) {
string channelName("disconnected");
Channel::shared_pointer chan(channel.lock());
if(chan) channelName = chan->getChannelName();
string message = "channel "
+ channelName
+" PvaClientRPC::requestDone"
+ " but not active";
throw std::runtime_error(message);
}
if(req && (responseTimeout<=0.0)) {
rpcState = rpcIdle;
} else {
rpcState = rpcComplete;
if(!req) this->pvResponse = pvResponse;
waitForDone.signal();
}
}
if(req) {
req->requestDone(status,shared_from_this(),pvResponse);
}
}
void PvaClientRPC::connect()
{
if(PvaClient::getDebug()) cout << "PvaClientRPC::connect\n";
issueConnect();
Status status = waitConnect();
if(status.isOK()) return;
Channel::shared_pointer chan(channel.lock());
string channelName("disconnected");
if(chan) channelName = chan->getChannelName();
string message = string("channel ")
+ channelName
+ " PvaClientRPC::connect "
+ status.getMessage();
throw RPCRequestException(Status::STATUSTYPE_ERROR,message);
}
void PvaClientRPC::issueConnect()
{
if(PvaClient::getDebug()) cout << "PvaClientRPC::issueConnect\n";
Channel::shared_pointer chan(channel.lock());
if(connectState!=connectIdle) {
string channelName("disconnected");
if(chan) channelName = chan->getChannelName();
string message = string("channel ")
+ channelName
+ " pvaClientRPC already connected ";
throw std::runtime_error(message);
}
if(chan) {
connectState = connectActive;
channelRPC = chan->createChannelRPC(rpcRequester,pvRequest);
return;
}
throw std::runtime_error("PvaClientRPC::issueConnect() but channel disconnected");
}
Status PvaClientRPC::waitConnect()
{
if(PvaClient::getDebug()) cout << "PvaClientRPC::waitConnect\n";
if(connectState==connected) {
if(!connectStatus.isOK()) connectState = connectIdle;
return connectStatus;
}
if(connectState!=connectActive) {
Channel::shared_pointer chan(channel.lock());
string channelName("disconnected");
if(chan) channelName = chan->getChannelName();
string message = string("channel ")
+ channelName
+ " PvaClientRPC::waitConnect illegal connect state ";
throw std::runtime_error(message);
}
if(PvaClient::getDebug()) {
cout << "PvaClientRPC::waitConnect calling waitForConnect.wait\n";
}
waitForConnect.wait();
connectState = connectStatus.isOK() ? connected : connectIdle;
if(PvaClient::getDebug()) {
cout << "PvaClientRPC::waitConnect"
<< " connectStatus " << (connectStatus.isOK() ? "connected" : "not connected");
}
return connectStatus;
}
PVStructure::shared_pointer PvaClientRPC::request(PVStructure::shared_pointer const & pvArgument)
{
checkRPCState();
{
Lock xx(mutex);
if(rpcState!=rpcIdle) {
Channel::shared_pointer chan(channel.lock());
string channelName("disconnected");
if(chan) channelName = chan->getChannelName();
string message = "channel "
+ channelName
+ " PvaClientRPC::request request aleady active ";
throw std::runtime_error(message);
}
rpcState = rpcActive;
}
channelRPC->request(pvArgument);
if(responseTimeout>0.0) {
waitForDone.wait(responseTimeout);
} else {
waitForDone.wait();
}
Lock xx(mutex);
if(rpcState!=rpcComplete) {
Channel::shared_pointer chan(channel.lock());
string channelName("disconnected");
if(chan) channelName = chan->getChannelName();
string message = "channel "
+ channelName
+ " PvaClientRPC::request request timeout ";
throw RPCRequestException(Status::STATUSTYPE_ERROR,message);
}
rpcState = rpcIdle;
if(requestStatus.isOK()) return pvResponse;
Channel::shared_pointer chan(channel.lock());
string channelName("disconnected");
if(chan) channelName = chan->getChannelName();
string message = "channel "
+ channelName
+ " PvaClientRPC::request status ";
message += requestStatus.getMessage();
throw RPCRequestException(Status::STATUSTYPE_ERROR,message);
}
void PvaClientRPC::request(
PVStructure::shared_pointer const & pvArgument,
PvaClientRPCRequesterPtr const & pvaClientRPCRequester)
{
checkRPCState();
this->pvaClientRPCRequester = pvaClientRPCRequester;
if(responseTimeout<=0.0) {
{
Lock xx(mutex);
if(rpcState!=rpcIdle) {
Channel::shared_pointer chan(channel.lock());
string channelName("disconnected");
if(chan) channelName = chan->getChannelName();
string message = "channel "
+ channelName
+ " PvaClientRPC::request request aleady active ";
throw std::runtime_error(message);
}
rpcState = rpcActive;
}
channelRPC->request(pvArgument);
return;
}
request(pvArgument);
}
}}