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/
lib/
doc/
include/
db/
dbd/
documentation/html
documentation/*.tag
/cfg/
/bin/
/lib/
/db/
/dbd/
/html/
/include/
/templates/
/configure/*.local
/documentation/html
/documentation/*.tag
O.*/
/QtC-*
envPaths
configure/*.local
!configure/ExampleRELEASE.local
**/O.*
*.orig
*.log
.*.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
# 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.
# 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
# could be handy for archiving the generated documentation or if some version
# 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
# for a project that appears at the top of each page and should give viewer a
@@ -46,10 +46,10 @@ PROJECT_NUMBER =
PROJECT_BRIEF =
# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
# the documentation. The maximum height of the logo should not exceed 55 pixels
# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
# to the output directory.
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
@@ -60,7 +60,7 @@ PROJECT_LOGO =
OUTPUT_DIRECTORY =
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
@@ -70,6 +70,14 @@ OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
# U+3044.
# The default value is: NO.
ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
@@ -85,14 +93,14 @@ CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
@@ -127,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = YES
# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
@@ -144,7 +152,7 @@ FULL_PATH_NAMES = YES
# will be relative from the directory where doxygen is started.
# 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
# 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
# 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
# less readable) file names. This can be useful is your file systems doesn't
@@ -169,7 +177,7 @@ SHORT_NAMES = NO
# description.)
# 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
# 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
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
# new page for each member. If set to NO, the documentation of a member will be
# part of the file/class/namespace that contains it.
# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
# page for each member. If set to NO, the documentation of a member will be part
# of the file/class/namespace that contains it.
# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
@@ -261,11 +269,14 @@ OPTIMIZE_OUTPUT_VHDL = NO
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# (default is Fortran), use: inc=Fortran f=C.
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
#
# Note For files without extension you can use no_extension as a placeholder.
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
@@ -284,8 +295,8 @@ MARKDOWN_SUPPORT = YES
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by by putting a % sign in front of the word
# or globally by setting AUTOLINK_SUPPORT to NO.
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
@@ -325,13 +336,20 @@ SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
# If one adds a struct or class to a group and this option is enabled, then also
# any nested class or struct is added to the same group. By default this option
# is disabled and one has to add nested compounds explicitly via \ingroup.
# The default value is: NO.
GROUP_NESTED_COMPOUNDS = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
@@ -390,7 +408,7 @@ LOOKUP_CACHE_SIZE = 0
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -400,35 +418,35 @@ LOOKUP_CACHE_SIZE = 0
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = NO
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
EXTRACT_PACKAGE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
EXTRACT_STATIC = NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO,
# only classes defined in header files are included. Does not have any effect
# for Java sources.
# The default value is: YES.
EXTRACT_LOCAL_CLASSES = NO
# This flag is only useful for Objective-C code. When set to YES local methods,
# This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are
# included in the documentation. If set to NO only methods in the interface are
# included in the documentation. If set to NO, only methods in the interface are
# included.
# The default value is: NO.
@@ -453,21 +471,21 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO these classes will be included in the various overviews. This option has
# no effect if EXTRACT_ALL is enabled.
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO these declarations will be
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
# documentation blocks found inside the body of a function. If set to NO these
# documentation blocks found inside the body of a function. If set to NO, these
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
@@ -481,7 +499,7 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES upper-case letters are also
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
@@ -490,12 +508,19 @@ INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES the
# their full class and namespace scopes in the documentation. If set to YES, the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
# YES the compound reference will be hidden.
# The default value is: NO.
HIDE_COMPOUND_REFERENCE= NO
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
@@ -523,14 +548,14 @@ INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member
# name. If set to NO the members will appear in declaration order.
# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
# name. If set to NO the members will appear in declaration order. Note that
# name. If set to NO, the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
@@ -575,27 +600,25 @@ SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
# todo list. This list is created by putting \todo commands in the
# documentation.
# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
# list. This list is created by putting \todo commands in the documentation.
# The default value is: YES.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
# test list. This list is created by putting \test commands in the
# documentation.
# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
# list. This list is created by putting \test commands in the documentation.
# The default value is: YES.
GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
# list. This list is created by putting \bug commands in the documentation.
# The default value is: YES.
GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
# the deprecated list. This list is created by putting \deprecated commands in
# the documentation.
# The default value is: YES.
@@ -620,8 +643,8 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
# the bottom of the documentation of classes and structs. If set to YES the list
# will mention the files that were used to generate the documentation.
# the bottom of the documentation of classes and structs. If set to YES, the
# list will mention the files that were used to generate the documentation.
# The default value is: YES.
SHOW_USED_FILES = YES
@@ -669,8 +692,7 @@ LAYOUT_FILE =
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. Do not use file names with spaces, bibtex cannot handle them. See
# also \cite for info how to create references.
# search path. See also \cite for info how to create references.
CITE_BIB_FILES =
@@ -686,7 +708,7 @@ CITE_BIB_FILES =
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
# this implies that the warnings are on.
#
# Tip: Turn warnings on while writing the documentation.
@@ -694,7 +716,7 @@ QUIET = NO
WARNINGS = YES
# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
@@ -711,8 +733,8 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO doxygen will only warn about wrong or incomplete parameter
# documentation, but not about the absence of documentation.
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
@@ -740,10 +762,11 @@ WARN_LOGFILE =
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces.
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = include
INPUT = src \
src/pv
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -756,12 +779,17 @@ INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank the
# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
# *.qsf, *.as and *.js.
# *.h) to filter out the source-files in the directories.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd,
# *.vhdl, *.ucf, *.qsf, *.as and *.js.
FILE_PATTERNS =
@@ -769,7 +797,7 @@ FILE_PATTERNS =
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = YES
RECURSIVE = NO
# 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
@@ -860,7 +888,7 @@ INPUT_FILTER =
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER ) will also be used to filter the input files that are used for
# INPUT_FILTER) will also be used to filter the input files that are used for
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO.
@@ -920,7 +948,7 @@ REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation.
# The default value is: YES.
@@ -997,7 +1025,7 @@ IGNORE_PREFIX =
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = YES
@@ -1008,7 +1036,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = documentation/html
HTML_OUTPUT = html/doxygen
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
@@ -1059,13 +1087,15 @@ HTML_FOOTER =
HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
# defined cascading style sheet that is included after the standard style sheets
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
# standard style sheet and is therefor more robust against future updates.
# Doxygen will copy the style sheet file to the output directory. For an example
# see the documentation.
# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@@ -1078,10 +1108,10 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES = documentation/overview.html
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the stylesheet and background images according to
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
@@ -1112,8 +1142,9 @@ HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: YES.
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
@@ -1209,28 +1240,29 @@ GENERATE_HTMLHELP = NO
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler ( hhc.exe). If non-empty
# including file name) of the HTML help compiler (hhc.exe). If non-empty,
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated (
# YES) or that it should be included in the master .chm file ( NO).
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated (
# YES) or a normal table of contents ( NO) in the .chm file.
# The BINARY_TOC flag controls whether a binary table of contents is generated
# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1343,7 +1375,7 @@ DISABLE_INDEX = NO
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
@@ -1371,7 +1403,7 @@ ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1400,7 +1432,7 @@ FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using prerendered bitmaps. Use this if you do not have LaTeX
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option.
@@ -1470,11 +1502,11 @@ SEARCHENGINE = NO
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# are two flavours of web server based searching depending on the
# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
# searching and an index file used by the script. When EXTERNAL_SEARCH is
# enabled the indexing and searching needs to be provided by external tools. See
# the section "External Indexing and Searching" for details.
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
# and searching needs to be provided by external tools. See the section
# "External Indexing and Searching" for details.
# The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1486,7 +1518,7 @@ SERVER_BASED_SEARCH = NO
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
# search results.
#
# Doxygen ships with an example indexer ( doxyindexer) and search engine
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/).
#
@@ -1499,7 +1531,7 @@ EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
# which will return the search results when EXTERNAL_SEARCH is enabled.
#
# Doxygen ships with an example indexer ( doxyindexer) and search engine
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/). See the section "External Indexing and
# Searching" for details.
@@ -1537,7 +1569,7 @@ EXTRA_SEARCH_MAPPINGS =
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
@@ -1568,7 +1600,7 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1586,9 +1618,12 @@ COMPACT_LATEX = NO
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
# that should be included in the LaTeX output. To get the times font for
# instance you can specify
# EXTRA_PACKAGES=times
# that should be included in the LaTeX output. The package can be specified just
# by its name or with the correct syntax as to be used with the LaTeX
# \usepackage command. To get the times font for instance you can specify :
# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
# To use the option intlimits with the amsmath package you can specify:
# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1602,23 +1637,36 @@ EXTRA_PACKAGES =
#
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
# replace them by respectively the title of the page, the current date and time,
# only the current date, the version number of doxygen, the project name (see
# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
# string, for the replacement values of the other commands the user is referred
# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last
# chapter. If it is left blank doxygen will generate a standard footer.
# chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer.
#
# Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# LaTeX style sheets that are included after the standard style sheets created
# by doxygen. Using this option one can overrule certain style aspects. Doxygen
# will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list).
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_STYLESHEET =
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or
@@ -1636,8 +1684,8 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = NO
# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES to get a
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1678,11 +1726,19 @@ LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors.
# The default value is: NO.
@@ -1697,7 +1753,7 @@ GENERATE_RTF = NO
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1734,11 +1790,21 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
# classes and files.
# The default value is: NO.
@@ -1762,6 +1828,13 @@ MAN_OUTPUT = man
MAN_EXTENSION = .3
# The MAN_SUBDIR tag determines the name of the directory created within
# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
# MAN_EXTENSION with the initial . removed.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_SUBDIR =
# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
# will generate one additional man file for each entity documented in the real
# man page(s). These additional files only source the real man page, but without
@@ -1775,7 +1848,7 @@ MAN_LINKS = NO
# Configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
@@ -1789,19 +1862,7 @@ GENERATE_XML = NO
XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_SCHEMA =
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size
# of the XML output.
@@ -1814,7 +1875,7 @@ XML_PROGRAMLISTING = YES
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
# that can be used to generate PDF.
# The default value is: NO.
@@ -1828,14 +1889,23 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
# Definitions (see http://autogen.sf.net) file that captures the structure of
# the code including all documentation. Note that this feature is still
# experimental and incomplete at the moment.
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sf.net) file that captures the
# structure of the code including all documentation. Note that this feature is
# still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@@ -1844,7 +1914,7 @@ GENERATE_AUTOGEN_DEF = NO
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
# file that captures the structure of the code including all documentation.
#
# Note that this feature is still experimental and incomplete at the moment.
@@ -1852,7 +1922,7 @@ GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output.
# The default value is: NO.
@@ -1860,9 +1930,9 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
# formatted so it can be parsed by a human reader. This is useful if you want to
# understand what is going on. On the other hand, if this tag is set to NO the
# understand what is going on. On the other hand, if this tag is set to NO, the
# size of the Perl module output will be much smaller and Perl will parse it
# just the same.
# The default value is: YES.
@@ -1882,14 +1952,14 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
# in the source code. If set to NO only conditional compilation will be
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES.
# The default value is: NO.
@@ -1905,7 +1975,7 @@ MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES the includes files in the
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1947,9 +2017,9 @@ PREDEFINED =
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all refrences to function-like macros that are alone on a line, have an
# all uppercase name, and do not end with a semicolon. Such function macros are
# typically used for boiler-plate code, and will confuse the parser if not
# remove all references to function-like macros that are alone on a line, have
# an all uppercase name, and do not end with a semicolon. Such function macros
# are typically used for boiler-plate code, and will confuse the parser if not
# removed.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1969,7 +2039,7 @@ SKIP_FUNCTION_MACROS = YES
# where loc1 and loc2 can be relative or absolute paths or URLs. See the
# section "Linking to external documentation" for more information about the use
# of tag files.
# Note: Each tag file must have an unique name (where the name does NOT include
# Note: Each tag file must have a unique name (where the name does NOT include
# the path). If a tag file is not located in the directory in which doxygen is
# run, you must also specify the path to the tagfile here.
@@ -1981,20 +2051,21 @@ TAGFILES =
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
# class index. If set to NO only the inherited external classes will be listed.
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
# listed.
# The default value is: NO.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
# the modules index. If set to NO, only the current project's groups will be
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
EXTERNAL_GROUPS = YES
# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
# the related pages index. If set to NO, only the current project's pages will
# be listed.
# The default value is: YES.
@@ -2011,7 +2082,7 @@ PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
@@ -2036,7 +2107,7 @@ MSCGEN_PATH =
DIA_PATH =
# If set to YES, the inheritance and collaboration graphs will hide inheritance
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@@ -2061,7 +2132,7 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0
# When you want a differently looking font n the dot files that doxygen
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
@@ -2109,7 +2180,7 @@ COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
# The default value is: NO.
@@ -2161,7 +2232,8 @@ INCLUDED_BY_GRAPH = YES
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected
# functions only using the \callgraph command.
# functions only using the \callgraph command. Disabling a call graph can be
# accomplished by means of the command \hidecallgraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2172,7 +2244,8 @@ CALL_GRAPH = NO
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected
# functions only using the \callergraph command.
# functions only using the \callergraph command. Disabling a caller graph can be
# accomplished by means of the command \hidecallergraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2195,11 +2268,15 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot.
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
# http://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
# Possible values are: png, jpg, gif and svg.
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2242,6 +2319,19 @@ MSCFILE_DIRS =
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
PLANTUML_JAR_PATH =
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
PLANTUML_INCLUDE_PATH =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized
@@ -2278,7 +2368,7 @@ MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default.
@@ -2295,7 +2385,7 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# files that are used to generate the various graphs.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
+31 -44
View File
@@ -1,12 +1,17 @@
Copyright and License Terms
---------------------------
Copyright (c) 2008 Martin R. Kraimer
Copyright (c) 2006 The University of Chicago, as Operator of Argonne
Copyright (c) 2006-2016 Martin R. Kraimer
Copyright (c) 2006-2016 UChicago Argonne LLC, as Operator of Argonne
National Laboratory.
Copyright (c) 2006 Deutsches Elektronen-Synchrotron,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
Copyright (c) 2007 Control System Laboratory,
Copyright (c) 2007-2016 Control System Laboratory,
(COSYLAB) Ljubljana Slovenia
Copyright (c) 2010-2016 Brookhaven Science Associates, as Operator
of Brookhaven National Laboratory
Copyright (c) 2011-2016 Diamond Light Source Limited,
(DLS) Didcot, United Kingdom
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
@@ -31,48 +36,30 @@ OTHER DEALINGS IN THE SOFTWARE.
________________________________________________________________________
This software is in part copyrighted by the University of Chicago (UofC)
Additional Disclaimers
----------------------
In no event shall UofC be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
UofC has been advised of the possibility of such damage.
This software is copyright in part by these institutions:
UofC specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and UofC has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
* Brookhaven Science Associates, as Operator of Brookhaven
National Laboratory, New York, USA
* Control System Laboratory, Ljubljana, Slovenia
* Deutsches Elektronen-Synchroton, Member of the Helmholtz
Association, Hamburg, Germany
* Diamond Light Source Limited, Didcot, United Kingdom
* Helmholtz-Zentrum Berlin fuer Materialien und Energie m.b.H.,
Berlin, Germany.
* UChicage Argonne LLC, as Operator of Argonne National Laboratory,
Illinois, USA
________________________________________________________________________
In no event shall these institutions be liable to any party for direct,
indirect, special, incidental, or consequential damages arising out of
the use of this software, its documentation, or any derivatives thereof,
even if advised of the possibility of such damage.
This software is in part copyrighted by the BERLINER SPEICHERRING
GESELLSCHAFT FUER SYNCHROTRONSTRAHLUNG M.B.H. (BESSY), BERLIN, GERMANY.
These institutions specifically disclaim any warranties, including, but
not limited to, the implied warranties of merchantability, fitness for a
particular purpose, and non-infringement. This software is provided on
an "as is" basis, and these institutions have no obligation to provide
maintenance, support, updates, enhancements, or modifications.
In no event shall BESSY be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
BESSY has been advised of the possibility of such damage.
BESSY specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and BESSY has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
________________________________________________________________________
This software is in part copyrighted by the Deutsches Elektronen-Synchroton,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
In no event shall DESY be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
DESY has been advised of the possibility of such damage.
DESY specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and DESY has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
________________________________________________________________________
+4 -14
View File
@@ -1,20 +1,10 @@
#Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), configure)
DIRS := $(DIRS) $(filter-out $(DIRS), src)
DIRS := $(DIRS) $(filter-out $(DIRS), example)
DIRS += configure
EMBEDDED_TOPS := $(EMBEDDED_TOPS) $(filter-out $(EMBEDDED_TOPS), example)
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))))
DIRS += src
src_DEPEND_DIRS = configure
include $(TOP)/configure/RULES_TOP
+11 -44
View File
@@ -1,50 +1,17 @@
pvaClientCPP
============
# pvaClientCPP
pvaClient is a synchronous client interface to pvAccess,
which is callback based.
pvaClient is thus easier to use than pvAccess itself.
The **pvaClient** API provides a synchronous client interface that was designed to be easier to use than the original basic pvAccess client API.
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
then just type:
- General information about EPICS can be found at the
[EPICS Controls website](https://epics-controls.org).
- API documentation for this module can be found in its
documentation directory, in particular the file
pvaClientCPP.html
make
## Building
If RELEASE.local does not exist then look at <b>configure/RELEASE</b>
for directions for how to build.
Examples
------------
The examples require the database in 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.
This module is included as a submodule of a full EPICS 7 release and will be compiled during builds of that software.
-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=</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
-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
CFG += CONFIG_PVACLIENT_VERSION
TARGETS = $(CONFIG_TARGETS)
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
# subsequently do a "gnumake rebuild" in the application's
# top level directory.
# IF YOU CHANGE ANY PATHS in this file or make API changes to
# any modules it refers to, you should do a "make rebuild" in
# this application's top level directory.
#
# The build process does not check dependencies against files
# that are outside this application, thus you should also do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
# The EPICS build process does not check dependencies against
# any files from outside the application, so it is safest to
# rebuild it completely if any modules it depends on change.
#
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
# EPICS V4 Developers: Do not edit the locations in this file!
#
# A RELEASE.local must exist that has the following definitions
# EPICS_BASE=/home/install/epics/base
# EPICS4_DIR=/home/epicsv4
# PVCOMMON=${EPICS4_DIR}/pvCommonCPP
# PVDATA=${EPICS4_DIR}/pvDataCPP
# NORMATIVETYPES=${EPICSV4}/normativeTypesCPP
# PVACCESS=${EPICS4_DIR}/pvAccessCPP
#Either create a RELEASE.local one level above the TOP for this module
#OR copy ExampleRELEASE.local to RELEASE.local and edit it.
# This file is parsed by both GNUmake and an EPICS Perl script,
# so it may ONLY contain definititions of paths to other support
# modules, variable definitions that are used in module paths,
# and include statements that pull in other RELEASE files.
# Variables may be used before their values have been set.
# Build variables that are NOT used in paths should be set in
# the CONFIG_SITE file.
# Variables and paths to dependent modules:
#MODULES = /path/to/modules
#MYMODULE = $(MODULES)/my-module
# If building the EPICS modules individually, set these:
#EPICS_PVACCESS = $(MODULES)/pvAccess
#EPICS_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.$(EPICS_HOST_ARCH).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">
<head>
<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"
href="http://epics-pvdata.sourceforge.net/base.css" />
href="https://mrkraimer.github.io/website/css/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
href="https://mrkraimer.github.io/website/css/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
@@ -18,7 +18,7 @@
/*]]>*/</style>
<!-- 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>
@@ -26,31 +26,13 @@
<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">Release 4.8 - March 2021</h2>
<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
<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
@@ -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.
</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.
Additional methods provide access to the full features of pvAccess.
</p>
@@ -78,109 +60,59 @@ The data for the channels is presented via normative type NTMultiChannel.
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">
<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>
<h2>Overview</h2>
<p>
A user overview is available via
Documentation for pvaClientCPP is available at:
<a
href="./pvaClientOverview.html">pvaClientOverview.html
href="https://mrkraimer.github.io/website/developerGuide/pvaClient/pvaClientCPP.html">
pvaClient
</a>
</p>
<p>
Doxygen documentation is available at
<a
href="./html/index.html">doxygenDoc
pvaClientCPP is one of the components of
<a href="https://epics-controls.org/resources-and-support/base/epics-7/">
EPICS-7
</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>This document is only a guide to help locate code and documentation related to pvaClientCPP
</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>
It is intended for developers that want to use pvaClientCPP.
</p>
<h2>examplePvaClientNTMulti</h2>
<p>This is an example of using pvaClientMultiChannel,
pvaClientNTMultiGet, pvaClientNTMultiPut, pvaClientNTMultiMonitor, and pvaClientNTMultiData.
<h2>Developer Guide</h2>
<p>A guide for developers is available at
<a
href="https://mrkraimer.github.io/website/developerGuide/developerGuide.html">
developerGuide
</a>
</p>
<h2>helloWorldRPC</h2>
<p>This is an example of issuing a channelRPC request.
It does <b>not</b> use pva.</p>
<p>This guide provides an overview of the components that are part of an <b>EPICS V4</b> release.
Some understanding of the components and how they are related is necessary in order to
develop code that uses 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" -->
</body>
</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>
# 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.
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)
PVCOMMON_BRANCH="Release-4.1-"
PVDATA_BRANCH="Release-5.0-"
PVACCESS_BRANCH="Release-4.1-"
NORMATIVETYPES_BRANCH="Release-5.0-"
PVDATA_BRANCH="master"
PVACCESS_BRANCH="master"
NORMATIVETYPES_BRANCH="master"
###########################################
# Fetch and unpack dependencies
@@ -32,19 +47,12 @@ rm -fr ${STUFF}
mkdir -p ${STUFF}
cd ${STUFF}
wget -nv https://openepics.ci.cloudbees.com/job/Base-${BASE}_Build/lastSuccessfulBuild/artifact/base-${BASE}.CB-dist.tar.gz
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
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
installTool Boost 1.61.0
installTool Base ${BASE}
if [ "${USE_MB}" = "MB_YES" ]; then
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
tar -xzf pvCommon.CB-dist.tar.gz
fi
installE4 pvData ${PVDATA_BRANCH}
installE4 pvAccess ${PVACCESS_BRANCH}
installE4 normativeTypes ${NORMATIVETYPES_BRANCH}
###########################################
# Build
@@ -65,7 +73,8 @@ make distclean all
###########################################
# Test
make runtests
# no regression tests
#make runtests
###########################################
# Create distribution
+26 -11
View File
@@ -6,14 +6,32 @@
#
# Author: Ralph Lange <ralph.lange@gmx.de>
# 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.
###########################################
# Set EPICS Base version and upload target
installTool () {
local module=$1
local version=$2
BASE=3.15.2
PUBLISH=${1:-DONT}
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
}
installE4 () {
local module=$1
local branch=$2
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
tar -xzf ${module}.CB-dist.tar.gz
}
###########################################
# Defaults for EPICS Base and parameters
BASE=3.15.4
PUBLISH=${PUBLISH:-NO}
BRANCH=${BRANCH:-master}
MB=NO_MICROBENCH
###########################################
# Fetch and unpack dependencies
@@ -24,16 +42,14 @@ rm -fr ${STUFF}
mkdir -p ${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
tar -xzf doxygen-1.8.3.CB-dist.tar.gz
installTool Doxygen 1.8.11
###########################################
# Generate
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
tar -xzf pvaClient.CB-dist.tar.gz
installE4 pvaClient ${BRANCH}
export PATH=${STUFF}/bin:${PATH}
@@ -45,7 +61,6 @@ doxygen
if [ "${PUBLISH}" != "DONT" ]; then
# Upload explicit dummy to ensure target directory exists
echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY
rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/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}/
fi
+10 -5
View File
@@ -5,10 +5,14 @@ include $(TOP)/configure/CONFIG
LIBRARY += pvaClient
INC += pvaClient.h
INC += pvaClientMultiChannel.h
# shared library ABI version.
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 += pvaClientData.cpp
LIBSRCS += pvaClientPutData.cpp
LIBSRCS += pvaClientGetData.cpp
LIBSRCS += pvaClientMonitorData.cpp
@@ -26,9 +30,10 @@ LIBSRCS += pvaClientNTMultiPut.cpp
LIBSRCS += pvaClientNTMultiData.cpp
LIBSRCS += pvaClientNTMultiGet.cpp
LIBSRCS += pvaClientNTMultiMonitor.cpp
LIBSRCS += pvaClientRPC.cpp
pvaClient_LIBS += pvAccess pvData nt Com
pvaClient_LIBS += $(EPICS_BASE_IOC_LIBS)
pvaClient_LIBS += nt
pvaClient_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
pvaClient_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES
+1805
View File
File diff suppressed because it is too large Load Diff
@@ -12,16 +12,23 @@
#define PVACLIENTMULTICHANNEL_H
#ifdef epicsExportSharedSymbols
# define pvaClientEpicsExportSharedSymbols
# define pvaClientMultiChannelEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/pvaClient.h>
#include <pv/ntmultiChannel.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;
@@ -55,135 +62,122 @@ class epicsShareClass PvaClientMultiChannel :
{
public:
POINTER_DEFINITIONS(PvaClientMultiChannel);
/** Create a PvaClientMultiChannel.
/** @brief Create a PvaClientMultiChannel.
* @param pvaClient The interface to pvaClient.
* @param channelNames The names of the channel..
* @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 providerNames The providerName for each Channells
* @return The interface to the PvaClientMultiChannel
*/
static PvaClientMultiChannelPtr create(
PvaClientPtr const &pvaClient,
epics::pvData::shared_vector<const std::string> const & channelNames,
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();
/** Destroy the pvAccess connections.
*/
void destroy();
/** Get the channelNames.
/** @brief Get the channelNames.
* @return The names.
*/
epics::pvData::shared_vector<const std::string> getChannelNames();
/** Connect to the channels.
/** @brief Connect to the channels.
*
* This calls issueConnect and waitConnect.
* An exception is thrown if connect fails.
* @param timeout The time to wait for connecting to the channel.
* @return status of request
*/
epics::pvData::Status connect(double timeout=5);
/** Are all channels connected?
/** @brief Are all channels connected?
* @return if all are connected.
*/
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.
*/
bool connectionChange();
/** Get the connection state of each channel.
/** @brief Get the connection state of each channel.
* @return The state of each channel.
*/
epics::pvData::shared_vector<epics::pvData::boolean> getIsConnected();
/** Get the pvaClientChannelArray.
/** @brief Get the pvaClientChannelArray.
* @return The shared pointer.
*/
PvaClientChannelArray getPvaClientChannelArray();
/** Get pvaClient.
/** @brief Get pvaClient.
* @return The shared pointer.
*/
PvaClientPtr getPvaClient();
/**
* create a pvaClientMultiGetDouble
* @brief create a pvaClientMultiGetDouble
* @return The interface.
*/
PvaClientMultiGetDoublePtr createGet();
PvaClientMultiGetDoublePtr createGet();
/**
* create a pvaClientMultiPutDouble
* @brief Create a pvaClientMultiPutDouble.
* @return The interface.
*/
PvaClientMultiPutDoublePtr createPut();
/**
* Create a pvaClientMultiMonitorDouble.
* @brief Create a pvaClientMultiMonitorDouble.
* @return The interface.
*/
PvaClientMultiMonitorDoublePtr createMonitor();
/**
* Create a pvaClientNTMultiPut.
* @brief Create a pvaClientNTMultiPut.
* @return The interface.
*/
PvaClientNTMultiPutPtr createNTPut();
/**
* Create a pvaClientNTMultiGet.
* This calls the next method with request = "value,alarm,timeStamp"
* @return The interface.
*/
PvaClientNTMultiGetPtr createNTGet();
/**
* Create a pvaClientNTMultiGet;
* @brief Create a pvaClientNTMultiGet;
* @param request The request for each channel.
* @return The interface.
*/
PvaClientNTMultiGetPtr createNTGet(std::string const &request);
PvaClientNTMultiGetPtr createNTGet(
std::string const &request = "field(value,alarm,timeStamp)");
/**
* Create a pvaClientNTMultiMonitor.
* This calls the next method with request = "value,alarm,timeStamp"
* @return The interface.
*/
PvaClientNTMultiMonitorPtr createNTMonitor();
/**
* Create a pvaClientNTMultiPut.
* @brief Create a pvaClientNTMultiPut.
* @param request The request for each channel.
* @return The interface.
*/
PvaClientNTMultiMonitorPtr createNTMonitor(std::string const &request);
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientMultiChannelPtr getPtrSelf()
{
return shared_from_this();
}
PvaClientNTMultiMonitorPtr createNTMonitor(
std::string const &request= "field(value,alarm,timeStamp)");
private:
PvaClientMultiChannel(
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,
size_t maxNotConnected);
size_t maxNotConnected,
epics::pvData::shared_vector<const std::string> const & providerNames);
void checkConnected();
PvaClientPtr pvaClient;
epics::pvData::shared_vector<const std::string> channelName;
epics::pvData::shared_vector<const std::string> channelNames;
std::string providerName;
size_t maxNotConnected;
epics::pvData::shared_vector<const std::string> const & providerNames;
size_t numChannel;
size_t numProviderNames;
epics::pvData::Mutex mutex;
size_t numConnected;
bool firstConnect;
PvaClientChannelArray pvaClientChannelArray;
epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
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 :
public std::tr1::enable_shared_from_this<PvaClientMultiGetDouble>
@@ -191,38 +185,25 @@ class epicsShareClass PvaClientMultiGetDouble :
public:
POINTER_DEFINITIONS(PvaClientMultiGetDouble);
/**
* Factory method that creates a PvaClientMultiGetDouble.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
protected:
static PvaClientMultiGetDoublePtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~PvaClientMultiGetDouble();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Create a channelGet for each channel.
*/
* @brief Create a channelGet for each channel.
*/
void connect();
/**
* get the data.
* @brief Get the data.
* @return The double[] where each element is the value field of the corresponding channel.
*/
epics::pvData::shared_vector<double> get();
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientMultiGetDoublePtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientMultiGetDouble(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -232,15 +213,14 @@ private:
PvaClientChannelArray pvaClientChannelArray;
size_t nchannel;
epics::pvData::Mutex mutex;
epics::pvData::shared_vector<double> doubleValue;
std::vector<PvaClientGetPtr> pvaClientGet;
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 :
public std::tr1::enable_shared_from_this<PvaClientMultiPutDouble>
@@ -248,36 +228,25 @@ class epicsShareClass PvaClientMultiPutDouble :
public:
POINTER_DEFINITIONS(PvaClientMultiPutDouble);
/**
* Factory method that creates a PvaClientMultiPutDouble.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
protected:
static PvaClientMultiPutDoublePtr create(
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray);
~PvaClientMultiPutDouble();
/** Destroy the pvAccess connection.
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
void destroy();
~PvaClientMultiPutDouble();
/**
* Create a channelPut for each channel.
* @brief Create a channelPut for each channel.
*/
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.
*/
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:
PvaClientMultiPutDouble(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -290,11 +259,10 @@ private:
std::vector<PvaClientPutPtr> pvaClientPut;
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 :
public std::tr1::enable_shared_from_this<PvaClientMultiMonitorDouble>
@@ -302,50 +270,40 @@ class epicsShareClass PvaClientMultiMonitorDouble :
public:
POINTER_DEFINITIONS(PvaClientMultiMonitorDouble);
/**
* Factory method that creates a PvaClientMultiMonitorDouble.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
protected:
static PvaClientMultiMonitorDoublePtr create(
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~PvaClientMultiMonitorDouble();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Create a channel monitor for each channel.
*/
* @brief Connect a channel monitor for each channel.
*/
void connect();
/**
* poll each channel.
* @brief Poll each channel.
*
* If any has new data it is used to update the double[].
* @return (false,true) if (no, at least one) value was updated.
*/
bool poll();
/**
* Wait until poll returns true.
* @param waitForEvent The time to keep trying.
* @brief Wait until poll returns true.
* @param secondsToWait The time to keep trying.
* A thread sleep of .1 seconds occurs between each call to poll.
* @return (false,true) if (timeOut, poll returned true).
*/
bool waitEvent(double waitForEvent);
bool waitEvent(double secondsToWait);
/**
* get the data.
* @return The double[] where each element is the value field of the corresponding channel.
*/
epics::pvData::shared_vector<double> get();
/** Monitor the shared pointer to self.
* @return The shared pointer.
*/
PvaClientMultiMonitorDoublePtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientMultiMonitorDouble(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -359,11 +317,10 @@ private:
epics::pvData::shared_vector<double> doubleValue;
std::vector<PvaClientMonitorPtr> pvaClientMonitor;
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 :
public std::tr1::enable_shared_from_this<PvaClientNTMultiGet>
@@ -371,43 +328,33 @@ class epicsShareClass PvaClientNTMultiGet :
public:
POINTER_DEFINITIONS(PvaClientNTMultiGet);
/**
* 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.
*/
protected:
static PvaClientNTMultiGetPtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~PvaClientNTMultiGet();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Create a channelGet for each channel.
*/
* @brief Connect a channelGet for each channel.
*/
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.
*/
PvaClientNTMultiDataPtr getData();
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiGetPtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientNTMultiGet(
epics::pvData::UnionConstPtr const & u,
@@ -420,16 +367,14 @@ private:
epics::pvData::PVStructurePtr pvRequest;
size_t nchannel;
epics::pvData::Mutex mutex;
PvaClientNTMultiDataPtr pvaClientNTMultiData;
std::vector<PvaClientGetPtr> pvaClientGet;
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 :
public std::tr1::enable_shared_from_this<PvaClientNTMultiPut>
@@ -437,40 +382,30 @@ class epicsShareClass PvaClientNTMultiPut :
public:
POINTER_DEFINITIONS(PvaClientNTMultiPut);
/**
* Factory method that creates a PvaClientNTMultiPut.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
protected:
static PvaClientNTMultiPutPtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray);
~PvaClientNTMultiPut();
/** Destroy the pvAccess connection.
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
void destroy();
~PvaClientNTMultiPut();
/**
* Create a channelPut for each channel.
* @brief Connect a channelPut for each channel.
*/
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.
*/
epics::pvData::shared_vector<epics::pvData::PVUnionPtr> getValues();
/**
* put the data to each channel.
' */
void put();
/** Get the shared pointer to self.
* @return The shared pointer.
* @brief Issue a put for each channel.
*/
PvaClientNTMultiPutPtr getPtrSelf()
{
return shared_from_this();
}
void put();
private:
PvaClientNTMultiPut(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
@@ -485,11 +420,10 @@ private:
epics::pvData::shared_vector<epics::pvData::PVFieldPtr> value;
std::vector<PvaClientPutPtr> pvaClientPut;
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 :
public std::tr1::enable_shared_from_this<PvaClientNTMultiMonitor>
@@ -497,51 +431,42 @@ class epicsShareClass PvaClientNTMultiMonitor :
public:
POINTER_DEFINITIONS(PvaClientNTMultiMonitor);
/**
* 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.
*/
protected:
static PvaClientNTMultiMonitorPtr create(
PvaClientMultiChannelPtr const &pvaNTMultiChannel,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
friend class PvaClientMultiChannel;
public:
/**
* @brief Destructor
*/
~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();
/**
* 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[].
* @return (false,true) if (no, at least one) value was updated.
*/
bool poll();
bool poll(bool valueOnly = true);
/**
* Wait until poll returns true.
* @param waitForEvent The time to keep trying.
* @brief Wait until poll returns true.
* @param secondsToWait The time to keep trying.
* A thread sleep of .1 seconds occurs between each call to poll.
* @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.
*/
PvaClientNTMultiDataPtr getData();
/** Monitor the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiMonitorPtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientNTMultiMonitor(
epics::pvData::UnionConstPtr const & u,
@@ -557,11 +482,10 @@ private:
PvaClientNTMultiDataPtr pvaClientNTMultiData;
std::vector<PvaClientMonitorPtr> pvaClientMonitor;
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 :
public std::tr1::enable_shared_from_this<PvaClientNTMultiData>
@@ -569,64 +493,43 @@ class epicsShareClass PvaClientNTMultiData :
public:
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();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Get the number of channels.
/**
* @brief Get the number of channels.
* @return The number of channels.
*/
size_t getNumber();
/**
* Set the timeStamp base for computing deltaTimes.
*/
void startDeltaTime();
/**
* Update NTMultiChannel fields.
*/
void endDeltaTime();
/**
* Get the time when the last get was made.
/**
* @brief Get the time when the last get was made.
* @return The timeStamp.
*/
epics::pvData::TimeStamp getTimeStamp();
epics::pvData::TimeStamp getTimeStamp();
/**
* Get the NTMultiChannel.
* @brief Get the NTMultiChannel.
* @return The value.
*/
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()
{
return shared_from_this();
}
epics::pvData::shared_vector<epics::pvData::boolean> getChannelChangeFlags();
protected:
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:
PvaClientNTMultiData(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaNTMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
void setStructure(epics::pvData::StructureConstPtr const & structure,size_t index);
void setPVStructure(
epics::pvData::PVStructurePtr const &pvStructure,size_t index);
@@ -638,8 +541,8 @@ private:
std::vector<epics::pvData::PVStructurePtr> topPVStructure;
bool gotAlarm;
bool gotTimeStamp;
bool isDestroyed;
epics::pvData::shared_vector<epics::pvData::boolean> changeFlags;
epics::pvData::StructureConstPtr ntMultiChannelStructure;
epics::pvData::shared_vector<epics::pvData::PVUnionPtr> unionValue;
epics::pvData::shared_vector<epics::pvData::int32> severity;
@@ -651,19 +554,9 @@ private:
epics::pvData::Alarm alarm;
epics::pvData::TimeStamp timeStamp;;
epics::pvData::PVTimeStamp pvTimeStamp;
friend class PvaClientNTMultiGet;
friend class PvaClientNTMultiPut;
friend class PvaClientNTMultiMonitor;
};
}}
#endif /* PVACLIENTMULTICHANNEL_H */
/** @page Overview Documentation
*
* <a href = "../pvaClientOverview.html">pvaClientOverview.html</a>
*
*/
+88 -91
View File
@@ -9,86 +9,40 @@
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <map>
#include <pv/pvaClient.h>
#include <pv/createRequest.h>
#include <pv/clientFactory.h>
#include <pv/caProvider.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvAccess::ca;
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 {
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
class epicsShareClass PvaClientChannelCache
{
public:
PvaClientChannelCache(){}
~PvaClientChannelCache(){
destroy();
if(PvaClient::getDebug()) cout << "PvaClientChannelCache::~PvaClientChannelCache\n";
}
void destroy() {
pvaClientChannelMap.clear();
}
PvaClientChannelPtr getChannel(
string const & channelName,
string const & providerName);
void addChannel(PvaClientChannelPtr const & pvaClientChannel);
void removeChannel(string const & channelName,string const & providerName);
void showCache();
size_t cacheSize();
private:
map<string,PvaClientChannelPtr> pvaClientChannelMap;
};
PvaClientChannelPtr PvaClientChannelCache::getChannel(
string const & channelName,
string const & providerName)
@@ -104,17 +58,12 @@ void PvaClientChannelCache::addChannel(PvaClientChannelPtr const & pvaClientChan
Channel::shared_pointer channel = pvaClientChannel->getChannel();
string name = channel->getChannelName()
+ 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);
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()
@@ -127,10 +76,8 @@ void PvaClientChannelCache::showCache()
string channelName = channel->getChannelName();
string providerName = channel->getProvider()->getProviderName();
cout << "channel " << channelName << " provider " << providerName << endl;
cout << " get and put cacheSize " << pvaChannel->cacheSize() << endl;
pvaChannel->showCache();
}
}
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());
StartStopClientFactory::PvaClientBeingConstructed();
return xx;
debug = value;
}
PvaClient::PvaClient()
: pvaClientChannelCache(new PvaClientChannelCache()),
isDestroyed(false)
bool PvaClient::getDebug()
{
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() {
destroy();
}
void PvaClient::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
if(getDebug()) {
cout<< "PvaClient::~PvaClient()\n"
<< "pvaChannel cache:\n";
showCache();
}
pvaClientChannelCache.reset();
StartStopClientFactory::PvaClientBeingDestroyed();
if(pvaStarted){
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()
@@ -197,7 +191,7 @@ PvaClientChannelPtr PvaClient::channel(
std::string const & providerName,
double timeOut)
{
PvaClientChannelPtr pvaClientChannel =
PvaClientChannelPtr pvaClientChannel =
pvaClientChannelCache->getChannel(channelName,providerName);
if(pvaClientChannel) return pvaClientChannel;
pvaClientChannel = createChannel(channelName,providerName);
@@ -208,7 +202,7 @@ PvaClientChannelPtr PvaClient::channel(
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)
@@ -218,12 +212,16 @@ void PvaClient::setRequester(RequesterPtr const & requester)
void PvaClient::clearRequester()
{
requester = Requester::weak_pointer();
requester.reset();
}
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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <map>
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/pvaClient.h>
#include <pv/createRequest.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
@@ -25,13 +25,13 @@ using namespace std;
namespace epics { namespace pvaClient {
class PvaClientGetCache
class epicsShareClass PvaClientGetCache
{
public:
PvaClientGetCache(){}
~PvaClientGetCache();
void destroy() {
pvaClientGetMap.clear();
~PvaClientGetCache()
{
if(PvaClient::getDebug()) cout << "PvaClientGetCache::~PvaClientGetCache\n";
}
PvaClientGetPtr getGet(string const & request);
void addGet(string const & request,PvaClientGetPtr const & pvaClientGet);
@@ -41,11 +41,6 @@ private:
map<string,PvaClientGetPtr> pvaClientGetMap;
};
PvaClientGetCache::~PvaClientGetCache()
{
destroy();
}
PvaClientGetPtr PvaClientGetCache::getGet(string const & 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)
{
pvaClientGetMap.insert(std::pair<string,PvaClientGetPtr>(
request,pvaClientGet));
map<string,PvaClientGetPtr>::iterator iter = pvaClientGetMap.find(request);
if(iter!=pvaClientGetMap.end()) {
throw std::runtime_error("pvaClientGetCache::addGet pvaClientGet already cached");
}
pvaClientGetMap.insert(std::pair<string,PvaClientGetPtr>(request,pvaClientGet));
}
void PvaClientGetCache::showCache()
@@ -74,13 +72,13 @@ size_t PvaClientGetCache::cacheSize()
}
class PvaClientPutCache
class epicsShareClass PvaClientPutCache
{
public:
PvaClientPutCache(){}
~PvaClientPutCache();
void destroy() {
pvaClientPutMap.clear();
~PvaClientPutCache()
{
if(PvaClient::getDebug()) cout << "PvaClientPutCache::~PvaClientPutCache\n";
}
PvaClientPutPtr getPut(string const & request);
void addPut(string const & request,PvaClientPutPtr const & pvaClientPut);
@@ -90,10 +88,6 @@ private:
map<string,PvaClientPutPtr> pvaClientPutMap;
};
PvaClientPutCache::~PvaClientPutCache()
{
destroy();
}
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)
{
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>(
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;
public:
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();}
};
PvaClientChannelPtr channel(new PvaClientChannel(pvaClient,channelName,providerName));
return channel;
}
PvaClientChannel::PvaClientChannel(
@@ -156,52 +139,87 @@ PvaClientChannel::PvaClientChannel(
channelName(channelName),
providerName(providerName),
connectState(connectIdle),
isDestroyed(false),
createRequest(CreateRequest::create()),
pvaClientGetCache(new PvaClientGetCache()),
pvaClientPutCache(new PvaClientPutCache())
{}
{
if(PvaClient::getDebug()) {
cout << "PvaClientChannel::PvaClientChannel channelName " << channelName << endl;
}
}
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)
{
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
if(status.isOK()) {
this->channel = channel;
return;
if(PvaClient::getDebug()) {
cout << "PvaClientChannel::channelCreated"
<< " channelName " << channelName
<< " 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(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState)
{
Lock xx(mutex);
if(isDestroyed) return;
if(PvaClient::getDebug()) {
cout << " PvaClientChannel::channelStateChange "
<< " channelName " << channelName
<< " " << Channel::ConnectionStateNames[connectionState]
<< endl;
}
bool waitingForConnect = false;
if(connectState==connectActive) waitingForConnect = true;
if(connectionState!=Channel::CONNECTED) {
string mess(channelName +
" connection state " + Channel::ConnectionStateNames[connectionState]);
message(mess,errorMessage);
channelConnectStatus = Status(Status::STATUSTYPE_ERROR,mess);
connectState = notConnected;
Lock xx(mutex);
connectState = notConnected;
} else {
connectState = connected;
channelConnectStatus = Status::Ok;
Lock xx(mutex);
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()
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed");
if(!yyy) return string("PvaClientChannel::getRequesterName() PvaClient isDestroyed");
return yyy->getRequesterName();
}
@@ -209,99 +227,97 @@ void PvaClientChannel::message(
string const & message,
MessageType messageType)
{
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("PvaClient was destroyed");
if(!yyy) return;
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
return channelName;
}
Channel::shared_pointer PvaClientChannel::getChannel()
{
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
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)
{
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientChannel::connect"
<< " channelName " << channelName << endl;
}
issueConnect();
Status status = waitConnect(timeout);
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();
throw std::runtime_error(message);
}
void PvaClientChannel::issueConnect()
{
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
if(connectState!=connectIdle) {
throw std::runtime_error("pvaClientChannel already connected");
if(PvaClient::getDebug()) {
cout << "PvaClientChannel::issueConnect"
<< " channelName " << channelName << endl;
}
channelRequester = ChannelRequester::shared_pointer(new ChannelRequesterImpl(this));
channelConnectStatus = Status(
Status::STATUSTYPE_ERROR,
getChannelName() + " createChannel failed");
connectState = connectActive;
ChannelProviderRegistry::shared_pointer reg = getChannelProviderRegistry();
ChannelProvider::shared_pointer provider = reg->getProvider(providerName);
if(!provider) {
throw std::runtime_error(getChannelName() + " provider " + providerName + " not registered");
{
Lock xx(mutex);
if(connectState==connected) return;
if(connectState!=connectIdle) {
throw std::runtime_error("pvaClientChannel already connected");
}
connectState = connectActive;
}
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) {
throw std::runtime_error(getChannelName() + " channelCreate failed ");
throw std::runtime_error(channelName + " channelCreate failed ");
}
}
Status PvaClientChannel::waitConnect(double timeout)
{
if(isDestroyed) throw std::runtime_error("pvaClientChannel was destroyed");
waitForConnect.wait(timeout);
return channelConnectStatus;
}
PvaClientFieldPtr PvaClientChannel::createField()
{
return createField("");
}
PvaClientFieldPtr PvaClientChannel::createField(string const & subField)
{
if(connectState!=connected) connect(5.0);
throw std::runtime_error("PvaClientChannel::createField not implemented");
}
PvaClientProcessPtr PvaClientChannel::createProcess()
{
return createProcess("");
if(PvaClient::getDebug()) {
cout << "PvaClientChannel::waitConnect"
<< " channelName " << channelName << endl;
}
{
Lock xx(mutex);
if(!channel) return Status(Status::STATUSTYPE_ERROR,"");
if(channel->isConnected()) return Status::Ok;
}
if(timeout>0.0) {
waitForConnect.wait(timeout);
} else {
waitForConnect.wait();
}
if(!channel) return Status(Status::STATUSTYPE_ERROR,"pvaClientChannel::waitConnect channel is null");
if(channel->isConnected()) return Status::Ok;
return Status(Status::STATUSTYPE_ERROR," not connected");
}
PvaClientProcessPtr PvaClientChannel::createProcess(string const & request)
{
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
string message = string("channel ") + getChannelName()
string message = string("channel ") + channelName
+ " PvaClientChannel::createProcess invalid pvRequest: "
+ createRequest->getMessage();
throw std::runtime_error(message);
@@ -314,31 +330,28 @@ PvaClientProcessPtr PvaClientChannel::createProcess(PVStructurePtr const & pvRe
if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock();
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 pvaClientGet = pvaClientGetCache->getGet(request);
if(pvaClientGet) return pvaClientGet;
pvaClientGet = createGet(request);
pvaClientGet->connect();
pvaClientGetCache->addGet(request,pvaClientGet);
if(!pvaClientGet) {
pvaClientGet = createGet(request);
pvaClientGet->connect();
pvaClientGetCache->addGet(request,pvaClientGet);
}
pvaClientGet->get();
return pvaClientGet;
}
PvaClientGetPtr PvaClientChannel::createGet()
{
return PvaClientChannel::createGet("value,alarm,timeStamp");
}
PvaClientGetPtr PvaClientChannel::createGet(string const & request)
{
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
string message = string("channel ") + getChannelName()
string message = string("channel ") + channelName
+ " PvaClientChannel::createGet invalid pvRequest: "
+ createRequest->getMessage();
throw std::runtime_error(message);
@@ -351,32 +364,49 @@ PvaClientGetPtr PvaClientChannel::createGet(PVStructurePtr const & pvRequest)
if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock();
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 pvaClientPut = pvaClientPutCache->getPut(request);
if(pvaClientPut) return pvaClientPut;
pvaClientPut = createPut(request);
pvaClientPut->connect();
pvaClientPut->get();
pvaClientPutCache->addPut(request,pvaClientPut);
if(!pvaClientPut) {
pvaClientPut = createPut(request);
pvaClientPut->connect();
pvaClientPut->get();
pvaClientPutCache->addPut(request,pvaClientPut);
}
return pvaClientPut;
}
PvaClientPutPtr PvaClientChannel::createPut()
{
return createPut("value");
}
PvaClientPutPtr PvaClientChannel::createPut(string const & request)
{
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
string message = string("channel ") + getChannelName()
string message = string("channel ") + channelName
+ " PvaClientChannel::createPut invalid pvRequest: "
+ createRequest->getMessage();
throw std::runtime_error(message);
@@ -389,19 +419,52 @@ PvaClientPutPtr PvaClientChannel::createPut(PVStructurePtr const & pvRequest)
if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock();
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)
{
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
string message = string("channel ") + getChannelName()
string message = string("channel ") + channelName
+ " PvaClientChannel::createPutGet invalid pvRequest: "
+ createRequest->getMessage();
throw std::runtime_error(message);
@@ -414,36 +477,9 @@ PvaClientPutGetPtr PvaClientChannel::createPutGet(PVStructurePtr const & pvReque
if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock();
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 pvaClientMonitor = createMonitor(request);
@@ -454,7 +490,7 @@ PvaClientMonitorPtr PvaClientChannel::monitor(string const & request)
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,
@@ -467,16 +503,11 @@ PvaClientMonitorPtr PvaClientChannel::monitor(string const & request,
return pvaClientMonitor;
}
PvaClientMonitorPtr PvaClientChannel::createMonitor()
{
return createMonitor("value,alarm,timeStamp");
}
PvaClientMonitorPtr PvaClientChannel::createMonitor(string const & request)
{
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
string message = string("channel ") + getChannelName()
string message = string("channel ") + channelName
+ " PvaClientChannel::createMonitor invalid pvRequest: "
+ createRequest->getMessage();
throw std::runtime_error(message);
@@ -489,15 +520,55 @@ PvaClientMonitorPtr PvaClientChannel::createMonitor(PVStructurePtr const & pvR
if(connectState!=connected) connect(5.0);
PvaClientPtr yyy = pvaClient.lock();
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()
{
cout << " pvaClientGet" << endl;
pvaClientGetCache->showCache();
cout << " pvaClientPut" << endl;
pvaClientPutCache->showCache();
if(pvaClientGetCache->cacheSize()>=1) {
cout << " pvaClientGet cache" << endl;
pvaClientGetCache->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()
@@ -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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <pv/event.h>
#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 {
class ChannelGetRequesterImpl : public ChannelGetRequester
{
PvaClientGet * pvaClientGet;
PvaClientGet::weak_pointer pvaClientGet;
PvaClient::weak_pointer pvaClient;
public:
ChannelGetRequesterImpl(PvaClientGet * pvaClientGet)
: pvaClientGet(pvaClientGet) {}
string getRequesterName()
{return pvaClientGet->getRequesterName();}
void message(string const & message,MessageType messageType)
{pvaClientGet->message(message,messageType);}
void channelGetConnect(
ChannelGetRequesterImpl(
PvaClientGetPtr const & pvaClientGet,
PvaClientPtr const &pvaClient)
: pvaClientGet(pvaClientGet),
pvaClient(pvaClient)
{}
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,
ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const & structure)
{pvaClientGet->channelGetConnect(status,channelGet,structure);}
void getDone(
Structure::const_shared_pointer const & structure)
{
PvaClientGetPtr clientGet(pvaClientGet.lock());
if(!clientGet) return;
clientGet->channelGetConnect(status,channelGet,structure);
}
virtual void getDone(
const Status& status,
ChannelGet::shared_pointer const & channelGet,
PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet)
{pvaClientGet->getDone(status,channelGet,pvStructure,bitSet);}
BitSet::shared_pointer const & 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(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
: pvaClient(pvaClient),
channel(channel),
pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle),
getState(getIdle)
{
if(PvaClient::getDebug()) {
cout << "PvaClientGet::PvaClientGet channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
}
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(connectState==connectIdle) connect();
if(getState==getIdle) get();
if(PvaClient::getDebug()) {
cout << "PvaClientGet::checkConnectState channelName "
<< 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()
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
return pvaClientChannel->getRequesterName();
}
void PvaClientGet::message(string const & message,MessageType messageType)
{
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed");
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
pvaClientChannel->message(message,messageType);
}
void PvaClientGet::channelGetConnect(
@@ -90,16 +149,27 @@ void PvaClientGet::channelGetConnect(
ChannelGet::shared_pointer const & channelGet,
StructureConstPtr const & structure)
{
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed");
channelGetConnectStatus = status;
this->channelGet = channelGet;
if(status.isOK()) {
pvaClientData = PvaClientGetData::create(structure);
pvaClientData->setMessagePrefix(channel->getChannelName());
connectState = connected;
if(PvaClient::getDebug()) {
cout << "PvaClientGet::channelGetConnect channelName "
<< pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< "\n";
}
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(
@@ -108,82 +178,90 @@ void PvaClientGet::getDone(
PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet)
{
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed");
channelGetStatus = status;
if(status.isOK()) {
pvaClientData->setData(pvStructure,bitSet);
if(PvaClient::getDebug()) {
cout << "PvaClientGet::getDone channelName "
<< pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< "\n";
}
waitForGet.signal();
}
// from PvaClientGet
void PvaClientGet::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
channelGetStatus = status;
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientGet::connect channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
issueConnect();
Status status = waitConnect();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientGet::connect " + status.getMessage();
throw std::runtime_error(message);
}
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) {
string message = string("channel ") + channel->getChannelName()
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientGet already connected ";
throw std::runtime_error(message);
}
getRequester = ChannelGetRequester::shared_pointer(new ChannelGetRequesterImpl(this));
connectState = connectActive;
channelGet = channel->createChannelGet(getRequester,pvRequest);
channelGetConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelGet = pvaClientChannel->getChannel()->createChannelGet(channelGetRequester,pvRequest);
}
Status PvaClientGet::waitConnect()
{
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed");
if(connectState==connected) return channelGetConnectStatus;
if(connectState!=connectActive) {
string message = string("channel ") + channel->getChannelName()
+ " pvaClientGet illegal connect state ";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientGet::waitConnect channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
waitForConnect.wait();
connectState = channelGetConnectStatus.isOK() ? connected : connectIdle;
return channelGetConnectStatus;
}
void PvaClientGet::get()
{
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientGet::get channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
issueGet();
Status status = waitGet();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientGet::get " + status.getMessage();
throw std::runtime_error(message);
}
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(getState!=getIdle) {
string message = string("channel ") + channel->getChannelName()
if(getState==getActive) {
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientGet::issueGet get aleady active ";
throw std::runtime_error(message);
}
@@ -193,32 +271,38 @@ void PvaClientGet::issueGet()
Status PvaClientGet::waitGet()
{
if(isDestroyed) throw std::runtime_error("pvaClientGet was destroyed");
if(getState!=getActive){
string message = string("channel ") + channel->getChannelName()
+ " PvaClientGet::waitGet llegal get state";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientGet::waitGet channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
waitForGet.wait();
getState = getIdle;
if(channelGetStatus.isOK()) {
return Status::Ok;
}
return channelGetStatus;
}
PvaClientGetDataPtr PvaClientGet::getData()
{
checkGetState();
if(PvaClient::getDebug()) {
cout<< "PvaClientGet::getData channelName "
<< pvaClientChannel->getChannel()->getChannelName() << "\n";
}
checkConnectState();
if(getState==getIdle) get();
return pvaClientData;
}
PvaClientGetPtr PvaClientGet::create(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
void PvaClientGet::setRequester(PvaClientGetRequesterPtr const & pvaClientGetRequester)
{
PvaClientGetPtr epv(new PvaClientGet(pvaClient,channel,pvRequest));
return epv;
if(PvaClient::getDebug()) {
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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <typeinfo>
#include <sstream>
#include <pv/pvaClient.h>
#include <pv/createRequest.h>
#include <pv/convert.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
@@ -26,199 +26,15 @@ 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 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)
{
if(PvaClient::getDebug()) cout << "PvaClientGetData::create\n";
PvaClientGetDataPtr epv(new PvaClientGetData(structure));
return epv;
}
PvaClientGetData::PvaClientGetData(StructureConstPtr const & structure)
: structure(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);
}
: PvaClientData(structure)
{}
}}
+342 -97
View File
@@ -8,84 +8,205 @@
* @author mrk
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <sstream>
#include <pv/event.h>
#include <pv/pvaClient.h>
#include <pv/bitSetUtil.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvaClient {
class ChannelMonitorRequester : public MonitorRequester
class MonitorRequesterImpl : public MonitorRequester
{
PvaClientMonitor * pvaClientMonitor;
PvaClientMonitor::weak_pointer pvaClientMonitor;
PvaClient::weak_pointer pvaClient;
public:
ChannelMonitorRequester(PvaClientMonitor * pvaClientMonitor)
: pvaClientMonitor(pvaClientMonitor) {}
string getRequesterName()
{return pvaClientMonitor->getRequesterName();}
void message(string const & message,MessageType messageType)
{pvaClientMonitor->message(message,messageType);}
void monitorConnect(
MonitorRequesterImpl(
PvaClientMonitorPtr const & pvaClientMonitor,
PvaClientPtr const &pvaClient)
: pvaClientMonitor(pvaClientMonitor),
pvaClient(pvaClient)
{}
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,
Monitor::shared_pointer const & monitor,
StructureConstPtr const & structure)
{pvaClientMonitor->monitorConnect(status,monitor,structure);}
void monitorEvent(MonitorPtr const & monitor)
Structure::const_shared_pointer const & structure)
{
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(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
: pvaClient(pvaClient),
channel(channel),
pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest),
isDestroyed(false),
isStarted(false),
connectState(connectIdle),
userPoll(false),
userWait(false)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientMonitor::PvaClientMonitor\n"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
}
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(connectState==connectIdle) connect();
if(connectState==connected) start();
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::checkMonitorState"
<< " 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()
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
return pvaClientChannel->getRequesterName();
}
void PvaClientMonitor::message(string const & message,MessageType messageType)
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
pvaClientChannel->message(message,messageType);
}
void PvaClientMonitor::monitorConnect(
@@ -93,119 +214,234 @@ void PvaClientMonitor::monitorConnect(
Monitor::shared_pointer const & monitor,
StructureConstPtr const & structure)
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
connectStatus = status;
this->monitor = monitor;
if(status.isOK()) {
pvaClientData = PvaClientMonitorData::create(structure);
pvaClientData->setMessagePrefix(channel->getChannelName());
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::monitorConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
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)
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::monitorEvent"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
PvaClientMonitorRequesterPtr req = pvaClientMonitorRequester.lock();
if(req) req->event(getPtrSelf());
if(req) req->event(shared_from_this());
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(PvaClient::getDebug()) cout << "PvaClientMonitor::connect\n";
issueConnect();
Status status = waitConnect();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientMonitor::connect " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientMonitor::connect "
+ status.getMessage();
throw std::runtime_error(message);
}
void PvaClientMonitor::issueConnect()
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(PvaClient::getDebug()) cout << "PvaClientMonitor::issueConnect\n";
if(connectState!=connectIdle) {
string message = string("channel ") + channel->getChannelName()
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientMonitor already connected ";
throw std::runtime_error(message);
}
monitorRequester = ChannelMonitorRequester::shared_pointer(new ChannelMonitorRequester(this));
connectState = connectActive;
monitor = channel->createMonitor(monitorRequester,pvRequest);
connectState = connectWait;
monitor = pvaClientChannel->getChannel()->createMonitor(monitorRequester,pvRequest);
}
Status PvaClientMonitor::waitConnect()
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(connectState!=connectActive) {
string message = string("channel ") + channel->getChannelName()
+ " pvaClientMonitor illegal connect state ";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::waitConnect "
<< pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForConnect.wait();
connectState = connectStatus.isOK() ? connected : connectIdle;
return connectStatus;
if(PvaClient::getDebug()) {
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(connectState==monitorStarted) return;
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::start"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " connectState " << connectState
<< endl;
}
if(isStarted) {
return;
}
if(connectState==connectIdle) connect();
if(connectState!=connected) throw std::runtime_error("PvaClientMonitor::start illegal state");
connectState = monitorStarted;
if(connectState!=connected) {
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientMonitor::start illegal state ";
throw std::runtime_error(message);
}
isStarted = true;
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(connectState!=monitorStarted) return;
connectState = connected;
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::stop"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
if(!isStarted) return;
isStarted = false;
monitor->stop();
}
bool PvaClientMonitor::poll()
{
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::poll"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
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();
if(!monitorElement) return false;
userPoll = true;
pvaClientData->setData(monitorElement);
return true;
return true;
}
bool PvaClientMonitor::waitEvent(double secondsToWait)
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(connectState!=monitorStarted) throw std::runtime_error("PvaClientMonitor::waitEvent illegal state");
if(PvaClient::getDebug()) {
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;
userWait = true;
if(secondsToWait==0.0) {
@@ -219,26 +455,35 @@ bool PvaClientMonitor::waitEvent(double secondsToWait)
void PvaClientMonitor::releaseEvent()
{
if(isDestroyed) throw std::runtime_error("pvaClientMonitor was destroyed");
if(connectState!=monitorStarted) throw std::runtime_error("PvaClientMonitor::poll illegal state");
if(!userPoll) throw std::runtime_error("PvaClientMonitor::releaseEvent did not call poll");
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::releaseEvent"
<< " 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;
monitor->release(monitorElement);
}
PvaClientChannelPtr PvaClientMonitor::getPvaClientChannel()
{
return pvaClientChannel;
}
PvaClientMonitorDataPtr PvaClientMonitor::getData()
{
if(PvaClient::getDebug()) {
cout << "PvaClientMonitor::getData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkMonitorState();
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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <typeinfo>
#include <sstream>
#include <pv/pvaClient.h>
#include <pv/createRequest.h>
#include <pv/convert.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
@@ -52,43 +52,16 @@ PvaClientMonitorDataPtr PvaClientMonitorData::create(StructureConstPtr const & s
}
PvaClientMonitorData::PvaClientMonitorData(StructureConstPtr const & structure)
: structure(structure)
: PvaClientData(structure)
{
messagePrefix = "";
}
void PvaClientMonitorData::setData(MonitorElementPtr const & monitorElement)
{
pvStructure = monitorElement->pvStructurePtr;
changedBitSet = monitorElement->changedBitSet;
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
BitSetPtr changedBitSet = monitorElement->changedBitSet;
PvaClientData::setData(pvStructure,changedBitSet);
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()
@@ -97,24 +70,6 @@ BitSetPtr PvaClientMonitorData::getOverrunBitSet()
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)
{
if(!overrunBitSet) throw std::runtime_error(messagePrefix + noStructure);
@@ -122,9 +77,9 @@ std::ostream & PvaClientMonitorData::showOverrun(std::ostream & out)
PVFieldPtr pvField;
while(nextSet!=string::npos) {
if(nextSet==0) {
pvField = pvStructure;
pvField = getPVStructure();
} else {
pvField = pvStructure->getSubField(nextSet);
pvField = getPVStructure()->getSubField(nextSet);
}
string name = pvField->getFullName();
out << name << " = " << pvField << endl;
@@ -133,135 +88,4 @@ std::ostream & PvaClientMonitorData::showOverrun(std::ostream & 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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <map>
#include <pv/event.h>
#include <pv/lock.h>
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
@@ -29,71 +28,74 @@ static CreateRequest::shared_pointer createRequestPvt = CreateRequest::create()
PvaClientMultiChannelPtr PvaClientMultiChannel::create(
PvaClientPtr const &pvaClient,
epics::pvData::shared_vector<const string> const & channelNames,
shared_vector<const string> const & channelNames,
string const & providerName,
size_t maxNotConnected)
size_t maxNotConnected,
shared_vector<const string> const & providerNames)
{
return PvaClientMultiChannelPtr(
new PvaClientMultiChannel(pvaClient,channelNames,providerName,maxNotConnected));
new PvaClientMultiChannel(
pvaClient,channelNames,providerName,maxNotConnected,providerNames));
}
PvaClientMultiChannel::PvaClientMultiChannel(
PvaClientPtr const &pvaClient,
epics::pvData::shared_vector<const string> const & channelName,
shared_vector<const string> const & channelNames,
string const & providerName,
size_t maxNotConnected)
size_t maxNotConnected,
shared_vector<const string> const & providerNames)
: pvaClient(pvaClient),
channelName(channelName),
channelNames(channelNames),
providerName(providerName),
maxNotConnected(maxNotConnected),
numChannel(channelName.size()),
providerNames(providerNames),
numChannel(channelNames.size()),
numProviderNames(providerNames.size()),
numConnected(0),
firstConnect(true),
pvaClientChannelArray(PvaClientChannelArray(numChannel,PvaClientChannelPtr())),
isConnected(shared_vector<epics::pvData::boolean>(numChannel,false)),
createRequest(CreateRequest::create()),
isDestroyed(false)
createRequest(CreateRequest::create())
{
if(PvaClient::getDebug()) cout<< "PvaClientMultiChannel::PvaClientMultiChannel()\n";
}
PvaClientMultiChannel::~PvaClientMultiChannel()
{
destroy();
}
void PvaClientMultiChannel::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
if(PvaClient::getDebug()) cout<< "PvaClientMultiChannel::~PvaClientMultiChannel()\n";
}
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 channelName;
return channelNames;
}
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) {
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();
}
Status returnStatus = Status::Ok;
Status status = Status::Ok;
size_t numBad = 0;
for(size_t i=0; i< numChannel; ++i) {
if(numBad==0) {
if(numBad==0) {
status = pvaClientChannelArray[i]->waitConnect(timeout);
} else {
status = pvaClientChannelArray[i]->waitConnect(.001);
@@ -101,11 +103,10 @@ Status PvaClientMultiChannel::connect(double timeout)
if(status.isOK()) {
++numConnected;
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;
}
@@ -113,13 +114,11 @@ Status PvaClientMultiChannel::connect(double timeout)
bool PvaClientMultiChannel::allConnected()
{
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
return (numConnected==numChannel) ? true : false;
}
bool PvaClientMultiChannel::connectionChange()
{
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
for(size_t i=0; i<numChannel; ++i) {
PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i];
Channel::shared_pointer channel = pvaClientChannel->getChannel();
@@ -130,9 +129,8 @@ bool PvaClientMultiChannel::connectionChange()
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) {
PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i];
if(!pvaClientChannel) {
@@ -148,50 +146,43 @@ epics::pvData::shared_vector<epics::pvData::boolean> PvaClientMultiChannel::get
PvaClientChannelArray PvaClientMultiChannel::getPvaClientChannelArray()
{
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
return pvaClientChannelArray;
}
PvaClientPtr PvaClientMultiChannel::getPvaClient()
{
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
return pvaClient;
}
PvaClientMultiGetDoublePtr PvaClientMultiChannel::createGet()
{
checkConnected();
return PvaClientMultiGetDouble::create(getPtrSelf(),pvaClientChannelArray);
return PvaClientMultiGetDouble::create(shared_from_this(),pvaClientChannelArray);
}
PvaClientMultiPutDoublePtr PvaClientMultiChannel::createPut()
{
checkConnected();
return PvaClientMultiPutDouble::create(getPtrSelf(),pvaClientChannelArray);
return PvaClientMultiPutDouble::create(shared_from_this(),pvaClientChannelArray);
}
PvaClientMultiMonitorDoublePtr PvaClientMultiChannel::createMonitor()
{
checkConnected();
return PvaClientMultiMonitorDouble::create(getPtrSelf(), pvaClientChannelArray);
return PvaClientMultiMonitorDouble::create(shared_from_this(), pvaClientChannelArray);
}
PvaClientNTMultiPutPtr PvaClientMultiChannel::createNTPut()
{
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)
{
checkConnected();
@@ -201,13 +192,7 @@ PvaClientNTMultiGetPtr PvaClientMultiChannel::createNTGet(std::string const &req
+ createRequest->getMessage();
throw std::runtime_error(message);
}
return PvaClientNTMultiGet::create(getPtrSelf(), pvaClientChannelArray,pvRequest);
}
PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor()
{
return createNTMonitor("value,alarm,timeStamp");
return PvaClientNTMultiGet::create(shared_from_this(), pvaClientChannelArray,pvRequest);
}
PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor(std::string const &request)
@@ -219,7 +204,7 @@ PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor(std::string co
+ createRequest->getMessage();
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
*/
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::nt;
using namespace std;
namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
namespace epics { namespace pvaClient {
PvaClientMultiGetDoublePtr PvaClientMultiGetDouble::create(
@@ -44,31 +39,21 @@ PvaClientMultiGetDouble::PvaClientMultiGetDouble(
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()),
doubleValue(shared_vector<double>(nchannel)),
doubleValue( shared_vector<double>(nchannel)),
pvaClientGet(std::vector<PvaClientGetPtr>(nchannel,PvaClientGetPtr())),
isGetConnected(false),
isDestroyed(false)
isGetConnected(false)
{
if(PvaClient::getDebug()) cout<< "PvaClientMultiGetDouble::PvaClientMultiGetDouble()\n";
}
PvaClientMultiGetDouble::~PvaClientMultiGetDouble()
{
destroy();
}
void PvaClientMultiGetDouble::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
if(PvaClient::getDebug()) cout<< "PvaClientMultiGetDouble::~PvaClientMultiGetDouble()\n";
}
void PvaClientMultiGetDouble::connect()
{
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean>isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
for(size_t i=0; i<nchannel; ++i)
{
@@ -90,14 +75,14 @@ void PvaClientMultiGetDouble::connect()
isGetConnected = true;
}
epics::pvData::shared_vector<double> PvaClientMultiGetDouble::get()
shared_vector<double> PvaClientMultiGetDouble::get()
{
if(!isGetConnected) connect();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
if(!pvaClientGet[i]) pvaClientGet[i]=pvaClientChannelArray[i]->createGet("value");
pvaClientGet[i]->issueGet();
}
}
@@ -111,13 +96,22 @@ epics::pvData::shared_vector<double> PvaClientMultiGetDouble::get()
throw std::runtime_error(message);
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i])
{
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 {
doubleValue[i] = epicsNAN;
}
+21 -26
View File
@@ -9,25 +9,19 @@
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <epicsThread.h>
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::nt;
using namespace std;
namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
namespace epics { namespace pvaClient {
PvaClientMultiMonitorDoublePtr PvaClientMultiMonitorDouble::create(
@@ -47,24 +41,14 @@ PvaClientMultiMonitorDouble::PvaClientMultiMonitorDouble(
nchannel(pvaClientChannelArray.size()),
doubleValue(shared_vector<double>(nchannel,epicsNAN)),
pvaClientMonitor(std::vector<PvaClientMonitorPtr>(nchannel,PvaClientMonitorPtr())),
isMonitorConnected(false),
isDestroyed(false)
isMonitorConnected(false)
{
if(PvaClient::getDebug()) cout<< "PvaClientMultiMonitorDouble::PvaClientMultiMonitorDouble()\n";
}
PvaClientMultiMonitorDouble::~PvaClientMultiMonitorDouble()
{
destroy();
}
void PvaClientMultiMonitorDouble::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
if(PvaClient::getDebug()) cout<< "PvaClientMultiMonitorDouble::~PvaClientMultiMonitorDouble()\n";
}
void PvaClientMultiMonitorDouble::connect()
@@ -99,13 +83,24 @@ bool PvaClientMultiMonitorDouble::poll()
{
if(!isMonitorConnected){
connect();
epicsThreadSleep(.01);
epicsThreadSleep(.1);
}
bool result = false;
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++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()) {
doubleValue[i] = pvaClientMonitor[i]->getData()->getDouble();
pvaClientMonitor[i]->releaseEvent();
@@ -132,7 +127,7 @@ bool PvaClientMultiMonitorDouble::waitEvent(double waitForEvent)
return false;
}
epics::pvData::shared_vector<double> PvaClientMultiMonitorDouble::get()
shared_vector<double> PvaClientMultiMonitorDouble::get()
{
return doubleValue;
}
+20 -27
View File
@@ -9,25 +9,19 @@
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::nt;
using namespace std;
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();
namespace epics { namespace pvaClient {
PvaClientMultiPutDoublePtr PvaClientMultiPutDouble::create(
@@ -46,27 +40,18 @@ PvaClientMultiPutDouble::PvaClientMultiPutDouble(
pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()),
pvaClientPut(std::vector<PvaClientPutPtr>(nchannel,PvaClientPutPtr())),
isPutConnected(false),
isDestroyed(false)
isPutConnected(false)
{
if(PvaClient::getDebug()) cout<< "PvaClientMultiPutDouble::PvaClientMultiPutDouble()\n";
}
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()
{
@@ -91,7 +76,7 @@ void PvaClientMultiPutDouble::connect()
isPutConnected = true;
}
void PvaClientMultiPutDouble::put(epics::pvData::shared_vector<double> const &data)
void PvaClientMultiPutDouble::put(shared_vector<double> const &data)
{
if(!isPutConnected) connect();
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)
{
if(isConnected[i]) {
if(!pvaClientPut[i]) pvaClientPut[i]=pvaClientChannelArray[i]->createPut("value");
PVStructurePtr pvTop = pvaClientPut[i]->getData()->getPVStructure();
PVScalarPtr pvValue = pvTop->getSubField<PVScalar>("value");
convert->fromDouble(pvValue,data[i]);
pvaClientPut[i]->issuePut();
PVScalarPtr pvScalar= pvTop->getSubField<PVScalar>("value");
if(pvScalar && ScalarTypeFunc::isNumeric(pvScalar->getScalar()->getScalarType())) {
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]) {
Status status = pvaClientPut[i]->waitPut();
+62 -59
View File
@@ -9,23 +9,21 @@
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <epicsMath.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::nt;
using namespace std;
namespace epics { namespace pvaClient {
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
namespace epics { namespace pvaClient {
PvaClientNTMultiDataPtr PvaClientNTMultiData::create(
epics::pvData::UnionConstPtr const & u,
UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest)
@@ -35,23 +33,23 @@ PvaClientNTMultiDataPtr PvaClientNTMultiData::create(
}
PvaClientNTMultiData::PvaClientNTMultiData(
epics::pvData::UnionConstPtr const & u,
UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest)
PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()),
gotAlarm(false),
gotTimeStamp(false),
isDestroyed(false)
gotTimeStamp(false)
{
PVFieldPtr pvValue = pvRequest->getSubField("field.value");
if(!pvValue) {
throw std::runtime_error("pvRequest did not specify value");
}
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiData::PvaClientNTMultiData()\n";
changeFlags = shared_vector<epics::pvData::boolean>(nchannel);
topPVStructure.resize(nchannel);
unionValue.resize(nchannel);
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i< nchannel; ++i) {
topPVStructure[i] = PVStructurePtr();
unionValue[i] = pvDataCreate->createPVUnion(u);
@@ -68,7 +66,7 @@ PvaClientNTMultiData::PvaClientNTMultiData(
severity.resize(nchannel);
status.resize(nchannel);
message.resize(nchannel);
}
if(pvRequest->getSubField("field.timeStamp")) {
gotTimeStamp = true;
@@ -86,28 +84,7 @@ PvaClientNTMultiData::PvaClientNTMultiData(
PvaClientNTMultiData::~PvaClientNTMultiData()
{
destroy();
}
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);
}
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiData::~PvaClientNTMultiData()\n";
}
void PvaClientNTMultiData::setPVStructure(
@@ -116,12 +93,18 @@ void PvaClientNTMultiData::setPVStructure(
topPVStructure[index] = pvStructure;
}
shared_vector<epics::pvData::boolean> PvaClientNTMultiData::getChannelChangeFlags()
{
return changeFlags;
}
size_t PvaClientNTMultiData::getNumber()
{
return nchannel;
}
void PvaClientNTMultiData::startDeltaTime()
{
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)
{
PVStructurePtr pvst = topPVStructure[i];
if(!pvst) {
unionValue[i] = PVUnionPtr();
} else {
unionValue[i]->set(pvst->getSubField("value"));
changeFlags[i] = false;
if(pvst&&unionValue[i]) {
changeFlags[i] = true;
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()
{
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(ntMultiChannelStructure);
PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(ntMultiChannelStructure);
NTMultiChannelPtr ntMultiChannel = NTMultiChannel::wrap(pvStructure);
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];
ntMultiChannel->getValue()->replace(freeze(val));
shared_vector<epics::pvData::boolean> connected = pvaClientMultiChannel->getIsConnected();
+20 -35
View File
@@ -9,24 +9,18 @@
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::nt;
using namespace std;
namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static StandardFieldPtr standardField = getStandardField();
namespace epics { namespace pvaClient {
PvaClientNTMultiGetPtr PvaClientNTMultiGet::create(
@@ -34,7 +28,7 @@ PvaClientNTMultiGetPtr PvaClientNTMultiGet::create(
PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest)
{
UnionConstPtr u = fieldCreate->createVariantUnion();
UnionConstPtr u = getFieldCreate()->createVariantUnion();
PvaClientNTMultiGetPtr pvaClientNTMultiGet(
new PvaClientNTMultiGet(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiGet;
@@ -44,7 +38,7 @@ PvaClientNTMultiGet::PvaClientNTMultiGet(
UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest)
PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
pvRequest(pvRequest),
@@ -55,37 +49,24 @@ PvaClientNTMultiGet::PvaClientNTMultiGet(
pvaClientMultiChannel,
pvaClientChannelArray,
pvRequest)),
isConnected(false),
isDestroyed(false)
isConnected(false)
{
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiGet::PvaClientNTMultiGet()\n";
}
PvaClientNTMultiGet::~PvaClientNTMultiGet()
{
destroy();
}
void PvaClientNTMultiGet::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiGet::~PvaClientNTMultiGet()\n";
}
void PvaClientNTMultiGet::connect()
{
pvaClientGet.resize(nchannel);
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)
{
if(isConnected[i]) {
pvaClientGet[i] = pvaClientChannelArray[i]->createGet(request);
pvaClientGet[i] = pvaClientChannelArray[i]->createGet(pvRequest);
pvaClientGet[i]->issueConnect();
}
}
@@ -94,7 +75,7 @@ void PvaClientNTMultiGet::connect()
if(isConnected[i]) {
Status status = pvaClientGet[i]->waitConnect();
if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelGet::waitConnect " + status.getMessage();
throw std::runtime_error(message);
}
@@ -102,14 +83,18 @@ void PvaClientNTMultiGet::connect()
this->isConnected = true;
}
void PvaClientNTMultiGet::get()
void PvaClientNTMultiGet::get(bool valueOnly)
{
if(!isConnected) connect();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
if(!pvaClientGet[i]){
pvaClientGet[i]=pvaClientChannelArray[i]->createGet(pvRequest);
pvaClientGet[i]->connect();
}
pvaClientGet[i]->issueGet();
}
}
@@ -118,7 +103,7 @@ void PvaClientNTMultiGet::get()
if(isConnected[i]) {
Status status = pvaClientGet[i]->waitGet();
if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelGet::waitGet " + status.getMessage();
throw std::runtime_error(message);
}
@@ -130,7 +115,7 @@ void PvaClientNTMultiGet::get()
pvaClientNTMultiData->setPVStructure(pvaClientGet[i]->getData()->getPVStructure(),i);
}
}
pvaClientNTMultiData->endDeltaTime();
pvaClientNTMultiData->endDeltaTime(valueOnly);
}
PvaClientNTMultiDataPtr PvaClientNTMultiGet::getData()
+24 -33
View File
@@ -9,29 +9,28 @@
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <epicsThread.h>
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::nt;
using namespace std;
namespace epics { namespace pvaClient {
static FieldCreatePtr fieldCreate = getFieldCreate();
namespace epics { namespace pvaClient {
PvaClientNTMultiMonitorPtr PvaClientNTMultiMonitor::create(
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest)
PVStructurePtr const & pvRequest)
{
UnionConstPtr u = fieldCreate->createVariantUnion();
UnionConstPtr u = getFieldCreate()->createVariantUnion();
PvaClientNTMultiMonitorPtr pvaClientNTMultiMonitor(
new PvaClientNTMultiMonitor(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiMonitor;
@@ -52,25 +51,15 @@ PvaClientNTMultiMonitor::PvaClientNTMultiMonitor(
pvaClientMultiChannel,
pvaClientChannelArray,
pvRequest)),
isConnected(false),
isDestroyed(false)
isConnected(false)
{
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiMonitor::PvaClientNTMultiMonitor()\n";
}
PvaClientNTMultiMonitor::~PvaClientNTMultiMonitor()
{
destroy();
}
void PvaClientNTMultiMonitor::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiMonitor::~PvaClientNTMultiMonitor()\n";
}
@@ -78,13 +67,10 @@ void PvaClientNTMultiMonitor::connect()
{
pvaClientMonitor.resize(nchannel);
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)
{
if(isConnected[i]) {
pvaClientMonitor[i] = pvaClientChannelArray[i]->createMonitor(request);
pvaClientMonitor[i] = pvaClientChannelArray[i]->createMonitor(pvRequest);
pvaClientMonitor[i]->issueConnect();
}
}
@@ -93,7 +79,7 @@ void PvaClientNTMultiMonitor::connect()
if(isConnected[i]) {
Status status = pvaClientMonitor[i]->waitConnect();
if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelMonitor::waitConnect " + status.getMessage();
throw std::runtime_error(message);
}
@@ -105,24 +91,29 @@ void PvaClientNTMultiMonitor::connect()
this->isConnected = true;
}
bool PvaClientNTMultiMonitor::poll()
bool PvaClientNTMultiMonitor::poll(bool valueOnly)
{
if(!isConnected) connect();
bool result = false;
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
pvaClientNTMultiData->startDeltaTime();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
pvaClientNTMultiData->startDeltaTime();
for(size_t i=0; i<nchannel; ++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(
pvaClientMonitor[i]->getData()->getPVStructure(),i);
pvaClientMonitor[i]->getData()->getPVStructure(),i);
pvaClientMonitor[i]->releaseEvent();
result = true;
}
}
}
if(result) pvaClientNTMultiData->endDeltaTime();
}
if(result) pvaClientNTMultiData->endDeltaTime(valueOnly);
return result;
}
+52 -32
View File
@@ -9,23 +9,20 @@
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
using std::tr1::static_pointer_cast;
#define epicsExportSharedSymbols
#include <pv/pvaClientMultiChannel.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::nt;
using namespace std;
namespace epics { namespace pvaClient {
static ConvertPtr convert = getConvert();
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
namespace epics { namespace pvaClient {
PvaClientNTMultiPutPtr PvaClientNTMultiPut::create(
PvaClientMultiChannelPtr const &pvaMultiChannel,
@@ -41,27 +38,17 @@ PvaClientNTMultiPut::PvaClientNTMultiPut(
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()),
unionValue(shared_vector<epics::pvData::PVUnionPtr>(nchannel,PVUnionPtr())),
value(shared_vector<epics::pvData::PVFieldPtr>(nchannel,PVFieldPtr())),
isConnected(false),
isDestroyed(false)
unionValue(shared_vector<PVUnionPtr>(nchannel,PVUnionPtr())),
value(shared_vector<PVFieldPtr>(nchannel,PVFieldPtr())),
isConnected(false)
{
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiPut::PvaClientNTMultiPut()\n";
}
PvaClientNTMultiPut::~PvaClientNTMultiPut()
{
destroy();
}
void PvaClientNTMultiPut::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
if(PvaClient::getDebug()) cout<< "PvaClientNTMultiPut::~PvaClientNTMultiPut()\n";
}
void PvaClientNTMultiPut::connect()
@@ -80,7 +67,7 @@ void PvaClientNTMultiPut::connect()
if(isConnected[i]) {
Status status = pvaClientPut[i]->waitConnect();
if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelPut::waitConnect " + status.getMessage();
throw std::runtime_error(message);
}
@@ -96,11 +83,13 @@ void PvaClientNTMultiPut::connect()
if(isConnected[i]) {
Status status = pvaClientPut[i]->waitGet();
if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelPut::waitGet " + status.getMessage();
throw std::runtime_error(message);
}
}
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
@@ -113,9 +102,26 @@ void PvaClientNTMultiPut::connect()
this->isConnected = true;
}
shared_vector<epics::pvData::PVUnionPtr> PvaClientNTMultiPut::getValues()
shared_vector<PVUnionPtr> PvaClientNTMultiPut::getValues()
{
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;
}
@@ -126,15 +132,29 @@ void PvaClientNTMultiPut::put()
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());
}
value[i]->copy(*unionValue[i]->get());
pvaClientPut[i]->issuePut();
}
if(isConnected[i]) {
Status status = pvaClientPut[i]->waitPut();
if(status.isOK()) continue;
string message = string("channel ") +pvaClientChannelArray[i]->getChannelName()
+ " PvaChannelPut::waitPut " + status.getMessage();
throw std::runtime_error(message);
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
Status status = pvaClientPut[i]->waitPut();
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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <pv/event.h>
#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 {
class ChannelProcessRequesterImpl : public ChannelProcessRequester
{
PvaClientProcess * pvaClientProcess;
PvaClientProcess::weak_pointer pvaClientProcess;
PvaClient::weak_pointer pvaClient;
public:
ChannelProcessRequesterImpl(PvaClientProcess * pvaClientProcess)
: pvaClientProcess(pvaClientProcess) {}
string getRequesterName()
{return pvaClientProcess->getRequesterName();}
void message(string const & message,MessageType messageType)
{pvaClientProcess->message(message,messageType);}
void channelProcessConnect(
ChannelProcessRequesterImpl(
PvaClientProcessPtr const & pvaClientProcess,
PvaClientPtr const &pvaClient)
: pvaClientProcess(pvaClientProcess),
pvaClient(pvaClient)
{}
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,
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,
ChannelProcess::shared_pointer const & channelProcess)
{pvaClientProcess->processDone(status,channelProcess);}
ChannelProcess::shared_pointer const & 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(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
: pvaClient(pvaClient),
channel(channel),
pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle),
processState(processIdle)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientProcess::PvaClientProcess()"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
}
PvaClientProcess::~PvaClientProcess()
{
destroy();
if(PvaClient::getDebug()) {
cout<< "PvaClientProcess::~PvaClientProcess()"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
}
// from ChannelProcessRequester
string PvaClientProcess::getRequesterName()
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
return pvaClientChannel->getRequesterName();
}
void PvaClientProcess::message(string const & message,MessageType messageType)
{
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed");
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
pvaClientChannel->message(message,messageType);
}
void PvaClientProcess::channelProcessConnect(
const Status& status,
ChannelProcess::shared_pointer const & channelProcess)
{
if(isDestroyed) return;
channelProcessConnectStatus = status;
this->channelProcess = channelProcess;
waitForConnect.signal();
if(PvaClient::getDebug()) {
cout << "PvaClientProcess::channelProcessConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " 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(
const Status& status,
ChannelProcess::shared_pointer const & channelProcess)
{
if(isDestroyed) return;
channelProcessStatus = status;
waitForProcess.signal();
}
// from PvaClientProcess
void PvaClientProcess::destroy()
{
if(PvaClient::getDebug()) {
cout << "PvaClientProcess::processDone"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
channelProcessStatus = status;
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientProcess::connect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueConnect();
Status status = waitConnect();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientProcess::connect " + status.getMessage();
throw std::runtime_error(message);
}
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) {
string message = string("channel ") + channel->getChannelName()
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientProcess already connected ";
throw std::runtime_error(message);
}
processRequester = ChannelProcessRequester::shared_pointer(new ChannelProcessRequesterImpl(this));
connectState = connectActive;
channelProcess = channel->createChannelProcess(processRequester,pvRequest);
channelProcessConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelProcess = pvaClientChannel->getChannel()->createChannelProcess(channelProcessRequester,pvRequest);
}
Status PvaClientProcess::waitConnect()
{
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed");
if(connectState!=connectActive) {
string message = string("channel ") + channel->getChannelName()
+ " pvaClientProcess illegal connect state ";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientProcess::waitConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForConnect.wait();
connectState = channelProcessConnectStatus.isOK() ? connected : connectIdle;
return channelProcessConnectStatus;
}
void PvaClientProcess::process()
{
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientProcess::process"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueProcess();
Status status = waitProcess();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientProcess::process" + status.getMessage();
throw std::runtime_error(message);
}
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(processState!=processIdle) {
string message = string("channel ") + channel->getChannelName()
if(processState==processActive) {
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientProcess::issueProcess process aleady active ";
throw std::runtime_error(message);
}
@@ -171,24 +245,30 @@ void PvaClientProcess::issueProcess()
Status PvaClientProcess::waitProcess()
{
if(isDestroyed) throw std::runtime_error("pvaClientProcess was destroyed");
if(processState!=processActive){
string message = string("channel ") + channel->getChannelName()
+ " PvaClientProcess::waitProcess llegal process state";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientProcess::waitProcess"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForProcess.wait();
processState = processIdle;
processState = processComplete;
return channelProcessStatus;
}
PvaClientProcessPtr PvaClientProcess::create(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
void PvaClientProcess::setRequester(PvaClientProcessRequesterPtr const & pvaClientProcessRequester)
{
PvaClientProcessPtr epv(new PvaClientProcess(pvaClient,channel,pvRequest));
return epv;
if(PvaClient::getDebug()) {
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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <pv/event.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
@@ -22,72 +23,127 @@ namespace epics { namespace pvaClient {
class ChannelPutRequesterImpl : public ChannelPutRequester
{
PvaClientPut * pvaClientPut;
PvaClientPut::weak_pointer pvaClientPut;
PvaClient::weak_pointer pvaClient;
public:
ChannelPutRequesterImpl(PvaClientPut * pvaClientPut)
: pvaClientPut(pvaClientPut) {}
string getRequesterName()
{return pvaClientPut->getRequesterName();}
void message(string const & message,MessageType messageType)
{pvaClientPut->message(message,messageType);}
void channelPutConnect(
ChannelPutRequesterImpl(
PvaClientPutPtr const & pvaClientPut,
PvaClientPtr const &pvaClient)
: pvaClientPut(pvaClientPut),
pvaClient(pvaClient)
{}
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,
ChannelPut::shared_pointer const & channelPut,
StructureConstPtr const & structure)
{pvaClientPut->channelPutConnect(status,channelPut,structure);}
void getDone(
Structure::const_shared_pointer const & structure)
{
PvaClientPutPtr clientPut(pvaClientPut.lock());
if(!clientPut) return;
clientPut->channelPutConnect(status,channelPut,structure);
}
virtual void getDone(
const Status& status,
ChannelPut::shared_pointer const & channelPut,
PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet)
{pvaClientPut->getDone(status,channelPut,pvStructure,bitSet);}
void putDone(
BitSet::shared_pointer const & bitSet)
{
PvaClientPutPtr clientPut(pvaClientPut.lock());
if(!clientPut) return;
clientPut->getDone(status,channelPut,pvStructure,bitSet);
}
virtual void putDone(
const Status& status,
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(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
: pvaClient(pvaClient),
channel(channel),
pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle),
putState(putIdle)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientPut::PvaClientPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
}
PvaClientPut::~PvaClientPut()
{
destroy();
}
void PvaClientPut::checkPutState()
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
if(connectState==connectIdle){
connect();
get();
if(PvaClient::getDebug()) {
cout<< "PvaClientPut::~PvaClientPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
}
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()
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
return pvaClientChannel->getRequesterName();
}
void PvaClientPut::message(string const & message,MessageType messageType)
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
pvaClientChannel->message(message,messageType);
}
void PvaClientPut::channelPutConnect(
@@ -95,15 +151,27 @@ void PvaClientPut::channelPutConnect(
ChannelPut::shared_pointer const & channelPut,
StructureConstPtr const & structure)
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
channelPutConnectStatus = status;
this->channelPut = channelPut;
if(status.isOK()) {
pvaClientData = PvaClientPutData::create(structure);
pvaClientData->setMessagePrefix(channel->getChannelName());
if(PvaClient::getDebug()) {
cout << "PvaClientPut::channelPutConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
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(
@@ -112,133 +180,175 @@ void PvaClientPut::getDone(
PVStructurePtr const & pvStructure,
BitSetPtr const & bitSet)
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
channelGetPutStatus = status;
if(status.isOK()) {
PVStructurePtr pvs = pvaClientData->getPVStructure();
pvs->copyUnchecked(*pvStructure,*bitSet);
BitSetPtr bs = pvaClientData->getChangedBitSet();
bs->clear();
*bs |= *bitSet;
if(PvaClient::getDebug()) {
cout << "PvaClientPut::getDone"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
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(
const Status& status,
ChannelPut::shared_pointer const & channelPut)
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
channelGetPutStatus = status;
waitForGetPut.signal();
}
// from PvaClientPut
void PvaClientPut::destroy()
{
if(PvaClient::getDebug()) {
cout << "PvaClientPut::putDone"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
channelGetPutStatus = status;
putState = putComplete;
waitForGetPut.signal();
}
if(channelPut) channelPut->destroy();
channelPut.reset();
PvaClientPutRequesterPtr req(pvaClientPutRequester.lock());
if(req) { req->putDone(status,shared_from_this());}
}
void PvaClientPut::connect()
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientPut::connect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueConnect();
Status status = waitConnect();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPut::connect " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::connect "
+ status.getMessage();
throw std::runtime_error(message);
}
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) {
string message = string("channel ") + channel->getChannelName()
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientPut already connected ";
throw std::runtime_error(message);
}
putRequester = ChannelPutRequester::shared_pointer(new ChannelPutRequesterImpl(this));
connectState = connectActive;
channelPut = channel->createChannelPut(putRequester,pvRequest);
channelPutConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelPut = pvaClientChannel->getChannel()->createChannelPut(channelPutRequester,pvRequest);
}
Status PvaClientPut::waitConnect()
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
if(connectState!=connectActive) {
string message = string("channel ") + channel->getChannelName()
+ " pvaClientPut illegal connect state ";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientPut::waitConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForConnect.wait();
connectState = channelPutConnectStatus.isOK() ? connected : connectIdle;
return channelPutConnectStatus;
}
void PvaClientPut::get()
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientPut::get"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueGet();
Status status = waitGet();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPut::get " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::get "
+ status.getMessage();
throw std::runtime_error(message);
}
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(putState!=putIdle) {
string message = string("channel ") + channel->getChannelName()
if(putState==getActive || putState==putActive) {
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ "PvaClientPut::issueGet get or put aleady active ";
throw std::runtime_error(message);
}
putState = getActive;
pvaClientData->getChangedBitSet()->clear();
channelPut->get();
}
Status PvaClientPut::waitGet()
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
if(putState!=getActive){
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPut::waitGet llegal put state";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientPut::waitGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForGetPut.wait();
putState = putIdle;
putState = putComplete;
return channelGetPutStatus;
}
void PvaClientPut::put()
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientPut::put"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issuePut();
Status status = waitPut();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPut::put " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::put "
+ status.getMessage();
throw std::runtime_error(message);
}
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(putState!=putIdle) {
string message = string("channel ") + channel->getChannelName()
+ "PvaClientPut::issueGet get or put aleady active ";
if(putState==getActive || putState==putActive) {
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::issuePut get or put aleady active ";
throw std::runtime_error(message);
}
putState = putActive;
@@ -247,32 +357,42 @@ void PvaClientPut::issuePut()
Status PvaClientPut::waitPut()
{
if(isDestroyed) throw std::runtime_error("pvaClientPut was destroyed");
if(putState!=putActive){
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPut::waitPut llegal put state";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientPut::waitPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForGetPut.wait();
putState = putIdle;
putState = putComplete;
if(channelGetPutStatus.isOK()) pvaClientData->getChangedBitSet()->clear();
return channelGetPutStatus;
}
PvaClientPutDataPtr PvaClientPut::getData()
{
checkPutState();
if(PvaClient::getDebug()) {
cout<< "PvaClientPut::getData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkConnectState();
if(putState==putIdle) get();
return pvaClientData;
}
PvaClientPutPtr PvaClientPut::create(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
void PvaClientPut::setRequester(PvaClientPutRequesterPtr const & pvaClientPutRequester)
{
PvaClientPutPtr epv(new PvaClientPut(pvaClient,channel,pvRequest));
return epv;
if(PvaClient::getDebug()) {
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
* @date 2015.02
*/
#define epicsExportSharedSymbols
#include <typeinfo>
#include <sstream>
#include <pv/pvaClient.h>
#include <pv/createRequest.h>
#include <pv/convert.h>
#define epicsExportSharedSymbols
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
@@ -24,40 +25,36 @@ using namespace epics::pvAccess;
using namespace std;
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 string noValue("no value field");
static string notScalar("value is not a 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 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)
{
if(PvaClient::getDebug()) cout << "PvaClientPutData::create\n";
PvaClientPutDataPtr epv(new PvaClientPutData(structure));
return epv;
}
PvaClientPutData::PvaClientPutData(StructureConstPtr const & structure)
: structure(structure),
pvStructure(getPVDataCreate()->createPVStructure(structure)),
bitSet(BitSetPtr(new BitSet(pvStructure->getNumberFields())))
: PvaClientData(structure)
{
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();
postHandler.resize(nfields);
PVFieldPtr pvField;
@@ -71,145 +68,18 @@ PvaClientPutData::PvaClientPutData(StructureConstPtr const & structure)
}
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)
{
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();
if(scalarType==pvDouble) {
PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar);
@@ -217,47 +87,68 @@ void PvaClientPutData::putDouble(double value)
return;
}
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);
}
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);
}
void PvaClientPutData::putDoubleArray(shared_vector<const double> const & value)
{
checkValue();
PVDoubleArrayPtr pv = pvStructure->getSubField<PVDoubleArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + notDoubleArray);
if(PvaClient::getDebug()) cout << "PvaClientPutData::putDoubleArray\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
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)
{
checkValue();
PVStringArrayPtr pv = pvStructure->getSubField<PVStringArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + notStringArray);
if(PvaClient::getDebug()) cout << "PvaClientPutData::putStringArray\n";
PVFieldPtr pvField = getSinglePVField();
Type type = pvField->getField()->getType();
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();
PVScalarArrayPtr pv = pvStructure->getSubField<PVScalarArray>("value");
if(!pv) {
throw std::runtime_error(messagePrefix + notScalarArray);
}
convert->fromStringArray(pv,0,value.size(),value,0);
size_t length = value.size();
shared_vector<string> val(length);
for(size_t i=0; i < length; ++i) val[i] = value[i];
putStringArray(freeze(val));
return;
}
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
* @date 2015.02
*/
#include <pv/event.h>
#define epicsExportSharedSymbols
#include <pv/event.h>
#include <pv/pvaClient.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
@@ -22,89 +22,140 @@ namespace epics { namespace pvaClient {
class ChannelPutGetRequesterImpl : public ChannelPutGetRequester
{
PvaClientPutGet * pvaClientPutGet;
PvaClientPutGet::weak_pointer pvaClientPutGet;
PvaClient::weak_pointer pvaClient;
public:
ChannelPutGetRequesterImpl(PvaClientPutGet * pvaClientPutGet)
: pvaClientPutGet(pvaClientPutGet) {}
string getRequesterName()
{return pvaClientPutGet->getRequesterName();}
void message(string const & message,MessageType messageType)
{pvaClientPutGet->message(message,messageType);}
void channelPutGetConnect(
const epics::pvData::Status& status,
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet,
epics::pvData::StructureConstPtr const & putStructure,
epics::pvData::StructureConstPtr const & getStructure)
{
pvaClientPutGet->channelPutGetConnect(status,channelPutGet,putStructure,getStructure);
ChannelPutGetRequesterImpl(
PvaClientPutGetPtr const & pvaClientPutGet,
PvaClientPtr const &pvaClient)
: pvaClientPutGet(pvaClientPutGet),
pvaClient(pvaClient)
{}
virtual ~ChannelPutGetRequesterImpl() {
if(PvaClient::getDebug()) std::cout << "~ChannelPutGetRequesterImpl" << std::endl;
}
void putGetDone(
const epics::pvData::Status& status,
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet,
epics::pvData::PVStructurePtr const & getPVStructure,
epics::pvData::BitSetPtr const & getChangedBitSet)
{
pvaClientPutGet->putGetDone(status,channelPutGet,getPVStructure,getChangedBitSet);
virtual std::string getRequesterName() {
PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
if(!clientPutGet) return string("clientPutGet is null");
return clientPutGet->getRequesterName();
}
void getPutDone(
const epics::pvData::Status& status,
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet,
epics::pvData::PVStructurePtr const & putPVStructure,
epics::pvData::BitSet::shared_pointer const & putBitSet)
{
pvaClientPutGet->getPutDone(status,channelPutGet,putPVStructure,putBitSet);
virtual void message(std::string const & message, MessageType messageType) {
PvaClientPutGetPtr clientPutGet(pvaClientPutGet.lock());
if(!clientPutGet) return;
clientPutGet->message(message,messageType);
}
void getGetDone(
const epics::pvData::Status& status,
epics::pvAccess::ChannelPutGet::shared_pointer const & channelPutGet,
epics::pvData::PVStructurePtr const & getPVStructure,
epics::pvData::BitSet::shared_pointer const & getChangedBitSet)
virtual void channelPutGetConnect(
const Status& status,
ChannelPutGet::shared_pointer const & channelPutGet,
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(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PvaClientChannelPtr const & pvaClientChannel,
PVStructurePtr const &pvRequest)
: pvaClient(pvaClient),
channel(channel),
pvaClientChannel(pvaClientChannel),
pvRequest(pvRequest),
isDestroyed(false),
connectState(connectIdle),
putGetState(putGetIdle)
{
if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::PvaClientPutGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
}
PvaClientPutGet::~PvaClientPutGet()
{
destroy();
if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::~PvaClientPutGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
}
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){
connect();
getPut();
connect();
}
if(connectState==connectActive){
string message = string("channel ") + pvaClientChannel->getChannel()->getChannelName()
+ " "
+ channelPutGetConnectStatus.getMessage();
throw std::runtime_error(message);
}
}
// from ChannelPutGetRequester
string PvaClientPutGet::getRequesterName()
{
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
return yyy->getRequesterName();
return pvaClientChannel->getRequesterName();
}
void PvaClientPutGet::message(string const & message,MessageType messageType)
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
PvaClientPtr yyy = pvaClient.lock();
if(!yyy) throw std::runtime_error("pvaClient was destroyed");
yyy->message(message, messageType);
pvaClientChannel->message(message,messageType);
}
void PvaClientPutGet::channelPutGetConnect(
@@ -113,17 +164,29 @@ void PvaClientPutGet::channelPutGetConnect(
StructureConstPtr const & putStructure,
StructureConstPtr const & getStructure)
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
channelPutGetConnectStatus = status;
this->channelPutGet = channelPutGet;
if(status.isOK()) {
pvaClientPutData = PvaClientPutData::create(putStructure);
pvaClientPutData->setMessagePrefix(channel->getChannelName());
pvaClientGetData = PvaClientGetData::create(getStructure);
pvaClientGetData->setMessagePrefix(channel->getChannelName());
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::channelPutGetConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
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(
@@ -132,12 +195,25 @@ void PvaClientPutGet::putGetDone(
PVStructurePtr const & getPVStructure,
BitSetPtr const & getChangedBitSet)
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
channelPutGetStatus = status;
if(status.isOK()) {
pvaClientGetData->setData(getPVStructure,getChangedBitSet);
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::putGetDone"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " 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(
@@ -146,16 +222,29 @@ void PvaClientPutGet::getPutDone(
PVStructurePtr const & putPVStructure,
BitSetPtr const & putBitSet)
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
channelPutGetStatus = status;
if(status.isOK()) {
PVStructurePtr pvs = pvaClientPutData->getPVStructure();
pvs->copyUnchecked(*putPVStructure,*putBitSet);
BitSetPtr bs = pvaClientPutData->getChangedBitSet();
bs->clear();
*bs |= *putBitSet;
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::getPutDone"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
{
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(
@@ -164,84 +253,103 @@ void PvaClientPutGet::getGetDone(
PVStructurePtr const & getPVStructure,
BitSetPtr const & getChangedBitSet)
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
channelPutGetStatus = status;
if(status.isOK()) {
pvaClientGetData->setData(getPVStructure,getChangedBitSet);
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::getGetDone"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< " status.isOK " << (status.isOK() ? "true" : "false")
<< endl;
}
waitForPutGet.signal();
}
// from PvaClientPutGet
void PvaClientPutGet::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
channelPutGetStatus = status;
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()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::connect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueConnect();
Status status = waitConnect();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::connect " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::connect "
+ status.getMessage();
throw std::runtime_error(message);
}
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) {
string message = string("channel ") + channel->getChannelName()
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " pvaClientPutGet already connected ";
throw std::runtime_error(message);
}
putGetRequester = ChannelPutGetRequester::shared_pointer(new ChannelPutGetRequesterImpl(this));
connectState = connectActive;
channelPutGet = channel->createChannelPutGet(putGetRequester,pvRequest);
channelPutGetConnectStatus = Status(Status::STATUSTYPE_ERROR, "connect active");
channelPutGet = pvaClientChannel->getChannel()->createChannelPutGet(channelPutGetRequester,pvRequest);
}
Status PvaClientPutGet::waitConnect()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(connectState!=connectActive) {
string message = string("channel ") + channel->getChannelName()
+ " pvaClientPutGet illegal connect state ";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::waitConnect"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForConnect.wait();
connectState = channelPutGetConnectStatus.isOK() ? connected : connectIdle;
return channelPutGetConnectStatus;
}
void PvaClientPutGet::putGet()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::putGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issuePutGet();
Status status = waitPutGet();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::putGet " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::putGet "
+ status.getMessage();
throw std::runtime_error(message);
}
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(putGetState!=putGetIdle) {
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::issueGet get or put aleady active ";
if(putGetState==putGetActive) {
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::issuePutGet get or put aleady active ";
throw std::runtime_error(message);
}
putGetState = putGetActive;
@@ -251,35 +359,45 @@ void PvaClientPutGet::issuePutGet()
Status PvaClientPutGet::waitPutGet()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(putGetState!=putGetActive){
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::waitPutGet llegal put state";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::waitPutGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForPutGet.wait();
putGetState = putGetIdle;
if(channelPutGetStatus.isOK()) pvaClientPutData->getChangedBitSet()->clear();
return channelPutGetStatus;
}
void PvaClientPutGet::getGet()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::getGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueGetGet();
Status status = waitGetGet();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::getGet " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::getGet "
+ status.getMessage();
throw std::runtime_error(message);
}
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(putGetState!=putGetIdle) {
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::issueGetGet aleady active ";
if(putGetState==putGetActive) {
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::issueGetGet get or put aleady active ";
throw std::runtime_error(message);
}
putGetState = putGetActive;
@@ -288,35 +406,44 @@ void PvaClientPutGet::issueGetGet()
Status PvaClientPutGet::waitGetGet()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(putGetState!=putGetActive){
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::waitGetGet illegal state";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::waitGetGet"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForPutGet.wait();
putGetState = putGetIdle;
return channelPutGetStatus;
}
void PvaClientPutGet::getPut()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::getGetPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
issueGetPut();
Status status = waitGetPut();
if(status.isOK()) return;
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::getPut " + status.getMessage();
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPut::getPut "
+ status.getMessage();
throw std::runtime_error(message);
}
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(putGetState!=putGetIdle) {
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::issueGetPut aleady active ";
if(putGetState==putGetActive) {
string message = string("channel ")
+ pvaClientChannel->getChannel()->getChannelName()
+ " PvaClientPutGet::issueGetPut get or put aleady active ";
throw std::runtime_error(message);
}
putGetState = putGetActive;
@@ -325,37 +452,59 @@ void PvaClientPutGet::issueGetPut()
Status PvaClientPutGet::waitGetPut()
{
if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
if(putGetState!=putGetActive){
string message = string("channel ") + channel->getChannelName()
+ " PvaClientPutGet::waitGetPut illegal state";
throw std::runtime_error(message);
if(PvaClient::getDebug()) {
cout << "PvaClientPutGet::waitGetPut"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
waitForPutGet.wait();
putGetState = putGetIdle;
return channelPutGetStatus;
}
PvaClientGetDataPtr PvaClientPutGet::getGetData()
{
if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::getGetData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkPutGetState();
if(putGetState==putGetIdle){
getGet();
getPut();
}
return pvaClientGetData;
}
PvaClientPutDataPtr PvaClientPutGet::getPutData()
{
if(PvaClient::getDebug()) {
cout<< "PvaClientPutGet::getPutData"
<< " channelName " << pvaClientChannel->getChannel()->getChannelName()
<< endl;
}
checkPutGetState();
if(putGetState==putGetIdle){
getGet();
getPut();
}
return pvaClientPutData;
}
PvaClientPutGetPtr PvaClientPutGet::create(
PvaClientPtr const &pvaClient,
Channel::shared_pointer const & channel,
PVStructurePtr const &pvRequest)
void PvaClientPutGet::setRequester(PvaClientPutGetRequesterPtr const & pvaClientPutGetRequester)
{
PvaClientPutGetPtr epv(new PvaClientPutGet(pvaClient,channel,pvRequest));
return epv;
if(PvaClient::getDebug()) {
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);
}
}}