Compare commits

...

126 Commits

Author SHA1 Message Date
Andrew Johnson
c7e42fab3c Set version number to 3.15.8, clear snapshot 2020-05-15 12:00:23 -05:00
Andrew Johnson
2f28ce94f4 Release Notes changes for 3.15.8 2020-05-15 11:36:45 -05:00
Andrew Johnson
732f8b19be Merge branch 'defaultMessageQueue' into 3.15 2020-05-14 10:41:52 -05:00
Andrew Johnson
b03e2f376b eMQTest: Start each test with a new (empty) queue
If fastReceiver() took more than 0.01 seconds to exit,
sleepySender() might have pushed a second message onto
the queue after setting recvExit, so there would be an
extra message in the queue for the next test, which I
was seeing on Appveyor. That's my current theory...
2020-05-13 16:11:31 -05:00
Andrew Johnson
59c68807b6 Heinz Junkes' fix for lp: #1812084 Build failure on RTEMS
I reduced some of the code duplication from his original.
2020-05-13 15:26:34 -05:00
Andrew Johnson
2e7ed02a60 Allow/expect MinGW to fail epicsStackTraceTest #5 2020-05-07 13:13:26 -05:00
Andrew Johnson
089954aaab MessageQueue Tests: Extend Mark's sleep tests 2020-05-07 13:12:12 -05:00
Andrew Johnson
34e0b2f305 osdMessageQueue: Undo change to -ve timeout handling
The internal mySend() and myReceive() routines do expect a timeout
of -1 to mean wait forever, see the epicsMessageQueueSend() and
epicsMessageQueueReceive() API routines.
2020-05-04 11:56:14 -05:00
Andrew Johnson
ceb13797a6 Cosmetic 2020-05-01 00:13:02 -05:00
Andrew Johnson
084557bd3e osdMessageQueue: Don't wake our sender until we're ready for it
Move the code that wakes up the next sending task to after we've
added our threadNode to the receiveQueue. He still has to wait for
us to release the Mutex though, so this might make no difference.
This commit also changes when we decrement the number of waiting
senders so it always happens immediately after a threadNode gets
taken off the sendQueue by the code that removed it.
2020-05-01 00:12:32 -05:00
Andrew Johnson
aeed7cfbdd osdMessageQueue: This is the mirror of Heinz Junkes' earlier fix
When sending a message, if the queue is full so we have to wait, we
create a threadNode with an eventNode in it and stick it on the
sendQueue, then wait for a receiver to signal that event, waking us.
If we awoke due to a timeout but a receiver was actually waking us
up anyway (i.e. eventSent was set), we shouldn't give up.
2020-04-30 23:55:30 -05:00
Andrew Johnson
183c3b2a3e osdMessageQueue: Clear eventNode before returning it
Introduced freeEventNode() which ensures eventNodes don't have a
signalled event in them before returning the node to the freeList.
Callers pass the status from epicsEventWaitWithTimeout() to indicate
whether it was signalled or not. If it timed out we must trigger it
and Wait to clear the event state.
2020-04-30 23:38:51 -05:00
Andrew Johnson
cf2fef2405 osdMessageQueue: Return sooner on -ve timeout
It appears that previously a negative timeout actually implemented a
'wait forever', but the VxWorks and RTEMS implementations both check
for (timeout <= 0) and return immediately if nothing can be done
without waiting.
2020-04-30 23:27:43 -05:00
Andrew Johnson
298c8706ec osdMessageQueue: Rename freeEventNode() -> destroyEventNode() 2020-04-30 22:59:58 -05:00
Ralph Lange
49de2ec498 Merge ralph@gh:use-ci-scripts-3.15 into 3.15 2020-04-27 12:10:24 +02:00
Ralph Lange
0aa6e9603b Update .ci submodule to v2.3.3
- fix appveyor issue when building base
- fix RTEMS cross build for Base 3.15
- run tests using parallel make
2020-04-27 11:59:57 +02:00
Andrew Johnson
314e09d8ca Build system release notes 2020-04-24 16:44:49 -05:00
Ralph Lange
076175386f ci: remove old integration in .ci-local 2020-04-24 19:27:05 +02:00
Ralph Lange
f40d379485 appveyor: update .appveyor.yml for ci-scripts 2020-04-24 19:27:05 +02:00
Ralph Lange
445cbb8221 travis-ci: update .travis.yml for ci-scripts
- use more EXTRAs on MacOS for make args
2020-04-24 19:27:05 +02:00
Ralph Lange
a9c8d8d5d3 Add ci-scripts v2.3.2 (submodule in .ci) 2020-04-24 15:11:32 +02:00
Ralph Lange
1ff64f72a9 ci: move ci -> .ci-local
also rename appveyor.yml -> .appveyor.yml
2020-04-23 16:00:53 +02:00
Ralph Lange
f10d0d95b0 Apply perl rules for .tap and .xml only to perl tests
Don't apply the %.tap: %.t and %.xml: %.tap rules to tap and junit
result files from other test frameworks.
(They would overwrite the other frameworks' own rules.)
2020-04-21 11:45:50 +02:00
Andrew Johnson
dfbda1394d Revert the runtests:: change but in an extensible way
Use only %.t files in new TESTSCRIPTS.t var for Perl tests.
TAPFILES and JUNITFILES can be appended to by other rules.
The runtests and test-results rules have no direct recipes.
Added run-tap-tests and tap-results rules, simlified recipe.
Make %.tap:%.t and %.xml:%.tap into static pattern rules.
2020-04-21 01:39:59 -05:00
Andrew Johnson
d05d8807ec Stop generating the testspec file
It was created before modern continuous integration systems
came along; Diamond were supposed to run the tests for us,
but they didn't last for very long.
2020-04-21 01:17:48 -05:00
Andrew Johnson
582a9dbef5 Replace pre-make rule with before-actions rules
For all standard build ACTIONS, a rule before-<action> is
run just before running that action in the subdirectories
given by the DIRS variable. Only works in Makefiles that
include RULES_DIRS or RULES_TOP.
2020-04-21 01:14:03 -05:00
Andrew Johnson
b655662131 Appveyor: Move 'make test-results' to the on_finish stage 2020-04-20 11:33:37 -05:00
Andrew Johnson
be061e1084 Tidy up testFailures script slighlty 2020-04-20 11:31:45 -05:00
Andrew Johnson
91c18c32d4 Have Appveyor make 'tapfiles test-results' instead of 'runtests' 2020-04-18 00:36:35 -05:00
Andrew Johnson
3790ce4452 Have 'make test-results' fail nicely if any tests did
Lists the directories with failed tests at the end of the build.
It is no longer necessary to use 'make -k' to see the results
of all tests after one or more failures as only the top-level
test-results recipe will generate a build error.
2020-04-18 00:18:11 -05:00
Andrew Johnson
566ab038d2 Make test-results not fail so it shows all results
For some reason 'make -k test-results' isn't always doing
the -k (continue-on-error) on Windows.
2020-04-17 16:51:48 -05:00
Andrew Johnson
648589e6ab podToHtml: Add bootstrap search path for EPICS::PodHtml 2020-04-17 16:42:18 -05:00
Andrew Johnson
841effe9ee epicsMessageQueueTest: Shorten the 1R4S tests 2020-04-16 17:14:58 -05:00
Andrew Johnson
a9727fd5cb Ben Franksen's fix for lp: #1868486 2020-04-16 17:12:25 -05:00
Andrew Johnson
fde0485d6b Added Mark Rivers' tests for the message queue timeout bug 2020-04-16 17:10:53 -05:00
Ralph Lange
cbf917e833 Improve automated testing rules to allow other test frameworks
- make runtests a double-colon rule, so that other test frameworks
  can add their own recipes independently
- only define runtests:: $TESTSCRIPTS rule when there are TESTSCRIPTS
  (to avoid having it run every time when no TESTSCRIPTS are defined)
- $(strip $TAPFILES) inside ifneq to fix trouble when TAPFILES=' '
2020-04-16 12:04:16 +02:00
Andrew Johnson
45cf2ea5ce Modify the POD to HTML conversion code to work on older Perls 2020-04-14 16:41:20 -05:00
Andrew Johnson
a95635a018 Merge Freddie's bit_operations branch into 3.15 2020-04-14 15:28:22 -05:00
Andrew Johnson
9df39475cd Merge Martin Konrad's fix-log-issues branch into 3.15 2020-04-14 11:41:23 -05:00
Andrew Johnson
bdf01e7a67 Merge Martin Konrad's Appveyor-worker-image branch into 3.15 2020-04-14 11:28:53 -05:00
Andrew Johnson
0dd5f863ef Add some release notes 2020-04-13 17:57:33 -05:00
Andrew Johnson
38339b6ccf Initialize main thread as OkToBlock 2020-04-13 17:56:09 -05:00
Martin Konrad
2aecf3142a Explicitly specify worker image 2020-04-13 16:45:21 -04:00
Ralph Lange
1687757752 catools: make camonitor handle type changes
taken from a patch provided by Dirk Zimoch (in 2014)
2020-04-06 10:58:40 +02:00
Andrew Johnson
1533a4f13f Updates to record POD documentation. 2020-04-03 00:33:51 -05:00
Andrew Johnson
a1aeb23314 Modify POD to HTML tools to better support links
Introduce derived classes to process links the way we need them.
Unify the generation of an ID from a section heading.
2020-04-03 00:29:22 -05:00
Andrew Johnson
933e276e1a Rolf Keitel's POD documentation for dbCommon (from the Wiki)
I split his two "Fields Common to ..." sections back into separate docs,
added links between them all, and made the appropriate build changes.
Also added these and the aai/aao records to the documentation index.
2020-04-02 15:47:10 -05:00
Freddie Akeroyd
7f02f8a386 Exclude VS2012 from -FS option
(cherry picked from 7.0 / commit 4aee25e8 and e29a53f0)
2020-03-28 15:55:35 +01:00
Rold Keitel
cb3fb18f40 POD docs: add aai & aai, update others 2020-03-26 17:41:12 -05:00
Rold Keitel
062c75a078 Prepare for POD documentation of the aa[io]Records 2020-03-26 16:35:58 -05:00
Andrew Johnson
b2160bd618 Merge Martin Konrad's replace-usleep branch into 3.15 2020-03-20 13:40:35 -05:00
Andrew Johnson
5b7f896312 Merge Dirk's emptyArrayCrashFix branch into 3.15 2020-03-20 13:28:34 -05:00
Andrew Johnson
a9034bb586 Fix clock_gettime issue on newer MinGW builds
Fixes lp: #1853168
2020-03-07 00:40:13 -06:00
Martin Konrad
f9820577c1 Replace usleep call by nanosleep
Also improve behavior in case signals are delivered to the sleeping
thread. This fixes a potential security weakness reported by codacy
(interaction of usleep with SIGALRM and other timer functions such
as sleep(), alarm(), setitimer(), and nanosleep() is unspecified).
2020-03-04 11:19:02 -05:00
Michael Davidsaver
e6914f3b80 osdSockUnsentCount.c check for existance of SIO_TCP_INFO 2020-02-20 15:37:18 -05:00
Andrew Johnson
41f1b0ffb5 Fix histogram record allocation bug
Found by Peter Heesterman: Potential use of NULL pcallback pointer.

Nothing looks at the return value from wdogInit(), so don't bother.
2020-02-19 15:09:13 -06:00
Andrew Johnson
d82d3d3679 Combine the iocVirgin and iocStopped states into iocVoid 2020-02-18 18:05:46 -06:00
e48cdb48ac dbGet should not crash when source is an empty array 2020-02-18 17:45:12 +01:00
Freddie Akeroyd
3944b32e04 Add back in optimisation disable 2020-02-17 13:30:15 +00:00
Freddie Akeroyd
a0667a122b Excluded x64 tests now need to be excluded on x86 too 2020-02-17 13:29:38 +00:00
Freddie Akeroyd
f2b4c412d3 Fix doc typo 2020-02-17 12:49:45 +00:00
Freddie Akeroyd
8250339e0d Update record pod documentation 2020-02-17 12:46:11 +00:00
Freddie Akeroyd
803593560d Remove redundant left logical shift 2020-02-17 12:22:20 +00:00
Freddie Akeroyd
bfae080af4 Merge branch '3.15' of git+ssh://git.launchpad.net/epics-base into bit_operations 2020-02-17 11:45:25 +00:00
Michael Davidsaver
6ae3f56560 Merge remote-tracking branch 'lp-konrad/fix-crash-dbloadrecords-after-iocinit' into 3.15
* lp-konrad/fix-crash-dbloadrecords-after-iocinit:
  Fix mingw cross-build
  Use accessor in iocInit
  Fix segfault when calling dbLoadRecords after iocInit
2020-02-14 17:18:01 +00:00
Bryan Robert Tester
4844fbbd82 moved listen into rsrv_grab_tcp to allow retry if failed
Fixes race condition with multiple IOCs starting simultaneously.
2020-02-14 17:10:04 +00:00
Gabriel Fedel
983937a52f Fix event record device support with constant INP
This fix apply to event record device with constant INP.
Now when the event record is proccessed the associated records with the
same SCAN setup get triggered correctly, it is not more necessary to set
VAL on event record.

Fixes lp: #1829770
2020-02-14 17:08:36 +00:00
Freddie Akeroyd
6867f97346 Fix bit operations failures on VS2019 32bit
Working with Dirk Zimoch @dirk.zimoch, fixed various issues
with bit operations on VS2019 32bit. These seem to relate to
handling bit 31 of a 32 bit number.

As EPICS << is an arithmetic bit shift, following Java we
have added <<< and >>> operators for logical shifts

Though it is on a different architecture, this looks like
a similar issue to LP: #1838792
2020-02-14 01:16:09 +00:00
Andrew Johnson
1d9e9ff4f7 Add new POD output files to RecordReference index 2020-02-13 09:06:48 -06:00
Andrew Johnson
eb8ca22704 Add new POD documentation, from Rolf Keitel
Documents the lsi, lso and printf record types.
2020-02-13 09:06:14 -06:00
Andrew Johnson
bfd289e85f Add converted histogram POD 2020-02-13 05:11:36 -06:00
Andrew Johnson
a5bae49dab Rename lsi, lso and printf *Record.dbd to .dbd.pod 2020-02-13 04:58:06 -06:00
Andrew Johnson
7a612f9524 Update to stringout POD from Rolf Keitel
Fix spelling of OMSL.
Document the stdio device support.
2020-02-12 09:25:54 -06:00
Andrew Johnson
0db8f8ca1b Rename histogramRecord.dbd to .dbd.pod 2020-02-12 07:45:04 -06:00
Andrew Johnson
dbd6f7e807 Adding tests for epicsThreadClass API
Two tests are disabled which hang the parent in the epicsThread destuctor
2020-01-23 14:26:33 -06:00
Andrew Johnson
54cd7e7ba1 MinGW: Replace -Wno-format with -D__USE_MINGW_ANSI_STDIO 2020-01-08 17:21:04 -06:00
Andrew Johnson
cbe6173417 Updates to the subArrayRecord reference page 2020-01-08 17:19:25 -06:00
Michael Davidsaver
f64f84744e more fun with isinf() and friends.
GNU libstdc++ prior to GCC 6.1.0, the overlay math.h always
includes math.h from glibc, which defines isinf() and friends.

GCC 6.1.0 includes a change (6c8ced3f4f867b72a623fe2f23efa204c5786a28)
so that the overlay math.h never includes the glibc math.h
when compiling c++.
The overlay math.h sometimes includes "using std::isinf"
Determined by inspecting libc math.h when building gcc.
2019-12-18 20:30:23 -08:00
Michael Davidsaver
d97a12f095 travis-ci test trusty w/ c++11 2019-12-18 20:30:23 -08:00
Andrew Johnson
475963453c Merge Martin Konrad's retire-epicsexcept branch into 3.15 2019-12-17 23:48:45 -06:00
Andrew Johnson
f5a442c0de Merge Martin Konrad's fix-typos branch 2019-12-17 23:46:07 -06:00
Martin Konrad
df519ce1a2 Fix typos in calcoutRecord.dbd.pod 2019-12-17 15:53:41 -05:00
Michael Davidsaver
feb938fae2 minor epicsTimerTest
(cherry picked from commit 7acd7c6145)
2019-12-16 13:16:31 -08:00
Michael Davidsaver
e068191684 epicsTimerTest loosen test threshold
(cherry picked from commit f955199805)
2019-12-16 13:16:30 -08:00
Michael Davidsaver
33f2d8c4aa debug epicsTimerTest
(cherry picked from commit 2af0c10470)
2019-12-16 13:16:29 -08:00
Michael Davidsaver
60a092fa50 posix/epicsMath.h
Include "<cmath>" for c++11 and pull in
non-namespace versions of isnan() and friends.
2019-12-16 11:40:13 -08:00
Michael Davidsaver
24f08460bb Revert "libcom: fix colliding isnan/isinf between C99 and C++0x for gcc-4"
This reverts commit 09ec3af337.
2019-12-16 11:40:13 -08:00
Michael Davidsaver
247fea0fa9 Revert "libcom: properly declare isnan() in C++ code"
This reverts commit 2e89a60c2d.
2019-12-16 11:40:13 -08:00
Michael Davidsaver
8a9637568e travis-ci /etc/hosts workaround 2019-12-16 11:40:13 -08:00
Michael Davidsaver
87229fdef0 redo travis-ci with matrix
add mix of Ubuntu versions
2019-12-16 11:40:13 -08:00
Michael Davidsaver
b0418e5274 epicsSockResolveTest add detail 2019-12-16 11:40:13 -08:00
Ralph Lange
2e89a60c2d libcom: properly declare isnan() in C++ code 2019-12-11 14:51:16 +01:00
Ralph Lange
09ec3af337 libcom: fix colliding isnan/isinf between C99 and C++0x for gcc-4
This fix can be removed once support for gcc-4 is dropped in 2038
2019-12-06 10:52:38 +01:00
Ralph Lange
70e9d46d75 libcom: import some C99 math (isnan etc.) into global namespace 2019-12-05 16:44:59 +01:00
Andrew Johnson
1d18aa3e6c Disable printf() format warnings on MinGW, they're broken 2019-11-21 12:20:56 -06:00
Andrew Johnson
a85967caea Cross-builds of 64-bit MinGW should inherit from 32-bit
Don't duplicate, this file missed an important change as a result.
2019-11-21 12:20:13 -06:00
Martin Konrad
a50b850ebd Fix mingw cross-build 2019-11-15 09:33:15 -05:00
Martin Konrad
6767bcd31e Use accessor in iocInit
This is simpler than using init hooks.
2019-11-14 13:57:45 -05:00
Martin Konrad
81550ac4d3 Fix segfault when calling dbLoadRecords after iocInit
This fixes lp:1829919.
2019-11-14 10:11:16 -05:00
d2d8674cb9 use EPICS_PRIVATE_API macro and fix bug with darwin/ios 2019-11-13 14:02:25 -05:00
6f193242e0 renamed epicsSocketCountUnsentBytes to epicsSocketUnsentCount and moved it to osi/os/ 2019-11-13 14:02:23 -05:00
39e8ccdef4 fix bug from commit f85454. Apparently epicsExportSharedSymbols is needed even though epicsExport.h is included 2019-11-13 13:49:28 -05:00
eb8992a750 epicsSocketCountUnsentBytes returns -1 on failure 2019-11-13 13:49:27 -05:00
62fb49f93b bugfix: memmove'ed to much 2019-11-13 13:49:27 -05:00
a5c9db8c8e epicsSockCountUnsentBytes renamed to epicsSocketCountUnsentBytes 2019-11-13 13:49:26 -05:00
04e752c83a moved logClientSendMessage and made it static 2019-11-13 13:49:26 -05:00
a16ce877e7 fix wrong function name in comment 2019-11-13 13:49:26 -05:00
15f28f1183 sending 0 bytes helps to detect broken connections on some systems (but is undefined behavior on Linux, fails on vxWorks and is a documented no-op on Windows) 2019-11-13 13:49:25 -05:00
9c18ce007a cannot print sockets with %d in Windows, they are not small ints but maybe pointers. 2019-11-13 13:49:25 -05:00
765af2efea ask logClient socket how many bytes are still in the send queue and don't discard them in case the connection turns out broken. 2019-11-13 13:49:24 -05:00
059c385286 use dynamic debug flag for logClient 2019-11-13 13:49:24 -05:00
feb1f9b0df increase error message buffer size for long (Windows) error messges 2019-11-13 13:49:23 -05:00
9d9840ad1e improve logClientShow to show unsent bytes on level 2 (and fix level 1) 2019-11-13 13:49:23 -05:00
af73e4cf65 removed unneeded include 2019-11-13 13:49:23 -05:00
ad861a0617 no need to delay startup only because log server is currently not available 2019-11-13 13:49:22 -05:00
1b88e834d6 send pending log messages directly after connecting 2019-11-13 13:49:22 -05:00
e000ea4913 avoid needless memmove calls 2019-11-13 13:49:21 -05:00
06f1a8ec23 elimitate duplicate code in logClient 2019-11-13 13:49:21 -05:00
cf2658be53 do not discard unsent messages when log server has closed connection, instead try to send them after reconnect 2019-11-13 13:49:20 -05:00
74a403090b speed up logRestart thread termination at exit 2019-11-13 13:49:20 -05:00
dc123a0a37 don't send errlog on all logClients 2019-11-13 13:49:20 -05:00
Andrew Johnson
7eee262486 Shorten/simplify uninstall recipes 2019-11-12 16:16:02 -06:00
Andrew Johnson
a10379327c Replace broken cleandirs recipe 2019-11-12 16:14:39 -06:00
Martin Konrad
b37bfe3ed0 Retire unused epicsExcept.h
Due to a syntax error this header has been unusable since 2001
(since 34ea7db15b), and no one
noticed. Let's remove it.
2019-11-12 12:12:47 -05:00
Andrew Johnson
41d86ecd7a Add a document containing Record Reference links 2019-11-11 11:30:46 -06:00
Andrew Johnson
961dd2bc5d Don't check empty (overridden) RELEASE definitions
Bug reported by Dirk Zimoch
2019-11-11 11:29:03 -06:00
94 changed files with 4789 additions and 2008 deletions

131
.appveyor.yml Normal file
View File

@@ -0,0 +1,131 @@
# .appveyor.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# Version format
version: base-{branch}-{build}
#---------------------------------#
# build cache #
#---------------------------------#
# The AppVeyor cache allowance is way too small (1GB per account across all projects, branches and jobs)
# to be used for the dependency builds.
cache:
- C:\Users\appveyor\.tools
#---------------------------------#
# repository cloning #
#---------------------------------#
# Called at very beginning, before repo cloning
init:
# Set autocrlf to make batch files work
- git config --global core.autocrlf true
# Set clone depth (do not fetch complete history)
clone_depth: 5
# Skipping commits affecting only specific files
skip_commits:
files:
- 'documentation/*'
- 'templates/*'
- '**/*.html'
- '**/*.md'
#---------------------------------#
# build matrix configuration #
#---------------------------------#
# Build Configurations: dll/static, regular/debug
configuration:
- dynamic
- static
- dynamic-debug
- static-debug
# Environment variables: compiler toolchain, base version, setup file, ...
environment:
# common / default variables for all jobs
SETUP_PATH: .ci-local:.ci
BASE: SELF
matrix:
- CMP: vs2019
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
- CMP: vs2017
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- CMP: vs2015
- CMP: vs2013
- CMP: vs2012
- CMP: vs2010
- CMP: mingw
# Platform: processor architecture
platform:
- x86
- x64
# Matrix configuration: exclude sets of jobs
matrix:
exclude:
# VS2012 and older installs don't have the 64 bit compiler
- platform: x64
CMP: vs2012
- platform: x64
CMP: vs2010
- platform: x64
CMP: vs2008
# Exclude more jobs to reduce build time
# Skip 32-bit for "middle-aged" compilers
- platform: x86
CMP: vs2017
- platform: x86
CMP: vs2015
#---------------------------------#
# building & testing #
#---------------------------------#
install:
- cmd: git submodule update --init --recursive
- cmd: python .ci/appveyor/do.py prepare
build_script:
- cmd: python .ci/appveyor/do.py build
test_script:
- cmd: python .ci/appveyor/do.py test
on_finish:
- ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
- cmd: python .ci/appveyor/do.py build test-results -s
#---------------------------------#
# debugging #
#---------------------------------#
## if you want to connect by remote desktop to a failed build, uncomment these lines
## note that you will need to connect within the usual build timeout limit (60 minutes)
## so you may want to adjust the build matrix above to just build the one of interest
# print the connection info
#init:
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# block a failed build (until the watchdog barks)
#on_failure:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
#---------------------------------#
# notifications #
#---------------------------------#
notifications:
- provider: Email
to:
- core-talk@aps.anl.gov
on_build_success: false
- provider: GitHubPullRequest

1
.ci Submodule

Submodule .ci added at e91a588370

1
.gitignore vendored
View File

@@ -7,6 +7,7 @@
/include/
/templates/
/configure/*.local
/.tests-failed
O.*/
/QtC-*
*.orig

4
.gitmodules vendored Normal file
View File

@@ -0,0 +1,4 @@
[submodule ".ci"]
path = .ci
url = https://github.com/epics-base/ci-scripts
branch = master

View File

@@ -1,32 +1,93 @@
sudo: false
dist: trusty
language: c
compiler:
- gcc
# .travis.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
language: cpp
compiler: gcc
dist: xenial
cache:
directories:
- $HOME/.cache
env:
- CMPLR=gcc
- CMPLR=gcc EXTRA=CMD_CXXFLAGS=-std=c++11
- CMPLR=gcc STATIC=YES
- CMPLR=clang
- CMPLR=clang STATIC=YES
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=NO
- RTEMS=4.9 TEST=NO
global:
- SETUP_PATH=.ci-local:.ci
- BASE=SELF
addons:
apt:
packages:
# for all EPICS builds
- libreadline6-dev
- libncurses5-dev
- perl
# for clang compiler
- clang
# for mingw builds (32bit and 64bit)
- g++-mingw-w64-i686
- bison
- flex
- texinfo
- install-info
cache:
directories:
- $HOME/.cache
install: sh ci/travis-prepare.sh </dev/null
script: sh ci/travis-build.sh </dev/null
- g++-mingw-w64-x86-64
# for RTEMS cross builds
- qemu-system-x86
homebrew:
packages:
# for all EPICS builds
- bash
update: true
install:
- ./.ci/travis/prepare.sh
script:
- ./.ci/travis/build.sh
# Define build jobs
jobs:
include:
# Different configurations of default gcc and clang
# (the DIST settings are just FYI on the travis-ci.org site)
- dist: bionic
env: DIST=bionic
- env: DIST=xenial
- dist: bionic
env: DIST=bionic EXTRA="CMD_CXXFLAGS=-std=c++11"
- dist: trusty
env: DIST=trusty STATIC=YES EXTRA="CMD_CXXFLAGS=-std=c++11"
- dist: bionic
compiler: clang
env: DIST=bionic
- compiler: clang
env: DIST=xenial
- dist: trusty
compiler: clang
env: DIST=trusty STATIC=YES
# Cross-compilations to Windows using MinGW and WINE
- env: WINE=32 TEST=NO STATIC=YES
compiler: mingw
- env: WINE=32 TEST=NO STATIC=NO
compiler: mingw
# Cross-compilation to RTEMS
- env: RTEMS=4.10 TEST=NO
- env: RTEMS=4.9 TEST=NO
# MacOS build
- os: osx
env:
- EXTRA="CMD_CFLAGS=-mmacosx-version-min=10.7"
- EXTRA1="CMD_CXXFLAGS=-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++"
- EXTRA2="CMD_LDXFLAGS=-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++"
compiler: clang

View File

@@ -1,89 +0,0 @@
# AppVeyor configuration for EPICS Base
# Ralph Lange <ralph.lange@gmx.de>
# Copyright (c) 2016-2017 ITER Organization
# Version format
version: base-{branch}-{build}
#---------------------------------#
# repository cloning #
#---------------------------------#
# Called at very beginning, before repo cloning
init:
# Set autocrlf to make batch files work
- git config --global core.autocrlf true
# Set clone depth (do not fetch complete history)
clone_depth: 2
# Skipping commits affecting only specific files
skip_commits:
files:
- 'documentation/*'
- 'templates/*'
- '**/*.html'
- '**/*.md'
#---------------------------------#
# build matrix configuration #
#---------------------------------#
# Build Configurations: dll/static, regular/debug
configuration:
- dynamic
- static
- dynamic-debug
- static-debug
# Environment variables: compiler toolchain
environment:
matrix:
- TOOLCHAIN: 10.0
- TOOLCHAIN: 11.0
- TOOLCHAIN: 12.0
- TOOLCHAIN: 14.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLCHAIN: 2017
- TOOLCHAIN: mingw
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# Platform: architecture
platform:
- x86
- x64
# Matrix configuration: allow specific failing jobs
matrix:
exclude:
# VS Express installs don't have the 64 bit compiler
- platform: x64
TOOLCHAIN: 10.0
#---------------------------------#
# building & testing #
#---------------------------------#
install:
- cmd: ci/appveyor-prepare.bat
build_script:
- cmd: ci/appveyor-make.bat
test_script:
- cmd: ci/appveyor-make.bat runtests
#---------------------------------#
# notifications #
#---------------------------------#
notifications:
- provider: Email
to:
- core-talk@aps.anl.gov
on_build_success: false
- provider: GitHubPullRequest

View File

@@ -1,119 +0,0 @@
:: Universal build script for AppVeyor (https://ci.appveyor.com/)
:: Environment:
:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/mingw]
:: CONFIGURATION - determines EPICS build [dynamic/static]
:: PLATFORM - architecture [x86/x64]
::
:: All command line args are passed to make
Setlocal EnableDelayedExpansion
set "ST="
if /i "%CONFIGURATION%"=="static" set ST=-static
set OS=64BIT
if "%PLATFORM%"=="x86" set OS=32BIT
echo [INFO] Platform: %OS%
:: Use parallel make, except for 3.14
set "MAKEARGS=-j2 -Otarget"
if "%APPVEYOR_REPO_BRANCH%"=="3.14" set MAKEARGS=
if "%TOOLCHAIN%"=="mingw" (
set "MAKE=mingw32-make"
if "%OS%"=="64BIT" (
set "EPICS_HOST_ARCH=windows-x64-mingw"
set "INCLUDE=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\include;%INCLUDE%"
set "PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%"
echo [INFO] MinGW Toolchain 64bit
) else (
set "EPICS_HOST_ARCH=win32-x86-mingw"
set "INCLUDE=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\include;%INCLUDE%"
set "PATH=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin;%PATH%"
echo [INFO] MinGW Toolchain 32bit
)
echo [INFO] Compiler Version
gcc -v
goto Finish
)
set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio %TOOLCHAIN%"
if not exist "%VSINSTALL%\" set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio\%TOOLCHAIN%\Community"
if not exist "%VSINSTALL%\" goto MSMissing
set "MAKE=C:\tools\make"
echo [INFO] APPVEYOR_BUILD_WORKER_IMAGE=%APPVEYOR_BUILD_WORKER_IMAGE%
if "%OS%"=="64BIT" (
set EPICS_HOST_ARCH=windows-x64%ST%
:: VS 2017
if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" (
call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat"
where cl
if !ERRORLEVEL! NEQ 0 goto MSMissing
goto MSFound
)
if exist "%VSINSTALL%\VC\vcvarsall.bat" (
call "%VSINSTALL%\VC\vcvarsall.bat" amd64
where cl
if !ERRORLEVEL! NEQ 0 (
call "%VSINSTALL%\VC\vcvarsall.bat" x86_amd64
where cl
if !ERRORLEVEL! NEQ 0 goto MSMissing
)
goto MSFound
)
if exist "%VSINSTALL%\VC\bin\amd64\vcvars64.bat" (
call "%VSINSTALL%\VC\bin\amd64\vcvars64.bat"
where cl
if !ERRORLEVEL! NEQ 0 goto MSMissing
goto MSFound
)
) else (
set EPICS_HOST_ARCH=win32-x86%ST%
:: VS 2017
if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat" (
call "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat"
where cl
if !ERRORLEVEL! NEQ 0 goto MSMissing
goto MSFound
)
if exist "%VSINSTALL%\VC\vcvarsall.bat" (
call "%VSINSTALL%\VC\vcvarsall.bat" x86
where cl
if !ERRORLEVEL! NEQ 0 goto MSMissing
goto MSFound
)
if exist "%VSINSTALL%\VC\bin\vcvars32.bat" (
call "%VSINSTALL%\VC\bin\vcvars32.bat"
where cl
if !ERRORLEVEL! NEQ 0 goto MSMissing
goto MSFound
)
if exist "%VSINSTALL%\Common7\Tools\vsvars32.bat" (
call "%VSINSTALL%\Common7\Tools\vsvars32.bat"
where cl
if !ERRORLEVEL! NEQ 0 goto MSMissing
goto MSFound
)
)
:MSMissing
echo [INFO] Installation for MSVC Toolchain %TOOLCHAIN% / %OS% seems to be missing
exit 1
:MSFound
echo [INFO] Microsoft Visual Studio Toolchain %TOOLCHAIN%
echo [INFO] Compiler Version
cl
:Finish
echo [INFO] EPICS_HOST_ARCH: %EPICS_HOST_ARCH%
echo [INFO] Make version
%MAKE% --version
echo [INFO] Perl version
perl --version
%MAKE% %MAKEARGS% %*

View File

@@ -1,38 +0,0 @@
:: Build script for AppVeyor (https://ci.appveyor.com/)
:: Environment:
:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/mingw]
:: CONFIGURATION - determines EPICS build [dynamic/static, -debug]
:: PLATFORM - "x86" -> use 32bit architecture
::
:: Prepares an Appveyor build by excuting the following steps
:: - Set up configure\CONFIG_SITE for static vs. dynamic build
:: - Install Mingw (TOOLCHAIN setting) in the in the appropriate flavor
:: - Download and install Make-4.1 from EPICS download page
Setlocal EnableDelayedExpansion
set OS=64BIT
if "%PLATFORM%"=="x86" set OS=32BIT
echo [INFO] Platform: %OS%
if "%TOOLCHAIN%"=="mingw" (
echo.%CONFIGURATION% | findstr /C:"static">nul && (
echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE
echo STATIC_BUILD=YES>> configure\CONFIG_SITE
echo [INFO] EPICS set up for static build
) || (
echo [INFO] EPICS set up for dynamic build
)
echo.%CONFIGURATION% | findstr /C:"debug">nul && (
echo HOST_OPT=NO>> configure\CONFIG_SITE
echo [INFO] EPICS set up for debug build
) || (
echo [INFO] EPICS set up for optimized build
)
)
echo [INFO] Installing Make 4.2.1 from ANL web site
curl -fsS --retry 3 -o C:\tools\make-4.2.1.zip https://epics.anl.gov/download/tools/make-4.2.1-win64.zip
cd \tools
"C:\Program Files\7-Zip\7z" e make-4.2.1.zip

View File

@@ -1,90 +0,0 @@
#!/bin/sh
set -e -x
die() {
echo "$1" >&2
exit 1
}
ticker() {
while true
do
sleep 60
date -R
[ -r "$1" ] && tail -n10 "$1"
done
}
CACHEKEY=1
EPICS_HOST_ARCH=`perl src/tools/EpicsHostArch.pl`
[ -e configure/os/CONFIG_SITE.Common.linux-x86 ] || die "Wrong location: $PWD"
case "$CMPLR" in
clang)
echo "Host compiler is clang"
cat << EOF >> configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
GNU = NO
CMPLR_CLASS = clang
CC = clang
CCC = clang++
EOF
;;
*) echo "Host compiler is default";;
esac
if [ "$STATIC" = "YES" ]
then
echo "Build static libraries/executables"
cat << EOF >> configure/CONFIG_SITE
SHARED_LIBRARIES=NO
STATIC_BUILD=YES
EOF
fi
# requires wine and g++-mingw-w64-i686
if [ "$WINE" = "32" ]
then
echo "Cross mingw32"
sed -i -e '/CMPLR_PREFIX/d' configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
cat << EOF >> configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
CMPLR_PREFIX=i686-w64-mingw32-
EOF
cat << EOF >> configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
EOF
fi
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
install -d /home/travis/.cache
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \
| tar -C /home/travis/.cache -xj
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386
EOF
cat << EOF >> configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
EOF
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make tapfiles
make -s test-results
fi

View File

@@ -1,40 +0,0 @@
#!/bin/sh
set -e -x
die() {
echo "$1" >&2
exit 1
}
CURDIR="$PWD"
QDIR="$HOME/.cache/qemu"
if [ -n "$RTEMS" -a "$TEST" = "YES" ]
then
git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
cd "$HOME/.build/qemu"
HEAD=`git log -n1 --pretty=format:%H`
echo "HEAD revision $HEAD"
[ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
echo "Cached revision $BUILT"
if [ "$HEAD" != "$BUILT" ]
then
echo "Building QEMU"
git submodule --quiet update --init
install -d "$HOME/.build/qemu/build"
cd "$HOME/.build/qemu/build"
"$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
make -j2
make install
echo "$HEAD" > "$HOME/.cache/qemu/built"
fi
fi
cd "$CURDIR"

View File

@@ -68,8 +68,6 @@ DBTOMENUH = $(PERL) $(TOOLS)/dbdToMenuH.pl
REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
PROVE = $(PERL) $(TOOLS)/epicsProve.pl
#-------------------------------------------------------
# tools for installing libraries and products
@@ -83,6 +81,15 @@ INSTALL_LIBRARY = $(INSTALL)
MKMF = $(PERL) $(TOOLS)/mkmf.pl
REPLACEVAR = $(PERL) $(TOOLS)/replaceVAR.pl
#---------------------------------------------------------------
# Tools for testing
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
PROVE = $(PERL) $(TOOLS)/epicsProve.pl
PROVE.tap = $(PROVE) --ext .tap --exec "$(CAT)"
TEST_FAILURE_FILE = $(TOP)/.tests-failed
PROVE_FAILURE = echo $(abspath .)>> $(TEST_FAILURE_FILE)
#---------------------------------------------------------------
# private versions of lex/yacc from EPICS
EYACC = $(TOOLS)/antelope$(HOSTEXE)

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
# in the file LICENSE that is included with this distribution.
#*************************************************************************
#
# EPICS Version information
@@ -27,23 +27,19 @@ EPICS_VERSION = 3
EPICS_REVISION = 15
# EPICS_MODIFICATION must be a number >=0 and <256
EPICS_MODIFICATION = 7
EPICS_MODIFICATION = 8
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included if zero
EPICS_PATCH_LEVEL = 1
EPICS_PATCH_LEVEL = 0
# This will end in -DEV between official releases
EPICS_DEV_SNAPSHOT=-DEV
#EPICS_DEV_SNAPSHOT=-DEV
#EPICS_DEV_SNAPSHOT=-pre1
#EPICS_DEV_SNAPSHOT=-pre1-DEV
#EPICS_DEV_SNAPSHOT=-pre2
#EPICS_DEV_SNAPSHOT=-pre2-DEV
#EPICS_DEV_SNAPSHOT=-rc1
#EPICS_DEV_SNAPSHOT=-rc1-DEV
#EPICS_DEV_SNAPSHOT=-rc2
#EPICS_DEV_SNAPSHOT=-rc2-DEV
#EPICS_DEV_SNAPSHOT=
EPICS_DEV_SNAPSHOT=
# No changes should be needed below here

View File

@@ -105,17 +105,17 @@ PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
TESTPRODTARGETS += $(TESTPRODNAME) $(TESTMUNCHNAME)
#---------------------------------------------------------------
# Test specifications and test result files
# Test result files
#
ifneq (,$(strip $(TESTS)))
TARGETS += testspec
endif
# Enable testing if this host can run tests on the current target
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
# Enable testing if this host can run tests for the current target
ifneq (,$(filter $(T_A), $(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
RUNTESTS_ENABLED = YES
TAPFILES += $(TESTSCRIPTS:.t=.tap)
JUNITFILES += $(TAPFILES:.tap=.xml)
TESTSCRIPTS.t = $(filter %.t, $(TESTSCRIPTS))
TAPFILES.t += $(TESTSCRIPTS.t:.t=.tap)
JUNITFILES.t += $(TESTSCRIPTS.t:.t=.xml)
TAPFILES += $(TAPFILES.t)
JUNITFILES += $(JUNITFILES.t)
endif
#---------------------------------------------------------------
@@ -335,23 +335,22 @@ $(MODNAME): %$(MODEXT): %$(EXE)
#---------------------------------------------------------------
# Automated testing
runtests: $(TESTSCRIPTS)
runtests: run-tap-tests
run-tap-tests: $(TESTSCRIPTS.t)
ifneq ($(TESTSCRIPTS.t),)
ifdef RUNTESTS_ENABLED
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
$(PROVE) --failures --color $^ || $(PROVE_FAILURE)
endif
endif
testspec: $(TESTSCRIPTS)
@$(RM) $@
@echo OS-class: $(OS_CLASS) > $@
@echo Target-arch: $(T_A) >> $@
$(if $^, @echo Tests: $^ >> $@)
$(if $(TESTFILES), @echo Files: $(TESTFILES) >> $@)
$(if $(TESTSPEC_$(OS_CLASS)), @echo "Harness: $(TESTSPEC_$(OS_CLASS))" >> $@)
tapfiles: $(TAPFILES)
junitfiles: $(JUNITFILES)
test-results: tapfiles
ifneq ($(TAPFILES),)
test-results: tap-results
tap-results: $(TAPFILES)
ifneq ($(strip $(TAPFILES)),)
ifdef RUNTESTS_ENABLED
$(PROVE) --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES)
$(PROVE.tap) --failures --color $^ || $(PROVE_FAILURE)
endif
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
@@ -366,16 +365,13 @@ ifneq ($(CURRENT_JUNITFILES),)
$(RM) $(CURRENT_JUNITFILES)
endif
tapfiles: $(TESTSCRIPTS) $(TAPFILES)
junitfiles: $(JUNITFILES)
# A .tap file is the output from running the associated test script
%.tap: %.t
$(TAPFILES.t): %.tap: %.t
ifdef RUNTESTS_ENABLED
-$(PERL) $< -tap > $@
endif
%.xml: %.tap
$(JUNITFILES.t): %.xml: %.tap
$(TAPTOJUNIT) --puretap --output $@ --input $< $*
# If there's a perl test script (.plt) available, use it
@@ -522,8 +518,8 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
.PRECIOUS: $(COMMON_INC)
.PHONY: all host inc build install clean rebuild buildInstall build_clean
.PHONY: runtests tapfiles clean-tests test-results junitfiles
.PHONY: checkRelease warnRelease noCheckRelease
.PHONY: runtests run-tap-tests tapfiles junitfiles test-results tap-results
.PHONY: clean-tests checkRelease warnRelease noCheckRelease
endif # BASE_RULES_BUILD
# EOF RULES_BUILD

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
# in the file LICENSE that is included with this distribution.
#*************************************************************************
ARCHS += $(BUILD_ARCHS)
@@ -54,7 +54,7 @@ $(foreach dir, $(DIRS), \
define DEP_template2
$(1)$$(DIVIDER)$(2) : $$(foreach ddir, $$($(1)_DEPEND_DIRS), \
$$(addsuffix $$(DIVIDER)$(2),$$(ddir)))
$$(addsuffix $$(DIVIDER)$(2),$$(ddir))) | before-$(2)
endef
$(foreach action, $(ACTIONS), \
$(foreach dir, $(DIRS), \
@@ -79,15 +79,22 @@ $(foreach arch, $(ARCHS), \
dirPart = $(join $(dir $@), $(word 1, $(subst $(DIVIDER), ,$(notdir $@))))
actionArchPart = $(join $(word 2, $(subst $(DIVIDER), ,$(notdir $@))), \
$(addprefix $(DIVIDER),$(word 3, $(subst $(DIVIDER), ,$(notdir $@)))))
$(DIRS) $(dirActionTargets) $(dirArchTargets) $(dirActionArchTargets) :
$(addprefix $(DIVIDER),$(word 3, $(subst $(DIVIDER), ,$(notdir $@)))))
$(DIRS) $(dirActionTargets) $(dirArchTargets) $(dirActionArchTargets):
$(MAKE) -C $(dirPart) $(actionArchPart)
# before-action rules are run once prior to recursing through the
# list of subdirectories and running the action rule in each one.
# See DEP_template2 above for how that rule ordering is achieved.
beforeActions = $(addprefix before-,$(ACTIONS))
$(beforeActions):
$(ARCHS) $(ACTIONS) $(actionArchTargets) :%: \
$(foreach dir, $(DIRS), $(dir)$(DIVIDER)%)
.PHONY : $(DIRS) all host rebuild
.PHONY : $(ARCHS) $(ACTIONS)
.PHONY : $(ARCHS) $(ACTIONS) $(beforeActions)
.PHONY : $(dirActionTargets) $(dirArchTargets)
.PHONY : $(dirActionArchTargets)
.PHONY : $(actionArchTargets)

View File

@@ -16,32 +16,30 @@ cvsclean:
$(PERL) $(CVSCLEAN)
realuninstall: uninstallDirs
$(RMDIR) $(INSTALL_LOCATION_BIN)
$(RMDIR) $(INSTALL_LOCATION_LIB)
$(RMDIR) $(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB)
UNINSTALL_DIRS += $(INSTALL_DBD) $(INSTALL_INCLUDE) $(INSTALL_DOC) \
$(INSTALL_HTML) $(INSTALL_TEMPLATES) $(INSTALL_DB) $(DIRECTORY_TARGETS)
uninstallDirs:
$(RMDIR) $(UNINSTALL_DIRS)
EMPTY_INSTALL_DIRS = \
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
uninstall: archuninstall uninstallDirs
$(RMDIR) $(EMPTY_INSTALL_DIRS)
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS)) | cleandirs
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
archPart = $(word 2, $(subst $(DIVIDER), ,$@))
uninstall$(DIVIDER)%:
$(RMDIR) $(INSTALL_LOCATION_BIN)/$(archPart)
$(RMDIR) $(INSTALL_LOCATION_LIB)/$(archPart)
cleandirs:
@$(NOP)
ifeq ($(wildcard $(INSTALL_LOCATION_BIN)/*),)
$(RMDIR) $(INSTALL_LOCATION_BIN)
endif
ifeq ($(wildcard $(INSTALL_LOCATION_LIB)/*),)
$(RMDIR) $(INSTALL_LOCATION_LIB)
endif
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))
before-runtests before-test-results: rm-failure-file
rm-failure-file:
@$(RM) $(TEST_FAILURE_FILE)
runtests test-results:
$(PERL) $(TOOLS)/testFailures.pl $(TEST_FAILURE_FILE)
help:
@echo "Usage: gnumake [options] [target] ..."
@@ -75,8 +73,8 @@ help:
@echo "Indiv. object targets are supported by O.<arch> level Makefile .e.g"
@echo " xxxRecord.o"
.PHONY: cleandirs distclean cvsclean realuninstall archuninstall uninstallDirs
.PHONY: uninstall help
.PHONY: distclean cvsclean realuninstall archuninstall uninstallDirs
.PHONY: uninstall rm-failure-file help
# Include <top>/cfg/TOP_RULES* files from tops defined in RELEASE* files
#

View File

@@ -30,7 +30,7 @@ ARCH_DEP_LDFLAGS += -m32
# Compiler does not define __unix __unix__ unix
# Override for -DUNIX from CONFIG.Common.UnixCommon
OP_SYS_CPPFLAGS = -D_MINGW
OP_SYS_CPPFLAGS = -D_MINGW -D__USE_MINGW_ANSI_STDIO
EXE = .exe
RES = .coff

View File

@@ -4,21 +4,5 @@
# Override these definitions in CONFIG_SITE.linux-x86.windows-x64-mingw
#-------------------------------------------------------
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon
# Add resource compiler
RCCMD = $(GNU_BIN)/$(CMPLR_PREFIX)windres$(CMPLR_SUFFIX) $(INCLUDES) $< $@
# Remove -fPIC flags, add out-implib
SHRLIB_CFLAGS =
SHRLIB_LDFLAGS = -shared \
-Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX)
LOADABLE_SHRLIB_LDFLAGS = -shared \
-Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX)
# No need to explicitly link with gcc library
GNU_LDLIBS_YES =
# Link with winsock2
OP_SYS_LDLIBS = -lws2_32
# Use the definitions from the win32-x86-mingw target
include $(CONFIG)/os/CONFIG.linux-x86.win32-x86-mingw

View File

@@ -141,13 +141,16 @@ STATIC_LDFLAGS=
RANLIB=
#
# option needed for parallel builds with Visual Studio 2015 onward
#
# option needed for parallel builds with Visual Studio 2013 onward
# VS2012 and above have VisualStudioVersion, so just need to exclude 2012 (11.0)
# -FS Force Synchronous PDB Writes
#
ifneq ($(VisualStudioVersion),)
ifneq ($(VisualStudioVersion),11.0)
OPT_CXXFLAGS_NO += -FS
OPT_CFLAGS_NO += -FS
endif
endif
#

View File

@@ -1,10 +1,110 @@
# EPICS Base Release 3.15.8
This version of EPICS Base has not been released yet.
## Changes made between 3.15.7 and 3.15.8
## Changes made on the 3.15 branch since 3.15.7
### Bug fixes
The following launchpad bugs have fixes included in this release:
- [lp: 1812084](https://bugs.launchpad.net/epics-base/+bug/1812084), Build
failure on RTEMS 4.10.2
- [lp: 1829770](https://bugs.launchpad.net/epics-base/+bug/1829770), event
record device support broken with constant INP
- [lp: 1829919](https://bugs.launchpad.net/epics-base/+bug/1829919), IOC
segfaults when calling dbLoadRecords after iocInit
- [lp: 1838792](https://bugs.launchpad.net/epics-base/+bug/1838792), epicsCalc
bit-wise operators on aarch64
- [lp: 1841608](https://bugs.launchpad.net/epics-base/+bug/1841608), logClient
falsely sends error logs on all connections
- [lp: 1853168](https://bugs.launchpad.net/epics-base/+bug/1853168), undefined
reference to `clock_gettime()`
- [lp: 1862328](https://bugs.launchpad.net/epics-base/+bug/1862328), Race
condition on IOC start leaves rsrv unresponsive
- [lp: 1868486](https://bugs.launchpad.net/epics-base/+bug/1868486),
epicsMessageQueue lost messages
### Improvements to the self-test build targets
This release contains changes that make it possible to integrate another test
running and reporting system (such as Google's gtest) into the EPICS build
system. The built-in test-runner and reporting system will continue to be used
by the test programs inside Base however.
These GNUmake `tapfiles` and `test-results` build targets now collect a list of
the directories that experienced test failures and display those at the end of
running and/or reporting all of the tests. The GNUmake process will also only
exit with an error status after running and/or reporting all of the test
results; previously the `-k` flag to make was needed and even that didn't always
work.
Continuous Integration systems are recommended to run `make tapfiles` (or if
they can read junittest output instead of TAP `make junitests`) followed by
`make -s test-results` to display the results of the tests. If multiple CPUs are
available the `-j` flag can be used to run tests in parallel, giving the maximum
jobs that should be allowed so `make -j4 tapfiles` for a system with 4 CPUs say.
Running many more jobs than you have CPUs is likely to be slower and is not
recommended.
### Calc Engine Fixes and Enhancements
The code that implements bit operations for Calc expressions has been reworked
to better handle some CPU architectures and compilers. As part of this work a
new operator has been added: `>>>` performs a logical right-shift, inserting
zero bits into the most significant bits (the operator `>>` is an arithmetic
right-shift which copies the sign bit as it shifts the value rightwards).
### IOC logClient Changes
The IOC's error logging system has been updated significantly to fix a number
of issues including:
- Only send errlog messages to iocLogClient listeners
- Try to minimize lost messages while the log server is down:
+ Detect disconnects sooner
+ Don't discard the buffer on disconnect
+ Flush the buffer immediately after a server reconnects
### epicsThread: Main thread defaults to allow blocking I/O
VxWorks IOCs (and potentially RTEMS IOCs running GeSys) have had problems with
garbled error messages from dbStaticLib routines for some time &mdash; messages
printed before `iocInit` were being queued through the errlog thread instead of
being output immediately. This has been fixed by initializing the main thread
with its `OkToBlock` flag set instead of cleared. IOCs running on other
operating systems that use iocsh to execute the startup script previously had
that set anyway in iocsh so were not affected, but this change might cause other
programs that don't use iocsh to change their behavior slightly if they use
`errlogPrintf()`, `epicsPrintf()` or `errPrintf()`.
### catools: Handle data type changes in camonitor
The camonitor program didn't properly cope if subscribed to a channel whose data
type changed when its IOC was rebooted without restarting the camonitor program.
This has now been fixed.
### More Record Reference Documentation
The remaining record types have had their reference pages moved from the Wiki,
and some new reference pages have been written to cover the analog array and
long string input and output record types plus the printf record type, none of
which were previously documented. The wiki reference pages covering the fields
common to all, input, and output record types have also been added, thanks to
Rolf Keitel. The POD conversion scripts have also been improved and they now
properly support linking to subsections in a different document, although the
POD changes to add the cross-links that appeared in the original wiki pages
still needs to be done in most cases.
### Fix build issues with newer MinGW versions
The `clock_gettime()` routine is no longer used under MinGW since newer versions
don't provide it any more.
### Fix race for port in RSRV when multiple IOCs start simultaneously
If multiple IOCs were started at the same time, by systemd say, they could race
to obtain the Channel Access TCP port number 5064. This issue has been fixed.
<!-- Insert new items immediately below here ... -->
## Changes made between 3.15.6 and 3.15.7

View File

@@ -0,0 +1,65 @@
# Record Reference Documentation
The following documentation for the record types and menus include with Base was
converted from the old EPICS Wiki pages and updated. This list only includes the
record types supplied with Base.
* [Fields Common to All Record Types](dbCommonRecord.html)
* [Fields Common to Input Record Types](dbCommonInputs.html)
* [Fields Common to Output Record Types](dbCommonOutputs.html)
## Record Types
* [Analog Array Input Record (aai)](aaiRecord.html)
* [Analog Array Output Record (aao)](aaoRecord.html)
* [Analog Input Record (ai)](aiRecord.html)
* [Analog Output Record (ao)](aoRecord.html)
* [Array Subroutine Record (aSub)](aSubRecord.html)
* [Binary Input Record (bi)](biRecord.html)
* [Binary Output Record (bo)](boRecord.html)
* [Calculation Output Record (calcout)](calcoutRecord.html)
* [Calculation Record (calc)](calcRecord.html)
* [Compression Record (compress)](compressRecord.html)
* [Data Fanout Record (dfanout)](dfanoutRecord.html)
* [Event Record (event)](eventRecord.html)
* [Fanout Record (fanout)](fanoutRecord.html)
* [Histogram Record (histogram)](histogramRecord.html)
* [Long Input Record (longin)](longinRecord.html)
* [Long Output Record (longout)](longoutRecord.html)
* [Long String Input Record (lsi)](lsiRecord.html)
* [Long String Output Record (lso)](lsoRecord.html)
* [Multi-Bit Binary Input Direct Record (mbbiDirect)](mbbiDirectRecord.html)
* [Multi-Bit Binary Input Record (mbbi)](mbbiRecord.html)
* [Multi-Bit Binary Output Direct Record (mbboDirect)](mbboDirectRecord.html)
* [Multi-Bit Binary Output Record (mbbo)](mbboRecord.html)
* [Permissive Record (permissive)](permissiveRecord.html)
* [Printf Record (prinf)](printfRecord.html)
* [Select Record (sel)](selRecord.html)
* [Sequence Record (seq)](seqRecord.html)
* [State Record (state)](stateRecord.html)
* [String Input Record (stringin)](stringinRecord.html)
* [String Output Record (stringout)](stringoutRecord.html)
* [Sub-Array Record (subArray)](subArrayRecord.html)
* [Subroutine Record (sub)](subRecord.html)
* [Waveform Record (waveform)](waveformRecord.html)
## Menu Definitions
* [Alarm Severity Menu](menuAlarmSevr.html)
* [Alarm Status Menu](menuAlarmStat.html)
* [Analog Conversions Menu](menuConvert.html)
* [Field Type Menu](menuFtype.html)
* [Invalid Value Output Action Menu](menuIvoa.html)
* [Output Mode Select Menu](menuOmsl.html)
* [Scan Menu](menuScan.html)
* [Simulation Mode Menu](menuSimm.html)
* [Yes/No Menu](menuYesNo.html)
## Corrections and Updates
Corrections to these documents can be submitted as patch files to the EPICS core
developers, or as merge requests or pull requests to the 3.15 branch of Base.
The document sources can be found in the `src/std/rec` and `src/ioc/db`
directories in files with extension `.dbd.pod`. The documentation source format
is a combination of the EPICS DBD file format with an extended version of Perl's
POD (plain old documentation); run `perldoc pod` for details of POD.

View File

@@ -138,7 +138,14 @@ static void connection_handler ( struct connection_handler_args args )
pv *ppv = ( pv * ) ca_puser ( args.chid );
if ( args.op == CA_OP_CONN_UP ) {
nConn++;
if (!ppv->onceConnected) {
if (ppv->onceConnected && ppv->dbfType != ca_field_type(ppv->chid)) {
/* Data type has changed. Rebuild connection with new type. */
ca_clear_subscription(ppv->evid);
ppv->evid = NULL;
}
if (!ppv->evid) {
ppv->onceConnected = 1;
/* Set up pv structure */
/* ------------------- */
@@ -169,7 +176,7 @@ static void connection_handler ( struct connection_handler_args args )
eventMask,
event_handler,
(void*)ppv,
NULL);
&ppv->evid);
}
}
else if ( args.op == CA_OP_CONN_DOWN ) {

View File

@@ -78,6 +78,7 @@ typedef struct
epicsTimeStamp tsPreviousS;
char firstStampPrinted;
char onceConnected;
evid evid;
} pv;

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
@@ -59,6 +59,9 @@ DBDINC += dbCommon
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
HTMLS += $(patsubst %.dbd.pod,%.html,$(dbMenusPod))
HTMLS += dbCommonRecord.html
HTMLS += dbCommonInput.html
HTMLS += dbCommonOutput.html
dbCore_SRCS += dbLock.c
dbCore_SRCS += dbAccess.c
@@ -91,4 +94,3 @@ dbCore_SRCS += chfPlugin.c
dbCore_SRCS += dbState.c
dbCore_SRCS += dbUnitTest.c
dbCore_SRCS += dbServer.c

View File

@@ -6,21 +6,25 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
dbCommon.h$(DEP): $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
@$(RM) $@
@$(DBTORECORDTYPEH) -D -I ../db -o $(COMMONDEP_TARGET) $< > $@
THESE_RULES := $(IOCDIR)/db/RULES
$(COMMON_DIR)/dbCommon.h: $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
@$(RM) $@
@$(DBTORECORDTYPEH) -D -I ../db -I $(COMMON_DIR) -o $(COMMONDEP_TARGET) $< > $@
$(COMMON_DIR)/dbCommonRecord.html: ../db/dbCommon.dbd.pod
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) -I ../db -o $(notdir $@) $<
$(DBTORECORDTYPEH) -I ../db -I $(COMMON_DIR) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menuGlobal.dbd: $(IOCDIR)/db/Makefile $(IOCDIR)/db/RULES
$(COMMON_DIR)/menuGlobal.dbd: $(IOCDIR)/db/Makefile $(THESE_RULES)
# This is a target-specific variable
$(COMMON_DIR)/menuGlobal.dbd: DBDCAT_COMMAND = \

View File

@@ -730,9 +730,18 @@ int dbLoadDatabase(const char *file, const char *path, const char *subs)
int dbLoadRecords(const char* file, const char* subs)
{
int status = dbReadDatabase(&pdbbase, file, 0, subs);
if (!status && dbLoadRecordsHook)
dbLoadRecordsHook(file, subs);
switch(status)
{
case 0:
if(dbLoadRecordsHook)
dbLoadRecordsHook(file, subs);
break;
case -2:
errlogPrintf("dbLoadRecords: failed to load %s - cannot load records after running iocBuild!\n", file);
break;
default:
errlogPrintf("dbLoadRecords: failed to load %s\n", file);
}
return status;
}
@@ -898,6 +907,11 @@ long dbGet(DBADDR *paddr, short dbrType,
} else {
DBADDR localAddr = *paddr; /* Structure copy */
if (pfl->no_elements < 1) {
status = S_db_badField;
goto done;
}
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
localAddr.no_elements = pfl->no_elements;

View File

@@ -1,261 +0,0 @@
#*************************************************************************
# Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
%#include "epicsTypes.h"
%#include "link.h"
field(NAME,DBF_STRING) {
prompt("Record Name")
special(SPC_NOMOD)
size(61)
}
field(DESC,DBF_STRING) {
prompt("Descriptor")
promptgroup("10 - Common")
size(41)
}
field(ASG,DBF_STRING) {
prompt("Access Security Group")
promptgroup("10 - Common")
special(SPC_AS)
size(29)
}
field(SCAN,DBF_MENU) {
prompt("Scan Mechanism")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuScan)
}
field(PINI,DBF_MENU) {
prompt("Process at iocInit")
promptgroup("20 - Scan")
interest(1)
menu(menuPini)
}
field(PHAS,DBF_SHORT) {
prompt("Scan Phase")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
}
field(EVNT,DBF_STRING) {
prompt("Event Name")
promptgroup("20 - Scan")
special(SPC_SCAN)
size(40)
interest(1)
}
field(TSE,DBF_SHORT) {
prompt("Time Stamp Event")
promptgroup("20 - Scan")
interest(1)
}
field(TSEL,DBF_INLINK) {
prompt("Time Stamp Link")
promptgroup("20 - Scan")
interest(1)
}
field(DTYP,DBF_DEVICE) {
prompt("Device Type")
promptgroup("10 - Common")
interest(1)
}
field(DISV,DBF_SHORT) {
prompt("Disable Value")
promptgroup("20 - Scan")
initial("1")
}
field(DISA,DBF_SHORT) {
prompt("Disable")
}
field(SDIS,DBF_INLINK) {
prompt("Scanning Disable")
promptgroup("20 - Scan")
interest(1)
}
%#include "epicsMutex.h"
field(MLOK,DBF_NOACCESS) {
prompt("Monitor lock")
special(SPC_NOMOD)
interest(4)
extra("epicsMutexId mlok")
}
%#include "ellLib.h"
field(MLIS,DBF_NOACCESS) {
prompt("Monitor List")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST mlis")
}
field(DISP,DBF_UCHAR) {
prompt("Disable putField")
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
pp(TRUE)
interest(3)
}
field(STAT,DBF_MENU) {
prompt("Alarm Status")
special(SPC_NOMOD)
menu(menuAlarmStat)
initial("UDF")
}
field(SEVR,DBF_MENU) {
prompt("Alarm Severity")
special(SPC_NOMOD)
menu(menuAlarmSevr)
}
field(NSTA,DBF_MENU) {
prompt("New Alarm Status")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmStat)
}
field(NSEV,DBF_MENU) {
prompt("New Alarm Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKS,DBF_MENU) {
prompt("Alarm Ack Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKT,DBF_MENU) {
prompt("Alarm Ack Transient")
promptgroup("70 - Alarm")
special(SPC_NOMOD)
interest(2)
menu(menuYesNo)
initial("YES")
}
field(DISS,DBF_MENU) {
prompt("Disable Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
}
field(LCNT,DBF_UCHAR) {
prompt("Lock Count")
special(SPC_NOMOD)
interest(2)
}
field(PACT,DBF_UCHAR) {
prompt("Record active")
special(SPC_NOMOD)
interest(1)
}
field(PUTF,DBF_UCHAR) {
prompt("dbPutField process")
special(SPC_NOMOD)
interest(1)
}
field(RPRO,DBF_UCHAR) {
prompt("Reprocess ")
special(SPC_NOMOD)
interest(1)
}
field(ASP,DBF_NOACCESS) {
prompt("Access Security Pvt")
special(SPC_NOMOD)
interest(4)
extra("struct asgMember *asp")
}
field(PPN,DBF_NOACCESS) {
prompt("pprocessNotify")
special(SPC_NOMOD)
interest(4)
extra("struct processNotify *ppn")
}
field(PPNR,DBF_NOACCESS) {
prompt("pprocessNotifyRecord")
special(SPC_NOMOD)
interest(4)
extra("struct processNotifyRecord *ppnr")
}
field(SPVT,DBF_NOACCESS) {
prompt("Scan Private")
special(SPC_NOMOD)
interest(4)
extra("struct scan_element *spvt")
}
field(RSET,DBF_NOACCESS) {
prompt("Address of RSET")
special(SPC_NOMOD)
interest(4)
extra("struct rset *rset")
}
field(DSET,DBF_NOACCESS) {
prompt("DSET address")
special(SPC_NOMOD)
interest(4)
extra("struct dset *dset")
}
field(DPVT,DBF_NOACCESS) {
prompt("Device Private")
special(SPC_NOMOD)
interest(4)
extra("void *dpvt")
}
field(RDES,DBF_NOACCESS) {
prompt("Address of dbRecordType")
special(SPC_NOMOD)
interest(4)
extra("struct dbRecordType *rdes")
}
field(LSET,DBF_NOACCESS) {
prompt("Lock Set")
special(SPC_NOMOD)
interest(4)
extra("struct lockRecord *lset")
}
field(PRIO,DBF_MENU) {
prompt("Scheduling Priority")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuPriority)
}
field(TPRO,DBF_UCHAR) {
prompt("Trace Processing")
}
field(BKPT,DBF_NOACCESS) {
prompt("Break Point")
special(SPC_NOMOD)
interest(1)
extra("char bkpt")
}
field(UDF,DBF_UCHAR) {
prompt("Undefined")
promptgroup("10 - Common")
pp(TRUE)
interest(1)
initial("1")
}
field(UDFS,DBF_MENU) {
prompt("Undefined Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
initial("INVALID")
}
%#include "epicsTime.h"
field(TIME,DBF_NOACCESS) {
prompt("Time")
special(SPC_NOMOD)
interest(2)
extra("epicsTimeStamp time")
}
field(FLNK,DBF_FWDLINK) {
prompt("Forward Process Link")
promptgroup("20 - Scan")
interest(1)
}

514
src/ioc/db/dbCommon.dbd.pod Normal file
View File

@@ -0,0 +1,514 @@
#*************************************************************************
# Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head3 Operator Display Parameters
The B<NAME> field contains the record name which must be unique within an
EPICS Channel Access name space. The name is supplied by the application
developer and is the means of identifying a specific record. The name has a
maximum length of 60 characters and should use only this limited set of
characters:
a-z A-Z 0-9 _ - : [ ] < > ;
The B<DESC> field may be set to provide a meaningful description of the
record's purpose. Maximum length is 40 characters.
=fields NAME, DESC
=cut
%#include "epicsTypes.h"
%#include "link.h"
field(NAME,DBF_STRING) {
prompt("Record Name")
special(SPC_NOMOD)
size(61)
}
field(DESC,DBF_STRING) {
prompt("Descriptor")
promptgroup("10 - Common")
size(41)
}
field(ASG,DBF_STRING) {
prompt("Access Security Group")
promptgroup("10 - Common")
special(SPC_AS)
size(29)
}
=head3 Scan Fields
These fields contain information related to how and when a record processes. A
few records have unique fields that also affect how they process. These
fields, if any, will be listed and explained in the section for each record.
The B<SCAN> field specifies the scanning period for periodic record scans or the
scan type for non-periodic record scans. The default set of values for SCAN can
be found in L<menuScan.dbd|menuScan>.
The choices provided by this menu are:
=over
=item *
C<Passive> for the record scan to be triggered by other records or Channel
Access
=item *
C<Event> for event-driven scan
=item *
C<I/O Intr> for interrupt-driven scan
=item *
A set of periodic scan intervals
=back
Additional periodic scan rates may be defined for individual IOCs by making a
local copy of menuScan.dbd and adding more choices as required. Scan rates
should normally be defined in order, with the fastest rates appearing first.
Scan periods may now be specified in seconds, minutes, hours or Hertz/Hz, and
plural time units will also be accepted (seconds are used if no unit is
mentioned in the choice string). For example the rates given below are all
valid:
1 hour
0.5 hours
15 minutes
3 seconds
1 second
2 Hertz
The B<PINI> field specifies record processing at initialization. If it is set
to YES during database configuration, the record is processed once at IOC
initialization (before the normal scan tasks are started).
The B<PHAS> field orders the records within a specific SCAN group. This is not
meaningful for passive records. All records of a specified phase are processed
before those with higher phase number. Whenever possible it is better to use
linked passive records to enforce the order of processing rather than a phase
number.
The B<EVNT> field specifies an event number. This event number is used if the
SCAN field is set to C<Event>. All records with scan type C<Event> and the
same EVNT value will be processed when a call to post_event for EVNT is made.
The call to post_event is: post_event(short event_number).
The B<PRIO> field specifies the scheduling priority for processing records
with SCAN=C<I/O Event> and asynchronous record completion tasks.
The B<DISV> field specifies a "disable value". Record processing is
immediately terminated if the value of this field is equal to the value of the
DISA field, i.e. the record is disabled. Note that field values of a record
can be changed by database put or Channel Access, even if a record is
disabled.
The B<DISA> field contains the value that is compared with DISV to determine
if the record is disabled. The value of the DISA field is obtained via SDIS if
SDIS is a database or channel access link. If SDIS is not a database or
channel access link, then DISA can be set via dbPutField or dbPutLink.
If the B<PROC> field of a record is written to, the record is processed.
The B<DISS> field defines the record's "disable severity". If this field is
not NO_ALARM and the record is disabled, the record will be put into alarm
with this severity and a status of DISABLE_ALARM.
The B<LSET> field contains the lock set to which this record belongs. All
records linked in any way via input, output, or forward database links belong
to the same lock set. Lock sets are determined at IOC initialization time, and
are updated whenever a database link is added, removed or altered.
The B<LCNT> field counts the number of times dbProcess finds the record active
during successive scans, i.e. PACT is TRUE. If dbProcess finds the record
active MAX_LOCK times (currently set to 10) it raises a SCAN_ALARM.
The B<PACT> field is TRUE while the record is being processed. For
asynchronous records PACT can be TRUE from the time record processing is
started until the asynchronous completion occurs. As long as PACT is TRUE,
dbProcess will not call the record processing routine. See Application
Developers Guide for details on usage of PACT.
The B<FLNK> field is a database link to another record (the "target" record).
Processing a record with a specified FLNK field will force processing of the
target record, provided the target record's SCAN field is set to C<Passive>.
The B<SPVT> field is for internal use by the scanning system.
=fields SCAN, PINI, PHAS, EVNT, PRIO, DISV, DISA, SDIS, PROC, DISS, LCNT, PACT, FLNK, SPVT
=cut
field(SCAN,DBF_MENU) {
prompt("Scan Mechanism")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuScan)
}
field(PINI,DBF_MENU) {
prompt("Process at iocInit")
promptgroup("20 - Scan")
interest(1)
menu(menuPini)
}
field(PHAS,DBF_SHORT) {
prompt("Scan Phase")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
}
field(EVNT,DBF_STRING) {
prompt("Event Name")
promptgroup("20 - Scan")
special(SPC_SCAN)
size(40)
interest(1)
}
field(TSE,DBF_SHORT) {
prompt("Time Stamp Event")
promptgroup("20 - Scan")
interest(1)
}
field(TSEL,DBF_INLINK) {
prompt("Time Stamp Link")
promptgroup("20 - Scan")
interest(1)
}
field(DTYP,DBF_DEVICE) {
prompt("Device Type")
promptgroup("10 - Common")
interest(1)
}
field(DISV,DBF_SHORT) {
prompt("Disable Value")
promptgroup("20 - Scan")
initial("1")
}
field(DISA,DBF_SHORT) {
prompt("Disable")
}
field(SDIS,DBF_INLINK) {
prompt("Scanning Disable")
promptgroup("20 - Scan")
interest(1)
}
%#include "epicsMutex.h"
field(MLOK,DBF_NOACCESS) {
prompt("Monitor lock")
special(SPC_NOMOD)
interest(4)
extra("epicsMutexId mlok")
}
%#include "ellLib.h"
field(MLIS,DBF_NOACCESS) {
prompt("Monitor List")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST mlis")
}
field(DISP,DBF_UCHAR) {
prompt("Disable putField")
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
pp(TRUE)
interest(3)
}
=head3 Alarm Fields
These fields indicate the status and severity of alarms, or else determine the
how and when alarms are triggered. Of course, many records have alarm-related
fields not common to all records. These fields are listed and explained in the
appropriate section on each record.
The B<STAT> field contains the current alarm status.
The B<SEVR> field contains the current alarm severity.
These two fields are seen outside database access. The B<NSTA> and B<NSEV>
fields are used by the database access, record support, and device support
routines to set new alarm status and severity values. Whenever any software
component discovers an alarm condition, it uses the following macro function:
recGblSetSevr(precord,new_status,new_severity) This ensures that the current
alarm severity is set equal to the highest outstanding alarm. The file alarm.h
defines all allowed alarm status and severity values.
The B<ACKS> field contains the highest unacknowledged alarm severity.
The B<ACKT> field specifies if it is necessary to acknowledge transient
alarms.
The B<UDF> indicates if the record's value is B<U>nB<D>eB<F>ined. Typically
this is caused by a failure in device support, the fact that the record has
never been processed, or that the VAL field currently contains a NaN (not a
number). UDF is initialized to TRUE at IOC initialization. Record and device
support routines which write to the VAL field are responsible for setting UDF.
=fields STAT, SEVR, NSTA, NSEV, ACKS, ACKT, UDF
=cut
field(STAT,DBF_MENU) {
prompt("Alarm Status")
special(SPC_NOMOD)
menu(menuAlarmStat)
initial("UDF")
}
field(SEVR,DBF_MENU) {
prompt("Alarm Severity")
special(SPC_NOMOD)
menu(menuAlarmSevr)
}
field(NSTA,DBF_MENU) {
prompt("New Alarm Status")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmStat)
}
field(NSEV,DBF_MENU) {
prompt("New Alarm Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKS,DBF_MENU) {
prompt("Alarm Ack Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKT,DBF_MENU) {
prompt("Alarm Ack Transient")
promptgroup("70 - Alarm")
special(SPC_NOMOD)
interest(2)
menu(menuYesNo)
initial("YES")
}
field(DISS,DBF_MENU) {
prompt("Disable Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
}
field(LCNT,DBF_UCHAR) {
prompt("Lock Count")
special(SPC_NOMOD)
interest(2)
}
field(PACT,DBF_UCHAR) {
prompt("Record active")
special(SPC_NOMOD)
interest(1)
}
field(PUTF,DBF_UCHAR) {
prompt("dbPutField process")
special(SPC_NOMOD)
interest(1)
}
field(RPRO,DBF_UCHAR) {
prompt("Reprocess ")
special(SPC_NOMOD)
interest(1)
}
field(ASP,DBF_NOACCESS) {
prompt("Access Security Pvt")
special(SPC_NOMOD)
interest(4)
extra("struct asgMember *asp")
}
field(PPN,DBF_NOACCESS) {
prompt("pprocessNotify")
special(SPC_NOMOD)
interest(4)
extra("struct processNotify *ppn")
}
field(PPNR,DBF_NOACCESS) {
prompt("pprocessNotifyRecord")
special(SPC_NOMOD)
interest(4)
extra("struct processNotifyRecord *ppnr")
}
field(SPVT,DBF_NOACCESS) {
prompt("Scan Private")
special(SPC_NOMOD)
interest(4)
extra("struct scan_element *spvt")
}
=head3 Device Fields
The B<RSET> field contains the address of the Record Support Entry Table. See
the Application Developers Guide for details on usage.
The B<DSET> field contains the address of Device Support Entry Table. The
value of this field is determined at IOC initialization time. Record support
routines use this field to locate their device support routines.
The B<DPVT> field is is for private use of the device support modules.
=fields RSET, DSET, DPVT
=cut
field(RSET,DBF_NOACCESS) {
prompt("Address of RSET")
special(SPC_NOMOD)
interest(4)
extra("struct rset *rset")
}
field(DSET,DBF_NOACCESS) {
prompt("DSET address")
special(SPC_NOMOD)
interest(4)
extra("struct dset *dset")
}
field(DPVT,DBF_NOACCESS) {
prompt("Device Private")
special(SPC_NOMOD)
interest(4)
extra("void *dpvt")
}
field(RDES,DBF_NOACCESS) {
prompt("Address of dbRecordType")
special(SPC_NOMOD)
interest(4)
extra("struct dbRecordType *rdes")
}
field(LSET,DBF_NOACCESS) {
prompt("Lock Set")
special(SPC_NOMOD)
interest(4)
extra("struct lockRecord *lset")
}
field(PRIO,DBF_MENU) {
prompt("Scheduling Priority")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuPriority)
}
=head3 Debugging Fields
The B<TPRO> field is used for trace processing. If this field is non-zero a
message is printed whenever this record is processed, and when any other
record in the same lock-set is processed by a database link from this record.
The B<BKPT> field indicates if there is a breakpoint set at this record. This
supports setting a debug breakpoint in the record processing. STEP through
database processing can be supported using this.
=fields TPRO, BKPT
=head3 Miscellaneous Fields
The B<ASG> field contains a character string value defining the access
security group for this record. If left empty, the record is placed in group
DEFAULT.
The B<ASP> field is a field for private use of the access security system.
The B<DISP> field controls dbPutFields to this record which are normally
issued by channel access. If the field is set to TRUE all dbPutFields
directed to this record are ignored except to the field DISP itself.
The B<DTYP> field specifies the device type for the record. Each record type
has its own set of device support routines which are specified in
devSup.ASCII. If a record type does not have any associated device support,
DTYP and DSET are meaningless.
The B<MLOK> field contains the monitor lock. The lock used by the monitor
routines when the monitor list is being used. The list is locked whenever
monitors are being scheduled, invoked, or when monitors are being added to or
removed from the list. This field is accessed only by the dbEvent routines.
The B<MLIS> field is the head of the list of monitors connected to this
record. Each record support module is responsible for triggering monitors for
any fields that change as a result of record processing. Monitors are present
if mlis count is greater than zero. The call to trigger monitors is:
db_post_event(precord,&data,mask), where "mask" is some combination of
DBE_ALARM, DBE_VALUE, and DBE_LOG.
The B<PPN> field contains the address of a putNotify callback.
The B<PPNR> field contains the next record for PutNotify.
The B<PUTF> field is set to TRUE if dbPutField caused the current record
processing.
The B<RDES> field contains the address of dbRecordType
The B<RPRO> field specifies a reprocessing of the record when current
processing completes.
The B<TIME> field contains the time when this record was last processed in
standard format.
The B<TSE> field indicates the mechanism to use to get the time stamp. '0' -
call get time as before '-1' - call the time stamp driver and use the best
source available. '-2' - the device support provides the time stamp from the
hardware. Values between 1-255 request the time of the last occurance of a
generalTime event.
The B<TSEL> field contains an input link for obtaining the time stamp. If this
link references the .TIME field of a record then the time stamp of the
referenced record becomes the time stamp for this record as well. In this
case, an internal flag is set and ".TIME" is then overwritten by ".VAL". If
any other field is referenced, the field value is read and stored in the .TSE
field which is then used to acquire a timestamp.
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, TSE, TSEL
=cut
field(TPRO,DBF_UCHAR) {
prompt("Trace Processing")
}
field(BKPT,DBF_NOACCESS) {
prompt("Break Point")
special(SPC_NOMOD)
interest(1)
extra("char bkpt")
}
field(UDF,DBF_UCHAR) {
prompt("Undefined")
promptgroup("10 - Common")
pp(TRUE)
interest(1)
initial("1")
}
field(UDFS,DBF_MENU) {
prompt("Undefined Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
initial("INVALID")
}
%#include "epicsTime.h"
field(TIME,DBF_NOACCESS) {
prompt("Time")
special(SPC_NOMOD)
interest(2)
extra("epicsTimeStamp time")
}
field(FLNK,DBF_FWDLINK) {
prompt("Forward Process Link")
promptgroup("20 - Scan")
interest(1)
}

View File

@@ -0,0 +1,181 @@
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Input Record Types
This section describes fields that are found in many input record types.
These fields usually have the same meaning whenever they are used.
See also L<Fields Common to All Record Types|dbCommonRecord> and L<Fields Common
to Output Record Types|dbCommonOutput>.
=head3 Input and Value Fields
The B<INP> field specifies an input link. It is used by the device support
routines to obtain input. For soft analog records it can be a constant, a
database link, or a channel access link.
The B<DTYP> field specifies the name of the device support module that will
input values. Each record type has its own set of device support routines. If
a record type does not have any associated device support, DTYP is
meaningless.
The B<RVAL> field contains - whenever possible - the raw data value exactly as
it is obtained from the hardware or from the associated device driver and
before it undergoes any conversions. The Soft Channel device support module
reads values directly into VAL, bypassing this field.
The B<VAL> field contains the record's final value, after any needed
conversions have been performed.
=head3 Device Input
A device input routine normally returns one of the following values to its
associated record support routine:
=over
=item *
0: Success and convert. The input value is in RVAL. The record support module
will compute VAL from RVAL.
=item *
2: Success, but don't convert. The device support module can specify this
value if it does not want any conversions. It might do this for two reasons:
=over
=item *
A hardware error is detected (in this case, it should also raise an alarm
condition).
=item *
The device support routine reads values directly into the VAL field and then
sets UDF to FALSE. For some record types the device support routine may have to
do other record-specific processing as well such as applying a smoothing filter
to the engineering units value.
=back
=back
=head3 Device Support for Soft Records
In most cases, two soft output device support modules are provided: Soft Channel
and Raw Soft Channel. Both allow INP to be a constant, a database link, or a
channel access link. The Soft Channel device support module reads input directly
into the VAL field and specifies that no value conversion should be performed.
This allows the record to store values in the data type of its VAL field. Note
that for Soft Channel input, the RVAL field is not used. The Raw Soft Channel
support module reads input into RVAL and indicates that any specified unit
conversions be performed.
The device support read routine normally calls C<dbGetLink()> which
fetches a value from the link.
If a value was returned by the link the UDF field is set to FALSE. The device
support read routine normally returns the status from C<dbGetLink()>.
=head3 Input Simulation Fields
The B<SIMM> field controls simulation mode. It has either the value YES or NO.
By setting this field to YES, the record can be switched into simulation mode
of operation. While in simulation mode, input will be obtained from SIOL
instead of INP.
Ths B<SIML> specifies the simulation mode location. This field can be a
constant, a database link, or a channel access link. If SIML is a database or
channel access link, then SIMM is read from SIML. If SIML is a constant link
then SIMM is initialized with the constant value but can be changed via
dbPuts.
Ths B<SVAL> field contains the simulation value. This is the record's input
value, in engineering units, when the record is switched into simulation mode,
i.e. when SIMM is set to YES.
The B<SIOL> field is a link that can be used to fetch the simulation value. The
link can be a constant, a database link, or a channel access link. If SIOL is a
database or channel access link, then SVAL is read from SIOL. If SIOL is a
constant link then SVAL is initialized with the constant value but can be
changed via dbPuts.
The B<SIMS> field specifies the simulation mode alarm severity. When this
field is set to a value other than NO_ALARM and the record is in simulation
mode, it will be put into alarm with this severity and a status of SIMM.
=head3 Simulation Mode for Input Records
An input record can be switched into simulation mode of operation by setting
the value of SIMM to YES or RAW. During simulation, the record will be put
into alarm with a severity of SIMS and a status of SIMM_ALARM. While in
simulation mode, input values will be read from SIOL instead of INP:
-- (SIMM = NO?) INP (if supported and directed by device support, -> RVAL -- convert -> VAL), (else -> VAL)
/
SIML -> SIMM
\
-- (SIMM = YES?) SIOL -> SVAL -> VAL
\
-- (SIMM = RAW?) SIOL -> SVAL -> RVAL -- convert -> VAL
A record can be switched into simulation mode of operation by setting the
value of SIMM to YES. During simulation, the record will be put into alarm
with a severity of SIMS and a status of SIMM_ALARM. While in simulation mode,
input values, in engineering units, will be obtained from SIOL instead of INP.
Also, while the record is in simulation mode, there will be no raw value
conversion and no calls to device support when the record is processed.
Normally input records contain a private readValue() routine which performs
the following steps:
=over
=item *
If PACT is TRUE, the device support read routine is called, status is set to
its return code, and readValue returns.
=item *
Call C<dbGetLink()> to get a new value for SIMM from SIML.
=item *
Check value of SIMM.
=item *
If SIMM is NO, then call the device support read routine, set status to its
return code, and return.
=item *
If SIMM is YES, then call C<dbGetLink()> to read the input value from SIOL
into SVAL. If success, then set VAL to SVAL and UDF to FALSE and set status to
2 (don't convert) if input record supports conversion. If SIMS is greater than
zero, set alarm status to SIMM and severity to SIMS. Set status to the return
code from recGblGetLinkValue and return.
=item *
If SIMM is RAW, then call C<dbGetLink()> to read the input value from SIOL
into SVAL. If success, then set RVAL to SVAL and UDF to FALSE and set status
to 0 (convert) if input record supports conversion. If SIMS is greater than
zero, set alarm status to SIMM and severity to SIMS. Set status to the return
code from recGblGetLinkValue and return.
=item *
If SIMM is not YES, NO or RAW, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back

View File

@@ -0,0 +1,211 @@
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Output Record Types
This section describes fields that are found in many output record types.
These fields usually have the same meaning whenever they are used.
See also L<Fields Common to All Record Types|dbCommonRecord> and L<Fields Common to
Input Records|dbCommonInput>.
=head3 Output and Value Fields
The B<OUT> field specifies an output link. It is used by the device support
routines to decide where to send output. For soft records, it can be a
constant, a database link, or a channel access link. If the link is a
constant, the result is no output.
The B<DTYP> field specifies the name of the device support module that will
input values. Each record type has its own set of device support routines. If
a record type does not have any associated device support, DTYP is
meaningless.
The B<VAL> field contains the desired value before any conversions to raw
output have been performed.
The B<OVAL> field is used to decide when to invoke monitors. Archive and value
change monitors are invoked if OVAL is not equal to VAL. If a record type
needs to make adjustments, OVAL is used to enforce the maximum rate of change
limit before converting the desired value to a raw value.
The B<RVAL> field contains - whenever possible - the actual value sent to the
hardware itself or to the associated device driver.
The B<RBV> field contains - whenever possible - the actual read back value
obtained from the hardware itself or from the associated device driver.
=head3 Device Support for Soft Records
Normally two soft output device support modules are provided, Soft Channel and
and Raw Soft Channel. Both write a value through the output link OUT.
The Soft Channel module writes output from the value associated with OVAL or
VAL (if OVAL does not exist). The Raw Soft Channel support module writes the
value associated with the RVAL field after conversion has been performed.
The device support write routine normally calls C<dbPutLink()> which writes a
value through the OUT link, and returns the status from that call.
=head3 Input and Mode Select Fields
The B<DOL> field is a link from which the desired output value can be fetched.
DOL can be a constant, a database link, or a channel access link. If DOL is a
database or channel access link and OMSL is closed_loop, then VAL is obtained
from DOL.
The B<OMSL> field selects the output mode. This field has either the value
C<supervisory> or C<closed_loop>. DOL is used to fetch VAL only if OMSL has the
value C<closed_loop>. By setting this field a record can be switched between
supervisory and closed loop mode of operation. While in closed loop mode, the
VAL field cannot be set via dbPuts.
=head3 Output Mode Selection
The fields DOL and OMSL are used to allow the output record to be part of a
closed loop control algorithm. OMSL is meaningful only if DOL refers to a
database or channel access link. It can have the values C<supervisory> or
C<closed_loop>. If the mode is C<supervisory>, then nothing is done to VAL. If
the mode is C<closed_loop> and the record type does not contain an OIF field,
then each time the record is processed, VAL is set equal to the value obtained
from the location referenced by DOL. If the mode is C<closed_loop> in record
types with an OIF field and OIF is Full, VAL is set equal to the value obtained
from the location referenced by DOL; if OIF is Incremental VAL is incremented by
the value obtained from DOL.
=head3 Invalid Output Action Fields
The B<IVOA> field specifies the output action for the case that the record is
put into an INVALID alarm severity. IVOA can be one of the following actions:
=over
=item *
C<Continue normally>
=item *
C<Don't drive outputs>
=item *
C<Set output to IVOV>
=back
The B<IVOV> field contains the value for the IVOA action C<Set output to IVOV>
in engineering units. If a new severity has been set to INVALID and IVOA is
C<Set output to IVOV>, then VAL is set to IVOV and converted to RVAL before
device support is called.
=head3 Invalid Alarm Output Action
Whenever an output record is put into INVALID alarm severity, IVOA specifies
an action to take. The record support process routine for each output record
contains code which performs the following steps.
=over
=item *
If new severity is less than INVALID, then call C<writeValue()>:
=item *
Else do the following:
=over
=item *
If IVOA is C<Continue normally> then call C<writeValue()>.
=item *
If IVOA is C<Don't drive outputs> then do not write output.
=item *
If IVOA is C<Set output to IVOV> then set VAL to IVOV, call C<convert()> if
necessary, and then call C<writeValue()>.
=item *
If IVOA not one of the above, an error message is generated.
=back
=back
=head3 Simulation Fields
The B<SIMM> field controls simulation mode. It has either the value YES or NO.
By setting this field to YES, the record can be switched into simulation mode
of operation. While in simulation mode, output will be forwarded through SIOL
instead of OUT.
Ths B<SIML> specifies the simulation mode location. This field can be a
constant, a database link, or a channel access link. If SIML is a database or
channel access link, then SIMM is read from SIML. If SIML is a constant link
then SIMM is initialized with the constant value but can be changed via
dbPuts.
The B<SIOL> field is a link that the output value is written to when the record
is in simulation mode.
The B<SIMS> field specifies the simulation mode alarm severity. When this
field is set to a value other than NO_ALARM and the record is in simulation
mode, it will be put into alarm with this severity and a status of SIMM.
=head3 Simulation Mode
An output record can be switched into simulation mode of operation by setting
the value of SIMM to YES. During simulation, the record will be put into alarm
with a severity of SIMS and a status of SIMM_ALARM. While in simulation mode,
output values, in engineering units, will be written to SIOL instead of OUT.
However, the output values are never converted. Also, while the record is in
simulation mode, there will be no calls to device support during record
processing.
Normally output records contain a private C<writeValue()> routine which performs
the following steps:
=over
=item *
If PACT is TRUE, the device support write routine is called, status is set to
its return code, and readValue returns.
=item *
Call C<dbGetLink()> to get a new value for SIMM if SIML is a DB_LINK or a
CA_LINK.
=item *
Check value of SIMM.
=item *
If SIMM is NO, then call the device support write routine, set status to its
return code, and return.
=item *
If SIMM is YES, then call C<dbPutLink()> to write the output value from VAL or
OVAL to SIOL. Set alarm status to SIMM and severity to SIMS, if SIMS is
greater than zero. Set status to the return code from C<dbPutLink()> and
return.
=item *
If SIMM not one of the above, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back

View File

@@ -1,12 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7
# and higher are distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(dbCommon) {
include "dbCommon.dbd"
}

View File

@@ -0,0 +1,20 @@
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to All Record Types
This section contains a description of the fields that are common to all record
types. These fields are defined in dbCommon.dbd.
See also L<Fields Common to Input Record Types|dbCommonInput> and L<Fields
Common to Output Record Types|dbCommonOutput>.
=recordtype dbCommon
=cut
recordtype(dbCommon) {
include "dbCommon.dbd.pod"
}

View File

@@ -35,6 +35,7 @@
#include "epicsExport.h"
#include "link.h"
#include "special.h"
#include "iocInit.h"
@@ -215,6 +216,9 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
char *penv;
char **macPairs;
if(getIocState() != iocVoid)
return -2;
if(*ppdbbase == 0) *ppdbbase = dbAllocBase();
pdbbase = *ppdbbase;
if(path && strlen(path)>0) {

View File

@@ -25,3 +25,6 @@ variable(callbackParallelThreadsDefault,int)
# Real-time operation
variable(dbThreadRealtimeLock,int)
# show logClient network activity
variable(logClientDebug,int)

View File

@@ -70,9 +70,7 @@
#include "registryRecordType.h"
#include "rsrv.h"
static enum {
iocVirgin, iocBuilding, iocBuilt, iocRunning, iocPaused, iocStopped
} iocState = iocVirgin;
static enum iocStateEnum iocState = iocVoid;
static enum {
buildRSRV, buildIsolated
} iocBuildMode;
@@ -91,6 +89,11 @@ static void exitDatabase(void *dummy);
int dbThreadRealtimeLock = 1;
epicsExportAddress(int, dbThreadRealtimeLock);
enum iocStateEnum getIocState(void)
{
return iocState;
}
/*
* Initialize EPICS on the IOC.
*/
@@ -101,7 +104,7 @@ int iocInit(void)
static int iocBuild_1(void)
{
if (iocState != iocVirgin && iocState != iocStopped) {
if (iocState != iocVoid) {
errlogPrintf("iocBuild: IOC can only be initialized from uninitialized or stopped state\n");
return -1;
}
@@ -701,7 +704,7 @@ static void doFreeRecord(dbRecordType *pdbRecordType, dbCommon *precord,
int iocShutdown(void)
{
if (iocState == iocVirgin || iocState == iocStopped) return 0;
if (iocState == iocVoid) return 0;
iterateRecords(doCloseLinks, NULL);
if (iocBuildMode==buildIsolated) {
/* stop and "join" threads */
@@ -720,7 +723,7 @@ int iocShutdown(void)
dbProcessNotifyExit();
iocshFree();
}
iocState = iocStopped;
iocState = iocVoid;
iocBuildMode = buildRSRV;
return 0;
}

View File

@@ -13,10 +13,15 @@
#include "shareLib.h"
enum iocStateEnum {
iocVoid, iocBuilding, iocBuilt, iocRunning, iocPaused
};
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc enum iocStateEnum getIocState(void);
epicsShareFunc int iocInit(void);
epicsShareFunc int iocBuild(void);
epicsShareFunc int iocBuildIsolated(void);

View File

@@ -66,17 +66,6 @@ static void req_server (void *pParm)
IOC_sock = conf->tcp;
/* listen and accept new connections */
if ( listen ( IOC_sock, 20 ) < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: Listen error: %s\n",
sockErrBuf );
epicsSocketDestroy (IOC_sock);
epicsThreadSuspendSelf ();
}
epicsEventSignal(castcp_startStopEvent);
while (TRUE) {
@@ -194,7 +183,7 @@ SOCKET* rsrv_grab_tcp(unsigned short *port)
epicsSocketEnableAddressReuseDuringTimeWaitState ( tcpsock );
if(bind(tcpsock, &scratch.sa, sizeof(scratch))==0) {
if(bind(tcpsock, &scratch.sa, sizeof(scratch))==0 && listen(tcpsock, 20)==0) {
if(scratch.ia.sin_port==0) {
/* use first socket to pick a random port */
osiSocklen_t alen = sizeof(ifaceAddr);

View File

@@ -25,6 +25,7 @@
#include "postfix.h"
#include "postfixPvt.h"
static double calcRandom(void);
static int cond_search(const char **ppinst, int match);
@@ -48,7 +49,6 @@ epicsShareFunc long
double *ptop; /* stack pointer */
double top; /* value from top of stack */
epicsInt32 itop; /* integer from top of stack */
epicsUInt32 utop; /* unsigned integer from top of stack */
int op;
int nargs;
@@ -287,45 +287,60 @@ epicsShareFunc long
*ptop = ! *ptop;
break;
/* For bitwise operations on values with bit 31 set, double values
* must first be cast to unsigned to correctly set that bit; the
* double value must be negative in that case. The result must be
* cast to a signed integer before converting to the double result.
/* Be VERY careful converting double to int in case bit 31 is set!
* Out-of-range errors give very different results on different sytems.
* Convert negative doubles to signed and positive doubles to unsigned
* first to avoid overflows if bit 32 is set.
* The result is always signed, values with bit 31 set are negative
* to avoid problems when writing the value to signed integer fields
* like longout.VAL or ao.RVAL. However unsigned fields may give
* problems on some architectures. (Fewer than giving problems with
* signed integer. Maybe the conversion functions should handle
* overflows better.)
*/
#define d2i(x) ((x)<0?(epicsInt32)(x):(epicsInt32)(epicsUInt32)(x))
#define d2ui(x) ((x)<0?(epicsUInt32)(epicsInt32)(x):(epicsUInt32)(x))
case BIT_OR:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop | utop);
top = *ptop--;
*ptop = (double)(d2i(*ptop) | d2i(top));
break;
case BIT_AND:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop & utop);
top = *ptop--;
*ptop = (double)(d2i(*ptop) & d2i(top));
break;
case BIT_EXCL_OR:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop);
top = *ptop--;
*ptop = (double)(d2i(*ptop) ^ d2i(top));
break;
case BIT_NOT:
utop = *ptop;
*ptop = (epicsInt32) ~utop;
*ptop = (double)~d2i(*ptop);
break;
/* The shift operators use signed integers, so a right-shift will
* extend the sign bit into the left-hand end of the value. The
* double-casting through unsigned here is important, see above.
/* In C the shift operators decide on an arithmetic or logical shift
* based on whether the integer is signed or unsigned.
* With signed integers, a right-shift is arithmetic and will
* extend the sign bit into the left-hand end of the value. When used
* with unsigned values a logical shift is performed. The
* double-casting through signed/unsigned here is important, see above.
*/
case RIGHT_SHIFT:
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31);
case RIGHT_SHIFT_ARITH:
top = *ptop--;
*ptop = (double)(d2i(*ptop) >> (d2i(top) & 31));
break;
case LEFT_SHIFT:
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31);
case LEFT_SHIFT_ARITH:
top = *ptop--;
*ptop = (double)(d2i(*ptop) << (d2i(top) & 31));
break;
case RIGHT_SHIFT_LOGIC:
top = *ptop--;
*ptop = (double)(d2ui(*ptop) >> (d2ui(top) & 31u));
break;
case NOT_EQ:
@@ -382,11 +397,11 @@ epicsShareFunc long
*presult = *ptop;
return 0;
}
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
# pragma optimize("", on)
#endif
epicsShareFunc long
calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores)
{

View File

@@ -148,13 +148,14 @@ static const ELEMENT operators[] = {
{":=", 0, 0, -1, STORE_OPERATOR, STORE_A},
{";", 0, 0, 0, EXPR_TERMINATOR,NOT_GENERATED},
{"<", 3, 3, -1, BINARY_OPERATOR,LESS_THAN},
{"<<", 2, 2, -1, BINARY_OPERATOR,LEFT_SHIFT},
{"<<", 2, 2, -1, BINARY_OPERATOR,LEFT_SHIFT_ARITH},
{"<=", 3, 3, -1, BINARY_OPERATOR,LESS_OR_EQ},
{"=", 3, 3, -1, BINARY_OPERATOR,EQUAL},
{"==", 3, 3, -1, BINARY_OPERATOR,EQUAL},
{">", 3, 3, -1, BINARY_OPERATOR,GR_THAN},
{">=", 3, 3, -1, BINARY_OPERATOR,GR_OR_EQ},
{">>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT},
{">>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT_ARITH},
{">>>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT_LOGIC},
{"?", 0, 0, -1, CONDITIONAL, COND_IF},
{"AND", 2, 2, -1, BINARY_OPERATOR,BIT_AND},
{"OR", 1, 1, -1, BINARY_OPERATOR,BIT_OR},
@@ -579,8 +580,9 @@ epicsShareFunc void
"BIT_AND",
"BIT_EXCL_OR",
"BIT_NOT",
"RIGHT_SHIFT",
"LEFT_SHIFT",
"RIGHT_SHIFT_ARITH",
"LEFT_SHIFT_ARITH",
"RIGHT_SHIFT_LOGIC",
/* Relationals */
"NOT_EQ",
"LESS_THAN",

View File

@@ -84,8 +84,9 @@ typedef enum {
BIT_AND,
BIT_EXCL_OR,
BIT_NOT,
RIGHT_SHIFT,
LEFT_SHIFT,
RIGHT_SHIFT_ARITH,
LEFT_SHIFT_ARITH,
RIGHT_SHIFT_LOGIC,
/* Relationals */
NOT_EQ,
LESS_THAN,

View File

@@ -9,6 +9,5 @@
SRC_DIRS += $(LIBCOM)/cppStd
INC += epicsAlgorithm.h
INC += epicsExcept.h
INC += epicsMemory.h

View File

@@ -1,71 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
// Author: Andrew Johnson & Jeff Hill
// Date: December 2000
#ifndef __EPICS_EXCEPT_H__
#define __EPICS_EXCEPT_H__
#define epicsThrowHere(exc) \
throw locationException(exc, __FILE__, __LINE__)
class sourceLocation {
public: // Functions
sourceLocation(const char *fileName, int lineNumber);
// sourceLocation(const sourceLocation&); Copy constructable
// sourceLocation& operator=(const sourceLocation&); Assignable
const char *fileName() const;
int lineNumber() const;
private: // Hide compiler-generated member functions
sourceLocation(); // default constructor
private: // Data
const char *file;
int line;
};
template <class T>
class locationException : public T, public sourceLocation {
public:
locationException(const T& exc, const char *fileName, int lineNumber);
};
/* Example:
* if (status) epicsThrowHere(std::logic_error("operation failed!"));
* try { ... } catch(sourceLocation& where) { ... }
*/
// END OF DECLARATIONS
// INLINE FUNCTIONS
// sourceFileLocation
inline sourceLocation::sourceLocation (const char *fileName, int lineNumber) :
file(fileName), line(lineNumber) {}
inline const char* sourceLocation::fileName () const {
return this->file;
}
inline int sourceLocation::lineNumber () const {
return this->line;
}
// locationException<T>
template <class T>
inline locationException<T>::locationException
(const char *fileName, int lineNumber, const E& exc) :
T(exc), sourceLocation(fileName, lineNumber) {}
#endif // __EPICS_EXCEPT_H__

View File

@@ -18,8 +18,10 @@
#define epicsExportSharedSymbols
#include "envDefs.h"
#include "errlog.h"
#include "logClient.h"
#include "iocLog.h"
#include "epicsExit.h"
int iocLogDisable = 0;
@@ -74,6 +76,24 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void)
}
}
/*
* logClientSendMessage ()
*/
static void logClientSendMessage ( logClientId id, const char * message )
{
if ( !iocLogDisable ) {
logClientSend (id, message);
}
}
/*
* iocLogClientDestroy()
*/
static void iocLogClientDestroy (logClientId id)
{
errlogRemoveListeners (logClientSendMessage, id);
}
/*
* iocLogClientInit()
*/
@@ -89,6 +109,10 @@ static logClientId iocLogClientInit (void)
return NULL;
}
id = logClientCreate (addr, port);
if (id != NULL) {
errlogAddListener (logClientSendMessage, id);
epicsAtExit (iocLogClientDestroy, id);
}
return id;
}
@@ -135,3 +159,4 @@ logClientId epicsShareAPI logClientInit (void)
{
return iocLogClientInit ();
}

View File

@@ -21,11 +21,11 @@
#include <string.h>
#include <stdio.h>
#define EPICS_PRIVATE_API
#define epicsExportSharedSymbols
#include "dbDefs.h"
#include "epicsEvent.h"
#include "iocLog.h"
#include "errlog.h"
#include "epicsMutex.h"
#include "epicsThread.h"
#include "epicsTime.h"
@@ -33,9 +33,13 @@
#include "epicsAssert.h"
#include "epicsExit.h"
#include "epicsSignal.h"
#include "epicsExport.h"
#include "logClient.h"
int logClientDebug = 0;
epicsExportAddress (int, logClientDebug);
typedef struct {
char msgBuf[0x4000];
struct sockaddr_in addr;
@@ -44,8 +48,10 @@ typedef struct {
SOCKET sock;
epicsThreadId restartThreadId;
epicsEventId stateChangeNotify;
epicsEventId shutdownNotify;
unsigned connectCount;
unsigned nextMsgIndex;
unsigned backlog;
unsigned connected;
unsigned shutdown;
unsigned shutdownConfirm;
@@ -53,7 +59,6 @@ typedef struct {
} logClient;
static const double LOG_RESTART_DELAY = 5.0; /* sec */
static const double LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT = 5.0; /* sec */
static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */
/*
@@ -66,10 +71,10 @@ static char* logClientPrefix = NULL;
*/
static void logClientClose ( logClient *pClient )
{
# ifdef DEBUG
if (logClientDebug) {
fprintf (stderr, "log client: lingering for connection close...");
fflush (stderr);
# endif
}
/*
* mutex on
@@ -84,8 +89,6 @@ static void logClientClose ( logClient *pClient )
pClient->sock = INVALID_SOCKET;
}
pClient->nextMsgIndex = 0u;
memset ( pClient->msgBuf, '\0', sizeof ( pClient->msgBuf ) );
pClient->connected = 0u;
/*
@@ -93,9 +96,8 @@ static void logClientClose ( logClient *pClient )
*/
epicsMutexUnlock (pClient->mutex);
# ifdef DEBUG
if (logClientDebug)
fprintf (stderr, "done\n");
# endif
}
/*
@@ -113,6 +115,7 @@ static void logClientDestroy (logClientId id)
epicsMutexMustLock ( pClient->mutex );
pClient->shutdown = 1u;
epicsMutexUnlock ( pClient->mutex );
epicsEventSignal ( pClient->shutdownNotify );
/* unblock log client thread blocking in send() or connect() */
interruptInfo =
@@ -154,13 +157,11 @@ static void logClientDestroy (logClientId id)
return;
}
errlogRemoveListeners ( logClientSendMessage, (void *) pClient );
logClientClose ( pClient );
epicsMutexDestroy ( pClient->mutex );
epicsEventDestroy ( pClient->stateChangeNotify );
epicsEventDestroy ( pClient->shutdownNotify );
free ( pClient );
}
@@ -176,61 +177,26 @@ static void sendMessageChunk(logClient * pClient, const char * message) {
unsigned msgBufBytesLeft =
sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
if ( strSize > msgBufBytesLeft ) {
int status;
if ( ! pClient->connected ) {
break;
}
if ( msgBufBytesLeft > 0u ) {
memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
message, msgBufBytesLeft );
pClient->nextMsgIndex += msgBufBytesLeft;
strSize -= msgBufBytesLeft;
message += msgBufBytesLeft;
}
status = send ( pClient->sock, pClient->msgBuf,
pClient->nextMsgIndex, 0 );
if ( status > 0 ) {
unsigned nSent = (unsigned) status;
if ( nSent < pClient->nextMsgIndex ) {
unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;
memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
newNextMsgIndex );
pClient->nextMsgIndex = newNextMsgIndex;
}
else {
pClient->nextMsgIndex = 0u;
}
}
else {
if ( ! pClient->shutdown ) {
char sockErrBuf[64];
if ( status ) {
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
}
else {
strcpy ( sockErrBuf, "server initiated disconnect" );
}
fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
pClient->name, sockErrBuf );
}
logClientClose ( pClient );
break;
}
if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected)
{
/* buffer is full, thus flush it */
logClientFlush ( pClient );
msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
}
else {
memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
message, strSize );
pClient->nextMsgIndex += strSize;
if ( msgBufBytesLeft == 0u ) {
fprintf ( stderr, "log client: messages to \"%s\" are lost\n",
pClient->name );
break;
}
if ( msgBufBytesLeft > strSize) msgBufBytesLeft = strSize;
memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
message, msgBufBytesLeft );
pClient->nextMsgIndex += msgBufBytesLeft;
strSize -= msgBufBytesLeft;
message += msgBufBytesLeft;
}
}
/*
* logClientSend ()
*/
@@ -255,43 +221,54 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message )
void epicsShareAPI logClientFlush ( logClientId id )
{
unsigned nSent;
int status = 0;
logClient * pClient = ( logClient * ) id;
if ( ! pClient ) {
if ( ! pClient || ! pClient->connected ) {
return;
}
epicsMutexMustLock ( pClient->mutex );
while ( pClient->nextMsgIndex && pClient->connected ) {
int status = send ( pClient->sock, pClient->msgBuf,
pClient->nextMsgIndex, 0 );
if ( status > 0 ) {
unsigned nSent = (unsigned) status;
if ( nSent < pClient->nextMsgIndex ) {
unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;
memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
newNextMsgIndex );
pClient->nextMsgIndex = newNextMsgIndex;
}
else {
pClient->nextMsgIndex = 0u;
}
nSent = pClient->backlog;
while ( nSent < pClient->nextMsgIndex && pClient->connected ) {
status = send ( pClient->sock, pClient->msgBuf + nSent,
pClient->nextMsgIndex - nSent, 0 );
if ( status < 0 ) break;
nSent += status;
}
if ( pClient->backlog > 0 && status >= 0 )
{
/* On Linux send 0 bytes can detect EPIPE */
/* NOOP on Windows, fails on vxWorks */
errno = 0;
status = send ( pClient->sock, NULL, 0, 0 );
if (!(errno == ECONNRESET || errno == EPIPE)) status = 0;
}
if ( status < 0 ) {
if ( ! pClient->shutdown ) {
char sockErrBuf[128];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
pClient->name, sockErrBuf );
}
else {
if ( ! pClient->shutdown ) {
char sockErrBuf[64];
if ( status ) {
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
}
else {
strcpy ( sockErrBuf, "server initiated disconnect" );
}
fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
pClient->name, sockErrBuf );
}
logClientClose ( pClient );
break;
pClient->backlog = 0;
logClientClose ( pClient );
}
else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) {
int backlog = epicsSocketUnsentCount ( pClient->sock );
if (backlog >= 0) {
pClient->backlog = backlog;
nSent -= backlog;
}
pClient->nextMsgIndex -= nSent;
if ( nSent > 0 && pClient->nextMsgIndex > 0 ) {
memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
pClient->nextMsgIndex );
}
}
epicsMutexUnlock ( pClient->mutex );
@@ -302,10 +279,10 @@ void epicsShareAPI logClientFlush ( logClientId id )
*/
static void logClientMakeSock (logClient *pClient)
{
# ifdef DEBUG
if (logClientDebug) {
fprintf (stderr, "log client: creating socket...");
# endif
fflush (stderr);
}
epicsMutexMustLock (pClient->mutex);
@@ -314,7 +291,7 @@ static void logClientMakeSock (logClient *pClient)
*/
pClient->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, 0 );
if ( pClient->sock == INVALID_SOCKET ) {
char sockErrBuf[64];
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf ( stderr, "log client: no socket error %s\n",
@@ -323,10 +300,8 @@ static void logClientMakeSock (logClient *pClient)
epicsMutexUnlock (pClient->mutex);
# ifdef DEBUG
if (logClientDebug)
fprintf (stderr, "done\n");
# endif
}
/*
@@ -366,7 +341,7 @@ static void logClientConnect (logClient *pClient)
}
else {
if ( pClient->connFailStatus != errnoCpy && ! pClient->shutdown ) {
char sockErrBuf[64];
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr,
@@ -392,7 +367,7 @@ static void logClientConnect (logClient *pClient)
optval = TRUE;
status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval));
if (status<0) {
char sockErrBuf[64];
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf);
@@ -404,11 +379,11 @@ static void logClientConnect (logClient *pClient)
*/
status = shutdown (pClient->sock, SHUT_RD);
if (status < 0) {
char sockErrBuf[64];
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr, "%s:%d shutdown(%d,SHUT_RD) error was \"%s\"\n",
__FILE__, __LINE__, pClient->sock, sockErrBuf);
fprintf (stderr, "%s:%d shutdown(sock,SHUT_RD) error was \"%s\"\n",
__FILE__, __LINE__, sockErrBuf);
/* not fatal (although it shouldn't happen) */
}
@@ -425,7 +400,7 @@ static void logClientConnect (logClient *pClient)
lingerval.l_linger = 60*5;
status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER, (char *) &lingerval, sizeof(lingerval));
if (status<0) {
char sockErrBuf[64];
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr, "log client: unable to set linger options because \"%s\"\n", sockErrBuf);
@@ -457,14 +432,10 @@ static void logClientRestart ( logClientId id )
epicsMutexUnlock ( pClient->mutex );
if ( isConn ) {
logClientFlush ( pClient );
}
else {
logClientConnect ( pClient );
}
epicsThreadSleep ( LOG_RESTART_DELAY );
if ( ! isConn ) logClientConnect ( pClient );
logClientFlush ( pClient );
epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY);
epicsMutexMustLock ( pClient->mutex );
}
@@ -480,9 +451,7 @@ static void logClientRestart ( logClientId id )
logClientId epicsShareAPI logClientCreate (
struct in_addr server_addr, unsigned short server_port)
{
epicsTimeStamp begin, current;
logClient *pClient;
double diff;
pClient = calloc (1, sizeof (*pClient));
if (pClient==NULL) {
@@ -507,14 +476,22 @@ logClientId epicsShareAPI logClientCreate (
pClient->shutdownConfirm = 0;
epicsAtExit (logClientDestroy, (void*) pClient);
pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty);
if ( ! pClient->stateChangeNotify ) {
epicsMutexDestroy ( pClient->mutex );
free ( pClient );
return NULL;
}
pClient->shutdownNotify = epicsEventCreate (epicsEventEmpty);
if ( ! pClient->shutdownNotify ) {
epicsMutexDestroy ( pClient->mutex );
epicsEventDestroy ( pClient->stateChangeNotify );
free ( pClient );
return NULL;
}
pClient->restartThreadId = epicsThreadCreate (
"logRestart", epicsThreadPriorityLow,
epicsThreadGetStackSize(epicsThreadStackSmall),
@@ -522,35 +499,12 @@ logClientId epicsShareAPI logClientCreate (
if ( pClient->restartThreadId == NULL ) {
epicsMutexDestroy ( pClient->mutex );
epicsEventDestroy ( pClient->stateChangeNotify );
epicsEventDestroy ( pClient->shutdownNotify );
free (pClient);
fprintf(stderr, "log client: unable to start log client connection watch dog thread\n");
return NULL;
}
/*
* attempt to synchronize with circuit connect
*/
epicsTimeGetCurrent ( & begin );
epicsMutexMustLock ( pClient->mutex );
do {
epicsMutexUnlock ( pClient->mutex );
epicsEventWaitWithTimeout (
pClient->stateChangeNotify,
LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 );
epicsTimeGetCurrent ( & current );
diff = epicsTimeDiffInSeconds ( & current, & begin );
epicsMutexMustLock ( pClient->mutex );
}
while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
epicsMutexUnlock ( pClient->mutex );
if ( ! pClient->connected ) {
fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n",
pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
}
errlogAddListener ( logClientSendMessage, (void *) pClient );
return (void *) pClient;
}
@@ -568,24 +522,21 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level)
printf ("log client: disconnected from log server at \"%s\"\n", pClient->name);
}
if (level>1) {
printf ("log client: sock=%s, connect cycles = %u\n",
pClient->sock==INVALID_SOCKET?"INVALID":"OK",
pClient->connectCount);
}
if (logClientPrefix) {
printf ("log client: prefix is \"%s\"\n", logClientPrefix);
}
}
/*
* logClientSendMessage (); deprecated
*/
void logClientSendMessage ( logClientId id, const char * message )
{
if ( !iocLogDisable ) {
logClientSend (id, message);
if (level>0) {
printf ("log client: sock %s, connect cycles = %u\n",
pClient->sock==INVALID_SOCKET?"INVALID":"OK",
pClient->connectCount);
}
if (level>1) {
printf ("log client: %u bytes in buffer\n", pClient->nextMsgIndex);
if (pClient->nextMsgIndex)
printf("-------------------------\n"
"%.*s-------------------------\n",
(int)(pClient->nextMsgIndex), pClient->msgBuf);
}
}

View File

@@ -38,7 +38,6 @@ epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix);
/* deprecated interface; retained for backward compatibility */
/* note: implementations are in iocLog.c, not logClient.c */
epicsShareFunc logClientId epicsShareAPI logClientInit (void);
epicsShareFunc void logClientSendMessage (logClientId id, const char *message);
#ifdef __cplusplus
}

View File

@@ -86,6 +86,7 @@ endif
Com_SRCS += osdSock.c
Com_SRCS += osdSockAddrReuse.cpp
Com_SRCS += osdSockUnsentCount.c
Com_SRCS += osiSock.c
Com_SRCS += systemCallIntMech.cpp
Com_SRCS += epicsSocketConvertErrnoToString.cpp

View File

@@ -350,5 +350,11 @@ extern "C" {
}
} // extern "C"
// Ensure the main thread gets a unique ID
epicsThreadId epicsThreadMainId = epicsThreadGetIdSelf();
static epicsThreadId initMainThread(void) {
epicsThreadId main = epicsThreadGetIdSelf();
epicsThreadSetOkToBlock(1);
return main;
}
// Ensure the main thread gets a unique ID and allows blocking I/O
epicsThreadId epicsThreadMainId = initMainThread();

View File

@@ -0,0 +1,19 @@
/*************************************************************************\
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define EPICS_PRIVATE_API
#include "osiSock.h"
/*
* epicsSocketUnsentCount ()
* See https://www.unix.com/man-page/osx/2/setsockopt
*/
int epicsSocketUnsentCount(SOCKET sock) {
int unsent;
socklen_t len = sizeof(unsent);
if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0)
return unsent;
return -1;
}

View File

@@ -0,0 +1,19 @@
/*************************************************************************\
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <linux/sockios.h>
#define EPICS_PRIVATE_API
#include "osiSock.h"
/*
* epicsSocketUnsentCount ()
* See https://linux.die.net/man/7/tcp
*/
int epicsSocketUnsentCount(SOCKET sock) {
int unsent;
if (ioctl(sock, SIOCOUTQ, &unsent) == 0)
return unsent;
return -1;
}

View File

@@ -25,6 +25,7 @@
#include <assert.h>
#include <syslog.h>
#include <limits.h>
#include <pthread.h>
#include <rtems.h>
#include <rtems/error.h>
@@ -615,6 +616,23 @@ showInternalTaskInfo (rtems_id tid)
}
thread = *the_thread;
_Thread_Enable_dispatch();
/* This looks a bit weird, but it has to support RTEMS versions both before
* and after 4.10.2 when threads changed how their priorities are stored.
*/
int policy;
struct sched_param sp;
rtems_task_priority real_priority, current_priority;
rtems_status_code sc = pthread_getschedparam(tid, &policy, &sp);
if (sc == RTEMS_SUCCESSFUL) {
real_priority = sp.sched_priority;
sc = rtems_task_set_priority(tid, RTEMS_CURRENT_PRIORITY, &current_priority);
}
if (sc != RTEMS_SUCCESSFUL) {
fprintf(epicsGetStdout(),"%-30s", " *** RTEMS task gone! ***");
return;
}
/*
* Show both real and current priorities if they differ.
* Note that the epicsThreadGetOsiPriorityValue routine is not used here.
@@ -622,17 +640,17 @@ showInternalTaskInfo (rtems_id tid)
* that priority should be displayed, not the value truncated to
* the EPICS range.
*/
epicsPri = 199-thread.real_priority;
epicsPri = 199-real_priority;
if (epicsPri < 0)
fprintf(epicsGetStdout()," <0");
else if (epicsPri > 99)
fprintf(epicsGetStdout()," >99");
else
fprintf(epicsGetStdout()," %4d", epicsPri);
if (thread.current_priority == thread.real_priority)
fprintf(epicsGetStdout(),"%4d ", (int)thread.current_priority);
if (current_priority == real_priority)
fprintf(epicsGetStdout(),"%4d ", (int)current_priority);
else
fprintf(epicsGetStdout(),"%4d/%-3d", (int)thread.real_priority, (int)thread.current_priority);
fprintf(epicsGetStdout(),"%4d/%-3d", (int)real_priority, (int)current_priority);
showBitmap (bitbuf, thread.current_state, taskState);
fprintf(epicsGetStdout(),"%8.8s", bitbuf);
if (thread.current_state & (STATES_WAITING_FOR_SEMAPHORE |

View File

@@ -0,0 +1,26 @@
/*************************************************************************\
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define epicsExportSharedSymbols
#define EPICS_PRIVATE_API
#include "osiSock.h"
#include <mstcpip.h>
/*
* epicsSocketUnsentCount ()
* See https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0
*/
int epicsSocketUnsentCount(SOCKET sock) {
#ifdef SIO_TCP_INFO
/* Windows 10 Version 1703 / Server 2016 */
DWORD infoVersion = 0, bytesReturned;
TCP_INFO_v0 tcpInfo;
int status;
if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion),
&tcpInfo, sizeof(tcpInfo), &bytesReturned, NULL, NULL)) == 0)
return tcpInfo.BytesInFlight;
#endif
return -1;
}

View File

@@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author W. Eric Norum
@@ -50,7 +50,7 @@ struct epicsMessageQueueOSD {
ELLLIST receiveQueue;
ELLLIST eventFreeList;
int numberOfSendersWaiting;
epicsMutexId mutex;
unsigned long capacity;
unsigned long maxMessageSize;
@@ -106,7 +106,7 @@ epicsShareFunc epicsMessageQueueId epicsShareAPI epicsMessageQueueCreate(
}
static void
freeEventNode(struct eventNode *enode)
destroyEventNode(struct eventNode *enode)
{
epicsEventDestroy(enode->event);
free(enode);
@@ -119,7 +119,7 @@ epicsMessageQueueDestroy(epicsMessageQueueId pmsg)
while ((evp = reinterpret_cast < struct eventNode * >
( ellGet(&pmsg->eventFreeList) ) ) != NULL) {
freeEventNode(evp);
destroyEventNode(evp);
}
epicsMutexDestroy(pmsg->mutex);
free(pmsg->buf);
@@ -145,6 +145,16 @@ getEventNode(epicsMessageQueueId pmsg)
return evp;
}
static void
freeEventNode(epicsMessageQueueId pmsg, eventNode *evp, epicsEventStatus status)
{
if (status == epicsEventWaitTimeout) {
epicsEventSignal(evp->event);
epicsEventWait(evp->event);
}
ellAdd(&pmsg->eventFreeList, &evp->link);
}
static int
mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
double timeout)
@@ -163,7 +173,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
if ((pmsg->numberOfSendersWaiting > 0)
|| (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL))) {
/*
* Return if not allowed to wait
* Return if not allowed to wait. NB -1 means wait forever.
*/
if (timeout == 0) {
epicsMutexUnlock(pmsg->mutex);
@@ -171,7 +181,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
/*
* Wait
* Indicate that we're waiting
*/
struct threadNode threadNode;
threadNode.evp = getEventNode(pmsg);
@@ -186,22 +196,25 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
epicsMutexUnlock(pmsg->mutex);
epicsEventStatus status;
if (timeout > 0)
status = epicsEventWaitWithTimeout(threadNode.evp->event, timeout);
else
status = epicsEventWait(threadNode.evp->event);
/*
* Wait for receiver to wake us
*/
epicsEventStatus status = timeout < 0 ?
epicsEventWait(threadNode.evp->event) :
epicsEventWaitWithTimeout(threadNode.evp->event, timeout);
epicsMutexMustLock(pmsg->mutex);
if(!threadNode.eventSent)
if (!threadNode.eventSent) {
/* Receiver didn't take us off the sendQueue, do it ourselves */
ellDelete(&pmsg->sendQueue, &threadNode.link);
pmsg->numberOfSendersWaiting--;
pmsg->numberOfSendersWaiting--;
}
ellAdd(&pmsg->eventFreeList, &threadNode.evp->link);
freeEventNode(pmsg, threadNode.evp, status);
if ((pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) ||
status != epicsEventOK) {
if (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) {
/* State of the queue didn't change, exit */
epicsMutexUnlock(pmsg->mutex);
return -1;
}
@@ -294,6 +307,7 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
*/
if ((pthr = reinterpret_cast < struct threadNode * >
( ellGet(&pmsg->sendQueue) ) ) != NULL) {
pmsg->numberOfSendersWaiting--;
pthr->eventSent = true;
epicsEventSignal(pthr->evp->event);
}
@@ -302,7 +316,7 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
/*
* Return if not allowed to wait
* Return if not allowed to wait. NB -1 means wait forever.
*/
if (timeout == 0) {
epicsMutexUnlock(pmsg->mutex);
@@ -310,16 +324,7 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
/*
* Wake up the oldest task waiting to send
*/
if ((pthr = reinterpret_cast < struct threadNode * >
( ellGet(&pmsg->sendQueue) ) ) != NULL) {
pthr->eventSent = true;
epicsEventSignal(pthr->evp->event);
}
/*
* Wait for message to arrive
* Indicate that we're waiting
*/
struct threadNode threadNode;
threadNode.evp = getEventNode(pmsg);
@@ -333,24 +338,36 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
ellAdd(&pmsg->receiveQueue, &threadNode.link);
/*
* Wake up the oldest task waiting to send
*/
if ((pthr = reinterpret_cast < struct threadNode * >
( ellGet(&pmsg->sendQueue) ) ) != NULL) {
pmsg->numberOfSendersWaiting--;
pthr->eventSent = true;
epicsEventSignal(pthr->evp->event);
}
epicsMutexUnlock(pmsg->mutex);
epicsEventStatus status;
if (timeout > 0)
status = epicsEventWaitWithTimeout(threadNode.evp->event, timeout);
else
status = epicsEventWait(threadNode.evp->event);
/*
* Wait for a message to arrive
*/
epicsEventStatus status = timeout < 0 ?
epicsEventWait(threadNode.evp->event) :
epicsEventWaitWithTimeout(threadNode.evp->event, timeout);
epicsMutexMustLock(pmsg->mutex);
if (!threadNode.eventSent)
ellDelete(&pmsg->receiveQueue, &threadNode.link);
ellAdd(&pmsg->eventFreeList, &threadNode.evp->link);
freeEventNode(pmsg, threadNode.evp, status);
epicsMutexUnlock(pmsg->mutex);
if (threadNode.eventSent && (threadNode.size <= size) &&
status == epicsEventOK)
if (threadNode.eventSent && (threadNode.size <= size))
return threadNode.size;
return -1;
}
@@ -398,7 +415,8 @@ epicsMessageQueuePending(epicsMessageQueueId pmsg)
epicsShareFunc void epicsShareAPI
epicsMessageQueueShow(epicsMessageQueueId pmsg, int level)
{
printf("Message Queue Used:%d Slots:%lu", epicsMessageQueuePending(pmsg), pmsg->capacity);
printf("Message Queue Used:%d Slots:%lu",
epicsMessageQueuePending(pmsg), pmsg->capacity);
if (level >= 1)
printf(" Maximum size:%lu", pmsg->maxMessageSize);
printf("\n");

View File

@@ -0,0 +1,15 @@
/*************************************************************************\
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define EPICS_PRIVATE_API
#include "osiSock.h"
/*
* epicsSocketUnsentCount ()
*/
int epicsSocketUnsentCount(SOCKET sock) {
/* not implemented */
return -1;
}

View File

@@ -0,0 +1,19 @@
/*************************************************************************\
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define EPICS_PRIVATE_API
#include "osiSock.h"
/*
* epicsSocketUnsentCount ()
* See https://www.unix.com/man-page/osx/2/setsockopt
*/
int epicsSocketUnsentCount(SOCKET sock) {
int unsent;
socklen_t len = sizeof(unsent);
if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0)
return unsent;
return -1;
}

View File

@@ -48,8 +48,10 @@ void epicsAtomicLock ( EpicsAtomicLockKey * )
status = pthread_mutex_lock ( & mutex );
if ( status == 0 ) return;
assert ( status == EINTR );
static const useconds_t retryDelayUSec = 100000;
usleep ( retryDelayUSec );
struct timespec retryDelay = { 0, 100000000 };
struct timespec remainingDelay;
while (nanosleep(&retryDelay, &remainingDelay) == -1 && errno == EINTR)
retryDelay = remainingDelay;
countDown--;
assert ( countDown );
}

View File

@@ -14,6 +14,18 @@
#include <shareLib.h>
#ifdef __cplusplus
#if __cplusplus>=201103L
#include <cmath>
#if __GLIBCXX__>20160427
using std::isfinite;
using std::isinf;
using std::isnan;
using std::isnormal;
#endif
#endif /* c++11 */
extern "C" {
#endif

View File

@@ -41,7 +41,7 @@ static struct {
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
#ifdef CLOCK_REALTIME
#if defined(CLOCK_REALTIME) && !defined(_WIN32)
/* This code is not used on systems without Posix CLOCK_REALTIME,
* but the only way to detect that is from the OS headers, so the
* Makefile can't exclude compiling this file on those systems.
@@ -229,7 +229,11 @@ static int ClockTimeGetCurrent(epicsTimeStamp *pDest)
return 0;
}
#endif /* CLOCK_REALTIME */
/* Used in Report function below: */
#define UNINIT_ERROR "initialized"
#else
#define UNINIT_ERROR "available"
#endif /* CLOCK_REALTIME && !WIN32 */
/* Allow the following report routine to be compiled anyway
* to avoid getting a build warning from ranlib.
@@ -242,13 +246,7 @@ int ClockTime_Report(int level)
char timebuf[32];
if (onceId == EPICS_THREAD_ONCE_INIT) {
printf("OS Clock driver not %s.\n",
#ifdef CLOCK_REALTIME
"initialized"
#else
"available"
#endif /* CLOCK_REALTIME */
);
puts("OS Clock driver not " UNINIT_ERROR);
}
else if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) {
int synchronized, syncFromPriority;

View File

@@ -52,6 +52,14 @@ enum epicsSocketSystemCallInterruptMechanismQueryInfo {
epicsShareFunc enum epicsSocketSystemCallInterruptMechanismQueryInfo
epicsSocketSystemCallInterruptMechanismQuery ();
#ifdef EPICS_PRIVATE_API
/*
* Some systems (e.g Linux and Windows 10) allow to check the amount
* of unsent data in the output queue.
* Returns -1 if the information is not available.
*/
epicsShareFunc int epicsSocketUnsentCount(SOCKET sock);
#endif
/*
* convert socket address to ASCII in this order

View File

@@ -107,6 +107,11 @@ epicsThreadTest_SRCS += epicsThreadTest.cpp
testHarness_SRCS += epicsThreadTest.cpp
TESTS += epicsThreadTest
TESTPROD_HOST += epicsThreadClassTest
epicsThreadClassTest_SRCS += epicsThreadClassTest.cpp
testHarness_SRCS += epicsThreadClassTest.cpp
TESTS += epicsThreadClassTest
TESTPROD_HOST += epicsThreadOnceTest
epicsThreadOnceTest_SRCS += epicsThreadOnceTest.c
testHarness_SRCS += epicsThreadOnceTest.c

View File

@@ -104,7 +104,7 @@ void testUInt32Calc(const char *expr, epicsUInt32 expected) {
testDiag("calcPerform: error evaluating '%s'", expr);
}
uresult = (epicsUInt32) result;
uresult = (result < 0.0 ? (epicsUInt32)(epicsInt32)result : (epicsUInt32)result);
pass = (uresult == expected);
if (!testOk(pass, "%s", expr)) {
testDiag("Expected result is 0x%x (%u), actually got 0x%x (%u)",
@@ -297,7 +297,7 @@ MAIN(epicsCalcTest)
const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0,
g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0;
testPlan(613);
testPlan(630);
/* LITERAL_OPERAND elements */
testExpr(0);
@@ -612,14 +612,14 @@ MAIN(epicsCalcTest)
testExpr(0.0 + NaN);
testExpr(Inf + 0.0);
testExpr(Inf + Inf);
#if defined(_WIN64) && defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testCalc("Inf + -Inf", NaN);
#else
testExpr(Inf + -Inf);
#endif
testExpr(Inf + NaN);
testExpr(-Inf + 0.0);
#if defined(_WIN64) && defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testCalc("-Inf + Inf", NaN);
#else
testExpr(-Inf + Inf);
@@ -688,7 +688,7 @@ MAIN(epicsCalcTest)
testExpr(NaN < NaN);
testExpr(1 << 2);
testExpr(1 << 3 << 2)
testExpr(1 << 3 << 2);
testExpr(0 <= 1);
testExpr(0 <= 0);
@@ -776,7 +776,9 @@ MAIN(epicsCalcTest)
testExpr(NaN >= NaN);
testExpr(8 >> 1);
testCalc("8 >>> 1", 8u >> 1u);
testExpr(64 >> 2 >> 1);
testCalc("64 >>> 2 >>> 1", 64u >> 2u >> 1u);
testExpr(7 AND 4);
@@ -875,11 +877,14 @@ MAIN(epicsCalcTest)
testExpr(3 << 2 & 10); // 2 2
testCalc("18 & 6 << 2", (18 & 6) << 2); // 2 2
testExpr(36 >> 2 & 10); // 2 2
testCalc("36 >>> 2 & 10", 36u >> 2u & 10u); // 2 2
testCalc("18 & 20 >> 2", (18 & 20) >> 2); // 2 2
testCalc("18 & 20 >>> 2", (18u & 20u) >> 2u); // 2 2
testExpr(3 & 4 == 4); // 2 3
testExpr(3 AND 4 == 4); // 2 3
testCalc("1 << 2 != 4", 1 << (2 != 4)); // 2 3
testCalc("16 >> 2 != 4", 16 >> (2 != 4)); // 2 3
testCalc("16 >>> 2 != 4", 16u >> (2u != 4u)); // 2 3
testExpr(3 AND -2); // 2 8
testExpr(0 < 1 ? 2 : 3); // 3 0
testExpr(1 <= 0 ? 2 : 3); // 3 0
@@ -951,7 +956,11 @@ MAIN(epicsCalcTest)
testUInt32Calc("~0xaaaaaaaa", 0x55555555u);
testUInt32Calc("~~0xaaaaaaaa", 0xaaaaaaaau);
testUInt32Calc("0xaaaaaaaa >> 8", 0xffaaaaaau);
testUInt32Calc("0x55555555 >> 8", 0x00555555u);
testUInt32Calc("0xaaaaaaaa >>> 8", 0x00aaaaaau);
testUInt32Calc("0x55555555 >>> 8", 0x00555555u);
testUInt32Calc("0xaaaaaaaa << 8", 0xaaaaaa00u);
testUInt32Calc("0x55555555 << 8", 0x55555500u);
// using integer literals assigned to variables
testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a AND b", 0xaaaa0000u);
testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a OR b", 0xffffaaaau);
@@ -959,7 +968,11 @@ MAIN(epicsCalcTest)
testUInt32Calc("a:=0xaaaaaaaa; ~a", 0x55555555u);
testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau);
testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau);
testUInt32Calc("a:=0xaaaaaaaa; a >>> 8", 0x00aaaaaau);
testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u);
testUInt32Calc("a:=0x55555555; a >> 8", 0x00555555u);
testUInt32Calc("a:=0x55555555; a >>> 8", 0x00555555u);
testUInt32Calc("a:=0x55555555; a << 8", 0x55555500u);
// Test proper conversion of double values (+ 0.1 enforces double literal)
// when used as inputs to the bitwise operations.
@@ -979,9 +992,13 @@ MAIN(epicsCalcTest)
testUInt32Calc("~ -1431655766.1", 0x55555555u);
testUInt32Calc("~ 2863311530.1", 0x55555555u);
testUInt32Calc("-1431655766.1 >> 0", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 >>> 0", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >> 0", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >>> 0", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 >> 0.1", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 >>> 0.1", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >> 0.1", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >>> 0.1", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 << 0", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 << 0", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 << 0.1", 0xaaaaaaaau);
@@ -989,4 +1006,3 @@ MAIN(epicsCalcTest)
return testDone();
}

View File

@@ -32,23 +32,23 @@ MAIN(epicsMathTest)
testOk1(epicsINF > 0.0);
testOk1(epicsINF - epicsINF != 0.0);
#if defined(_WIN64) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64");
#if defined(_WIN32) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64 and win32-x86");
#endif
testOk1(epicsINF + -epicsINF != 0.0);
testOk1(-epicsINF + epicsINF != 0.0);
#if defined(_WIN64) && defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testTodoEnd();
#endif
testOk1(isnan(epicsINF - epicsINF));
#if defined(_WIN64) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64");
#if defined(_WIN32) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64 and win32-x86");
#endif
testOk1(isnan(epicsINF + -epicsINF));
testOk1(isnan(-epicsINF + epicsINF));
#if defined(_WIN64) && defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testTodoEnd();
#endif
@@ -62,12 +62,12 @@ MAIN(epicsMathTest)
testOk1(!(epicsNAN > epicsNAN));
testOk1(isnan(epicsNAN - epicsNAN));
#if defined(_WIN64) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64");
#if defined(_WIN32) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64 and win32-x86");
#endif
testOk1(isnan(epicsNAN + -epicsNAN));
testOk1(isnan(-epicsNAN + epicsNAN));
#if defined(_WIN64) && defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testTodoEnd();
#endif

View File

@@ -28,6 +28,10 @@ static volatile int recvExit = 0;
static epicsEventId finished;
static unsigned int mediumStack;
#define SLEEPY_TESTS 500
static int numSent, numReceived;
static epicsEventId complete;
/*
* In Numerical Recipes in C: The Art of Scientific Computing (William H.
* Press, Brian P. Flannery, Saul A. Teukolsky, William T. Vetterling; New
@@ -115,6 +119,106 @@ receiver(void *arg)
epicsEventSignal(finished);
}
extern "C" void
fastReceiver(void *arg)
{
epicsMessageQueue *q = (epicsMessageQueue *)arg;
char cbuf[80];
int len;
numReceived = 0;
while (!recvExit) {
len = q->receive(cbuf, sizeof cbuf, 0.010);
if (len > 0) {
numReceived++;
}
}
recvExit = 0;
epicsEventSignal(complete);
}
void sleepySender(double delay)
{
testDiag("sleepySender: sending every %.3f seconds", delay);
epicsMessageQueue q(4, 20);
epicsThreadCreate("Fast Receiver", epicsThreadPriorityMedium,
mediumStack, fastReceiver, &q);
numSent = 0;
for (int i = 0 ; i < SLEEPY_TESTS ; i++) {
if (q.send((void *)msg1, 4) == 0) {
numSent++;
}
epicsThreadSleep(delay);
}
epicsThreadSleep(1.0);
testOk(numSent == SLEEPY_TESTS, "Sent %d (should be %d)",
numSent, SLEEPY_TESTS);
testOk(numReceived == SLEEPY_TESTS, "Received %d (should be %d)",
numReceived, SLEEPY_TESTS);
recvExit = 1;
while (q.send((void *)msg1, 4) != 0)
epicsThreadSleep(0.01);
epicsEventMustWait(complete);
}
extern "C" void
fastSender(void *arg)
{
epicsMessageQueue *q = (epicsMessageQueue *)arg;
numSent = 0;
// Send first withough timeout
q->send((void *)msg1, 4);
numSent++;
// The rest have a timeout
while (!sendExit) {
if (q->send((void *)msg1, 4, 0.010) == 0) {
numSent++;
}
}
sendExit = 0;
epicsEventSignal(complete);
}
void sleepyReceiver(double delay)
{
testDiag("sleepyReceiver: acquiring every %.3f seconds", delay);
epicsMessageQueue q(4, 20);
// Fill the queue
for (int i = q.pending(); i < 4 ;i++) {
q.send((void *)msg1, 4);
}
epicsThreadCreate("Fast Sender", epicsThreadPriorityMedium,
mediumStack, fastSender, &q);
epicsThreadSleep(0.5);
char cbuf[80];
int len;
numReceived = 0;
for (int i = 0 ; i < SLEEPY_TESTS ; i++) {
len = q.receive(cbuf, sizeof cbuf);
if (len > 0) {
numReceived++;
}
epicsThreadSleep(delay);
}
testOk(numSent == SLEEPY_TESTS, "Sent %d (should be %d)",
numSent, SLEEPY_TESTS);
testOk(numReceived == SLEEPY_TESTS, "Received %d (should be %d)",
numReceived, SLEEPY_TESTS);
sendExit = 1;
while (q.receive(cbuf, sizeof cbuf) <= 0)
epicsThreadSleep(0.01);
epicsEventMustWait(complete);
}
extern "C" void
sender(void *arg)
{
@@ -251,6 +355,18 @@ extern "C" void messageQueueTest(void *parm)
testOk(q1->send((void *)msg1, 10) == 0, "Send with no receiver");
epicsThreadSleep(2.0);
testDiag("6 Single receiver single sender 'Sleepy timeout' tests,");
testDiag(" these should take about %.2f seconds each:",
SLEEPY_TESTS * 0.010);
complete = epicsEventMustCreate(epicsEventEmpty);
sleepySender(0.009);
sleepySender(0.010);
sleepySender(0.011);
sleepyReceiver(0.009);
sleepyReceiver(0.010);
sleepyReceiver(0.011);
testDiag("Single receiver, single sender tests:");
epicsThreadSetPriority(myThreadId, epicsThreadPriorityHigh);
epicsThreadCreate("Receiver one", epicsThreadPriorityMedium,
@@ -285,7 +401,7 @@ extern "C" void messageQueueTest(void *parm)
* Single receiver, multiple sender tests
*/
testDiag("Single receiver, multiple sender tests:");
testDiag("This test lasts 60 seconds...");
testDiag("This test lasts 30 seconds...");
testOk(!!epicsThreadCreate("Sender 1", epicsThreadPriorityLow,
mediumStack, sender, q1),
"Created Sender 1");
@@ -299,9 +415,9 @@ extern "C" void messageQueueTest(void *parm)
mediumStack, sender, q1),
"Created Sender 4");
for (i = 0; i < 10; i++) {
testDiag("... %2d", 10 - i);
epicsThreadSleep(6.0);
for (i = 0; i < 6; i++) {
testDiag("... %2d", 6 - i);
epicsThreadSleep(5.0);
}
sendExit = 1;
@@ -312,7 +428,7 @@ extern "C" void messageQueueTest(void *parm)
MAIN(epicsMessageQueueTest)
{
testPlan(62);
testPlan(74);
finished = epicsEventMustCreate(epicsEventEmpty);
mediumStack = epicsThreadGetStackSize(epicsThreadStackMedium);

View File

@@ -75,8 +75,11 @@ MAIN(epicsSockResolveTest)
testSkip(2, " aToIPAddr() failed");
}
else {
testOk(addr.sin_addr.s_addr == htonl(okdata[i].IP), " IP correct");
testOk(addr.sin_port == htons(okdata[i].port), " Port correct");
testOk(addr.sin_addr.s_addr == htonl(okdata[i].IP),
" IP correct 0x%08x == 0x%08x", (unsigned)ntohl(addr.sin_addr.s_addr),
(unsigned)okdata[i].IP);
testOk(addr.sin_port == htons(okdata[i].port), " Port correct %u == %u",
ntohs(addr.sin_port), okdata[i].port);
}
}

View File

@@ -1,11 +1,11 @@
/*
/*
* Copyright: Stanford University / SLAC National Laboratory.
*
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
*
* Author: Till Straumann <strauman@slac.stanford.edu>, 2014
*/
*/
/*
* Check stack trace functionality
@@ -135,14 +135,14 @@ findNumOcc(const char *buf)
}
/* We should find an address close to epicsStackTraceRecurseGbl twice */
for (i=0; i<n_ptrs-1; i++) {
/* I got a (unjustified) index-out-of-bound warning
/* I got a (unjustified) index-out-of-bound warning
* when setting j=i+1 here. Thus the weird j!= i check...
*/
j = i;
while ( j < n_ptrs ) {
if ( j != i && ptrs[j] == ptrs[i] ) {
if ( (char*)ptrs[i] >= (char*)epicsStackTraceRecurseGbl && (char*)ptrs[i] < (char*)epicsStackTraceRecurseGbl + WINDOW_SZ ) {
rval ++;
rval ++;
if ( test_debug )
testDiag("found address %p again\n", ptrs[i]);
}
@@ -167,7 +167,7 @@ MAIN(epicsStackTraceTest)
testPlan(5);
features = epicsStackTraceGetFeatures();
features = epicsStackTraceGetFeatures();
all_features = EPICS_STACKTRACE_LCL_SYMBOLS
| EPICS_STACKTRACE_GBL_SYMBOLS
@@ -217,7 +217,13 @@ MAIN(epicsStackTraceTest)
}
if ( (features & EPICS_STACKTRACE_ADDRESSES) ) {
#ifdef _MINGW
testTodoBegin("MinGW, might fail");
#endif
testOk( numFound > 0, "dumping addresses" );
#ifdef _MINGW
testTodoEnd();
#endif
} else {
testSkip(1 , "no support for dumping addresses on this platform");
}

View File

@@ -0,0 +1,210 @@
/*************************************************************************\
* Copyright (c) 2020 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* epicsThreadClassTest.cpp */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "dbDefs.h"
#include "epicsAssert.h"
#include "epicsThread.h"
#include "epicsUnitTest.h"
#include "testMain.h"
/* Key to the char's that define the test case actions:
*
* Upper case letters are for parent thread actions
* B - Parent calls thread->start() and waits for child to start
* D - Parent deletes thread. This waits for child to return if it hasn't yet
* E - Parent calls thread->exitWait(), this may wait for child to return
* S - Parent sleeps for SLEEP_TIME seconds
* T - Parent sends sync trigger to child (w)
* W - Parent waits for sync trigger from child (t)
* X - Parent calls thread->exitWait(0)
*
* Lower case letters are for child thread actions
* d - Child deletes thread
* e - Child calls thread->exitWait()
* r - Child returns
* s - Child sleeps for SLEEP_TIME seconds
* t - Child sends sync trigger to parent (W)
* w - Child waits for sync trigger from child (T)
*
* Note that it is possible to write test cases that can hang,
* segfault, or that trigger errors from thread APIs.
*/
// The test cases
const char * const cases[] = {
// These cases don't start the thread:
"D", // Parent deletes thread
"ED", // Parent does exitWait(), deletes thread
// In these cases the parent deletes the thread
"BrSD", // Child returns; parent deletes thread
"BsDr", // Parent deletes thread; child returns
"BrSED", // Child returns; parent does exitWait(), deletes thread
"BsErD", // Parent does exitWait(); child returns; parent deletes thread
"BsXDr", // Parent does exitWait(0); parent deletes thread; child returns
"BwXTDsr", // Parent does exitWait(0); parent deletes thread; child returns
// These are currently broken
// "BetWSrD", // Child does exitWait(); sync; child returns; parent deletes thread
// "BetWsDr", // Child does exitWait(); sync; parent deletes thread; child returns
// In these cases the child deletes the thread
"BdrS", // Child deletes thread, returns
"BedrS", // Child does exitWait(), deletes thread, returns
"BwXTSdr", // Parent does exitWait(0); sync; child deletes thread, returns
NULL // Terminator
};
// How long to sleep for while the other thread works
#define SLEEP_TIME 1.0
class threadCase: public epicsThreadRunable {
public:
threadCase(const char * const tcase);
virtual ~threadCase();
virtual void run();
epicsThread *pthread;
epicsEvent startEvt;
epicsEvent childEvt;
epicsEvent parentEvt;
private:
const char * const name;
};
threadCase::threadCase(const char * const tcase) :
pthread(new epicsThread(*this, tcase,
epicsThreadGetStackSize(epicsThreadStackSmall))),
name(tcase)
{
testDiag("Constructing test case '%s'", name);
}
threadCase::~threadCase()
{
testDiag("Destroying test case '%s'", name);
}
void threadCase::run()
{
testDiag("Child running for '%s'", name);
startEvt.signal();
for (const char * pdo = name;
const char tdo = *pdo;
pdo++)
{
switch (tdo)
{
case 'd':
testDiag("'%c': Child deleting epicsThread", tdo);
delete pthread;
pthread = NULL;
break;
case 'e':
testDiag("'%c': Child calling exitWait()", tdo);
assert(pthread);
pthread->exitWait();
break;
case 's':
testDiag("'%c': Child sleeping", tdo);
epicsThreadSleep(SLEEP_TIME);
break;
case 't':
testDiag("'%c': Child sending trigger", tdo);
parentEvt.signal();
break;
case 'w':
testDiag("'%c': Child awaiting trigger", tdo);
childEvt.wait();
break;
case 'r':
testDiag("'%c': Child returning", tdo);
return;
}
}
testFail("Test case '%s' is missing 'r'", name);
}
MAIN(epicsThreadClassTest)
{
const int ntests = NELEMENTS(cases);
testPlan(ntests - 1); // The last element is the NULL terminator
for (const char * const * pcase = cases;
const char * const tcase = *pcase;
pcase++)
{
testDiag("======= Test case '%s' =======", tcase);
threadCase thrCase(tcase);
for (const char * pdo = tcase;
const char tdo = *pdo;
pdo++)
{
switch (tdo)
{
case 'B':
testDiag("'%c': Parent starting child", tdo);
assert(thrCase.pthread);
thrCase.pthread->start();
thrCase.startEvt.wait();
break;
case 'D':
testDiag("'%c': Parent deleting epicsThread", tdo);
assert(thrCase.pthread);
delete thrCase.pthread;
thrCase.pthread = NULL;
break;
case 'E':
testDiag("'%c': Parent calling exitWait()", tdo);
assert(thrCase.pthread);
thrCase.pthread->exitWait();
break;
case 'X':
testDiag("'%c': Parent calling exitWait(0)", tdo);
assert(thrCase.pthread);
thrCase.pthread->exitWait(0);
break;
case 'S':
testDiag("'%c': Parent sleeping", tdo);
epicsThreadSleep(SLEEP_TIME);
break;
case 'T':
testDiag("'%c': Parent sending trigger", tdo);
thrCase.childEvt.signal();
break;
case 'W':
testDiag("'%c': Parent awaiting trigger", tdo);
thrCase.parentEvt.wait();
break;
}
}
testPass("Test case '%s' passed", tcase);
}
return testDone();
}

View File

@@ -108,14 +108,13 @@ inline double delayVerify::delay () const
double delayVerify::checkError () const
{
const double messageThresh = 2.0; // percent
const double messageThresh = 5.0; // percent
double actualDelay = this->expireStamp - this->beginStamp;
double measuredError = actualDelay - this->expectedDelay;
double percentError = 100.0 * fabs ( measuredError ) / this->expectedDelay;
if ( ! testOk1 ( percentError < messageThresh ) ) {
testDiag ( "delay = %f s, error = %f s (%.1f %%)",
this->expectedDelay, measuredError, percentError );
}
testOk ( percentError < messageThresh, "%f < %f, delay = %f s, error = %f s (%.1f %%)",
percentError, messageThresh,
this->expectedDelay, measuredError, percentError );
return measuredError;
}

View File

@@ -1,116 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
menu(aaiPOST) {
choice(aaiPOST_Always,"Always")
choice(aaiPOST_OnChange,"On Change")
}
recordtype(aai) {
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode Location")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Sim Input Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}

View File

@@ -0,0 +1,478 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Array Analog Input (aai)
The array analog input record type is used to read array data. The array data can
contain any of the supported data types. The record is in many ways similar to the
waveform record. It allows, however, the device support to allocate the array
storage.
=recordtype aai
=cut
include "menuFtype.dbd"
menu(aaiPOST) {
choice(aaiPOST_Always,"Always")
choice(aaiPOST_OnChange,"On Change")
}
recordtype(aai) {
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=head3 Scan Parameters
The array analog input record has the standard fields for specifying under what
circumstances the record will be processed. These fields are listed in L<Scan
Fields>. In addition, L<Scanning Specification> explains how these fields are
used. Note that I/O event scanning is only supported for those card types that
interrupt.
=head3 Read Parameters
These fields are configurable by the user to specify how and from where the record
reads its data. The INP field determines from where the array analog input gets
its input. It can be a hardware address, a channel access or database link, or a
constant. Only in records that use soft device support can the INP field be a
channel access link, a database link, or a constant. Otherwise, the INP field must
be a hardware address. See L<Address Specification> for information on the format
of hardware addresses and database links.
=head4 Fields related to waveform reading
The DTYP field must contain the name of the appropriate device support module.
The values retrieved from the input link are placed in an array referenced by
VAL. (If the INP link is a constant, elements can be placed in the array via
dbPuts.) NELM specifies the number of elements that the array will hold, while
FTVL specifies the data type of the elements.
=fields DTYP, INP, NELM, FTVL
=head4 Possible data types for FTVL
=menu menuFtype
=head3 Operator Display Parameters
These parameters are used to present meaningful data to the operator. They
display the value and other parameters of the waveform either textually or
graphically.
=head4 Fields related to I<Operator Display>
EGU is a string of up to 16 characters describing the units that the array data
measures. It is retrieved by the C<<< get_units() >>> record support routine.
The HOPR and LOPR fields set the upper and lower display limits for array
elements referenced by the VAL field. Both the C<<< get_graphic_double() >>> and
C<<< get_control_double() >>> record support routines retrieve these fields.
The PREC field determines the floating point precision with which to display the
array values. It is used whenever the C<<< get_precision() >>> record support
routine is called.
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields EGU, HOPR, LOPR, PREC, NAME, DESC
=head3 Alarm Parameters
The array analog input record has the alarm parameters common to all record types.
=head3 Monitor Parameters
These parameters are used to determine when to send monitors placed on the VAL
field. The APST and MPST fields are a menu with choices "Always" and "On
Change". The default is "Always", thus monitors will normally be sent every time
the record processes. Selecting "On Change" causes a 32-bit hash of the VAL
field buffer to be calculated and compared with the previous hash value every
time the record processes; the monitor will only be sent if the hash is
different, indicating that the buffer has changed. Note that there is a small
chance that two different value buffers might result in the same hash value, so
for critical systems "Always" may be a better choice, even though it re-sends
duplicate data.
=head4 Record fields related to I<Monitor Parameters>
=fields APST, MPST, HASH
=head4 Menu choices for C<APST> and C<MPST> fields
=menu aaiPOST
=head3 Run-time Parameters
These parameters are used by the run-time code for processing the array analog
input record. They are not configured using a configuration tool. Only the VAL
field is modifiable at run-time.
VAL references the array where the array analog input record stores its data. The
BPTR field holds the address of the array.
The NORD field holds a counter of the number of elements that have been read
into the array.
=fields VAL, BPTR, NORD
The following fields are used to operate the array analog input record in the
simulation mode. See L<Simulation Mode> for more information on the simulation
mode fields.
=fields SIOL, SIML, SIMM, SIMS
=begin html
<br>
<hr>
<br>
=end html
=head2 Record Support
=head3 Record Support Routines
=head4 init_record
static long init_record(aaiRecord *prec, int pass)
If device support includes C<init_record()>, it is called.
Checks if device support allocated array space. If not, space for the array is
allocated using NELM and FTVL. The array address is stored in the record.
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT
link or creates a channel access link if SIML type is PV_LINK. VAL is likewise
initialized if SIOL is CONSTANT or PV_LINK.
This routine next checks to see that device support is available and a device
support read routine is defined. If either does not exist, an error message is
issued and processing is terminated
=head4 process
static long process(aaiRecord *prec)
See L</"Record Processing"> section below.
=head4 cvt_dbaddr
static long cvt_dbaddr(DBADDR *paddr)
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
actual buffer holding the result.
=head4 get_array_info
static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
Obtains values from the array referenced by VAL.
=head4 put_array_info
static long put_array_info(DBADDR *paddr, long nNew)
Writes values into the array referenced by VAL.
=head4 get_units
static long get_units(DBADDR *paddr, char *units)
Retrieves EGU.
=head4 get_prec
static long get_precision(DBADDR *paddr, long *precision)
Retrieves PREC if field is VAL field. Otherwise, calls C<<< recGblGetPrec() >>>.
=head4 get_graphic_double
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
Sets the upper display and lower display limits for a field. If the field is VAL
the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values:
upper_disp_limit = HOPR
lower_disp_limit = LOPR
=head4 get_control_double
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
Sets the upper control and the lower control limits for a field. If the field is
VAL the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values
upper_ctrl_limit = HOPR
lower_ctrl_limit = LOPR
=head3 Record Processing
Routine process implements the following algorithm:
=over
=item 1.
Check to see that the appropriate device support module exists. If it doesn't,
an error message is issued and processing is terminated with the PACT field
still set to TRUE. This ensures that processes will no longer be called for this
record. Thus error storms will not occur.
=item 2.
Call device support read routine C<read_aai()>.
=item 3.
If PACT has been changed to TRUE, the device support read routine has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE.
=item 4.
Check to see if monitors should be invoked.
=over
=item *
Alarm monitors are invoked if the alarm status or severity has changed.
=item *
Archive and value change monitors are invoked if APST or MPST are Always or if
the result of the hash calculation is different.
=item *
NSEV and NSTA are reset to 0.
=back
=item 5.
Scan forward link if necessary, set PACT FALSE, and return.
=back
=begin html
<br>
<hr>
<br>
=end html
=cut
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode Location")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Sim Input Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}
=head2 Device Support
=head3 Fields Of Interest To Device Support
Each array analog input record record must have an associated set of device
support routines. The primary responsibility of the device support routines is to
obtain a new array value whenever C<read_aai()> is called. The device support
routines are primarily interested in the following fields:
=fields PACT, DPVT, NSEV, NSTA, INP, NELM, FTVL, BPTR, NORD
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
long init_record(dbCommon *precord)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. cmd has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 read_aai
long read_aai(dbCommon *precord)
This routine must provide a new input value. It returns the following values:
=over
=item *
0: Success.
=item *
Other: Error.
=back
=head3 Device Support For Soft Records
The C<<< Soft Channel >>> device support module is provided to read values from
other records and store them in arrays. If INP is a constant link, then read_aai
does nothing. In this case, the record can be used to hold arrays written via
dbPuts. If INP is a database or channel access link, the new array value is read
from the link. NORD is set.
This module places a value directly in VAL and NORD is set to the number of items
in the array.
If the INP link type is constant, then NORD is set to zero.
=cut

View File

@@ -1,116 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
menu(aaoPOST) {
choice(aaoPOST_Always,"Always")
choice(aaoPOST_OnChange,"On Change")
}
recordtype(aao) {
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode Location")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Sim Output Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}

View File

@@ -0,0 +1,476 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Array Analog Output (aao)
The array analog output record type is used to write array data. The array data
can contain any of the supported data types. The record is in many ways similar to
the waveform record but outputs arrays instead of reading them. It also allows the
device support to allocate the array storage.
=recordtype aao
=cut
include "menuFtype.dbd"
menu(aaoPOST) {
choice(aaoPOST_Always,"Always")
choice(aaoPOST_OnChange,"On Change")
}
recordtype(aao) {
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=head3 Scan Parameters
The array analog output record has the standard fields for specifying under what
circumstances the record will be processed. These fields are listed in L<Scan
Fields>. In addition, L<Scanning Specification> explains how these fields are
used. I/O event scanning is only available when supported by device support.
=head3 Write Parameters
These fields are configurable by the user to specify how and where to the record
writes its data. The OUT field determines where the array analog output writes its
output. It can be a hardware address, a channel access or database link, or a
constant. Only in records that use soft device support can the OUT field be a
channel access link, a database link, or a constant. Otherwise, the OUT field must
be a hardware address. See L<Address Specification> for information on the format
of hardware addresses and database links.
=head4 Fields related to array writing
The DTYP field must contain the name of the appropriate device support module. The
values in the array referenced by are written to the location specified in the OUT
field. (If the OUT link is a constant, no data are written.) NELM specifies the
maximum number of elements that the array can hold, while FTVL specifies the data
type of the elements.
=fields DTYP, OUT, NELM, FTVL
=head4 Possible data types for FTVL
=menu menuFtype
=head3 Operator Display Parameters
These parameters are used to present meaningful data to the operator. They
display the value and other parameters of the waveform either textually or
graphically.
=head4 Fields related to I<Operator Display>
EGU is a string of up to 16 characters describing the units that the array data
measures. It is retrieved by the C<<< get_units >>> record support routine.
The HOPR and LOPR fields set the upper and lower display limits for array
elements referenced by the VAL field. Both the C<<< get_graphic_double >>> and
C<<< get_control_double >>> record support routines retrieve these fields.
The PREC field determines the floating point precision with which to display the
array values. It is used whenever the C<<< get_precision >>> record support
routine is called.
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields EGU, HOPR, LOPR, PREC, NAME, DESC
=head3 Alarm Parameters
The array analog output record has the alarm parameters common to all record
types.
=head3 Monitor Parameters
These parameters are used to determine when to send monitors placed on the VAL
field. The APST and MPST fields are a menu with choices "Always" and "On
Change". The default is "Always", thus monitors will normally be sent every time
the record processes. Selecting "On Change" causes a 32-bit hash of the VAL
field buffer to be calculated and compared with the previous hash value every
time the record processes; the monitor will only be sent if the hash is
different, indicating that the buffer has changed. Note that there is a small
chance that two different value buffers might result in the same hash value, so
for critical systems "Always" may be a better choice, even though it re-sends
duplicate data.
=head4 Record fields related to I<Monitor Parameters>
=fields APST, MPST, HASH
=head4 Menu choices for C<APST> and C<MPST> fields
=menu aaoPOST
=head3 Run-time Parameters
These parameters are used by the run-time code for processing the array analog
output record. They are not configured using a configuration tool. Only the VAL
field is modifiable at run-time.
VAL references the array where the array analog output record stores its data. The
BPTR field holds the address of the array.
The NORD field holds a counter of the number of elements that have been written to
the output,
=fields VAL, BPTR, NORD
The following fields are used to operate the array analog output record in the
simulation mode. See L<Simulation Mode> for more information on the simulation
mode fields.
=fields SIOL, SIML, SIMM, SIMS
=begin html
<br>
<hr>
<br>
=end html
=head2 Record Support
=head3 Record Support Routines
=head4 init_record
static long init_record(aaoRecord *prec, int pass)
If device support includes C<init_record()>, it is called.
Checks if device support allocated array space. If not, space for the array is
allocated using NELM and FTVL. The array address is stored in the record.
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT
link or creates a channel access link if SIML type is PV_LINK. VAL is likewise
initialized if SIOL is CONSTANT or PV_LINK.
This routine next checks to see that device support is available and a device
support write routine is defined. If either does not exist, an error message is
issued and processing is terminated
=head4 process
static long process(aaoRecord *prec)
See L</"Record Processing"> section below.
=head4 cvt_dbaddr
static long cvt_dbaddr(DBADDR *paddr)
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
actual buffer holding the result.
=head4 get_array_info
static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
Obtains values from the array referenced by VAL.
=head4 put_array_info
static long put_array_info(DBADDR *paddr, long nNew)
Writes values into the array referenced by VAL.
=head4 get_units
static long get_units(DBADDR *paddr, char *units)
Retrieves EGU.
=head4 get_prec
static long get_precision(DBADDR *paddr, long *precision)
Retrieves PREC if field is VAL field. Otherwise, calls C<<< recGblGetPrec() >>>.
=head4 get_graphic_double
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
Sets the upper display and lower display limits for a field. If the field is VAL
the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values:
upper_disp_limit = HOPR
lower_disp_limit = LOPR
=head4 get_control_double
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
Sets the upper control and the lower control limits for a field. If the field is
VAL the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values
upper_ctrl_limit = HOPR
lower_ctrl_limit = LOPR
=head3 Record Processing
Routine process implements the following algorithm:
=over
=item 1.
Check to see that the appropriate device support module exists. If it doesn't,
an error message is issued and processing is terminated with the PACT field
still set to TRUE. This ensures that processes will no longer be called for this
record. Thus error storms will not occur.
=item 2.
Call device support write routine C<write_aao>.
=item 3.
If PACT has been changed to TRUE, the device support read routine has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE.
=item 4.
Check to see if monitors should be invoked.
=over
=item *
Alarm monitors are invoked if the alarm status or severity has changed.
=item *
Archive and value change monitors are invoked if APST or MPST are Always or if
the result of the hash calculation is different.
=item *
NSEV and NSTA are reset to 0.
=back
=item 5.
Scan forward link if necessary, set PACT FALSE, and return.
=back
=begin html
<br>
<hr>
<br>
=end html
=cut
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode Location")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Sim Output Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}
=head2 Device Support
=head3 Fields Of Interest To Device Support
Each array analog output record record must have an associated set of device
support routines. The primary responsibility of the device support routines is to
write the array data value whenever C<write_aao()> is called. The device support
routines are primarily interested in the following fields:
=fields PACT, DPVT, NSEV, NSTA, OUT, NELM, FTVL, BPTR, NORD
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
init_record(dbCommon *precord)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. cmd has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 write_aao
long write_aao(dbCommon *precord)
This routine must write the array data to output. It returns the following values:
=over
=item *
0: Success.
=item *
Other: Error.
=back
=head3 Device Support For Soft Records
The C<<< Soft Channel >>> device support module is provided to write values to
other records and store them in arrays. If OUT is a constant link, then
C<write_aao()> does nothing. In this case, the record can be used to hold arrays
written via dbPuts. If OUT is a database or channel access link, the array value
is written to the link. NORD is set to the number of items in the array.
If the OUT link type is constant, then NORD is set to zero.
=cut

View File

@@ -190,7 +190,13 @@ noise.
The AFTC field sets the time constant on a low-pass filter that delays the
reporting of limit alarms until the signal has been within the alarm range for
that number of seconds (the default AFTC value of zero retains the previous
behavior).
behavior). The record must be scanned often enough for the filtering action to
work effectively and the alarm severity can only change when the record is
processed, but that processing does not have to be regular; the filter uses the
time since the record last processed in its calculation. Setting AFTC to a
positive number of seconds will delay the record going into or out of a minor
alarm severity or from minor to major severity until the input signal has been
in the alarm range for that number of seconds.
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC, LALM

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Analog Output Record (ao)
@@ -104,33 +104,32 @@ The LINR field can specify C<LINEAR> or C<SLOPE> for linear conversions,
C<NO CONVERSION> for no conversions at all, or the name of a breakpoint table
such as C<typeKdegC> for breakpoint conversions.
Note that the ESLO, EOFF, EGUF, and EGUL fields are only used for linear
conversions.
Also note that none of these fields have any significance for records that use
the Soft Channel device support module.
The EGUF and EGUL fields should be set for C<LINEAR> conversions, and the ESLO
and EOFF fields for C<SLOPE> conversion. Note that none of these fields have any
significance for records that use the Soft Channel device support module.
=over
=item EGUF, EGUF
The user must calculate these fields when configuring the database for records
The user must set these fields when configuring the database for records
that use C<LINEAR> conversions.
They are used to calculate the values for ESLO and EOFF.
See Conversion Specification for more information on how to calculate these
fields.
=item ESLO, EOFF
Computed by device support from EGUF and EGUL when LINR specifies C<LINEAR>.
These values must be supplied by the user when LINR specifies C<SLOPE>.
Used only when LINR is C<LINEAR> or C<SLOPE>.
=item AOFF, ASLO
These fields are adjustment parameters for the raw output values.
They are applied to the raw output value after conversion from engineering
units.
=item ESLO, EOFF
Computed by device support using EGUF and EGUL when LINR specifies C<LINEAR>.
These values must be supplied by the user when LINR specifies C<SLOPE>.
Used only when LINR is C<LINEAR> or C<SLOPE>.
=item ROFF
This field can be used to offset the raw value generated by the conversion
@@ -168,8 +167,7 @@ addresses.
For soft records the output link can be a database link, a channel
access link, or a constant value. If the link is a constant, no output
is sent. See Address Specification for information on the format of
database and channel access addresses.
is sent.
=fields DTYP, OUT
@@ -193,8 +191,8 @@ The PREC field determines the floating point precision with which to
display VAL, OVAL and PVAL. It is used whenever the get_precision
record support routine is called.
See Fields Common to All Record Types for more on the record name
(NAME) and description (DESC) fields.
See L<Fields Common to All Record Types|dbCommonRecord/Operator Display
Parameters> for more on the record name (NAME) and description (DESC) fields.
=fields EGU, HOPR, LOPR, PREC, NAME, DESC
@@ -209,9 +207,10 @@ and LOW fields, which must be floating-point values. For each of these
fields, there is a corresponding severity field which can be either
NO_ALARM, MINOR, or MAJOR.
See Alarm Specification for a complete explanation of alarms and these
fields. See Invalid Alarm Output Action for more information on the
IVOA and IVOV fields. Alarm Fields lists other fields related to a
See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>
for more information on the IVOA and IVOV fields.
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related to a
alarms that are common to all record types.
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV
@@ -260,15 +259,15 @@ processing.
=fields ORAW, RBV, ORBV, LALM, ALST, MLST, INIT, PBRK, LBRK, PVAL, OMOD
The following fields are used to operate the analog output in the
simulation mode. See Fields Common to Many Record Types for more
information on these fields.
The following fields are used when the record is in simulation mode. See
L<Fields Common to Output Record Types|dbCommonOutput/Simulation Fields> for
more information on these fields.
=fields SIOL, SIML, SIMM, SIMS
=cut
include "dbCommon.dbd"
include "dbCommon.dbd"
field(VAL,DBF_DOUBLE) {
prompt("Desired Output")
promptgroup("50 - Output")
@@ -575,6 +574,8 @@ get_precision, get_graphic_double, and get_control_double routines.
=item init_record
C<long init_record(aoRecord *prec, int pass);>
This routine initializes SIMM if SIML is a constant or creates a
channel access link if SIML is PV_LINK. If SIOL is PV_LINK a channel
access link is created.
@@ -606,10 +607,14 @@ then set to FALSE. PVAL is set to VAL.
=item process
C<long process(aoRecord *prec);>
See next section.
=item special
C<long special(DBADDR *paddr, int after);>
The only special processing for analog output records is SPC_LINCONV
which is invoked whenever either of the fields LINR, EGUF, EGUL or ROFF
is changed If the device support routine special_linconv exists it is
@@ -620,6 +625,8 @@ re-initialized.
=item get_alarm_double
C<long get_alarm_double(DBADDR *, struct dbr_alDouble *);>
Sets the following values:
upper_alarm_limit = HIHI
@@ -769,7 +776,9 @@ Device support consists of the following routines:
=over
=item C<long report(int level)>
=item report
C<long report(int level);>
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
@@ -779,7 +788,9 @@ information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=item C<long init(int after)>
=item init
C<long init(int after);>
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
@@ -787,7 +798,9 @@ the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=item C<long init_record(aoRecord *prec)>
=item init_record
C<long init_record(aoRecord *prec);>
This optional routine is called by the record initialization code for each ao
record instance that has its DTYP field set to use this device support.
@@ -809,7 +822,9 @@ should also fetch that value and put it into the record's RVAL or VAL field. The
return value should be zero if the RVAL field has been set, or 2 if either the
VAL field has been set or if the last output value cannot be retrieved.
=item C<long get_ioint_info(int cmd, aoRecord *prec, IOSCANPVT *piosl)>
=item get_ioint_info
C<long get_ioint_info(int cmd, aoRecord *prec, IOSCANPVT *piosl);>
This optional routine is called whenever the record's SCAN field is being
changed to or from the value C<I/O Intr> to find out which I/O Interrupt Scan
@@ -837,7 +852,9 @@ thread.
The C<scanIoRequest()> routine is safe to call from an interrupt service routine
on embedded architectures (vxWorks and RTEMS).
=item C<long write_ao(aoRecord *prec)>
=item write_ao
C<long write_ao(aoRecord *prec);>
This essential routine is called whenever the record has a new output value to
send to the device. It is responsible for performing the write operation, using
@@ -856,7 +873,9 @@ that happens the C<write_ao()> routine will be called again with PACT still set
to TRUE; it should then set it to FALSE to indicate the write has completed, and
return.
=item C<long special_linconv(aoRecord *prec, int after)>
=item special_linconv
C<long special_linconv(aoRecord *prec, int after);>
This optional routine should be provided if the record type's unit conversion
features are used by the device support's C<write_ao()> routine utilizing the

View File

@@ -318,10 +318,13 @@ XOR : Bitwise Exclusive Or
C<~> : One's Complement
=item *
C<<< << >>> : Left shift
C<<< << >>> : Arithmetic Left Shift
=item *
C<<< >> >>> : Right shift
C<<< >> >>> : Arithmetic Right Shift
=item *
C<<<< >>> >>>> : Logical Right Shift
=back

View File

@@ -350,10 +350,13 @@ XOR : Bitwise Exclusive Or
C<~> : One's Complement
=item *
C<<< << >>> : Left shift
C<<< << >>> : Arithmetic Left Shift
=item *
C<<< >> >>> : Right shift
C<<< >> >>> : Arithmetic Right Shift
=item *
C<<<< >>> >>>> : Logical Right Shift
=back
@@ -366,7 +369,7 @@ C<:=> : assigns a value (right hand side) to a variable (i.e. field)
=back
=head3 Parantheses, Comma, and Semicolon
=head3 Parentheses, Comma, and Semicolon
The open and close parentheses are supported. Nested parentheses are
supported.
@@ -437,7 +440,7 @@ Result is E if (A + B)<(C + D)
=item
Result is unchanged if (A + B)>=(C + D)
From 3.14.9 onwards, this expresion must be written as
From 3.14.9 onwards, this expression must be written as
C<(A + B) < (C + D) ? E : VAL>
=back
@@ -505,7 +508,7 @@ C<On Change> -- write output every time VAL changes, i.e., every time the
result of the expression changes.
=item *
C<When Zero> -- when record is preocessed, write output if VAL is zero.
C<When Zero> -- when record is processed, write output if VAL is zero.
=item *
C<When Non-zero> -- when record is processed, write output if VAL is
@@ -531,9 +534,9 @@ output is executed. The field is a menu field with two options:
If C<Use CALC> is specified, when the record writes its
output it will write the result of the expression in the CALC field, that
is, it will write the value of the VAL field. If C<Use OCAL> is specified,
the record will instead write the result of the expresion in the OCAL
the record will instead write the result of the expression in the OCAL
field, which is contained in the OVAL field. The OCAL field is exactly like
the CALC field and has the same fuctionality it can contain the string
the CALC field and has the same functionality it can contain the string
representation of an expression which is evaluated at run-time. Thus, if
necessary, the record can use the result of the CALC expression to
determine if data should be written and can use the result of the OCAL
@@ -548,7 +551,7 @@ the wait is over. The field DLYA is equal to 1 during the delay period. The
resolution of the delay entry system dependent.
The IVOA field specifies what action to take with the OUT link if the
Calcout record eneters an INVALID alarm status. The options are
Calcout record enters an INVALID alarm status. The options are
C<Continue normally>, C<Don't drive outputs>, and C<Set output to IVOV>.
If the IVOA field is C<Set output to IVOV>, the data entered into the
IVOV field is written to the OUT link if the record alarm severity is
@@ -602,7 +605,7 @@ The CLCV and OLCV fields indicate the validity of the expression in the
CALC and OCAL fields respectfully. If the expression in invalid, the field
is set to one.
The DYLA field is set to one during the delay specified in ODLY.
The DLYA field is set to one during the delay specified in ODLY.
See L<Fields Common to All Record Types> for more information on the record
name (NAME) and description (DESC) fields.
@@ -617,7 +620,7 @@ record support routines. The Calculation alarm is called by the record
processing routine when the CALC expression is an invalid one, upon which
an error message is generated.
The following alarm parametersi, which are configured by the user, define the
The following alarm parameters, which are configured by the user, define the
limit alarms for the VAL field and the severity corresponding to those
conditions.
@@ -633,7 +636,7 @@ common to all record types.
These parameters are used to determine when to send monitors for the value
fields. These monitors are sent when the value field exceeds the last
monitored field by the appropriate deadband, the ADEL for archiver monitors
and the MDEL field for all aother types of monitors. If these fields have a
and the MDEL field for all other types of monitors. If these fields have a
value of zero, every time the value changes, monitors are triggered; if
they have a value of -1, every time the record is scanned, monitors are
triggered. See L<Monitor Specification> for a complete explanation of
@@ -1193,13 +1196,13 @@ Retrieves PREC.
Sets the upper display and lower display limits for a field. If the field
is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else
if the field has upper and lower limits defined they will be used, else the
upper and lower macimum values for the field type will be used.
upper and lower maximum values for the field type will be used.
=head2 C<get_control_double>
Sets the upper control and lower control limits for a field. If the VAL,
HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the
field has upper and lower limits defimed they will be used, else the upper
field has upper and lower limits defined they will be used, else the upper
and lower maximum values for the field will be used.
=head2 C<get_alarm_double>
@@ -1241,7 +1244,7 @@ honors the alarm hysteresis factor (HYST). Thus the value must change by at
least HYST before the alarm status and severity changes.
=item 4.
Determin if the Output Execution Option (OOPT) is met. If it met, either
Determine if the Output Execution Option (OOPT) is met. If it met, either
execute the output link (and output event) immediately (if ODLY = 0), or
schedule a callback after the specified interval. See the explanation for
the C<execOutput()> routine below.
@@ -1267,7 +1270,7 @@ NSEV and NSTA are reset to 0
=back
=item 6.
If no output delay was specified, scan forwark link if necessaru, set PACT
If no output delay was specified, scan forward link if necessary, set PACT
FALSE, and return.
=back
@@ -1290,7 +1293,7 @@ put the value of OVAL to the OUT link and post the event in OEVT (if
non-zero).
=item 4.
If an output delay was implemented, process the forwark link.
If an output delay was implemented, process the forward link.
=back

View File

@@ -106,10 +106,11 @@ static long init_record(eventRecord *prec, int pass)
recGblInitConstantLink(&prec->siol,DBF_STRING,&prec->sval);
}
prec->epvt = eventNameToHandle(prec->val);
if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) )
status=(*pdset->init_record)(prec);
prec->epvt = eventNameToHandle(prec->val);
return(status);
}

View File

@@ -133,33 +133,28 @@ static void wdogCallback(epicsCallback *arg)
return;
}
static long wdogInit(histogramRecord *prec)
static void wdogInit(histogramRecord *prec)
{
myCallback *pcallback;
if (!prec->wdog && prec->sdel > 0) {
/* initialize a callback object */
pcallback = calloc(1, sizeof(myCallback));
pcallback->prec = prec;
if (!pcallback)
return -1;
callbackSetCallback(wdogCallback, &pcallback->callback);
callbackSetUser(pcallback, &pcallback->callback);
callbackSetPriority(priorityLow, &pcallback->callback);
prec->wdog = pcallback;
}
if (!prec->wdog)
return -1;
pcallback = prec->wdog;
if (!pcallback)
return -1;
if (prec->sdel > 0) {
myCallback *pcallback = prec->wdog;
if (!pcallback) {
/* initialize a callback object */
pcallback = calloc(1, sizeof(myCallback));
if (!pcallback)
return;
pcallback->prec = prec;
callbackSetCallback(wdogCallback, &pcallback->callback);
callbackSetUser(pcallback, &pcallback->callback);
callbackSetPriority(priorityLow, &pcallback->callback);
prec->wdog = pcallback;
}
/* start new timer on monitor */
callbackRequestDelayed(&pcallback->callback, prec->sdel);
}
return 0;
}
static long init_record(histogramRecord *prec, int pass)

View File

@@ -1,146 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
menu(histogramCMD) {
choice(histogramCMD_Read,"Read")
choice(histogramCMD_Clear,"Clear")
choice(histogramCMD_Start,"Start")
choice(histogramCMD_Stop,"Stop")
}
recordtype(histogram) {
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
extra("void * val")
#=type ULONG[]
#=read Yes
#=write Yes
}
field(NELM,DBF_USHORT) {
prompt("Num of Array Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CSTA,DBF_SHORT) {
prompt("Collection Status")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CMD,DBF_MENU) {
prompt("Collection Control")
asl(ASL0)
special(SPC_CALC)
interest(1)
menu(histogramCMD)
}
field(ULIM,DBF_DOUBLE) {
prompt("Upper Signal Limit")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(LLIM,DBF_DOUBLE) {
prompt("Lower Signal Limit ")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(WDTH,DBF_DOUBLE) {
prompt("Element Width")
special(SPC_NOMOD)
interest(3)
}
field(SGNL,DBF_DOUBLE) {
prompt("Signal Value")
special(SPC_MOD)
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(SVL,DBF_INLINK) {
prompt("Signal Value Location")
promptgroup("40 - Input")
interest(1)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("epicsUInt32 *bptr")
}
field(WDOG,DBF_NOACCESS) {
prompt("Watchdog callback")
special(SPC_NOMOD)
interest(4)
extra("void * wdog")
}
field(MDEL,DBF_SHORT) {
prompt("Monitor Count Deadband")
promptgroup("80 - Display")
interest(1)
}
field(MCNT,DBF_SHORT) {
prompt("Counts Since Monitor")
special(SPC_NOMOD)
interest(3)
}
field(SDEL,DBF_DOUBLE) {
prompt("Monitor Seconds Dband")
promptgroup("80 - Display")
special(SPC_RESET)
interest(1)
}
field(SIOL,DBF_INLINK) {
prompt("Sim Input Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
field(SVAL,DBF_DOUBLE) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode Location")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(HOPR,DBF_ULONG) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_ULONG) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
}
variable(histogramSDELprecision, int)

View File

@@ -0,0 +1,419 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Histogram Record (histogram)
The histogram record is used to store frequency counts of a signal into an array
of arbitrary length. The user can configure the range of the signal value that
the array will store. Anything outside this range will be ignored.
=head2 Parameter Fields
The record-specific fields are described below.
=recordtype histogram
=cut
menu(histogramCMD) {
choice(histogramCMD_Read,"Read")
choice(histogramCMD_Clear,"Clear")
choice(histogramCMD_Start,"Start")
choice(histogramCMD_Stop,"Stop")
}
recordtype(histogram) {
=head3 Read Parameters
The SVL is the input link where the record reads its value. It can be a
constant, a database link, or a channel access link. If SVL is a database or
channel access link, then SGNL is read from SVL. If SVL is a constant, then SGNL
is initialized with the constant value but can be changed via dbPuts. The C<Soft
Channel> device support module can be specified in the DTYP field.
The ULIM and LLIM fields determine the usable range of signal values. Any value
of SGNL below LLIM or above ULIM is outside the range and will not be stored in
the array. In the NELM field the user must specify the array size, e.g., the
number of array elements. Each element in the NELM field holds the counts for an
interval of the range of signal counts, the range specified by ULIM and LLIM.
These intervals are determined by dividing the range by NELM:
(ULIM - LLIM) / NELM.
=fields SVL, SGNL, DTYP, NELM, ULIM, LLIM
=head3 Operator Display Parameters
These parameters are used to present meaningful data to the operator. These
fields are used to display the value and other parameters of the histogram
either textually or graphically. See L<Fields Common to All Record Types> for
more on the record name (NAME) and description (DESC) fields.
=fields NAME, DESC
=head3 Alarm Parameters
The Histogram record has the alarm parameters common to all record types.
L<Alarm Fields> lists other fields related to a alarms that are common to all
record types.
=head3 Monitor Parameters
The MDEL field implements the monitor count deadband. Only when MCNT is greater
than the value given to MDEL are monitors triggered, MCNT being the number of
counts since the last time the record was processed. If MDEL is -1, everytime
the record is processed, a monitor is triggered regardless.
If SDEL is greater than 0, it causes a callback routine to be called. The number
specified in SDEL is the callback routines interval. The callback routine is
called every SDEL seconds. The callback routine posts an event if MCNT is
greater than 0.
=fields MDEL, SDEL
=head3 Run-time and Simulation Mode Parameters
These parameters are used by the run-time code for processing the histogram.
They are not configurable by the user prior to run-time. They represent the
current state of the record. Many of them are used to process the histogram more
efficiently.
The BPTR field contains a pointer to the unsigned long array of frequency
values. The VAL field references this array as well. However, the BPTR field is
not accessible at run-time.
The MCNT field keeps counts the number of signal counts since the last monitor
was invoked.
The collections controls field (CMD) is a menu field with five choices:
=menu histogramCMD
When CMD is C<Read>, the record retrieves its values and adds them to the signal
array. This command will first clear the signal counts which have already been
read when it is first invoked.
The C<Clear> command erases the signal counts, setting the elements in the array
back to zero. Afterwards, the CMD field is set back to C<Read>.
The C<Start> command simply causes the record to read signal values into the
array. Unlike C<Read>, it doesn't clear the array first.
The C<Stop> command disables the reading of signal values into the array.
The C<Setup> command waits until the C<start> or C<read> command has been issued
to start counting.
The CSTA or collections status field implements the CMD field choices by
enabling or disabling the reading of values into the histogram array. While
FALSE, no signals are added to the array. While TRUE, signals are read and added
to the array. The field is initialized to TRUE. The C<Stop> command is the only
command that sets CSTA to FALSE. On the other hand, the C<Start> command is the
only command that sets it to TRUE. Thus, C<Start> must be invoked after each
C<Stop> command in order to enable counting; invoking C<Read> will not enable
signal counting after C<Stop> has been invoked.
A typical use of these fields would be to initialize the CMD field to C<Read>
(it is initialized to this command by default), to use the C<Stop> command to
disable counting when necessary, after which the C<Start> command can be invoked
to re-start the signal count.
The WDTH field is a private field that holds the signal width of the array
elements. For instance, if the LLIM was configured to be 4.0 and ULIM was
configured to be 12.0 and the NELM was set to 4, then the WDTH for each array
would be 2. Thus, it is (ULIM - LLIM) / NELM.
=fields BPTR, VAL, MCNT, CMD, CSTA, WDTH
The following fields are used to operate the histogram record in simulation
mode. See L<Fields Common to Many Record Types> for more information on the
simulation mode fields.
=fields SIOL, SVAL, SIML, SIMM, SIMS
=cut
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
extra("void * val")
#=type ULONG[]
#=read Yes
#=write Yes
}
field(NELM,DBF_USHORT) {
prompt("Num of Array Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CSTA,DBF_SHORT) {
prompt("Collection Status")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CMD,DBF_MENU) {
prompt("Collection Control")
asl(ASL0)
special(SPC_CALC)
interest(1)
menu(histogramCMD)
}
field(ULIM,DBF_DOUBLE) {
prompt("Upper Signal Limit")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(LLIM,DBF_DOUBLE) {
prompt("Lower Signal Limit ")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(WDTH,DBF_DOUBLE) {
prompt("Element Width")
special(SPC_NOMOD)
interest(3)
}
field(SGNL,DBF_DOUBLE) {
prompt("Signal Value")
special(SPC_MOD)
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(SVL,DBF_INLINK) {
prompt("Signal Value Location")
promptgroup("40 - Input")
interest(1)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("epicsUInt32 *bptr")
}
field(WDOG,DBF_NOACCESS) {
prompt("Watchdog callback")
special(SPC_NOMOD)
interest(4)
extra("void * wdog")
}
field(MDEL,DBF_SHORT) {
prompt("Monitor Count Deadband")
promptgroup("80 - Display")
interest(1)
}
field(MCNT,DBF_SHORT) {
prompt("Counts Since Monitor")
special(SPC_NOMOD)
interest(3)
}
field(SDEL,DBF_DOUBLE) {
prompt("Monitor Seconds Dband")
promptgroup("80 - Display")
special(SPC_RESET)
interest(1)
}
field(SIOL,DBF_INLINK) {
prompt("Sim Input Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
field(SVAL,DBF_DOUBLE) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode Location")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(HOPR,DBF_ULONG) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_ULONG) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
=head2 Record Support
=head3 Record Support Routines
=head4 init_record
Using NELM, space for the unsigned long array is allocated and the width WDTH of
the array is calculated.
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT
link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise
initialized if SIOL is CONSTANT or PV_LINK.
This routine next checks to see that device support and a device support read
routine are available. If device support includes C<init_record()>, it is
called.
=head4 process
See next section.
=head4 special
Special is invoked whenever the fields CMD, SGNL, ULIM, or LLIM are changed.
If SGNL is changed, add_count is called.
If ULIM or LLIM are changed, WDTH is recalculated and clear_histogram is called.
If CMD is less or equal to 1, clear_histogram is called and CMD is reset to 0.
If CMD is 2, CSTA is set to TRUE and CMD is reset to 0. If CMD is 3, CSTA is set
to FALSE and CMD is reset to 0.
clear_histogram zeros out the histogram array. add_count increments the
frequency in the histogram array.
=head4 cvt_dbaddr
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
actual buffer holding the array.
=head4 get_array_info
Obtains values from the array referenced by VAL.
=head4 put_array_info
Writes values into the array referenced by VAL.
=head3 Record Processing
Routine process implements the following algorithm:
=over
=item 1.
Check to see that the appropriate device support module exists. If it doesn't,
an error message is issued and processing is terminated with the PACT field set
to TRUE. This ensures that processes will no longer be called for this record.
Thus error storms will not occur.
=item 2.
readValue is called. See L<Input Records> for more information
=item 3.
If PACT has been changed to TRUE, the device support read routine has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE.
=item 4.
Add count to histogram array.
=item 5.
Check to see if monitors should be invoked. Alarm monitors are invoked if the
alarm status or severity has changed. Archive and value change monitors are
invoked if MDEL conditions are met. NSEV and NSTA are reset to 0.
=item 6.
Scan forward link if necessary, set PACT and INIT to FALSE, and return.
=back
=head2 Device Support
=head3 Fields Of Interest To Device Support
The device support routines are primarily interested in the following fields:
=fields PACT, DPVT, UDF, NSEV, NSTA, SVL, SGNL
=head3 Device Support Routines
Device support consists of the following routines:
=head4 long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
init_record(precord)
This routine is called by the record support C<init_record()> routine. It makes
sure that SGNL is a CONSTANT, PV_LINK, DB_LINK, or CA_LINK. It also retrieves a
value for SVL from SGNL. If SGNL is none of the above, an error is generated.
=head4 read_histogram
read_histogram(*precord)
This routine is called by the record support routines. It retrieves a value for
SVL from SGNL.
=head3 Device Support For Soft Records
Only the device support module C<Soft Channel> is currently provided, though
other device support modules may be provided at the user's site.
=head4 Soft Channel
The C<Soft Channel> device support routine retrieves a value from SGNL. SGNL
must be CONSTANT, PV_LINK, DB_LINK, or CA_LINK.
=cut
}
variable(histogramSDELprecision, int)

View File

@@ -1,88 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(lsi) {
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsidset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN read_string;
%} lsidset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
}
field(OVAL,DBF_NOACCESS) {
prompt("Old Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("40 - Input")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(2)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(2)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Sim Input Specifctn")
promptgroup("90 - Simulate")
interest(2)
}
}

View File

@@ -0,0 +1,207 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Long String Input Record (lsi)
The long string input record is used to retrieve an arbitrary ASCII string with
a maximum length of 65535 characters.
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=recordtype lsi
=cut
recordtype(lsi) {
=head3 Scan Parameters
The long string input record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 Input Specification
The INP field determines where the long string input record obtains its string
from. It can be a database or channel access link, or a constant. If constant,
the VAL field is initialized with the constant and can be changed via dbPuts.
Otherwise, the string is read from the specified location each time the record
is processed and placed in the VAL field. The maximum number of characters in
VAL is given by SIZV, and cannot be larger than 65535. In addition, the
appropriate device support module must be entered into the DTYP field.
See L<Address Specification> for information on specifying links.
=fields VAL, OVAL, SIZV, INP, DTYP
=cut
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsidset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN read_string;
%} lsidset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
#=type STRING[SIZV]
#=read Yes
#=write Yes
}
field(OVAL,DBF_NOACCESS) {
prompt("Old Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
#=type STRING[SIZV]
#=read Yes
#=write No
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("40 - Input")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
=head3 Monitor Parameters
These parameters are used to specify when the monitor post should be sent by the
C<monitor()> routine. There are two possible choices:
APST is used for archiver monitors and MPST for all other type of monitors.
=fields MPST, APST
=cut
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
=head3 Operator Display Parameters
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields NAME, DESC
=head3 Alarm Parameters
The long string input record has the alarm parameters common to all record
types. L<Alarm Fields> lists other fields related to a alarms that are common to
all record types.
=head3 Run-time and Simulation Mode Parameters
The old value field (OVAL) of the long string input record is used to implement
value change monitors for VAL. If VAL is not equal to OVAL, then monitors are
triggered. LEN contains the length of the string in VAL, OLEN contains the
length of the string in OVAL.
=fields OVAL, LEN, OLEN
The following fields are used to operate the string input in the simulation
mode. See L<Simulation Mode> for more information on simulation mode fields.
=fields SIOL, SIML, SIMM, SIMS
=cut
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(2)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(2)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Sim Input Specifctn")
promptgroup("90 - Simulate")
interest(2)
}
}
=head2 Device Support Interface
The record requires device support to provide an entry table (dset) which
defines the following members:
typedef struct {
long number;
long (*report)(int level);
long (*init)(int after);
long (*init_record)(lsiRecord *prec);
long (*get_ioint_info)(int cmd, lsiRecord *prec, IOSCANPVT *piosl);
long (*read_string)(lsiRecord *prec);
} lsidset;
The module must set C<number> to at least 5, and provide a pointer to its
C<read_string()> routine; the other function pointers may be C<NULL> if their
associated functionality is not required for this support layer.
Most device supports also provide an C<init_record()> routine to configure the
record instance and connect it to the hardware or driver support layer.
=head2 Device Support for Soft Records
A device support module for DTYP C<Soft Channel> is provided for retrieving
values from other records or other software components.
Device support for DTYP C<getenv> is provided for retrieving strings from
environment variables. C<INST_IO> addressing C<< @<environment variable> >> is
used on the C<INP> link field to select the desired environment variable.
=cut

View File

@@ -1,112 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(lso) {
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsodset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} lsodset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
}
field(OVAL,DBF_NOACCESS) {
prompt("Previous Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("50 - Output")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
interest(3)
}
field(DOL,DBF_INLINK) {
prompt("Desired Output Link")
promptgroup("40 - Input")
interest(1)
}
field(IVOA,DBF_MENU) {
prompt("INVALID Output Action")
promptgroup("50 - Output")
interest(2)
menu(menuIvoa)
}
field(IVOV,DBF_STRING) {
prompt("INVALID Output Value")
promptgroup("50 - Output")
interest(2)
size(40)
}
field(OMSL,DBF_MENU) {
prompt("Output Mode Select")
promptgroup("50 - Output")
interest(1)
menu(menuOmsl)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(SIML,DBF_INLINK) {
prompt("Sim Mode link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Sim Output Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
}

View File

@@ -0,0 +1,272 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Long String Output Record (lso)
The long string output record is used to write an arbitrary ASCII string with a
maximum length of 65535 characters.
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=recordtype lso
=cut
include "menuIvoa.dbd"
recordtype(lso) {
=head3 Scan Parameters
The long string output record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 Desired Output Parameters
The long string output record must specify from where it gets its desired output
string. The first field that determines where the desired output originates is
the output mode select (OMSL) field, which can have two possible value:
C<closed_loop> or C<supervisory>. If C<supervisory> is specified, DOL is
ignored, the current value of VAL is written, and VAL can be changed externally
via dbPuts at run-time. If C<closed_loop> is specified, the VAL field's value is
obtained from the address specified in the desired output location field (DOL)
which can be either a database link or a channel access link.
The maximum number of characters in VAL is given by SIZV, and cannot be larger
than 65535.
DOL can also be a constant in addition to a link, in which case VAL is
initialized to the constant value. Your string constant, however, may be
interpreted as a CA link name. If you want to initialize your string output
record, it is therefore best to use the VAL field. Note that if DOL is a
constant, OMSL cannot be C<closed_loop>.
See L<Address Specification> for information on specifying links.
=fields VAL, SIZV, DOL, OMSL
=head3 Output Specification
The output link specified in the OUT field specifies where the long string
output record is to write its string. The link can be a database or channel
access link. If the OUT field is a constant, no output will be written.
See L<Address Specification> for information on specifying links.
In addition, the appropriate device support module must be entered into the DTYP
field.
=fields OUT, DTYP
=head3 Monitor Parameters
These parameters are used to specify when the monitor post should be sent by the
C<monitor()> routine. There are two possible choices:
APST is used for archiver monitors and MPST for all other type of monitors.
=fields MPST, APST
=head3 Operator Display Parameters
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields NAME, DESC
=head3 Alarm Parameters
The long string input record has the alarm parameters common to all record
types. L<Alarm Fields> lists other fields related to a alarms that are common to
all record types.
The IVOA field specifies an action to take when the INVALID alarm is triggered.
There are three possible actions:
=head4 Menu menuIvoa
=menu menuIvoa
When C<<< Set output to IVOV >>>, the value contained in the IVOV field is
written to the output link during an alarm condition. See
L<Invalid Alarm Output Action>
for more information on the IVOA and IVOV fields.
L<Alarm Fields>
lists other fields related to a alarms that are common to all record types.
=fields IVOA, IVOV
=cut
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsodset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} lsodset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
#=type STRING[SIZV]
#=read Yes
#=write Yes
}
field(OVAL,DBF_NOACCESS) {
prompt("Previous Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
#=type STRING[SIZV]
#=read Yes
#=write No
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("50 - Output")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
interest(3)
}
field(DOL,DBF_INLINK) {
prompt("Desired Output Link")
promptgroup("40 - Input")
interest(1)
}
field(IVOA,DBF_MENU) {
prompt("INVALID Output Action")
promptgroup("50 - Output")
interest(2)
menu(menuIvoa)
}
field(IVOV,DBF_STRING) {
prompt("INVALID Output Value")
promptgroup("50 - Output")
interest(2)
size(40)
}
field(OMSL,DBF_MENU) {
prompt("Output Mode Select")
promptgroup("50 - Output")
interest(1)
menu(menuOmsl)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
=head3 Run-time and Simulation Mode Parameters
The old value field (OVAL) of the long string input record is used to implement
value change monitors for VAL. If VAL is not equal to OVAL, then monitors are
triggered. LEN contains the length of the string in VAL, OLEN contains the
length of the string in OVAL.
=fields OVAL, LEN, OLEN
The following fields are used to operate the string input in the simulation
mode. See L<Simulation Mode> for more information on simulation mode fields.
=fields SIOL, SIML, SIMM, SIMS
=cut
field(SIML,DBF_INLINK) {
prompt("Sim Mode link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Sim mode Alarm Svrty")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Sim Output Specifctn")
promptgroup("90 - Simulate")
interest(1)
}
}
=head2 Device Support Interface
The record requires device support to provide an entry table (dset) which
defines the following members:
typedef struct {
long number;
long (*report)(int level);
long (*init)(int after);
long (*init_record)(lsoRecord *prec);
long (*get_ioint_info)(int cmd, lsoRecord *prec, IOSCANPVT *piosl);
long (*write_string)(lsoRecord *prec);
} lsodset;
The module must set C<number> to at least 5, and provide a pointer to its
C<write_string()> routine; the other function pointers may be C<NULL> if their
associated functionality is not required for this support layer.
Most device supports also provide an C<init_record()> routine to configure the
record instance and connect it to the hardware or driver support layer.
=head2 Device Support for Soft Records
Device support for DTYP C<Soft Channel> is provided for writing values to other
records or other software components.
Device support for DTYP C<stdio> is provided for writing values to the stdout,
stderr, or errlog streams. C<INST_IO> addressing C<@stdout>, C<@stderr> or
C<@errlog> is used on the OUT link field to select the desired stream.
=cut

View File

@@ -1,109 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(printf) {
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct printfdset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} printfdset;
%
field(VAL,DBF_NOACCESS) {
prompt("Result")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
}
field(SIZV,DBF_USHORT) {
prompt("Size of VAL buffer")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(FMT,DBF_STRING) {
prompt("Format String")
promptgroup("30 - Action")
pp(TRUE)
size(81)
}
field(IVLS,DBF_STRING) {
prompt("Invalid Link String")
promptgroup("30 - Action")
size(16)
initial("LNK")
}
field(INP0,DBF_INLINK) {
prompt("Input 0")
promptgroup("40 - Input")
interest(1)
}
field(INP1,DBF_INLINK) {
prompt("Input 1")
promptgroup("40 - Input")
interest(1)
}
field(INP2,DBF_INLINK) {
prompt("Input 2")
promptgroup("40 - Input")
interest(1)
}
field(INP3,DBF_INLINK) {
prompt("Input 3")
promptgroup("40 - Input")
interest(1)
}
field(INP4,DBF_INLINK) {
prompt("Input 4")
promptgroup("40 - Input")
interest(1)
}
field(INP5,DBF_INLINK) {
prompt("Input 5")
promptgroup("40 - Input")
interest(1)
}
field(INP6,DBF_INLINK) {
prompt("Input 6")
promptgroup("40 - Input")
interest(1)
}
field(INP7,DBF_INLINK) {
prompt("Input 7")
promptgroup("40 - Input")
interest(1)
}
field(INP8,DBF_INLINK) {
prompt("Input 8")
promptgroup("40 - Input")
interest(1)
}
field(INP9,DBF_INLINK) {
prompt("Input 9")
promptgroup("40 - Input")
interest(1)
}
%/* Number of INPx fields defined */
%#define PRINTF_NLINKS 10
}

View File

@@ -0,0 +1,323 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Printf Record (printf)
The printf record is used to generate and write a string using a format
specification and parameters, analogous to the C C<printf()> function.
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=recordtype printf
=cut
recordtype(printf) {
=head3 Scan Parameters
The printf record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 String Generation Parameters
The printf record must specify the desired output string with embedded format
specifiers in the FMT field. Plain characters are copied directly to the output
string. A pair of percent characters 'C<%%>' are converted into a single percent
character in the output string. A single precent character 'C<%>' introduces a
format specifier and is followed by zero or more of the standard C<printf()>
format flags and modifiers:
=over 4
=item *
Plus ('C<+>')
=item *
Minus ('C<->')
=item *
Space ('C< >')
=item *
Hash ('C<#>')
=item *
Minimum Field Width (decimal digits or 'C<*>')
=item *
Precision ('C<.>' followed by decimal digits or 'C<*>')
=item *
Length Modifier 'C<hh>' E<ndash> Reads link as DBR_CHAR or DBR_UCHAR
=item *
Length Modifier 'C<h>' E<ndash> Reads link as DBR_SHORT or DBR_USHORT for
integer conversions, DBR_FLOAT for floating-point conversions.
=item *
Length Modifier 'C<l>' E<ndash> Reads link as DBR_LONG or DBR_ULONG for integer
conversions, array of DBR_CHAR for string conversion.
=back
The following character specifies the conversion to perform, see your operating
system's C<printf()> documentation for more details. These conversions
ultimately call the C<snprintf()> routine for the actual string conversion
process, so are subject to the behaviour of that routine.
=over 4
=item *
'C<c>' E<ndash> Convert to a character. Only single byte characters are
permitted.
=item *
'C<d>' or 'C<i>' E<ndash> Convert to a decimal integer.
=item *
'C<o>' E<ndash> Convert to an unsigned octal integer.
=item *
'C<u>' E<ndash> Convert to an unsigned decimal integer.
=item *
'C<x>' E<ndash> Convert to an unsigned hexadecimal integer, using C<abcdef>.
=item *
'C<X>' E<ndash> Convert to an unsigned hexadecimal integer, using C<ABCDEF>.
=item *
'C<e>' or 'C<E>' E<ndash> Convert to floating-point in exponent style, reading
the link as DBR_DOUBLE or DBR_FLOAT.
=item *
'C<f>' or 'C<F>' E<ndash> Convert to floating-point in fixed-point style,
reading the link as DBR_DOUBLE or DBR_FLOAT.
=item *
'C<g>' or 'C<G>' E<ndash> Convert to floating-point in general style, reading
the link as DBR_DOUBLE or DBR_FLOAT.
=item *
'C<s>' E<ndash> Insert string, reading the link as DBR_STRING or array of
DBR_CHAR.
=back
The fields INP0 ... INP9 are input links that provide the parameter values to be
formatted into the output. The format specifiers in the FMT string determine
which type of the data is requested through the appropriate input link. As with
C<printf()> a C<*> character may be used in the format to specify width and/or
precision instead of numeric literals, in which case additional input links are
used to provide the necessary integer parameter or parameters. See L<Address
Specification> for information on specifying links.
The formatted string is written to the VAL field. The maximum number of
characters in VAL is given by SIZV, and cannot be larger than 65535. The LEN
field contains the length of the formatted string in the VAL field.
=fields FMT, INP0, INP1, INP2, INP3, INP4, INP5, INP6, INP7, INP8, INP9, VAL, SIZV, LEN
=head3 Output Specification
The output link specified in the OUT field specifies where the printf record is
to write the contents of its VAL field. The link can be a database or channel
access link. If the OUT field is a constant, no output will be written.
See L<Address Specification> for information on specifying links.
In addition, the appropriate device support module must be entered into the DTYP
field.
=fields OUT, DTYP
=head3 Operator Display Parameters
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields NAME, DESC
=cut
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct printfdset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} printfdset;
%
field(VAL,DBF_NOACCESS) {
prompt("Result")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
#=type STRING[SIZV]
#=read Yes
#=write Yes
}
field(SIZV,DBF_USHORT) {
prompt("Size of VAL buffer")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(FMT,DBF_STRING) {
prompt("Format String")
promptgroup("30 - Action")
pp(TRUE)
size(81)
}
=head3 Alarm Parameters
The printf record has the alarm parameters common to all record types.
L<Alarm Fields> lists other fields related to a alarms that are common to all
record types.
The IVLS field specifies a string which is sent to the OUT link if if input
link data are invalid.
=fields IVLS
=cut
field(IVLS,DBF_STRING) {
prompt("Invalid Link String")
promptgroup("30 - Action")
size(16)
initial("LNK")
}
field(INP0,DBF_INLINK) {
prompt("Input 0")
promptgroup("40 - Input")
interest(1)
}
field(INP1,DBF_INLINK) {
prompt("Input 1")
promptgroup("40 - Input")
interest(1)
}
field(INP2,DBF_INLINK) {
prompt("Input 2")
promptgroup("40 - Input")
interest(1)
}
field(INP3,DBF_INLINK) {
prompt("Input 3")
promptgroup("40 - Input")
interest(1)
}
field(INP4,DBF_INLINK) {
prompt("Input 4")
promptgroup("40 - Input")
interest(1)
}
field(INP5,DBF_INLINK) {
prompt("Input 5")
promptgroup("40 - Input")
interest(1)
}
field(INP6,DBF_INLINK) {
prompt("Input 6")
promptgroup("40 - Input")
interest(1)
}
field(INP7,DBF_INLINK) {
prompt("Input 7")
promptgroup("40 - Input")
interest(1)
}
field(INP8,DBF_INLINK) {
prompt("Input 8")
promptgroup("40 - Input")
interest(1)
}
field(INP9,DBF_INLINK) {
prompt("Input 9")
promptgroup("40 - Input")
interest(1)
}
%/* Number of INPx fields defined */
%#define PRINTF_NLINKS 10
}
=head2 Device Support Interface
The record requires device support to provide an entry table (dset) which
defines the following members:
typedef struct {
long number;
long (*report)(int level);
long (*init)(int after);
long (*init_record)(printfRecord *prec);
long (*get_ioint_info)(int cmd, printfRecord *prec, IOSCANPVT *piosl);
long (*write_string)(printfRecord *prec);
} printfdset;
The module must set C<number> to at least 5, and provide a pointer to its
C<write_string()> routine; the other function pointers may be C<NULL> if their
associated functionality is not required for this support layer.
Most device supports also provide an C<init_record()> routine to configure the
record instance and connect it to the hardware or driver support layer.
=head2 Device Support for Soft Records
A soft device support module Soft Channel is provided for writing values to
other records or other software components.
Device support for DTYP C<stdio> is provided for writing values to the stdout,
stderr, or errlog streams. C<INST_IO> addressing C<@stdout>, C<@stderr> or
C<@errlog> is used on the OUT link field to select the desired stream.
=cut

View File

@@ -42,7 +42,7 @@ The string input record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 Read Parameters
=head3 Input Specification
The INP field determines where the string input record gets its string. It can
be a database or channel access link, or a constant. If constant, the VAL field
@@ -112,8 +112,6 @@ monitors for VAL. If VAL is not equal to OVAL, then monitors are triggered.
=fields OVAL
The following fields are used to operate the string input in the simulation
mode. See L<Simulation Mode> for more information on simulation mode fields.
@@ -251,15 +249,48 @@ routines are primarily interested in the following fields:
=fields PACT, DPVT, UDF, VAL, INP
=head3 Device Support Routines (devSiSoft.c)
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
long init_record(stringinRecord *prec)
long init_record(dbCommon *prec)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. C<cmd> has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 read_stringin
long read_stringin(stringinRecord *prec)
@@ -276,17 +307,11 @@ This routine must provide a new input value. It returns the following values:
=head3 Device Support for Soft Records
The C<<< Soft Channel >>> module places a value directly in VAL.
The C<<< Soft Channel >>> module reads a value directly into VAL.
If the INP link type is constant, the double constant, if non-zero, is converted
to a string and stored into VAL by C<init_record()>, and UDF is set to FALSE. If
the INP link type is PV_LINK, then dbCaAddInlink is called by C<init_record()>.
read_stringin calls recGblGetLinkValue to read the current value of VAL. See
L<Soft Input>.
If the return status of recGblGetLinkValue is zero, then read_stringin sets UDF
to FALSE. The status of recGblGetLinkValue is returned.
Device support for DTYP C<getenv> is provided for retrieving strings from environment variables.
C<INST_IO> addressing C!!@<environment variable> !!is used on the C<INP> link field to select the
desired environment variable.
=cut

View File

@@ -48,7 +48,7 @@ explains how these fields are used.
The string output record must specify from where it gets its desired output
string. The first field that determines where the desired output originates is
the output mode select (OSML) field, which can have two possible value: C<<<
the output mode select (OMSL) field, which can have two possible value: C<<<
closed_loop >>> or C<<< supervisory >>>. If C<<< supervisory >>> is specified,
DOL is ignored, the current value of VAL is written, and the VAL can be changed
externally via dbPuts at run-time. If C<<< closed_loop >>> is specified, the VAL
@@ -80,7 +80,7 @@ for information on specifying links.
menu(menuOmsl)
}
=head3 Write Parameters
=head3 Output Specification
The output link specified in the OUT field specifies where the string output
record is to write its string. The link can be a database or channel access
@@ -334,7 +334,47 @@ primarily interested in the following fields:
=fields PACT, DPVT, NSEV, NSTA, VAL, OUT
=head3 Device Support Routines (devSoSoft.c)
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
long init_record(dbCommon *prec)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. C<cmd> has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 write_stringout
@@ -354,11 +394,9 @@ This routine must output a new value. It returns the following values:
The C<<< Soft Channel >>> device support module writes the current value of VAL.
If the OUT link type is PV_LINK, then dbCaAddInlink is called by
C<init_record()>.
write_so calls recGblPutLinkValue to write the current value of VAL. See
L<Soft Output>.
Device support for DTYP C<stdio> is provided for writing values to the stdout,
stderr, or errlog streams. C<INST_IO> addressing C<@stdout>, C<@stderr> or
C<@errlog> is used on the OUT link field to select the desired stream.
=cut

View File

@@ -49,7 +49,7 @@ L<Address Specification>
for information on specifying links.
In addition, the DTYP field must specify a device support module. Currently, the
only device support module is C<<< Soft Channel >>>.
only device support module is C<Soft Channel>.
=fields INP, DTYP
@@ -59,13 +59,13 @@ These parameters determine the number of array elements (the array length) and
the data type of those elements. The Field Type of Value (FTVL) field determines
the data type of the array.
The user specifies the maximum number of elements allowed in the subarray in the
MALM field. Generally, the number should be equal to the number of elements of
the Waveform array (found in the Waveform's NELM field). The MALM field is used
to allocate memory. The subArray's Number of Elements (NELM) field is where the
user specifies the actual number of elements that the subArray will contain. It
should of course be no greater than MALM; if it is, the record processing
routine sets it equal to MALM.
The user specifies the maximum number of elements that can be read into the
subarray in the MALM field. This number should normally be equal to the number
of elements of the Waveform array (found in the Waveform's NELM field). The MALM
field is used to allocate memory. The subArray's Number of Elements (NELM) field
is where the user specifies the actual number of elements that the subArray will
extract. It should of course be no greater than MALM; if it is, the record
processing routine sets it equal to MALM.
The INDX field determines the offset of the subArray record's array in relation
to the Waveform's. For instance, if INDX is 2, then the subArray will read NELM
@@ -83,15 +83,15 @@ display the value and other parameters of the subarray record either textually
or graphically.
EGU is a string of up to 16 characters describing the engineering units (if any)
of the values which the subArray holds. It is retrieved by the C<<< get_units
>>> record support routine.
of the values which the subArray holds. It is retrieved by the C<get_units()>
record support routine.
The HOPR and LOPR fields set the upper and lower display limits for the
sub-array elements. Both the C<<< get_graphic_double >>> and C<<<
get_control_double >>> record support routines retrieve these fields.
sub-array elements. Both the C<get_graphic_double()> and C<get_control_double()>
record support routines retrieve these fields.
The PREC field determines the floating point precision with which to display
VAL. It is used whenever the C<<< get_precision >>> record support routine is
VAL. It is used whenever the C<get_precision()> record support routine is
called.
See L<Fields Common to All Record Types>
@@ -110,9 +110,9 @@ record types.
These fields are not configurable by the user. They are used for the record's
internal processing or to represent the current state of the record.
The NORD field holds a counter of the number of elements read into the array. It
can be less than NELM even after the array is full if NELM exceeds the number of
existing elements in the referenced array, i.e., the Waveform's array.
The NORD field holds the number of elements that were actually read into the
array. It will be less than NELM whenever the sum of the NELM and INDX fields
exceeds the number of existing elements found in the source array.
BPTR contains a pointer to the record's array.
@@ -150,14 +150,14 @@ See L<Record Processing>.
long (*cvt_dbaddr)(struct dbAddr *paddr)
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
This is called by C<dbNameToAddr()>. It makes the dbAddr structure refer to the
actual buffer holding the result.
=head4 get_array_info
long (*get_array_info)(struct dbAddr *paddr, long *no_elements, long *offset)
Retrieves NELM.
Retrieves NORD.
=head4 put_array_info
@@ -171,14 +171,14 @@ Sets NORD.
For the elements in the array, this routine routines HOPR and LOPR. For the INDX
field, this routine returns MALM - 1 and 0. For NELM, it returns MALM and 1. For
other fields, it calls C<<< recGblGetGraphicDouble() >>>.
other fields, it calls C<recGblGetGraphicDouble()>.
=head4 get_control_double
long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p)
For array elements, this routine retrieves HOPR and LOPR. Otherwise, C<<<
recGblGetControlDouble() >>> is called.
For array elements, this routine retrieves HOPR and LOPR. Otherwise,
C<recGblGetControlDouble()> is called.
=head4 get_units
@@ -212,13 +212,13 @@ INDX is greater than or equal to MALM it is set to MALM-1.
=item 3.
Call device support read routine. This routine is expected to place the desired
sub-array at the beginning of the buffer and set NORD to the number of elements
of the sub-array that were read.
Call the device support's C<read_sa()> routine. This routine is expected to
place the desired sub-array at the beginning of the buffer and set NORD to the
number of elements of the sub-array that were read.
=item 4.
If PACT has been changed to TRUE, the device support read routine has started
If PACT has been changed to TRUE, the device support read operation has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE. Otherwise, process sets PACT TRUE at
this time. This asynchronous processing logic is not currently used but has been
@@ -305,12 +305,11 @@ sub-array were acquired.
=head3 Device Support For Soft Records
Only the device support module C<<< Soft Channel >>> is currently provided. The
INP link type must be either DB_LINK or CA_LINK.
Only the device support module C<Soft Channel> is currently provided.
=head4 Soft Channel
INP is expected to point to a waveform record.
INP is expected to point to an array field of a waveform record or similar.
=cut

View File

@@ -303,7 +303,9 @@ interested in the following fields:
Device support consists of the following routines:
=head4 long report(int level)
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
@@ -313,7 +315,9 @@ information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 long init(int after)
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
@@ -323,14 +327,14 @@ with C<after> set to 1.
=head4 init_record
init_record(precord)
long init_record(dbCommon *precord)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt)
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. cmd has the value (0,1) if the
@@ -339,7 +343,7 @@ provided for any device type that can use the ioEvent scanner.
=head4 read_wf
read_wf(precord)
long read_wf(waveformRecord *prec)
This routine must provide a new input value. It returns the following values:
@@ -361,38 +365,11 @@ The C<<< Soft Channel >>> device support module is provided to read values from
other records and store them in arrays. If INP is a constant link, then read_wf
does nothing. In this case, the record can be used to hold arrays written via
dbPuts. If INP is a database or channel access link, the new array value is read
from the link. NORD is set.
from the link. NORD is set to the number of items in the array.
This module places a value directly in VAL.
If the INP link type is constant, then NORD is set to zero. If the INP link type
is PV_LINK, then dbCaAddInlink is called by C<init_record()>.
read_wf calls recGblGetLinkValue which performs the following steps:
=over
=item *
If the INP link type is CONSTANT recGblGetLinkValue does nothing.
=item *
If the INP link type is DB_LINK, then dbGetLink is called to obtain a new input
value. If dbGetLink returns an error, a LINK_ALARM with a severity of
INVALID_ALARM is raised.
=item *
If the INP link type is CA_LINK, then dbCaGetLink is called to obtain a new
input value. If dbCaGetLink returns an error, a LINK_ALARM with a severity of
INVALID_ALARM is raised.
=item *
NORD is set to the number of values returned and read_wf returns.
=back
If the INP link type is constant, then NORD is set to zero.
=cut

View File

@@ -0,0 +1,62 @@
package EPICS::PodHtml;
use strict;
use warnings;
use base 'Pod::Simple::HTML';
sub encode_entities {
my ($self, $str) = @_;
my %entities = (
q{>} => 'gt',
q{<} => 'lt',
q{'} => '#39',
q{"} => 'quot',
q{&} => 'amp'
);
my $ents = join '', keys %entities;
$str =~ s/([$ents])/'&' . $entities{$1} . ';'/ge;
return $str;
}
# Translate L<link text|filename/Section name>
# into <a href="filename.html#Section-name">link text</a>
sub do_pod_link {
# EPICS::PodHtml object and Pod::Simple::PullParserStartToken object
my ($self, $link) = @_;
my $ret;
# Links to other EPICS POD files
if ($link->tagname eq 'L' and $link->attr('type') eq 'pod') {
my $to = $link->attr('to');
my $section = $link->attr('section');
$section = $self->section_escape($section)
if defined $section and length($section .= ''); # (stringify)
$ret = (defined $to and length $to) ? "$to.html" : '';
$ret .= "#$section" if defined $section and length $section;
}
else {
# all other links are generated by the parent class
$ret = $self->SUPER::do_pod_link($link);
}
return $ret;
}
# Generate the same section IDs as Pod::Simple::XHTML
sub section_name_tidy {
my($self, $section) = @_;
$section =~ s/^\s+//;
$section =~ s/\s+$//;
$section =~ tr/ /-/;
$section =~ s/[[:cntrl:][:^ascii:]]//g; # drop crazy characters
$section = $self->unicode_escape_url($section);
$section = '_' unless length $section;
return $section;
}
1;

View File

@@ -0,0 +1,40 @@
package EPICS::PodXHtml;
use strict;
use warnings;
use base 'Pod::Simple::XHTML';
BEGIN {
if ($Pod::Simple::XHTML::VERSION < '3.16') {
# encode_entities() wasn't a method, add it
our *encode_entities = sub {
my ($self, $str) = @_;
my %entities = (
q{>} => 'gt',
q{<} => 'lt',
q{'} => '#39',
q{"} => 'quot',
q{&} => 'amp'
);
my $ents = join '', keys %entities;
$str =~ s/([$ents])/'&' . $entities{$1} . ';'/ge;
return $str;
}
}
}
# Translate L<link text|filename/Section name>
# into <a href="filename.html#Section-name">link text</a>
sub resolve_pod_page_link {
my ($self, $to, $section) = @_;
my $ret = defined $to ? "$to.html" : '';
$ret .= '#' . $self->idify($self->encode_entities($section), 1)
if defined $section;
return $ret;
}
1;

View File

@@ -2,7 +2,7 @@
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP=../..
@@ -17,6 +17,8 @@ PERL_MODULES += EPICS/Release.pm
PERL_MODULES += EPICS/Readfile.pm
PERL_MODULES += EPICS/Getopts.pm
PERL_MODULES += EPICS/macLib.pm
PERL_MODULES += EPICS/PodHtml.pm
PERL_MODULES += EPICS/PodXHtml.pm
PERL_MODULES += DBD.pm
PERL_MODULES += DBD/Base.pm
@@ -50,6 +52,7 @@ PERL_SCRIPTS += mkmf.pl
PERL_SCRIPTS += munch.pl
PERL_SCRIPTS += replaceVAR.pl
PERL_SCRIPTS += tap-to-junit-xml.pl
PERL_SCRIPTS += testFailures.pl
PERL_SCRIPTS += useManifestTool.pl
PERL_SCRIPTS += dbdToMenuH.pl
@@ -82,8 +85,7 @@ EXPAND += $(PKGCONFIG:%=%@)
CLEANS += epics-base-$(T_A).pc@
include $(TOP)/configure/RULES
epics-base-$(T_A).pc@: ../epics-base-arch.pc@
@$(RM) $@
@$(CP) $< $@

View File

@@ -242,24 +242,26 @@ sub checkRelease {
my $latest = AbsPath($macros{$app});
my %paths = ($latest => $app);
foreach $app (@modules) {
my $path = AbsPath($macros{$app});
my $val = $macros{$app};
next if $val eq '';
my $path = AbsPath($val);
if ($path ne $latest && exists $paths{$path}) {
my $prev = $paths{$path};
print "\n" unless ($status);
print "This application's RELEASE file(s) define\n";
print "\t$app = $macros{$app}\n";
print "after but not adjacent to\n\t$prev = $macros{$prev}\n";
print "\t$app = $val\n";
print "and\n\t$prev = $macros{$prev}\n";
print "both of which resolve to $path\n"
if $path ne $macros{$app} || $path ne $macros{$prev};
if $path ne $val || $path ne $macros{$prev};
$status = 2;
}
$paths{$path} = $app;
$latest = $path;
}
if ($status == 2) {
print "Module definitions that share paths must be grouped together.\n";
print "Either remove a definition, or move it to a line immediately\n";
print "above or below the other(s).\n";
print "Module definitions that share the same path must have their\n";
print "first definitions grouped together. Either remove a module,\n";
print "or arrange them so all those with that path are adjacent.\n";
print "Any non-module definitions belong in configure/CONFIG_SITE.\n";
$status = 1;
}

View File

@@ -18,26 +18,9 @@ use EPICS::macLib;
use EPICS::Readfile;
BEGIN {
$::XHTML = eval "require Pod::Simple::XHTML; 1";
$::ENTITIES = eval "require HTML::Entities; 1";
$::XHTML = eval "require EPICS::PodXHtml; 1";
if (!$::XHTML) {
require Pod::Simple::HTML;
}
if (!$::ENTITIES) {
my %entities = (
q{>} => 'gt',
q{<} => 'lt',
q{'} => '#39',
q{"} => 'quot',
q{&} => 'amp',
);
sub encode_entities {
my $str = shift;
my $ents = join '', keys %entities;
$str =~ s/([ $ents ])/'&' . ($entities{$1} || sprintf '#x%X', ord $1) . ';'/xge;
return $str;
}
require EPICS::PodHtml;
}
}
@@ -130,7 +113,7 @@ my $contentType =
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >';
if ($::XHTML) {
$podHtml = Pod::Simple::XHTML->new();
$podHtml = EPICS::PodXHtml->new();
$podHtml->html_doctype(<< '__END_DOCTYPE');
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'
@@ -152,7 +135,7 @@ __END_DOCTYPE
}
} else { # Fall back to HTML
$Pod::Simple::HTML::Content_decl = $contentType;
$podHtml = Pod::Simple::HTML->new();
$podHtml = EPICS::PodHtml->new();
$podHtml->html_css('style.css');
$idify = sub {
@@ -190,7 +173,7 @@ my $pod = join "\n", '=for html <div class="pod">', '',
} $dbd->pod,
'=for html </div>', '';
$podHtml->force_title(encode_entities($title));
$podHtml->force_title($podHtml->encode_entities($title));
$podHtml->perldoc_url_prefix('');
$podHtml->perldoc_url_postfix('.html');
$podHtml->output_fh($out);

View File

@@ -9,8 +9,15 @@
use strict;
use warnings;
# To find the EPICS::PodHtml module used below we need to add our lib/perl to
# the lib search path. If the script is running from the src/tools directory
# before everything has been installed though, the search path must include
# our source directory (i.e. $Bin), so we add both here.
use FindBin qw($Bin);
use lib ("$Bin/../../lib/perl", $Bin);
use Getopt::Std;
use Pod::Simple::HTML;
use EPICS::PodHtml;
our ($opt_o);
@@ -27,11 +34,9 @@ if (!$opt_o) {
open my $out, '>', $opt_o or
die "Can't create $opt_o: $!\n";
my $podHtml = Pod::Simple::HTML->new();
my $podHtml = EPICS::PodHtml->new();
$podHtml->html_css('style.css');
$podHtml->perldoc_url_prefix('');
$podHtml->perldoc_url_postfix('.html');
$podHtml->set_source($infile);
$podHtml->output_string(\my $html);
$podHtml->run;

33
src/tools/testFailures.pl Normal file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env perl
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
# This file may appear trivial, but it exists to let the build system
# fail the 'make test-results' target with a nice output including a
# summary of the directories where test failures were reported.
# Test results are collected from the .tap files fed to epicsProve.pl
# which returns with an exit status of 0 (success) if all tests passed
# or 1 (failure) if any of the .tap files contained failed tests.
# When epicsProve.pl indicates a failure, the directory that it was
# running in is appended to the file $(TOP)/.tests-failed which this
# program reads in after all the test directories have been visited.
# The exit status of this program is 1 (failure) if any tests failed,
# otherwise 0 (success).
use strict;
use warnings;
die "Usage: testFailures.pl .tests-failed\n"
unless @ARGV == 1;
open FAILURES, '<', shift or
exit 0;
my @failures = <FAILURES>;
close FAILURES;
print "\nTest failures were reported in:\n",
(map {" $_"} @failures), "\n";
exit 1;