Compare commits

..

83 Commits

Author SHA1 Message Date
Andrew Johnson
448fde0671 Set release version numbers
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 2s
Base / Cross linux-aarch64 (push) Failing after 1s
Base / Cross linux-arm gnueabi (push) Failing after 2s
Base / Cross linux-arm gnueabihf (push) Failing after 1s
Base / CentOS-7 (push) Failing after 2s
Base / Fedora-33 (push) Failing after 1s
Base / Fedora-latest (push) Failing after 2s
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Ub-22 gcc-12 c++20 Werror (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
2023-12-14 16:42:10 -06:00
Andrew Johnson
477e36b1f0 Update submodules to tagged versions 2023-12-14 16:42:10 -06:00
Andrew Johnson
fad830bd14 Remove example sub-module 2023-12-14 16:42:10 -06:00
Andrew Johnson
331df3d7e4 UNRELEASED => 7.0.8 2023-12-14 16:42:10 -06:00
Andrew Johnson
4a53713f37 Update Release Procedures/Checklist 2023-12-14 16:31:42 -06:00
Andrew Johnson
2e6fd505d2 Use epicsSnprintf() for old MSVC compilers 2023-12-14 11:31:36 -06:00
Andrew Johnson
5ecf7d18a8 Clean up Clang 15 sprintf() warnings in libcom and ca 2023-12-13 13:34:25 -06:00
Andrew Johnson
56dbc949ff Add declarations to flex, cleans up Clang 15 warnings. 2023-12-12 13:44:08 -06:00
Simon Rose
6a369acd0b Add newline to help text 2023-12-05 08:05:12 -08:00
Simon Rose
d9d35a4eab Allow auto-declarations for dbdExpand.pl 2023-12-01 09:19:03 -06:00
Ralph Lange
116881ad87 Use split() for fetching last tag with darcs
(setting $/='' breaks reading multi-line into an array)
2023-11-29 09:53:24 -06:00
96857d92bc fix problem with commands returning multiple trailing newlines 2023-11-29 09:53:24 -06:00
Érico Nogueira
0cf8c934f9 Set ASL0 for mbboDirect Bx fields.
Since the record's VAL field is ASL0, it doesn't make sense to gate
writes into the Bx fields with ASL1.
2023-11-29 09:44:03 -06:00
Michael Davidsaver
69d05fe5b0 Add ERROR to error messages 2023-11-26 15:25:09 -08:00
Michael Davidsaver
511bf1ffca const-ify dbLink arrays
external code really should never be modifying pamaplinkType[]
2023-11-25 14:52:16 -08:00
Uchenna Ezeobi
7a7028de56 Config: Fixed Hard coded LDFLAGS in MVME2500 2023-11-17 15:20:32 -06:00
Michael Davidsaver
7a65c001ce update submodules 2023-11-15 07:31:53 -08:00
Michael Davidsaver
0bc6ff3d4c release notes 2023-11-07 16:00:46 -08:00
Michael Davidsaver
f2fe9d1203 bi "Raw Soft Channel" use MASK
If set, apply MASK to value read into RVAL.
2023-11-07 15:53:41 -08:00
Michael Davidsaver
ffc2d0f23a incorrect error check on GetStdHandle()
Likely inconsequential as GetConsoleMode() should
return 0 when given an invalid handle.
2023-11-07 15:53:41 -08:00
Michael Davidsaver
a352865df9 print ANSI escapes to stderr
unconditionally print ANSI some escapes (to colorize errors)
to the stderr stream.
2023-11-07 15:53:22 -08:00
Michael Davidsaver
63740f2edd colorize more errlog messages 2023-11-07 15:53:22 -08:00
Jeremy Lorelli
f4be9daf4d Null check callback function in callbackRequest
Previously, calling callbackRequest(pcallback), where pcallback->callback
is NULL, would result in a crash on one of the callback threads.
2023-11-07 15:17:04 -08:00
Michael Davidsaver
3fa1932345 update ci-scripts 2023-11-07 15:14:09 -08:00
Michael Davidsaver
95bd5453d9 dbRecordField() add "did you mean..." hint for unknown field 2023-11-01 09:52:32 -05:00
Michael Davidsaver
eb3f8a004c const-ify dbCopyEntry() and dbCopyEntryContents() 2023-11-01 09:52:32 -05:00
Michael Davidsaver
9f868a1074 avoid hang during concurrent db_cancel_event()
cf. fab8fd7102
2023-11-01 09:24:44 -05:00
Michael Davidsaver
b41787b6bf doc 2023-10-22 17:42:36 -07:00
19b232545c gha: turn most warnings into errors in github build 2023-10-22 17:42:36 -07:00
Michael Davidsaver
2ca70d3aa2 iocsh: keep history file 2023-10-22 17:42:36 -07:00
JJL772
395015aac4 Com: Make STATIC_ASSERT macro typedefs unique 2023-10-22 17:42:36 -07:00
Michael Davidsaver
92cae86ff2 dbRecordsOnceOnly allow append only with "*"
with

> record(ai, "myrec") {}

dbRecordsOnceOnly!=0 currently disallows appending fields with either form:

> record("*", "myrec") {} # error
> record(ai, "myrec") {}  # error

Change the meaning such that dbRecordsOnceOnly!=0
allways allows appending when explicitly intended (rtype "*").

> record("*", "myrec") {} # allowed
> record(ai, "myrec") {}  # error

Also clearly label this parse error.
2023-10-22 17:42:36 -07:00
Jack Harper
49ea46ee5e iocsh: add comment to cvtArg explaining default iocsharg behaviour 2023-10-22 17:42:36 -07:00
Michael Davidsaver
df908f299b remove unused local 2023-10-22 17:42:36 -07:00
AlexWells
6dec68554c iocsh: Add underline separator between help outputs
Also tweaks the overall format of the message a bit.
Add tests for new help output format
2023-10-22 17:42:36 -07:00
Michael Davidsaver
badd8f518d update modules/pvData 2023-10-22 17:42:35 -07:00
Michael Davidsaver
766c9906b5 update ci-scripts 2023-10-22 14:46:28 -07:00
Jeremy Lorelli
60fa2d31da libCom: Fix buggy pointer dereference in postfix() 2023-09-26 09:52:13 -07:00
Michael Davidsaver
88ea1507f4 Fix compile w/ vs2012 2023-09-22 08:20:27 -07:00
Emilio Perez
8c08c57247 Allow adding error symbols after early initialization
This was acomplished by making errSymbolAdd add the error symbol directly
into the global hash table and removing errnumlist which is not needed
anymore.

Unit tests were added for checking the following cases:
- Adding a valid symbol and checking that it exists (fixed by this change)
- Getting an existing error symbol
- Getting a non existing error symbol
- Adding an invalid error symbol (fixed by this change)
- Adding an error symbol with a code that already
  exists (fixed by this change)

Therefore, issue #268 was fixed

error: statically allocate error symbol hash table

This will allow calling errSymbolAdd before errSymBld, therefore, a
function adding error symbols can now be run before iocInit or errlogInit

error: add a constant for the minimum module number

Make adding an identical error symbol not fail

A test case was also added which test that adding an error symbol
with same error code and message as one added before will not fail

Add locking to error symbol table

This protects the cases of:
- simultaneously adding and requesting of an error symbol
- simultaneously adding many error symbols

Update release notes regarding adding error symbols
2023-09-22 08:20:19 -07:00
Michael Davidsaver
45b3bce515 epicsThreadShow() zombies
Flag when the thread has returned, but the tracking
struct is still around.  eg. in need of joining.
2023-09-22 08:19:25 -07:00
Érico Nogueira
7c4a21eab4 libCom: detect support for backtrace() with __has_include.
This is necessary in order to build epics-base with musl libc, for
example, and any other C libraries which don't include this
functionality. In order to not regress builds with older compilers, we
still support the uclibc check. Furthermore, it has been checked that
uclibc-ng (the maintained version of uclibc) doesn't install the
<execinfo.h> header when the functionality is disabled [1] [2].

To avoid repetition, we don't define HAS_EXECINFO to 0 when it is not
available.

[1] https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Makefile.in?id=cdb07d2cd52af39feb425e6d36c02b30916b9f0a#n224
[2] https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Makefile.in?id=cdb07d2cd52af39feb425e6d36c02b30916b9f0a#n277
2023-09-21 08:18:49 -07:00
Michael Davidsaver
fab8fd7102 dbEvent: handle multiple db_event_cancel()
Allow for multiple db_event_cancel() (concurrent or
self-cancel) prior to event_task wakeup.

In db_event_cancel(), immediate free() only if idle
(not queued or in progress).  Otherwise, defer free()
to event task.  Avoids need to immediately expunge
canceled event from queue.  Allow event task to
process canceled events as normal (except no user_sub)
until npend==0.
2023-09-21 08:18:49 -07:00
Michael Davidsaver
3d25756065 privatize evSubscrip 2023-09-21 08:18:49 -07:00
Michael Davidsaver
5aca4c684c dbEvent minor 2023-09-14 08:54:40 +02:00
Michael Davidsaver
39b5c01c5d minor 2023-09-14 08:54:40 +02:00
Michael Davidsaver
3b22e5f710 doc dbLock.h 2023-09-14 08:54:40 +02:00
Michael Davidsaver
9f660f2238 add initHookAtPrepare 2023-09-05 08:54:48 +02:00
Michael Davidsaver
ca9c957e62 doc add page for initHooks.h 2023-09-05 08:53:40 +02:00
Michael Davidsaver
8488c9e891 initHookName() assert length
basic compile time consistency check.
2023-09-05 08:53:07 +02:00
Michael Davidsaver
1f2edb69d2 silence -Wformat-security for printfRecord
we know what we are doing... right?
2023-09-05 08:53:03 +02:00
Michael Davidsaver
fe3ee85aee doc errSymTbl.h 2023-09-05 08:52:58 +02:00
Michael Davidsaver
a74789d9c0 db: decimate and sync filters don't drop DBE_PROPERTY 2023-08-28 14:17:00 +02:00
Michael Davidsaver
7830345e59 move IocshRegister() to iocshInit()
No need for both global ctor and lazy init
2023-08-28 14:17:00 +02:00
Michael Davidsaver
1595ed8860 quieting clang-tidy, non-functional changes
Changes to syntax which should not effect generated code
2023-08-28 14:17:00 +02:00
Michael Davidsaver
d97943b697 timerPrivate.h: mark override/final
Clarify the class hierarchy by decorating types and
method override and/or final whenever possible.
Does not change the hierarchy.
2023-08-28 14:17:00 +02:00
Michael Davidsaver
f8f4376594 ~fdRegForOldFdmgr() can't throw doubleDelete
Exceptions can't actually be thrown from a
C++ class destructor.
2023-08-28 14:17:00 +02:00
Érico Nogueira
df397f4ade fix typo in boRecord.dbd.pod 2023-08-28 14:17:00 +02:00
Zainab Olalekan
7fd690e53e Fix libcom test failure on RTEMS 2023-08-28 14:17:00 +02:00
Andrew Johnson
bc5d347bb2 Call perror() before close(), add detail to messages 2023-08-28 14:17:00 +02:00
Chris Johns
3ea29f581b rtems: Close NTP socket 2023-08-28 14:17:00 +02:00
AlexWells
6de82bb0fd Additional help messages for iocsh
Henrique Silva <henrique.silva@ess.eu>
2023-08-28 13:24:16 +02:00
e1a51e2839 extra parentheses around second sizeof to silence "does not compute number of elements" warning 2023-08-28 13:24:16 +02:00
Michael Davidsaver
0f59d823d3 appveyor remove skip_commits: 2023-08-28 13:24:16 +02:00
Ralph Lange
00dc55b8a2 Fix usage info in .tools/make-tar.sh 2023-08-08 10:29:09 +02:00
Rolf Keitel
524f81b8bd Doc updates to PINI, PHAS & EVNT 2023-07-25 11:36:44 -05:00
Michael Davidsaver
80e62031e9 doc 2023-07-23 08:43:32 -07:00
Minijackson
d87fd0db01 Fix MAKEFLAGS parsing with Make 4.4+
Since Make version 4.4, MAKEFLAGS also contains long options and
overridden variables on the command-line[1].

[1]: https://git.savannah.gnu.org/cgit/make.git/tree/NEWS?h=4.4#n67

This means that parsing by filtering out '--%' doesn't work reliably
anymore, since it doesn't remove overrides:

Running 'make VAR=quacks' gives 'MAKEFLAGS=" -- VAR=quacks"', and
'checkflags' would understand that flags -q, -s, ... were set.

This would get transmitted below into 'QUIET_FLAGS' and
'QUESTION_FLAG', then passed to the 'genVersionHeader.pl' as '-i' and
'-q'.

The result would be that 'genVersionHeader.pl' would never create the
version header (only check for its up-to-date status), leading to
confusing errors:

  ../misc/epicsRelease.c:25:32: error: expected ')' before 'EPICS_VCS_VERSION'
     25 |     printf ( "## %s\n", "Rev. " EPICS_VCS_VERSION );
        |            ~                   ^~~~~~~~~~~~~~~~~~

The NEWS file[1] recommends using 'firstword', but unfortunately this is
not compatible with GNUMake < 3.82.
2023-07-22 08:36:43 -07:00
Ralph Lange
6636b4b9e7 libCom: check calloc() failure in RTEMS-posix/osdMessageQueue.c 2023-07-22 08:35:59 -07:00
Ralph Lange
b51d1de283 libCom: fix possible memory leak in RTEMS-posix/osdMessageQueue.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
38c99df2e0 libCom: fix possible memory leaks in iocLogServer.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
688195a273 libCom: handle realloc() failures correctly in macEnv.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
d691acc001 ca: init local variable in catime.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
059d32a975 db: init struct members in dbChannel.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Henrique Silva
5c99031157 Add missing AFTC documentation to records
Fixes #313
2023-07-22 08:33:19 -07:00
Henrique Silva
a01c671399 Add missing HYST field documentation to longin record 2023-07-22 08:33:19 -07:00
Minijackson
b2c80efd33 release notes: link release notes from submodules'
fixes #226
2023-07-22 08:33:08 -07:00
Karl Vestin
39b6fa26da Added unit test for binary output record type 2023-07-22 08:32:16 -07:00
Karl Vestin
3ee6097ab7 Fixes #361 2023-07-22 08:30:44 -07:00
Emilio Perez
500a57738b Validate target record name when creating an alias
This fixes issue #312 by printing an error when a field is specified
2023-07-22 08:29:09 -07:00
AlexWells
f488765631 Add tests for PR#310
Also add missing NULL/empty checks
2023-07-22 08:28:25 -07:00
Sebastian Marsching
3a2d225682 Detect error in fprintf and return (fixes #309).
fprintf returns a negative value in order to signal an error. We have to
detect this situation in epicsStrPrintEscaped and return a negative
when fprintf returns a negative value in order to give the calling code
a chance to detect this situation.

The old implementation (of simply accumulating the return values of
fprintf) was wrong anyway, because it would not only lead to an error in
fprintf to be lost but would also cause the returned number to be too
small (not representing the actual number of bytes written) in such a
case.

The only case where the old implementation would work correctly was when
all calls to fprintf succeeded or all these calls failed.
2023-07-22 08:27:32 -07:00
Doug Murray
1d056c6fe4 Add support for CA tools timeout from environment variable EPICS_CLI_TIMEOUT 2023-07-22 08:24:22 -07:00
155 changed files with 3037 additions and 806 deletions

View File

@@ -25,22 +25,6 @@ init:
# Set clone depth (do not fetch complete history)
clone_depth: 5
# Skip commits affecting only specific files
skip_commits:
files:
# Removed - 'documentation/*'
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
# the last commit pushed to a PR only updates the Release Notes the whole
# PR build gets skipped. GitHub Actions looks at the complete list
# of files changed since its last build, which is much more useful.
- 'startup/*'
- '.github/*'
- '.tools/*'
- '.gitattributes'
- '.lgtm.yml'
- '**/*.html'
- '**/*.md'
#---------------------------------#
# build matrix configuration #
#---------------------------------#

View File

@@ -32,22 +32,6 @@ init:
# Set clone depth (do not fetch complete history)
clone_depth: 5
# Skip commits affecting only specific files
skip_commits:
files:
# Removed - 'documentation/*'
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
# the last commit pushed to a PR only updates the Release Notes the whole
# PR build gets skipped. GitHub Actions looks at the complete list
# of files changed since its last build, which is much more useful.
- 'startup/*'
- '.github/*'
- '.tools/*'
- '.lgtm.yml'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
#---------------------------------#
# build matrix configuration #
#---------------------------------#

2
.ci

Submodule .ci updated: 1e0e326f74...130e88b709

View File

@@ -51,6 +51,25 @@ jobs:
matrix:
# Job names also name artifacts, character limitations apply
include:
- os: ubuntu-22.04
cmp: gcc-12
name: "Ub-22 gcc-12 c++20 Werror"
# Turn all warnings into errors,
# except for those we could not fix (yet).
# Remove respective -Wno-error=... flag once it is fixed.
extra: "CMD_CXXFLAGS=-std=c++20
CMD_CPPFLAGS='-fdiagnostics-color
-Werror
-Wno-error=deprecated-declarations
-Wno-error=stringop-truncation
-Wno-error=restrict
-Wno-error=sizeof-pointer-memaccess
-Wno-error=nonnull
-Wno-error=dangling-pointer
-Wno-error=format-overflow
-Wno-error=format-security
-Wno-error=stringop-overread'"
- os: ubuntu-20.04
cmp: gcc
configuration: default

1
.gitignore vendored
View File

@@ -17,3 +17,4 @@ O.*/
*.log
.*.swp
.DS_Store
.iocsh_history

View File

@@ -20,9 +20,9 @@ maybedie() {
usage() {
cat <<EOF >&2
usage: $0 [-v] [-s] <rev> [<outfile> [<prefix>]]
usage: $0 [-v] [-d] <rev> [<outfile> [<prefix>]]
<rev> may be any git revision spec. (tag, branch, or commit id).
<rev> may be any git revision spec. (tag or, using -d, branch or commit id).
If provided, <outfile> must end with ".tar", ".tar.gz" or ".tar.bz2".
If <outfile> is omitted, "base-<rev>.tar.gz" will be used.

View File

@@ -48,15 +48,15 @@ EPICS_VERSION = 7
EPICS_REVISION = 0
# 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 in the official EPICS version number if zero
EPICS_PATCH_LEVEL = 1
EPICS_PATCH_LEVEL = 0
# Immediately after an official release the EPICS_PATCH_LEVEL is incremented
# and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions)
EPICS_DEV_SNAPSHOT=-DEV
EPICS_DEV_SNAPSHOT=
# No changes should be needed below here

View File

@@ -6,7 +6,7 @@ EPICS_CA_MAINTENANCE_VERSION = 3
# Development flag, set to zero for release versions
EPICS_CA_DEVELOPMENT_FLAG = 1
EPICS_CA_DEVELOPMENT_FLAG = 0
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -83,8 +83,9 @@ IOCS_APPL_TOP = $(INSTALL_ABSOLUTE)
#-------------------------------------------------------
# How to portably check the flags to make
makeflags := $(firstword $(filter-out -,$(filter-out --%,$(MAKEFLAGS))))
define checkflags
make-$1 = $(findstring $1,$(filter-out --%,$(MAKEFLAGS)))
make-$1 := $(findstring $1,$(makeflags))
endef
# This is extensible to most single letter flags:
$(foreach flag,s q, $(eval $(call checkflags,$(flag))))

View File

@@ -1,12 +1,12 @@
# Version number for the database APIs and shared library
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 22
EPICS_DATABASE_MAINTENANCE_VERSION = 1
EPICS_DATABASE_MINOR_VERSION = 23
EPICS_DATABASE_MAINTENANCE_VERSION = 0
# Development flag, set to zero for release versions
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -1,12 +1,12 @@
# Version number for the libcom APIs and shared library
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 22
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
EPICS_LIBCOM_MINOR_VERSION = 23
EPICS_LIBCOM_MAINTENANCE_VERSION = 0
# Development flag, set to zero for release versions
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -22,7 +22,7 @@ ARCH_DEP_CFLAGS += -DRTEMS_HAS_ALTIVEC
#OP_SYS_LDLIBS += -lbspExt #does not use posix stuff ... want to ignore
OP_SYS_LDLIBS += -Wl,--gc-sections
#ARCH_DEP_LDFLAGS = -mcpu=8540 -meabi -msdata=sysv -mstrict-align -mspe -mabi=spe -mfloat-gprs=double
ARCH_DEP_LDFLAGS = -L$(RTEMS_BASE)/powerpc-rtems5/qoriq_e500/lib
ARCH_DEP_LDFLAGS = -L$(RTEMS_BASE)/$(GNU_TARGET)$(RTEMS_VERSION)/$(RTEMS_BSP)/lib
MUNCH_SUFFIX = .img
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))

View File

@@ -9,11 +9,73 @@ important to read more than just the first section to understand everything that
has changed in each release.
The PVA submodules each have their own individual sets of release notes which
should also be read to understand what has changed since earlier releases.
should also be read to understand what has changed since earlier releases:
**This version of EPICS has not been released yet.**
- [normativeTypes](https://github.com/epics-base/normativeTypesCPP/blob/master/documentation/RELEASE_NOTES.md)
- [pvAccess](http://epics-base.github.io/pvAccessCPP/pvarelease_notes.html)
- [pvData](http://epics-base.github.io/pvDataCPP/release_notes.html)
- [pvDatabase](https://github.com/epics-base/pvDatabaseCPP/blob/master/documentation/RELEASE_NOTES.md)
- [pva2pva](https://epics-base.github.io/pva2pva/release_notes.html)
- [pvaClient](https://github.com/epics-base/pvaClientCPP/blob/master/documentation/RELEASE_NOTES.md)
## Changes made on the 7.0 branch since 7.0.7
## EPICS Release 7.0.8
### bi "Raw Soft Channel" use MASK
If MASK is non-zero, The raw device support will now apply MASK to the
value read into RVAL.
eg. allows extraction of a bit from an input integer.
```
record(longin, "integer") {
field(VAL, "0xff")
}
record(bi, "bit1") {
field(DESC, "extract bit 1")
field(DTYP, "Raw Soft Channel")
field(INP , "integer")
field(MASK, "0x2")
field(ZNAM, "Clear")
field(ONAM, "Set")
}
```
### ANSI escapes in stderr
ANSI escape charactor sequences may now be printed to the stderr stream.
These escapes will appear in logs captured from that stream.
Tools which parse and/or render these logs may need to be adjusted to
either strip out the escapes, or to translate them into markup.
(see [ansi2html](https://pypi.org/project/ansi2html/) for example)
### Allow explicit append with `dbRecordsOnceOnly!=0`
Previously setting `dbRecordsOnceOnly!=0` prevented any further changes to a record via a .db file. eg.
```
record(ai, "myrec") {}
```
`dbRecordsOnceOnly!=0` previously disallowed appending fields with either form:
```
record("*", "myrec") {} # error
record(ai, "myrec") {} # error
```
Beginning with this release, `dbRecordsOnceOnly!=0` allows appending when explicitly intended (when record type is `"*"`).
```
record("*", "myrec") {} # allowed
record(ai, "myrec") {} # error
```
### Add `$EPICS_CLI_TIMEOUT`
Add support for CA tools timeout from environment variable `$EPICS_CLI_TIMEOUT`
which sets the default the default timeout for `caget` et al.
The `-w` argument continues to take precedence.
### Fixed leak from a non-EPICS thread on WIN32
@@ -50,7 +112,7 @@ Previously, if a subRecord has an invalid `INP*` link, it was silently failing
(and not running the proc function). Now the the status code returned by the
subroutine is returned from `dbProcess()`.
### COMMANDLINE_LIBRARY fallback to GNU_DIR
### COMMANDLINE\_LIBRARY fallback to GNU\_DIR
Fall back to the previous behavior when searching for `readline.h` with older compilers.
@@ -89,6 +151,10 @@ and string formats, some of which support full nanosecond precision.
More information is included in the filters documentation, which can be found in
the `html/filters.html` document that is generated during the build
### Allow adding new error symbols at any time
`errSymbolAdd` can now be called after early initialization.
### Add conditional output (OOPT) to the longout record
The longout record can now be configured using its new OOPT and OOCH fields
@@ -101,7 +167,9 @@ This functionality was suggested in
be added to other output record types if the community finds it useful,
please send feedback about the feature to tech-talk.
### Tab completion for IOC shell
### IOC Shell
#### Tab completion
When built with optional GNU libreadline support, the interactive IOC shell
will perform tab completion for command names as well as for some arguments
@@ -113,14 +181,25 @@ using the new `iocshArgStringRecord` and `iocshArgStringPath` argument types.
Both function identically to `iocshArgString` but indicate how to suggest
completion strings.
Builds on macOS (darwin-x86 or darwin-aarch64 targets) normally use Apple's
Builds on macOS (`darwin-x86` or `darwin-aarch64` targets) normally use Apple's
libedit library in readline compatibility mode, which doesn't support the tab
completion API that GNU readline provides. You can use Homebrew or some other
third-party package manager to install the GNU readline package, then edit the
configure/os/CONFIG_SITE.darwinCommon.darwinCommon file to have EPICS use the
`configure/os/CONFIG_SITE.darwinCommon.darwinCommon` file to have EPICS use the
real thing to get tab completion in the IOC shell. The default settings in that
file currently look for and use a Homebrew-installed readline if present.
#### Persist history
Attempt to read and write command to a file (`./.iocsh_history` by default).
Name may be overwritten with by setting `$EPICS_IOCSH_HISTFILE` to an
alternate path, or disabled by setting to an empty string.
#### Changes to help output
Rework the `help` command output to improve formatting and readability,
and include a visual marker (a line of underlines) between different help commands.
### Add FMOD as CALC Expression
The floating point modulo function `FMOD(NUM,DEN)` has been added to the CALC

View File

@@ -48,14 +48,14 @@ everything that has to be done since it's so easy to miss steps.</p>
<p>The following roles are used below:</p>
<dl>
<dt><strong>Release Manager</strong> ()</dt>
<dt><strong>Release Manager</strong></dt>
<dd>Responsible for managing and tagging the release</dd>
<dt><strong>Platform Developers</strong> (informal)</dt>
<dd>Responsible for individual operating system platforms</dd>
<dt><strong>Core Developers</strong></dt>
<dd>Responsible for maintaining the EPICS software</dd>
<dt><strong>Application Developers</strong></dt>
<dd>Responsible for support modules that depend on EPICS Base.</dd>
<dt><strong>APS Website Editor</strong> (Andrew Johnson)</dt>
<dd>Responsible for the APS EPICS website</dd>
<dt><strong>Website Editors</strong></dt>
<dd>Responsible for the EPICS websites</dd>
</dl>
<form>
@@ -72,23 +72,22 @@ everything that has to be done since it's so easy to miss steps.</p>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Email all developers about the upcoming release and ask for a list
of remaining tasks that must be finished.</td>
<td>Notify core developers about the upcoming release and ask about any
remaining tasks that must be finished.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>All developers</td>
<td>Check the bug tracker for any outstanding items and handle
appropriately. All bugs that have been fixed should have been marked
as Fix Committed.</td>
appropriately.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Set the Feature Freeze date, by which time all Git commits for
enhancements and new functionality should have been completed. After
this date, commits should only be made to fix problems that show up
during testing.</td>
<td>Set a Feature Freeze date, by which time all Git branches for
enhancements and new functionality should have been merged. After this
date, commits and merges should only be made to fix problems that show
up during testing.</td>
</tr>
<tr>
<td>&nbsp;</td>
@@ -97,6 +96,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Ensure that documentation will be updated before the release date:
<ul>
<li>Release Notes</li>
<li>Doxygen annotations</li>
<li>Other documents</li>
</ul>
</td>
@@ -104,13 +104,8 @@ everything that has to be done since it's so easy to miss steps.</p>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Review and update this checklist for the upcoming release.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Create a release milestone on Launchpad. If a target release date is
known set "Date Targeted" to the expected release date.</td>
<td>Review and update this checklist for the upcoming release.
Update the release version number in the tags and messages below.</td>
</tr>
<tr>
<th colspan="3">Testing</th>
@@ -118,7 +113,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<tr>
<td>&nbsp;</td>
<td>Platform Developers</td>
<td>Run the built-in test programs on all available host platforms using
<td>Run the internal test programs on all available host platforms using
<blockquote><tt>
make -s runtests
</tt></blockquote></td>
@@ -156,6 +151,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Check that documentation has been updated:
<ul>
<li>Release Notes</li>
<li>Doxygen annotations</li>
<li>Other documents</li>
</ul>
</td>
@@ -167,8 +163,8 @@ everything that has to be done since it's so easy to miss steps.</p>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Obtain a positive <q>Ok to release</q> from developers.</td>
<td>Core Developers</td>
<td>Reach a consensus that the software is ready to release.</td>
</tr>
<tr>
<th colspan="3">Creating the final release version</th>
@@ -191,27 +187,29 @@ everything that has to be done since it's so easy to miss steps.</p>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
</tt></blockquote>
Commit changes (don't push).</li>
Commit these changes (don't push).</li>
<li>Edit the module's release version file
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and its top-level
<tt>Doxyfile</tt>; set the <tt>DEVELOPMENT_FLAG</tt> value to 0 and
remove <tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string.
Commit changes (don't push).</li>
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and the
<tt>Doxyfile</tt>s in the top-level and/or documentation
directories. In these, set <tt>DEVELOPMENT_FLAG</tt> to 0 and remove
<tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string. Commit these
changes (don't push).</li>
<li>Tag the module:
<blockquote><tt>
git tag -m 'ANJ: Tag for EPICS 7.0.7' &lt;module-version&gt;
git tag -m 'ANJ: Tag for EPICS 7.0.8' &lt;module-version&gt;
</tt></blockquote>
</li>
<li>Update the git submodule on the Base-7.0 branch to the
newly-tagged version, but don't commit yet:
newly-tagged version, check the module's status matches the tag:
<blockquote><tt>
cd base-7.0/modules<br />
git add &lt;module&gt;<br />
git submodule status --cached
</tt></blockquote>
Don't commit the submodule updates yet.
</li>
<li>Edit the module's release version file
@@ -221,7 +219,8 @@ everything that has to be done since it's so easy to miss steps.</p>
<tt>PROJECT_NUMBER</tt> string, appending <tt>-dev</tt> to the new
module version number. Commit changes.</li>
<li>Push commits and the new tag to the submodule's GitHub repository:
<li>Push commits and the new tag to the submodule's GitHub repository
(assumed to be the <tt>upstream</tt> remote):
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;<br />
git push --follow-tags upstream master
@@ -270,10 +269,9 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Tag the epics-base module in Git:
<blockquote><tt>
cd base-7.0<br />
git tag -m 'ANJ: Tagged for release' R7.0.7
git tag -m 'ANJ: Tagged for release' R7.0.8
</tt></blockquote>
<p>Don't push anything to the Launchpad repository
yet.</p>
<p>Don't push to GitHub yet.</p>
</td>
</tr>
<tr>
@@ -305,12 +303,12 @@ everything that has to be done since it's so easy to miss steps.</p>
files and directories that are only used for continuous integration:
<blockquote><tt>
cd base-7.0<br />
./.tools/make-tar.sh R7.0.7 ../base-7.0.7.tar.gz base-7.0.7/
./.tools/make-tar.sh R7.0.8 ../base-7.0.8.tar.gz base-7.0.8/
</tt></blockquote>
Create a GPG signature file of the tarfile as follows:
<blockquote><tt>
cd ..<br />
gpg --armor --sign --detach-sig base-7.0.7.tar.gz
gpg --armor --sign --detach-sig base-7.0.8.tar.gz
</tt></blockquote>
</td>
</tr>
@@ -318,8 +316,9 @@ everything that has to be done since it's so easy to miss steps.</p>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Test the tar file by extracting its contents and building it on at
least one supported platform. When this succeeds the commits and new git
tag can be pushed to the Launchpad repository:
least one supported platform. If this succeeds the commits and new git
tag can be pushed to the GitHub repository's 7.0 branch (assumed to be
the <tt>upstream</tt> remote):
<blockquote><tt>
git push --follow-tags upstream 7.0
</tt></blockquote>
@@ -367,7 +366,7 @@ everything that has to be done since it's so easy to miss steps.</p>
</tr>
<tr>
<th colspan="3">Publish to epics-controls</th>
<th colspan="3">Publish to epics-controls.org</th>
</tr>
<tr>
<td><input type="checkbox"></td>
@@ -375,7 +374,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
epics-controls web-server.
<blockquote><tt>
scp base-7.0.7.tar.gz base-7.0.7.tar.gz.asc epics-controls:download/base<br />
scp base-7.0.8.tar.gz base-7.0.8.tar.gz.asc epics-controls:download/base<br />
</tt></blockquote>
</td>
</tr>
@@ -392,22 +391,22 @@ everything that has to be done since it's so easy to miss steps.</p>
</tr>
<tr>
<th colspan="3">Publish to Launchpad</th>
<th colspan="3">Publish to GitHub</th>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Go to the Launchpad milestone for this release. Click the Create
release button and add the release date. Put a URL for the release page
in the Release notes box, and click the Create release button. Upload
the tar file and its <tt>.asc</tt> signature file to the new Launchpad
release page.</td>
<td>Go to the GitHub
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8">
Create release from tag R7.0.8</a> page.
Upload the tar file and its <tt>.asc</tt> signature file to the new
GitHub release page.</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Find all Launchpad bug reports with the status Fix Committed which
have been fixed in this release and mark them Fix Released.</td>
<td>We used to close out bug reports in Launchpad at release-time, this
would be the time to do that if we have an equivalent on GitHub.</td>
</tr>
<tr>

View File

@@ -34,9 +34,6 @@ pvDatabase_DEPEND_DIRS = pvAccess
SUBMODULES += pva2pva
pva2pva_DEPEND_DIRS = pvAccess
SUBMODULES += example
example_DEPEND_DIRS = pva2pva pvaClient
# Allow sites to add extra submodules
-include Makefile.local

View File

@@ -2575,7 +2575,8 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
SEVCHK ( ca_get ( DBR_FLOAT, chan, &temp ), NULL );
SEVCHK ( ca_pend_io ( timeoutToPendIO ), NULL );
/* printf ( "flow control bypassed %u events\n", flowCtrlCount ); */
if (0)
printf ( "flow control bypassed %u events\n", flowCtrlCount );
showProgressEnd ( interestLevel );
}

View File

@@ -25,6 +25,7 @@
#include <stdexcept>
#include <string> // vxWorks 6.0 requires this include
#include "epicsStdio.h"
#include "dbDefs.h"
#include "epicsGuard.h"
#include "epicsVersion.h"
@@ -1008,7 +1009,7 @@ bool cac::defaultExcep (
char buf[512];
char hostName[64];
iiu.getHostName ( guard, hostName, sizeof ( hostName ) );
sprintf ( buf, "host=%s ctx=%.400s", hostName, pCtx );
epicsSnprintf( buf, sizeof(buf), "host=%s ctx=%.400s", hostName, pCtx );
this->notify.exception ( guard, status, buf, 0, 0u );
return true;
}
@@ -1312,7 +1313,7 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
const char * pChannelName, const char * pAcc, const char * pRej )
{
char buf[256];
sprintf ( buf, "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s",
epicsSnprintf( buf, sizeof(buf), "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s",
pChannelName, pAcc, pRej );
{
callbackManager mgr ( this->notify, this->cbMutex );

View File

@@ -450,7 +450,7 @@ void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
epicsTimeStamp end_time;
epicsTimeStamp start_time;
double delay;
unsigned inlineIter;
unsigned inlineIter = 0;
epicsTimeGetCurrent ( &start_time );
(*pfunc) ( pItems, iterations, &inlineIter );

View File

@@ -549,7 +549,7 @@ void epicsStdCall caRepeaterRegistrationMessage (
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf ( stderr, "error sending registration message to CA repeater daemon was \"%s\"\n",
fprintf ( stderr, ERL_ERROR " sending registration message to CA repeater daemon was \"%s\"\n",
sockErrBuf );
}
}
@@ -813,13 +813,13 @@ bool udpiiu::exceptionRespAction (
if ( msg.m_postsize > sizeof ( caHdr ) ){
errlogPrintf (
"error condition \"%s\" detected by %s with context \"%s\" at %s\n",
ERL_ERROR " condition \"%s\" detected by %s with context \"%s\" at %s\n",
ca_message ( msg.m_available ),
name, reinterpret_cast <const char *> ( &reqMsg + 1 ), date );
}
else{
errlogPrintf (
"error condition \"%s\" detected by %s at %s\n",
ERL_ERROR " condition \"%s\" detected by %s at %s\n",
ca_message ( msg.m_available ), name, date );
}

View File

@@ -392,6 +392,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":taicnhsSVe:f:g:l:#:d:0:w:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -437,8 +439,8 @@ int main (int argc, char *argv[])
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('caget -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('caget -h' for help.)\n",
optarg, caTimeout);
}
break;
case '#': /* Array count */

View File

@@ -141,6 +141,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":nhVw:s:p:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -150,11 +152,16 @@ int main (int argc, char *argv[])
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
return 0;
case 'w': /* Set CA timeout value */
/*
* epicsScanDouble is a macro defined as epicsParseDouble,
* (found in modules/libcom/src/misc) which will only
* change caTimeout here if it finds an acceptable value.
*/
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('cainfo -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('cainfo -h' for help.)\n",
optarg, caTimeout);
}
break;
case 's': /* ca_client_status interest level */

View File

@@ -219,6 +219,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":nhVm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -251,11 +253,16 @@ int main (int argc, char *argv[])
}
break;
case 'w': /* Set CA timeout value */
/*
* epicsScanDouble is a macro defined as epicsParseDouble,
* (found in modules/libcom/src/misc) which will only
* change caTimeout here if it finds an acceptable value.
*/
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('camonitor -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('camonitor -h' for help.)\n",
optarg, caTimeout);
}
break;
case '#': /* Array count */

View File

@@ -35,6 +35,7 @@
#include <epicsStdlib.h>
#include <cadef.h>
#include <errlog.h>
#include <epicsGetopt.h>
#include <epicsEvent.h>
#include <epicsString.h>
@@ -284,6 +285,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":cnlhatsVS#:w:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -318,11 +321,16 @@ int main (int argc, char *argv[])
request = callback;
break;
case 'w': /* Set CA timeout value */
/*
* epicsScanDouble is a macro defined as epicsParseDouble,
* (found in modules/libcom/src/misc) which will only
* change caTimeout here if it finds an acceptable value.
*/
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('caput -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('caput -h' for help.)\n",
optarg, caTimeout);
}
break;
case '#': /* Array count */
@@ -337,7 +345,7 @@ int main (int argc, char *argv[])
if (sscanf(optarg,"%u", &caPriority) != 1)
{
fprintf(stderr, "'%s' is not a valid CA priority "
"- ignored. ('caget -h' for help.)\n", optarg);
"- ignored. ('caput -h' for help.)\n", optarg);
caPriority = DEFAULT_CA_PRIORITY;
}
if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX;
@@ -542,7 +550,7 @@ int main (int argc, char *argv[])
result = ca_array_put (dbrType, count, pvs[0].chid, pbuf);
}
if (result != ECA_NORMAL) {
fprintf(stderr, "Error from put operation: %s\n", ca_message(result));
fprintf(stderr, ERL_ERROR " from put operation: %s\n", ca_message(result));
free(sbuf); free(dbuf); free(ebuf);
return 1;
}
@@ -563,7 +571,7 @@ int main (int argc, char *argv[])
}
if (result != ECA_NORMAL) {
fprintf(stderr, "Error occured writing data: %s\n", ca_message(result));
fprintf(stderr, ERL_ERROR " occured writing data: %s\n", ca_message(result));
free(sbuf); free(dbuf); free(ebuf);
return 1;
}

View File

@@ -28,6 +28,7 @@
#include <alarm.h>
#include <epicsTime.h>
#include <epicsStdlib.h>
#include <epicsString.h>
#include <cadef.h>
@@ -53,7 +54,7 @@ char fieldSeparator = ' '; /* OFS default is whitespace */
int enumAsNr = 0; /* used for -n option - get DBF_ENUM as number */
int charArrAsStr = 0; /* used for -S option - treat char array as (long) string */
double caTimeout = 1.0; /* wait time default (see -w option) */
double caTimeout = DEFAULT_TIMEOUT; /* wait time default (see -w option) */
capri caPriority = DEFAULT_CA_PRIORITY; /* CA Priority */
#define TIMETEXTLEN 28 /* Length of timestamp text buffer */
@@ -639,3 +640,22 @@ int connect_pvs (pv* pvs, int nPvs)
}
return returncode;
}
/* Set the timeout to EPICS_CLI_TIMEOUT */
void use_ca_timeout_env ( double* timeout)
{
const char* tmoStr; /* contents of environment var */
if ((tmoStr = getenv("EPICS_CLI_TIMEOUT")) != NULL && timeout != NULL)
{
if(epicsScanDouble(tmoStr, timeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"(from 'EPICS_CLI_TIMEOUT' in the environment) - "
"ignored. (use '-h' for help.)\n", tmoStr);
*timeout = DEFAULT_TIMEOUT;
}
}
}

View File

@@ -100,6 +100,7 @@ extern char *dbr2str (const void *value, unsigned type);
extern void print_time_val_sts (pv *pv, unsigned long reqElems);
extern int create_pvs (pv *pvs, int nPvs, caCh *pCB );
extern int connect_pvs (pv *pvs, int nPvs );
extern void use_ca_timeout_env (double* timeout);
/*
* no additions below this endif

View File

@@ -21,7 +21,8 @@ static const iocshArg * const asSetFilenameArgs[] = {&asSetFilenameArg0};
static const iocshFuncDef asSetFilenameFuncDef =
{"asSetFilename",1,asSetFilenameArgs,
"Set path+file name of ACF file.\n"
"No immediate effect. Run as asInit() to (re)load.\n"};
"No immediate effect. Run asInit to (re)load.\n"
"Example: asSetFilename /full/path/to/accessSecurityFile\n"};
static void asSetFilenameCallFunc(const iocshArgBuf *args)
{
asSetFilename(args[0].sval);
@@ -33,7 +34,8 @@ static const iocshArg * const asSetSubstitutionsArgs[] = {&asSetSubstitutionsArg
static const iocshFuncDef asSetSubstitutionsFuncDef =
{"asSetSubstitutions",1,asSetSubstitutionsArgs,
"Set subtitutions used when reading ACF file.\n"
"No immediate effect. Run as asInit() to (re)load.\n"};
"No immediate effect. Run asInit to (re)load.\n"
"Example: asSetSubstitutions var1=5,var2=hello\n"};
static void asSetSubstitutionsCallFunc(const iocshArgBuf *args)
{
asSetSubstitutions(args[0].sval);
@@ -59,7 +61,10 @@ static void asdbdumpCallFunc(const iocshArgBuf *args)
static const iocshArg aspuagArg0 = { "uagname",iocshArgString};
static const iocshArg * const aspuagArgs[] = {&aspuagArg0};
static const iocshFuncDef aspuagFuncDef = {"aspuag",1,aspuagArgs,
"Show members of User Access Group.\n"};
"Show members of the User Access Group.\n"
"If no Group is specified then the members\n"
"of all user access groups are displayed.\n"
"Example: aspuag mygroup\n"};
static void aspuagCallFunc(const iocshArgBuf *args)
{
aspuag(args[0].sval);
@@ -69,7 +74,10 @@ static void aspuagCallFunc(const iocshArgBuf *args)
static const iocshArg asphagArg0 = { "hagname",iocshArgString};
static const iocshArg * const asphagArgs[] = {&asphagArg0};
static const iocshFuncDef asphagFuncDef = {"asphag",1,asphagArgs,
"Show members of Host Access Group.\n"};
"Show members of the Host Access Group.\n"
"If no Group is specified then the members\n"
"of all host access groups are displayed\n"
"Example: asphag mygroup\n"};
static void asphagCallFunc(const iocshArgBuf *args)
{
asphag(args[0].sval);
@@ -78,8 +86,12 @@ static void asphagCallFunc(const iocshArgBuf *args)
/* asprules */
static const iocshArg asprulesArg0 = { "asgname",iocshArgString};
static const iocshArg * const asprulesArgs[] = {&asprulesArg0};
static const iocshFuncDef asprulesFuncDef = {"asprules",1,asprulesArgs,
"List rules of an Access Security Group.\n"};
static const iocshFuncDef asprulesFuncDef = {
"asprules",1,asprulesArgs,
"List rules of an Access Security Group.\n"
"If no Group is specified then list the rules for all groups\n"
"Example: asprules mygroup\n"
};
static void asprulesCallFunc(const iocshArgBuf *args)
{
asprules(args[0].sval);
@@ -89,8 +101,14 @@ static void asprulesCallFunc(const iocshArgBuf *args)
static const iocshArg aspmemArg0 = { "asgname",iocshArgString};
static const iocshArg aspmemArg1 = { "clients",iocshArgInt};
static const iocshArg * const aspmemArgs[] = {&aspmemArg0,&aspmemArg1};
static const iocshFuncDef aspmemFuncDef = {"aspmem",2,aspmemArgs,
"List members of Access Security Group.\n"};
static const iocshFuncDef aspmemFuncDef = {
"aspmem",2,aspmemArgs,
"List members of Access Security Group.\n"
"If no Group is specified then print the members for all Groups.\n"
"If clients is (0, 1) then Channel Access clients attached to each member\n"
"(are not, are) shown\n"
"Example: aspmem mygroup 1\n",
};
static void aspmemCallFunc(const iocshArgBuf *args)
{
aspmem(args[0].sval,args[1].ival);
@@ -101,8 +119,10 @@ static const iocshArg astacArg0 = { "recordname",iocshArgStringRecord};
static const iocshArg astacArg1 = { "user",iocshArgString};
static const iocshArg astacArg2 = { "host",iocshArgString};
static const iocshArg * const astacArgs[] = {&astacArg0,&astacArg1,&astacArg2};
static const iocshFuncDef astacFuncDef = {"astac",3,astacArgs,
"Test Access Security privlages granted to user+host.\n"};
static const iocshFuncDef astacFuncDef = {
"astac",3,astacArgs,
"Show what read/write permissions the user:host would have when\n"
"accessing a certain PV.\n"};
static void astacCallFunc(const iocshArgBuf *args)
{
astac(args[0].sval,args[1].sval,args[2].sval);
@@ -111,8 +131,14 @@ static void astacCallFunc(const iocshArgBuf *args)
/* ascar */
static const iocshArg ascarArg0 = { "level",iocshArgInt};
static const iocshArg * const ascarArgs[] = {&ascarArg0};
static const iocshFuncDef ascarFuncDef = {"ascar",1,ascarArgs,
"Report status of PVs used in INP*() Access Security rules.\n"};
static const iocshFuncDef ascarFuncDef = {
"ascar",1,ascarArgs,
"Report status of PVs used in INP*() Access Security rules.\n"
"Level 0 - Summary report\n"
" 1 - Summary report plus details on unconnected channels\n"
" 2 - Summary report plus detail report on each channel\n"
"Example: ascar 1\n"
};
static void ascarCallFunc(const iocshArgBuf *args)
{
ascar(args[0].ival);

View File

@@ -21,6 +21,7 @@
#include <ctype.h>
#include "dbDefs.h"
#include "errlog.h"
#include "ellLib.h"
#include "cvtTable.h"
@@ -125,12 +126,12 @@ int main(int argc, char **argv)
}
inFile = fopen(argv[1],"r");
if(!inFile) {
fprintf(stderr,"Error opening %s\n",argv[1]);
fprintf(stderr,ERL_ERROR " opening %s\n",argv[1]);
exit(-1);
}
outFile = fopen(outFilename,"w");
if(!outFile) {
fprintf(stderr,"Error opening %s\n",outFilename);
fprintf(stderr,ERL_ERROR " opening %s\n",outFilename);
exit(-1);
}
while(fgets(inbuf,MAX_LINE_SIZE,inFile)) {

View File

@@ -344,6 +344,10 @@ int callbackRequest(epicsCallback *pcallback)
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback was NULL\n");
return S_db_notInit;
}
if (!pcallback->callback) {
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback->callback was NULL\n");
return S_db_notInit;
}
priority = pcallback->priority;
if (priority < 0 || priority >= NUM_CALLBACK_PRIORITIES) {
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Bad priority\n");

View File

@@ -798,18 +798,13 @@ int dbLoadRecords(const char* file, const char* subs)
return -1;
}
status = dbReadDatabase(&pdbbase, file, 0, subs);
switch(status)
{
case 0:
if(status==0) {
if(dbLoadRecordsHook)
dbLoadRecordsHook(file, subs);
break;
case -2:
errlogPrintf("dbLoadRecords: failed to load '%s'\n"
" Records cannot be loaded after iocInit!\n", file);
break;
default:
errlogPrintf("dbLoadRecords: failed to load '%s'\n", file);
} else {
fprintf(stderr, ERL_ERROR " failed to load '%s'\n", file);
if(status==-2)
fprintf(stderr, " Records cannot be loaded after iocInit!\n");
}
return status;
}

View File

@@ -575,15 +575,10 @@ long dbChannelOpen(dbChannel *chan)
}
/* Set up type probe */
probe.type = dbfl_type_val;
probe.ctx = dbfl_context_read;
memset(&probe, 0, sizeof(probe));
probe.field_type = dbChannelExportType(chan);
probe.no_elements = dbChannelElements(chan);
probe.field_size = dbChannelFieldSize(chan);
probe.sevr = NO_ALARM;
probe.stat = NO_ALARM;
probe.time.secPastEpoch = 0;
probe.time.nsec = 0;
p = probe;

View File

@@ -41,20 +41,35 @@ extern "C" {
/**
* event subscription
*/
typedef struct evSubscrip {
struct evSubscrip;
typedef struct evSubscrip evSubscrip;
#ifdef EPICS_PRIVATE_API
struct evSubscrip {
ELLNODE node;
struct dbChannel * chan;
/* user_sub==NULL used to indicate db_cancel_event() */
EVENTFUNC * user_sub;
void * user_arg;
/* associated queue, may be shared with other evSubscrip */
struct event_que * ev_que;
/* NULL if !npend. if npend!=0, pointer to last event added to event_que::valque */
db_field_log ** pLastLog;
unsigned long npend; /**< n times this event is on the queue */
unsigned long nreplace; /**< n times replacing event on the queue */
/* n times this event is on the queue */
unsigned long npend;
/* n times replacing event on the queue */
unsigned long nreplace;
/* DBE mask */
unsigned char select;
/* if set, subscription will yield dbfl_type_val */
char useValque;
/* event_task is handling this subscription */
char callBackInProgress;
/* this node added to dbCommon::mlis */
char enabled;
} evSubscrip;
};
#endif
typedef struct chFilter chFilter;

View File

@@ -91,20 +91,25 @@ For example these rates are all valid:
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<PINI> field specifies record processing at initialization. It can have the
values NO, YES, RUN, RUNNING, PAUSE, and PAUSED. If it is set to YES during
database configuration, the record is processed once at IOC initialization
(before the normal scan tasks are started). For the other values see
L<menuPini.dbd|menuPini> for more details.
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. It is generally better practice to use
linked passive records to enforce the order of processing rather than a phase
number.
The B<PHAS> field orders the records processed within a specific SCAN group or
PINI processing phase. All records of a specified phase are processed before
those with higher phase number. It is generally better practice to use linked
passive records to enforce the order of processing rather than a phase number.
If the PINI field is set to NO, the PHAS field is not meaningful for passive
records.
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<EVNT> field specifies an event name or number. This event identifier 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 that event is signalled by other
software running in the IOC, either by calling C<post_event(int event)> for
numeric events, or by calling C<postEvent()> with an event handle previously
looked up using C<eventNameToHandle()> for named events.
The B<PRIO> field specifies the scheduling priority for processing records
with SCAN=C<I/O Event> and asynchronous record completion tasks.

View File

@@ -18,6 +18,7 @@
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#define EPICS_PRIVATE_API
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
@@ -75,23 +76,23 @@ struct event_que {
unsigned short getix;
unsigned short quota; /* the number of assigned entries*/
unsigned short nDuplicates; /* N events duplicated on this q */
unsigned short nCanceled; /* the number of canceled entries */
unsigned possibleStall;
};
struct event_user {
struct event_que firstque; /* the first event que */
ELLLIST waiters; /* event_waiter::node */
epicsMutexId lock;
epicsEventId ppendsem; /* Wait while empty */
epicsEventId pflush_sem; /* wait for flush */
epicsEventId pexitsem; /* wait for event task to join */
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
void *extralabor_arg;/* parameter to above */
epicsThreadId taskid; /* event handler task id */
struct evSubscrip *pSuicideEvent; /* event that is deleting itself */
epicsUInt32 pflush_seq; /* worker cycle count for synchronization */
unsigned queovr; /* event que overflow count */
unsigned char pendexit; /* exit pend task */
unsigned char extra_labor; /* if set call extra labor func */
@@ -101,6 +102,11 @@ struct event_user {
epicsThreadId init_func_arg;
};
typedef struct {
ELLNODE node; /* event_user::waiters */
epicsEventId wake;
} event_waiter;
/*
* Reliable intertask communication requires copying the current value of the
* channel for later queuing so 3 stepper motor steps of 10 each do not turn
@@ -122,10 +128,9 @@ static void *dbevFieldLogFreeList;
static char *EVENT_PEND_NAME = "eventTask";
static struct evSubscrip canceledEvent;
static epicsMutexId stopSync;
/* unused space in queue (EVENTQUESIZE when empty) */
static unsigned short ringSpace ( const struct event_que *pevq )
{
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
@@ -139,17 +144,11 @@ static unsigned short ringSpace ( const struct event_que *pevq )
return 0;
}
/*
* db_event_list ()
*/
int db_event_list ( const char *pname, unsigned level )
{
return dbel ( pname, level );
}
/*
* dbel ()
*/
int dbel ( const char *pname, unsigned level )
{
DBADDR addr;
@@ -217,7 +216,6 @@ int dbel ( const char *pname, unsigned level )
if ( level > 2 ) {
unsigned nDuplicates;
unsigned nCanceled;
if ( pevent->nreplace ) {
printf (", discarded by replacement=%ld", pevent->nreplace);
}
@@ -226,14 +224,10 @@ int dbel ( const char *pname, unsigned level )
}
LOCKEVQUE(pevent->ev_que);
nDuplicates = pevent->ev_que->nDuplicates;
nCanceled = pevent->ev_que->nCanceled;
UNLOCKEVQUE(pevent->ev_que);
if ( nDuplicates ) {
printf (", duplicate count =%u\n", nDuplicates );
}
if ( nCanceled ) {
printf (", canceled count =%u\n", nCanceled );
}
}
if ( level > 3 ) {
@@ -318,9 +312,6 @@ dbEventCtx db_init_events (void)
evUser->ppendsem = epicsEventCreate(epicsEventEmpty);
if (!evUser->ppendsem)
goto fail;
evUser->pflush_sem = epicsEventCreate(epicsEventEmpty);
if (!evUser->pflush_sem)
goto fail;
evUser->lock = epicsMutexCreate();
if (!evUser->lock)
goto fail;
@@ -330,7 +321,6 @@ dbEventCtx db_init_events (void)
evUser->flowCtrlMode = FALSE;
evUser->extraLaborBusy = FALSE;
evUser->pSuicideEvent = NULL;
return (dbEventCtx) evUser;
fail:
if(evUser->lock)
@@ -339,8 +329,6 @@ fail:
epicsMutexDestroy (evUser->firstque.writelock);
if(evUser->ppendsem)
epicsEventDestroy (evUser->ppendsem);
if(evUser->pflush_sem)
epicsEventDestroy (evUser->pflush_sem);
if(evUser->pexitsem)
epicsEventDestroy (evUser->pexitsem);
freeListFree(dbevEventUserFreeList,evUser);
@@ -404,7 +392,6 @@ void db_close_events (dbEventCtx ctx)
epicsEventDestroy(evUser->pexitsem);
epicsEventDestroy(evUser->ppendsem);
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
epicsMutexUnlock (stopSync);
@@ -461,8 +448,7 @@ dbEventSubscription db_add_event (
while ( TRUE ) {
int success = 0;
LOCKEVQUE ( ev_que );
success = ( ev_que->quota + ev_que->nCanceled <
EVENTQUESIZE - EVENTENTRIES );
success = ( ev_que->quota < EVENTQUESIZE - EVENTENTRIES );
if ( success ) {
ev_que->quota += EVENTENTRIES;
}
@@ -579,62 +565,62 @@ static void event_remove ( struct event_que *ev_que,
void db_cancel_event (dbEventSubscription event)
{
struct evSubscrip * const pevent = (struct evSubscrip *) event;
unsigned short getix;
struct event_que *que = pevent->ev_que;
char sync = 0;
db_event_disable ( event );
/*
* flag the event as canceled by NULLing out the callback handler
*
* make certain that the event isn't being accessed while
* its call back changes
*/
LOCKEVQUE (pevent->ev_que);
LOCKEVQUE (que);
pevent->user_sub = NULL;
pevent->user_sub = NULL; /* callback pointer doubles as canceled flag */
/*
* purge this event from the queue
*
* Its better to take this approach rather than waiting
* for the event thread to finish removing this event
* from the queue because the event thread will not
* process if we are in flow control mode. Since blocking
* here will block CA's TCP input queue then a dead lock
* would be possible.
*/
for ( getix = pevent->ev_que->getix;
pevent->ev_que->evque[getix] != EVENTQEMPTY; ) {
if ( pevent->ev_que->evque[getix] == pevent ) {
assert ( pevent->ev_que->nCanceled < USHRT_MAX );
pevent->ev_que->nCanceled++;
event_remove ( pevent->ev_que, getix, &canceledEvent );
}
getix = RNGINC ( getix );
if ( getix == pevent->ev_que->getix ) {
break;
}
}
assert ( pevent->npend == 0u );
if(pevent->callBackInProgress) {
/* this event callback is pending or in-progress in event_task. */
if(pevent->ev_que->evUser->taskid != epicsThreadGetIdSelf())
sync = 1; /* concurrent to event_task, so wait */
if ( pevent->ev_que->evUser->taskid == epicsThreadGetIdSelf() ) {
pevent->ev_que->evUser->pSuicideEvent = pevent;
}
else {
while ( pevent->callBackInProgress ) {
UNLOCKEVQUE (pevent->ev_que);
epicsEventMustWait ( pevent->ev_que->evUser->pflush_sem );
LOCKEVQUE (pevent->ev_que);
}
} else if(pevent->npend) {
/* some (now defunct) events in the queue, defer free() to event_task */
} else {
/* no other references, cleanup now */
pevent->ev_que->quota -= EVENTENTRIES;
freeListFree ( dbevEventSubscriptionFreeList, pevent );
}
pevent->ev_que->quota -= EVENTENTRIES;
UNLOCKEVQUE (que);
UNLOCKEVQUE (pevent->ev_que);
if(sync) {
/* cycle through worker */
struct event_user *evUser = que->evUser;
epicsUInt32 curSeq;
event_waiter wait;
wait.wake = epicsEventCreate(epicsEventEmpty); /* may fail */
freeListFree ( dbevEventSubscriptionFreeList, pevent );
epicsMutexMustLock ( evUser->lock );
ellAdd(&evUser->waiters, &wait.node);
/* grab current cycle counter, then wait for it to change */
curSeq = evUser->pflush_seq;
do {
epicsMutexUnlock( evUser->lock );
/* ensure worker will cycle at least once */
epicsEventMustTrigger(evUser->ppendsem);
return;
if(wait.wake) {
epicsEventMustWait(wait.wake);
} else {
epicsThreadSleep(0.01); /* ick. but better than cantProceed() */
}
epicsMutexMustLock ( evUser->lock );
} while(curSeq == evUser->pflush_seq);
ellDelete(&evUser->waiters, &wait.node);
/* destroy under lock to ensure epicsEventMustTrigger() has returned */
if(wait.wake)
epicsEventDestroy(wait.wake);
epicsMutexUnlock( evUser->lock );
}
}
/*
@@ -934,10 +920,7 @@ void db_post_single_event (dbEventSubscription event)
*/
static int event_read ( struct event_que *ev_que )
{
db_field_log *pfl;
int notifiedRemaining = 0;
void ( *user_sub ) ( void *user_arg, struct dbChannel *chan,
int eventsRemaining, db_field_log *pfl );
/*
* evUser ring buffer must be locked for the multiple
@@ -958,19 +941,7 @@ static int event_read ( struct event_que *ev_que )
while ( ev_que->evque[ev_que->getix] != EVENTQEMPTY ) {
struct evSubscrip *pevent = ev_que->evque[ev_que->getix];
int eventsRemaining;
pfl = ev_que->valque[ev_que->getix];
if ( pevent == &canceledEvent ) {
ev_que->evque[ev_que->getix] = EVENTQEMPTY;
if (ev_que->valque[ev_que->getix]) {
db_delete_field_log(ev_que->valque[ev_que->getix]);
ev_que->valque[ev_que->getix] = NULL;
}
ev_que->getix = RNGINC ( ev_que->getix );
assert ( ev_que->nCanceled > 0 );
ev_que->nCanceled--;
continue;
}
db_field_log *pfl = ev_que->valque[ev_que->getix];
/*
* Simple type values queued up for reliable interprocess
@@ -980,13 +951,7 @@ static int event_read ( struct event_que *ev_que )
event_remove ( ev_que, ev_que->getix, EVENTQEMPTY );
ev_que->getix = RNGINC ( ev_que->getix );
eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY && !ev_que->nCanceled;
/*
* create a local copy of the call back parameters while
* we still have the lock
*/
user_sub = pevent->user_sub;
eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY;
/*
* Next event pointer can be used by event tasks to determine
@@ -998,14 +963,12 @@ static int event_read ( struct event_que *ev_que )
* record lock, and it is calling db_post_events() waiting
* for the event queue lock (which this thread now has).
*/
if ( user_sub ) {
/*
* This provides a way to test to see if an event is in use
* despite the fact that the event queue does not point to
* it.
*/
if ( pevent->user_sub ) {
EVENTFUNC* user_sub = pevent->user_sub;
pevent->callBackInProgress = TRUE;
UNLOCKEVQUE (ev_que);
/* Run post-event-queue filter chain */
if (ellCount(&pevent->chan->post_chain)) {
pfl = dbChannelRunPostChain(pevent->chan, pfl);
@@ -1016,27 +979,15 @@ static int event_read ( struct event_que *ev_que )
eventsRemaining, pfl );
notifiedRemaining = eventsRemaining;
}
LOCKEVQUE (ev_que);
/*
* check to see if this event has been canceled each
* time that the callBackInProgress flag is set to false
* while we have the event queue lock, and post the flush
* complete sem if there are no longer any events on the
* queue
*/
if ( ev_que->evUser->pSuicideEvent == pevent ) {
ev_que->evUser->pSuicideEvent = NULL;
}
else {
if ( pevent->user_sub==NULL && pevent->npend==0u ) {
pevent->callBackInProgress = FALSE;
epicsEventSignal ( ev_que->evUser->pflush_sem );
}
else {
pevent->callBackInProgress = FALSE;
}
}
pevent->callBackInProgress = FALSE;
}
/* callback may have called db_cancel_event(), so must check user_sub again */
if(!pevent->user_sub && !pevent->npend) {
pevent->ev_que->quota -= EVENTENTRIES;
freeListFree ( dbevEventSubscriptionFreeList, pevent );
}
db_delete_field_log(pfl);
}
@@ -1051,9 +1002,6 @@ static int event_read ( struct event_que *ev_que )
return DB_EVENT_OK;
}
/*
* EVENT_TASK()
*/
static void event_task (void *pParm)
{
struct event_user * const evUser = (struct event_user *) pParm;
@@ -1094,13 +1042,25 @@ static void event_task (void *pParm)
}
evUser->extraLaborBusy = FALSE;
for ( ev_que = &evUser->firstque; ev_que;
ev_que = ev_que->nextque ) {
for ( ev_que = &evUser->firstque; ev_que; ev_que = ev_que->nextque ) {
/* unlock during iteration is safe as event_que will not be free'd */
epicsMutexUnlock ( evUser->lock );
event_read (ev_que);
epicsMutexMustLock ( evUser->lock );
}
pendexit = evUser->pendexit;
evUser->pflush_seq++;
if(ellCount(&evUser->waiters)) {
/* hold lock throughout to avoid race between event trigger and destroy */
ELLNODE *cur;
for(cur = ellFirst(&evUser->waiters); cur; cur = ellNext(cur)) {
event_waiter *w = CONTAINER(cur, event_waiter, node);
if(w->wake)
epicsEventMustTrigger(w->wake);
}
}
epicsMutexUnlock ( evUser->lock );
} while( ! pendexit );

View File

@@ -72,7 +72,9 @@ static void dbLoadRecordsCallFunc(const iocshArgBuf *args)
static const iocshArg dbbArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbbArgs[1] = {&dbbArg0};
static const iocshFuncDef dbbFuncDef = {"dbb",1,dbbArgs,
"Add breakpoint to a lock set.\n"};
"Set Breakpoint on a record\n"
"This command spawns one breakpoint continuation task per lockset,"
" in which further record execution is run\n"};
static void dbbCallFunc(const iocshArgBuf *args) { dbb(args[0].sval);}
/* dbd */
@@ -86,27 +88,36 @@ static void dbdCallFunc(const iocshArgBuf *args) { dbd(args[0].sval);}
static const iocshArg dbcArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbcArgs[1] = {&dbcArg0};
static const iocshFuncDef dbcFuncDef = {"dbc",1,dbcArgs,
"Continue processing in a lock set.\n"};
"Continue processing in a lockset until next breakpoint is found.\n"};
static void dbcCallFunc(const iocshArgBuf *args) { dbc(args[0].sval);}
/* dbs */
static const iocshArg dbsArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbsArgs[1] = {&dbsArg0};
static const iocshFuncDef dbsFuncDef = {"dbs",1,dbsArgs,
"Step through record processing.\n"};
"Step through record processing within a lockset.\n"
"If called without an argument, automatically steps with the last breakpoint.\n"};
static void dbsCallFunc(const iocshArgBuf *args) { dbs(args[0].sval);}
/* dbstat */
static const iocshFuncDef dbstatFuncDef = {"dbstat",0,0,
"print list of stopped records, and breakpoints set in locksets.\n"};
"Print list of suspended records, and breakpoints set in locksets.\n"};
static void dbstatCallFunc(const iocshArgBuf *args) { dbstat();}
/* dbp */
static const iocshArg dbpArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbpArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dbpArgs[2] = {&dbpArg0,&dbpArg1};
static const iocshFuncDef dbpFuncDef = {"dbp",2,dbpArgs,
"print stopped record.\n"};
static const iocshFuncDef dbpFuncDef = {
"dbp",2,dbpArgs,
"Print Fields of a currently suspended record by a breakpoint.\n"
"interest level 0 - Fields of interest to an Application developer and\n"
" that can be changed as a result of record processing.\n"
" 1 - Fields of interest to an Application developer and\n"
" that do not change during record processing.\n"
" 2 - Fields of major interest to a System developer.\n"
" 3 - Fields of minor interest to a System developer.\n"
" 4 - Internal record fields.\n"};
static void dbpCallFunc(const iocshArgBuf *args)
{ dbp(args[0].sval,args[1].ival);}
@@ -114,14 +125,17 @@ static void dbpCallFunc(const iocshArgBuf *args)
static const iocshArg dbapArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbapArgs[1] = {&dbapArg0};
static const iocshFuncDef dbapFuncDef = {"dbap",1,dbapArgs,
"toggle printing after processing a certain record.\n"};
"Auto Print.\n"
"Toggle automatic printing after processing a record that has a breakpoint.\n"};
static void dbapCallFunc(const iocshArgBuf *args) { dbap(args[0].sval);}
/* dbsr */
static const iocshArg dbsrArg0 = { "interest level",iocshArgInt};
static const iocshArg * const dbsrArgs[1] = {&dbsrArg0};
static const iocshFuncDef dbsrFuncDef = {"dbsr",1,dbsrArgs,
"Database Server Report.\n"};
"Database Server Report.\n"
"Print current status of server and number of connected clients.\n"
"Level 0 prints summary information. Higher levels print more.\n"};
static void dbsrCallFunc(const iocshArgBuf *args) { dbsr(args[0].ival);}
/* dbcar */
@@ -131,9 +145,9 @@ static const iocshArg * const dbcarArgs[2] = {&dbcarArg0,&dbcarArg1};
static const iocshFuncDef dbcarFuncDef = {"dbcar",2,dbcarArgs,
"Database Channel Access Report.\n"
"Shows status of Channel Access links (CA_LINK).\n"
"interest level 0 - Shows statistics for all links.\n"
" 1 - Shows info. of only disconnected links.\n"
" 2 - Shows info. for all links.\n"};
" level 0 - Shows statistics for all links.\n"
" 1 - Shows info. of only disconnected links.\n"
" 2 - Shows info. for all links.\n"};
static void dbcarCallFunc(const iocshArgBuf *args)
{
dbcar(args[0].sval,args[1].ival);
@@ -144,7 +158,8 @@ static const iocshArg dbjlrArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbjlrArg1 = { "level",iocshArgInt};
static const iocshArg * const dbjlrArgs[2] = {&dbjlrArg0,&dbjlrArg1};
static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs,
"Database JSON link Report.\n"};
"Database JSON link Report.\n"
"List all JSON links in a record. If no record is specified, print for all\n"};
static void dbjlrCallFunc(const iocshArgBuf *args)
{
dbjlr(args[0].sval,args[1].ival);
@@ -156,7 +171,9 @@ static const iocshArg dbelArg1 = { "level",iocshArgInt};
static const iocshArg * const dbelArgs[2] = {&dbelArg0,&dbelArg1};
static const iocshFuncDef dbelFuncDef = {"dbel",2,dbelArgs,
"Database event list.\n"
"Show information on dbEvent subscriptions.\n"};
"Show information on dbEvent subscriptions.\n"
"Higher level shows more information (0 - 4)\n"
"Example: dbel aitest 2\n"};
static void dbelCallFunc(const iocshArgBuf *args)
{
dbel(args[0].sval, args[1].ival);
@@ -166,7 +183,10 @@ static void dbelCallFunc(const iocshArgBuf *args)
static const iocshArg dbaArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbaArgs[1] = {&dbaArg0};
static const iocshFuncDef dbaFuncDef = {"dba",1,dbaArgs,
"dbAddr info.\n"};
"Database Address.\n"
"Print information in the dbAddr structure for a specific field.\n"
"If no field is specified, VAL is assumed.\n\n"
"Example: dba(\"aitest.HIGH\")\n"};
static void dbaCallFunc(const iocshArgBuf *args) { dba(args[0].sval);}
/* dbl */
@@ -176,7 +196,12 @@ static const iocshArg * const dblArgs[] = {&dblArg0,&dblArg1};
static const iocshFuncDef dblFuncDef = {"dbl",2,dblArgs,
"Database list.\n"
"List record/field names.\n"
"With no arguments, lists all record names.\n"};
"With no arguments, lists all record names.\n"
"If record type is given, then only the names of records maching the type are printed\n"
"If a field list is given, then their values are also printed\n\n"
"Example: dbl(\"\")\n"
" dbl(\"ai\")\n"
" dbl(\"ai\",\"HIGH LOW VAL PREC\")\n"};
static void dblCallFunc(const iocshArgBuf *args)
{
dbl(args[0].sval,args[1].sval);
@@ -186,28 +211,35 @@ static void dblCallFunc(const iocshArgBuf *args)
static const iocshArg dbnrArg0 = { "verbose",iocshArgInt};
static const iocshArg * const dbnrArgs[1] = {&dbnrArg0};
static const iocshFuncDef dbnrFuncDef = {"dbnr",1,dbnrArgs,
"List stats on record alias()s.\n"};
"List number of records and aliases by type.\n"
"If verbose, list all record types regardless of being instanced\n"};
static void dbnrCallFunc(const iocshArgBuf *args) { dbnr(args[0].ival);}
/* dbli */
static const iocshArg dbliArg0 = { "pattern",iocshArgString};
static const iocshArg * const dbliArgs[1] = {&dbliArg0};
static const iocshFuncDef dbliFuncDef = {"dbli",1,dbliArgs,
"List info() tags with names matching pattern.\n"};
"List info() tags with names matching pattern.\n\n"
"Example: dbli(\"autosave*\")\n"};
static void dbliCallFunc(const iocshArgBuf *args) { dbli(args[0].sval);}
/* dbla */
static const iocshArg dblaArg0 = { "pattern",iocshArgStringRecord};
static const iocshArg * const dblaArgs[1] = {&dblaArg0};
static const iocshFuncDef dblaFuncDef = {"dbla",1,dblaArgs,
"List record alias()s by alias name pattern.\n"};
"List record alias()s by alias name pattern.\n\n"
"Example: dbla(\"alia*\")\n"};
static void dblaCallFunc(const iocshArgBuf *args) { dbla(args[0].sval);}
/* dbgrep */
static const iocshArg dbgrepArg0 = { "pattern",iocshArgStringRecord};
static const iocshArg * const dbgrepArgs[1] = {&dbgrepArg0};
static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs,
"List record names matching pattern.\n"};
"List record names matching pattern.\n"
"The pattern can contain any characters that are legal in record names as well as:\n"
" - \"?\", which matches 0 or one characters.\n"
" - \"*\", which matches 0 or more characters.\n\n"
"Example: dbgrep(\"*gpibAi*\")\n"};
static void dbgrepCallFunc(const iocshArgBuf *args) { dbgrep(args[0].sval);}
/* dbgf */
@@ -215,7 +247,9 @@ static const iocshArg dbgfArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbgfArgs[1] = {&dbgfArg0};
static const iocshFuncDef dbgfFuncDef = {"dbgf",1,dbgfArgs,
"Database Get Field.\n"
"Print current value of record field.\n"};
"Print current value of record field.\n"
"If no field name is specified, VAL is assumed.\n\n"
"Example: dbgf(\"aitest.VAL\")\n"};
static void dbgfCallFunc(const iocshArgBuf *args) { dbgf(args[0].sval);}
/* dbpf */
@@ -224,7 +258,8 @@ static const iocshArg dbpfArg1 = { "value",iocshArgString};
static const iocshArg * const dbpfArgs[2] = {&dbpfArg0,&dbpfArg1};
static const iocshFuncDef dbpfFuncDef = {"dbpf",2,dbpfArgs,
"Database Put Field.\n"
"Change value of record field.\n"};
"Change value of record field and read it back with dbgf.\n"
"If no field is specified, VAL is assumed\n"};
static void dbpfCallFunc(const iocshArgBuf *args)
{ dbpf(args[0].sval,args[1].sval);}
@@ -232,9 +267,17 @@ static void dbpfCallFunc(const iocshArgBuf *args)
static const iocshArg dbprArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbprArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dbprArgs[2] = {&dbprArg0,&dbprArg1};
static const iocshFuncDef dbprFuncDef = {"dbpr",2,dbprArgs,
"Database Print Record.\n"
"Print values of record fields.\n"};
static const iocshFuncDef dbprFuncDef = {
"dbpr",2,dbprArgs,
"Database Print Record.\n"
"Print values of record fields for given interest level.\n"
"interest level 0 - Fields that can be changed as a result of record processing.\n"
" 1 - Fields that do not change during record processing.\n"
" 2 - Fields of major interest to a System developer.\n"
" 3 - Fields of minor interest to a System developer.\n"
" 4 - Internal record fields.\n\n"
"Example: dbpr aitest 3\n"
};
static void dbprCallFunc(const iocshArgBuf *args)
{ dbpr(args[0].sval,args[1].ival);}
@@ -250,7 +293,9 @@ static const iocshArg dbtgfArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbtgfArgs[1] = {&dbtgfArg0};
static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs,
"Database Test Get Field.\n"
"Get field with different DBR_* types\n"};
"Get and print the specified field with all possible DBR_* types\n"
"Example: dbtgf aitest\n"
"Example: dbtgf aitest.VAL\n"};
static void dbtgfCallFunc(const iocshArgBuf *args) { dbtgf(args[0].sval);}
/* dbtpf */
@@ -258,7 +303,10 @@ static const iocshArg dbtpfArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbtpfArg1 = { "value",iocshArgString};
static const iocshArg * const dbtpfArgs[2] = {&dbtpfArg0,&dbtpfArg1};
static const iocshFuncDef dbtpfFuncDef = {"dbtpf",2,dbtpfArgs,
"Database Test Put Field.\n"};
"Database Test Put Field.\n"
"Put the given value to the given PV, then get the value\n"
"for all possible DBR_* types\n\n"
"Example: dbtpf aitest 5.0\n"};
static void dbtpfCallFunc(const iocshArgBuf *args)
{ dbtpf(args[0].sval,args[1].sval);}
@@ -273,14 +321,21 @@ static void dbiorCallFunc(const iocshArgBuf *args)
/* dbhcr */
static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0,
"Database Report Device Config.\n"};
"Database Hardware Configuration Report.\n"
"Produce a report of all hardware links.\n"
"The produced report will probably not be in the sort order desired.\n"
"Use the UNIX sort command:\n"
"dbhcr > report\n"
"sort report > report.sorted\n"};
static void dbhcrCallFunc(const iocshArgBuf *args) { dbhcr();}
/* gft */
static const iocshArg gftArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const gftArgs[1] = {&gftArg0};
static const iocshFuncDef gftFuncDef = {"gft",1,gftArgs,
"Report dbChannel info and value.\n"};
"Report dbChannel info and value.\n"
"Example: gft aitest\n"
"Example: gft aitest.VAL\n"};
static void gftCallFunc(const iocshArgBuf *args) { gft(args[0].sval);}
/* pft */
@@ -288,7 +343,8 @@ static const iocshArg pftArg0 = { "record name",iocshArgStringRecord};
static const iocshArg pftArg1 = { "value",iocshArgString};
static const iocshArg * const pftArgs[2] = {&pftArg0,&pftArg1};
static const iocshFuncDef pftFuncDef = {"pft",2,pftArgs,
"dbChannel put value.\n"};
"dbChannel put value.\n"
"Example: pft aitest 5.0\n"};
static void pftCallFunc(const iocshArgBuf *args)
{ pft(args[0].sval,args[1].sval);}
@@ -297,9 +353,11 @@ static const iocshArg dbtpnArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbtpnArg1 = { "value",iocshArgString};
static const iocshArg * const dbtpnArgs[2] = {&dbtpnArg0,&dbtpnArg1};
static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs,
"Database Put Notify\n"
"Database Test Process Notify\n"
"Without value, begin async. processing and get\n"
"With value, begin put, process, and get\n"};
"With value, begin put, process, and get\n"
"Example: dbtpn aitest\n"
"Example: dbtpn aitest 5.0\n"};
static void dbtpnCallFunc(const iocshArgBuf *args)
{ dbtpn(args[0].sval,args[1].sval);}
@@ -314,9 +372,8 @@ static const iocshArg dbPutAttrArg1 = { "attribute name",iocshArgString};
static const iocshArg dbPutAttrArg2 = { "value",iocshArgString};
static const iocshArg * const dbPutAttrArgs[] =
{&dbPutAttrArg0, &dbPutAttrArg1, &dbPutAttrArg2};
static const iocshFuncDef dbPutAttrFuncDef =
{"dbPutAttribute",3,dbPutAttrArgs,
"Set/Create record attribute.\n"};
static const iocshFuncDef dbPutAttrFuncDef = {"dbPutAttribute",3,dbPutAttrArgs,
"Set/Create record attribute.\n"};
static void dbPutAttrCallFunc(const iocshArgBuf *args)
{ dbPutAttribute(args[0].sval,args[1].sval,args[2].sval);}
@@ -325,7 +382,8 @@ static const iocshArg tpnArg0 = { "record name",iocshArgStringRecord};
static const iocshArg tpnArg1 = { "value",iocshArgString};
static const iocshArg * const tpnArgs[2] = {&tpnArg0,&tpnArg1};
static const iocshFuncDef tpnFuncDef = {"tpn",2,tpnArgs,
"Begin async. process and get.\n"};
"Test Process Notify.\n\n"
"Example: tpn aitest 5.0\n"};
static void tpnCallFunc(const iocshArgBuf *args)
{ tpn(args[0].sval,args[1].sval);}
@@ -334,16 +392,25 @@ static const iocshArg dblsrArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dblsrArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dblsrArgs[2] = {&dblsrArg0,&dblsrArg1};
static const iocshFuncDef dblsrFuncDef = {"dblsr",2,dblsrArgs,
"Database Lockset report.\n"};
"Database Lockset report.\n"
"Generate a report showing the lock set to which each record belongs.\n"
"interest level 0 - Show lock set information only.\n"
" 1 - Show each record in the lock set.\n"
" 2 - Show each record and all database links in the lock set.\n\n"
"Example: dblsr aitest 2\n"};
static void dblsrCallFunc(const iocshArgBuf *args)
{ dblsr(args[0].sval,args[1].ival);}
/* dbLockShowLocked */
static const iocshArg dbLockShowLockedArg0 = { "interest level",iocshArgInt};
static const iocshArg * const dbLockShowLockedArgs[1] = {&dbLockShowLockedArg0};
static const iocshFuncDef dbLockShowLockedFuncDef =
{"dbLockShowLocked",1,dbLockShowLockedArgs,
"Show Locksets which are currently locked.\n"};
static const iocshFuncDef dbLockShowLockedFuncDef = {
"dbLockShowLocked",1,dbLockShowLockedArgs,
"Show Locksets which are currently locked.\n"
"interest level argument is passed to epicsMutexShow to adjust reported\n"
"information.\n\n"
"Example: dbLockShowLocked 0\n"
};
static void dbLockShowLockedCallFunc(const iocshArgBuf *args)
{ dbLockShowLocked(args[0].ival);}
@@ -351,10 +418,9 @@ static void dbLockShowLockedCallFunc(const iocshArgBuf *args)
static const iocshArg scanOnceSetQueueSizeArg0 = { "size",iocshArgInt};
static const iocshArg * const scanOnceSetQueueSizeArgs[1] =
{&scanOnceSetQueueSizeArg0};
static const iocshFuncDef scanOnceSetQueueSizeFuncDef =
{"scanOnceSetQueueSize",1,scanOnceSetQueueSizeArgs,
"Change size of Scan once queue.\n"
"Must be called before iocInit().\n"};
static const iocshFuncDef scanOnceSetQueueSizeFuncDef = {"scanOnceSetQueueSize",1,scanOnceSetQueueSizeArgs,
"Change size of Scan once queue.\n"
"Must be called before iocInit().\n"};
static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
{
scanOnceSetQueueSize(args[0].ival);
@@ -364,9 +430,8 @@ static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
static const iocshArg scanOnceQueueShowArg0 = { "reset",iocshArgInt};
static const iocshArg * const scanOnceQueueShowArgs[1] =
{&scanOnceQueueShowArg0};
static const iocshFuncDef scanOnceQueueShowFuncDef =
{"scanOnceQueueShow",1,scanOnceQueueShowArgs,
"Show details and statitics of scan once queue processing.\n"};
static const iocshFuncDef scanOnceQueueShowFuncDef = {"scanOnceQueueShow",1,scanOnceQueueShowArgs,
"Show details and statitics of scan once queue processing.\n"};
static void scanOnceQueueShowCallFunc(const iocshArgBuf *args)
{
scanOnceQueueShow(args[0].ival);
@@ -376,7 +441,8 @@ static void scanOnceQueueShowCallFunc(const iocshArgBuf *args)
static const iocshArg scanpplArg0 = { "rate",iocshArgDouble};
static const iocshArg * const scanpplArgs[1] = {&scanpplArg0};
static const iocshFuncDef scanpplFuncDef = {"scanppl",1,scanpplArgs,
"print periodic scan lists.\n"};
"Print info for records with periodic scan.\n"
"If rate == 0.0, all periods are shown.\n"};
static void scanpplCallFunc(const iocshArgBuf *args)
{ scanppl(args[0].dval);}
@@ -408,10 +474,9 @@ static void scanpiolCallFunc(const iocshArgBuf *args) { scanpiol();}
static const iocshArg callbackSetQueueSizeArg0 = { "bufsize",iocshArgInt};
static const iocshArg * const callbackSetQueueSizeArgs[1] =
{&callbackSetQueueSizeArg0};
static const iocshFuncDef callbackSetQueueSizeFuncDef =
{"callbackSetQueueSize",1,callbackSetQueueSizeArgs,
"Change depth of queue for callback workers.\n"
"Must be called before iocInit().\n"};
static const iocshFuncDef callbackSetQueueSizeFuncDef = {"callbackSetQueueSize",1,callbackSetQueueSizeArgs,
"Change depth of queue for callback workers.\n"
"Must be called before iocInit().\n"};
static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
{
callbackSetQueueSize(args[0].ival);
@@ -421,9 +486,8 @@ static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
static const iocshArg callbackQueueShowArg0 = { "reset", iocshArgInt};
static const iocshArg * const callbackQueueShowArgs[1] =
{&callbackQueueShowArg0};
static const iocshFuncDef callbackQueueShowFuncDef =
{"callbackQueueShow",1,callbackQueueShowArgs,
"Show status of callback thread processing queue.\n"};
static const iocshFuncDef callbackQueueShowFuncDef = {"callbackQueueShow",1,callbackQueueShowArgs,
"Show status of callback thread processing queue.\n"};
static void callbackQueueShowCallFunc(const iocshArgBuf *args)
{
callbackQueueShow(args[0].ival);
@@ -434,11 +498,10 @@ static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgI
static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString};
static const iocshArg * const callbackParallelThreadsArgs[2] =
{&callbackParallelThreadsArg0,&callbackParallelThreadsArg1};
static const iocshFuncDef callbackParallelThreadsFuncDef =
{"callbackParallelThreads",2,callbackParallelThreadsArgs,
"Configure multiple workers for a given callback queue priority level.\n"
"priority may be omitted or \"*\" to act on all priorities\n"
"or one of LOW, MEDIUM, or HIGH.\n"};
static const iocshFuncDef callbackParallelThreadsFuncDef = {"callbackParallelThreads",2,callbackParallelThreadsArgs,
"Configure multiple workers for a given callback queue priority level.\n"
"priority may be omitted or \"*\" to act on all priorities\n"
"or one of LOW, MEDIUM, or HIGH.\n"};
static void callbackParallelThreadsCallFunc(const iocshArgBuf *args)
{
callbackParallelThreads(args[0].ival, args[1].sval);
@@ -447,8 +510,8 @@ static void callbackParallelThreadsCallFunc(const iocshArgBuf *args)
/* dbStateCreate */
static const iocshArg dbStateArgName = { "name", iocshArgString };
static const iocshArg * const dbStateCreateArgs[] = { &dbStateArgName };
static const iocshFuncDef dbStateCreateFuncDef = { "dbStateCreate", 1, dbStateCreateArgs,
"Allocate new state name for \"state\" filter.\n"};
static const iocshFuncDef dbStateCreateFuncDef = {"dbStateCreate", 1, dbStateCreateArgs,
"Allocate new state name for \"state\" filter.\n"};
static void dbStateCreateCallFunc (const iocshArgBuf *args)
{
dbStateCreate(args[0].sval);
@@ -456,8 +519,8 @@ static void dbStateCreateCallFunc (const iocshArgBuf *args)
/* dbStateSet */
static const iocshArg * const dbStateSetArgs[] = { &dbStateArgName };
static const iocshFuncDef dbStateSetFuncDef = { "dbStateSet", 1, dbStateSetArgs,
"Change state to set for \"state\" filter.\n"};
static const iocshFuncDef dbStateSetFuncDef = {"dbStateSet", 1, dbStateSetArgs,
"Change state to set for \"state\" filter.\n"};
static void dbStateSetCallFunc (const iocshArgBuf *args)
{
dbStateId sid = dbStateFind(args[0].sval);
@@ -468,8 +531,8 @@ static void dbStateSetCallFunc (const iocshArgBuf *args)
/* dbStateClear */
static const iocshArg * const dbStateClearArgs[] = { &dbStateArgName };
static const iocshFuncDef dbStateClearFuncDef = { "dbStateClear", 1, dbStateClearArgs,
"Change state to clear for \"state\" filter.\n" };
static const iocshFuncDef dbStateClearFuncDef = {"dbStateClear", 1, dbStateClearArgs,
"Change state to clear for \"state\" filter.\n"};
static void dbStateClearCallFunc (const iocshArgBuf *args)
{
dbStateId sid = dbStateFind(args[0].sval);
@@ -481,8 +544,8 @@ static void dbStateClearCallFunc (const iocshArgBuf *args)
/* dbStateShow */
static const iocshArg dbStateShowArg1 = { "level", iocshArgInt };
static const iocshArg * const dbStateShowArgs[] = { &dbStateArgName, &dbStateShowArg1 };
static const iocshFuncDef dbStateShowFuncDef = { "dbStateShow", 2, dbStateShowArgs,
"Show set/clear status of named state. (cf. \"state\" filter)\n" };
static const iocshFuncDef dbStateShowFuncDef = {"dbStateShow", 2, dbStateShowArgs,
"Show set/clear status of named state. (cf. \"state\" filter)\n"};
static void dbStateShowCallFunc (const iocshArgBuf *args)
{
dbStateId sid = dbStateFind(args[0].sval);
@@ -494,8 +557,8 @@ static void dbStateShowCallFunc (const iocshArgBuf *args)
/* dbStateShowAll */
static const iocshArg dbStateShowAllArg0 = { "level", iocshArgInt };
static const iocshArg * const dbStateShowAllArgs[] = { &dbStateShowAllArg0 };
static const iocshFuncDef dbStateShowAllFuncDef = { "dbStateShowAll", 1, dbStateShowAllArgs,
"Show set/clear status of all named states. (cf. \"state\" filter)\n" };
static const iocshFuncDef dbStateShowAllFuncDef = {"dbStateShowAll", 1, dbStateShowAllArgs,
"Show set/clear status of all named states. (cf. \"state\" filter)\n"};
static void dbStateShowAllCallFunc (const iocshArgBuf *args)
{
dbStateShowAll(args[0].ival);

View File

@@ -359,6 +359,8 @@ typedef struct lset {
* @param plink the link
* @param rtn routine to execute
* @returns status value
*
* @since 3.16.1
*/
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);

View File

@@ -869,7 +869,7 @@ nosplit:
}
}
static char *msstring[4]={"NMS","MS","MSI","MSS"};
static const char *msstring[4]={"NMS","MS","MSI","MSS"};
long dblsr(char *recordname,int level)
{

View File

@@ -24,18 +24,64 @@ extern "C" {
struct dbCommon;
struct dbBase;
/** @brief Lock multiple records.
*
* A dbLocker allows a caller to simultaneously lock multiple records.
* The list of records is provided to dbLockerAlloc().
* And the resulting dbLocker can be locked/unlocked repeatedly.
*
* Each thread can only lock one dbLocker at a time.
* While locked, dbScanLock() may be called only on those records
* included in the dbLocker.
*
* @since 3.16.0.1
*/
struct dbLocker;
typedef struct dbLocker dbLocker;
/** @brief Lock a record for modification.
*
* While locked, caller may access record using eg. dbGet() or dbPut(),
* but not dbGetField() or dbPutField().
* The caller must later call dbScanUnlock().
* dbScanLock() may be called again as the record lock behaves as a recursive mutex.
*/
DBCORE_API void dbScanLock(struct dbCommon *precord);
/** @brief Unlock a record.
*
* Reverse the action of dbScanLock()
*/
DBCORE_API void dbScanUnlock(struct dbCommon *precord);
/** @brief Prepare to lock a set of records.
* @param precs Array of nrecs dbCommon pointers.
* @param nrecs Length of precs array
* @param flags Set to 0
* @return NULL on error
* @since 3.16.0.1
*/
DBCORE_API dbLocker *dbLockerAlloc(struct dbCommon * const *precs,
size_t nrecs,
unsigned int flags);
DBCORE_API void dbLockerFree(dbLocker *);
/** @brief Free dbLocker allocated by dbLockerAlloc()
* @param plocker Must not be NULL
* @since 3.16.0.1
*/
DBCORE_API void dbLockerFree(dbLocker *plocker);
/** @brief Lock all records of dbLocker
*
* While locked, caller may access any associated record passed to dbLockerAlloc() .
* dbScanLockMany() may not be called again (multi-lock is not recursive).
* dbScanLock()/dbScanUnlock() may be called on individual record.
* The caller must later call dbScanUnlockMany().
* @since 3.16.0.1
*/
DBCORE_API void dbScanLockMany(dbLocker*);
/** @brief Unlock all records of dbLocker
* @since 3.16.0.1
*/
DBCORE_API void dbScanUnlockMany(dbLocker*);
DBCORE_API unsigned long dbLockGetLockId(

View File

@@ -10,6 +10,7 @@
#define DBLOCKPVT_H
#include "dbLock.h"
#include "epicsMutex.h"
#include "epicsSpin.h"
/* Define to enable additional error checking */

View File

@@ -506,62 +506,62 @@ long dbtgf(const char *pname)
ret_options=0;
dbr_type = DBR_STRING;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/MAX_STRING_SIZE));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_CHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt8))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UCHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt8))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_SHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt16))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_USHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt16))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_LONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt32))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ULONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt32))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_INT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt64))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UINT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt64))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_FLOAT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsFloat32))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_DOUBLE;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsFloat64))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ENUM;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16)));
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsEnum16))));
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);

View File

@@ -50,6 +50,7 @@ void testdbPrepare(void)
{
if(!testEvtLock)
testEvtLock = epicsMutexMustCreate();
initHookAnnounce(initHookAfterPrepareDatabase);
}
void testdbReadDatabase(const char* file,
@@ -94,6 +95,7 @@ void testIocShutdownOk(void)
void testdbCleanup(void)
{
initHookAnnounce(initHookBeforeCleanupDatabase);
dbFreeBase(pdbbase);
db_cleanup_events();
initHookFree();

View File

@@ -1068,7 +1068,7 @@ int dbRecordNameValidate(const char *name)
const char *pos = name;
if (!*name) {
yyerrorAbort("Error: Record/Alias name can't be empty");
yyerrorAbort(ERL_ERROR ": Record/Alias name can't be empty");
return 1;
}
@@ -1086,7 +1086,7 @@ int dbRecordNameValidate(const char *name)
name, c);
} else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') {
epicsPrintf("Error: Bad character '%c' in Record/Alias name \"%s\"\n",
epicsPrintf(ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n",
c, name);
yyerrorAbort(NULL);
return 1;
@@ -1110,14 +1110,10 @@ static void dbRecordHead(char *recordType, char *name, int visible)
allocTemp(pdbentry);
if (recordType[0] == '*' && recordType[1] == 0) {
if (dbRecordsOnceOnly)
epicsPrintf("Record-type \"*\" not valid with dbRecordsOnceOnly\n");
else {
status = dbFindRecord(pdbentry, name);
if (status == 0)
return; /* done */
epicsPrintf("Record \"%s\" not found\n", name);
}
status = dbFindRecord(pdbentry, name);
if (status == 0)
return; /* done */
epicsPrintf(ERL_ERROR ": Record \"%s\" not found\n", name);
yyerror(NULL);
duplicate = TRUE;
return;
@@ -1136,15 +1132,16 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbCreateRecord(pdbentry,name);
if (status == S_dbLib_recExists) {
if (strcmp(recordType, dbGetRecordTypeName(pdbentry)) != 0) {
epicsPrintf("Record \"%s\" of type \"%s\" redefined with new type "
epicsPrintf(ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type "
"\"%s\"\n", name, dbGetRecordTypeName(pdbentry), recordType);
yyerror(NULL);
duplicate = TRUE;
return;
}
else if (dbRecordsOnceOnly) {
epicsPrintf("Record \"%s\" already defined (dbRecordsOnceOnly is "
"set)\n", name);
epicsPrintf(ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n"
"Used record type \"*\" to append.\n",
name);
yyerror(NULL);
duplicate = TRUE;
}
@@ -1170,8 +1167,28 @@ static void dbRecordField(char *name,char *value)
pdbentry = ptempListNode->item;
status = dbFindField(pdbentry,name);
if (status) {
epicsPrintf("Record \"%s\" does not have a field \"%s\"\n",
dbGetRecordName(pdbentry), name);
epicsPrintf("%s Record \"%s\" does not have a field \"%s\"\n",
dbGetRecordTypeName(pdbentry), dbGetRecordName(pdbentry), name);
if(dbGetRecordName(pdbentry)) {
DBENTRY temp;
double bestSim = -1.0;
const dbFldDes *bestFld = NULL;
dbCopyEntryContents(pdbentry, &temp);
for(status = dbFirstField(&temp, 0); !status; status = dbNextField(&temp, 0)) {
double sim = epicsStrSimilarity(name, temp.pflddes->name);
if(!bestFld || sim > bestSim) {
bestSim = sim;
bestFld = temp.pflddes;
}
}
dbFinishEntry(&temp);
if(bestSim>0.0) {
epicsPrintf(" Did you mean \"%s\"?", bestFld->name);
if(bestFld->prompt)
epicsPrintf(" (%s)", bestFld->prompt);
epicsPrintf("\n");
}
}
yyerror(NULL);
return;
}
@@ -1258,7 +1275,7 @@ static void dbAlias(char *name, char *alias)
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
if(dbRecordNameValidate(alias))
if(dbRecordNameValidate(alias) || dbRecordNameValidate(name))
return;
dbInitEntry(savedPdbbase, pdbEntry);

View File

@@ -10,6 +10,7 @@
#include "iocsh.h"
#include "errSymTbl.h"
#include "errlog.h"
#include "dbStaticIocRegister.h"
#include "dbStaticLib.h"
@@ -24,7 +25,8 @@ static const iocshArg argRecType = { "recordTypeName", iocshArgString};
/* dbDumpPath */
static const iocshArg * const dbDumpPathArgs[] = {&argPdbbase};
static const iocshFuncDef dbDumpPathFuncDef = {"dbDumpPath",1,dbDumpPathArgs,
"Dump .db/.dbd file search path.\n"};
"Dump .db/.dbd file search path.\n"
"Example: dbDumpPath pdbbase\n"};
static void dbDumpPathCallFunc(const iocshArgBuf *args)
{
dbDumpPath(*iocshPpdbbase);
@@ -99,7 +101,8 @@ static void dbDumpDeviceCallFunc(const iocshArgBuf *args)
static const iocshArg * const dbDumpDriverArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpDriverFuncDef = {"dbDumpDriver",1,dbDumpDriverArgs,
"Dump device support information.\n"
"Example: dbDumpDriver pdbbase\n"};
"Example: dbDumpDriver pdbbase\n"
"If the last argument(s) are missing, dump all device support information.\n",};
static void dbDumpDriverCallFunc(const iocshArgBuf *args)
{
dbDumpDriver(*iocshPpdbbase);
@@ -124,7 +127,8 @@ static const iocshArg * const dbDumpRegistrarArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs,
"Dump list of registered functions including ones for subroutine records,\n"
"and ones that can be invoked from iocsh.\n"
"Example: dbDumpRegistrar pdbbase\n"};
"Example: dbDumpRegistrar pdbbase\n"
"If last argument(s) are missing, dump all registered functions\n"};
static void dbDumpRegistrarCallFunc(const iocshArgBuf *args)
{
dbDumpRegistrar(*iocshPpdbbase);
@@ -134,7 +138,8 @@ static void dbDumpRegistrarCallFunc(const iocshArgBuf *args)
static const iocshArg * const dbDumpFunctionArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpFunctionFuncDef = {"dbDumpFunction",1,dbDumpFunctionArgs,
"Dump list of registered subroutine functions.\n"
"Example: dbDumpFunction pddbase\n"};
"Example: dbDumpFunction pddbase\n"
"If last argument(s) are missing, dump all registered subroutine functions\n"};
static void dbDumpFunctionCallFunc(const iocshArgBuf *args)
{
dbDumpFunction(*iocshPpdbbase);
@@ -144,7 +149,8 @@ static void dbDumpFunctionCallFunc(const iocshArgBuf *args)
static const iocshArg * const dbDumpVariableArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpVariableFuncDef = {"dbDumpVariable",1,dbDumpVariableArgs,
"Dump list of variables used in the database.\n"
"Example: dbDumpVariable pddbase\n"};
"Example: dbDumpVariable pddbase\n"
"If last argument(s) are missing, dump all variables.\n"};
static void dbDumpVariableCallFunc(const iocshArgBuf *args)
{
dbDumpVariable(*iocshPpdbbase);
@@ -159,7 +165,8 @@ static const iocshFuncDef dbDumpBreaktableFuncDef = {
2,
dbDumpBreaktableArgs,
"Dump the given break table\n"
"Example: dbDumpBreaktable pdbbase typeKdegC\n",
"Example: dbDumpBreaktable pdbbase typeKdegC\n"
"If last argument(s) are missing, dump all breakpoint tables.\n",
};
static void dbDumpBreaktableCallFunc(const iocshArgBuf *args)
{
@@ -176,7 +183,8 @@ static const iocshFuncDef dbPvdDumpFuncDef = {
dbPvdDumpArgs,
"Dump the various buckets of the process variable directory.\n"
"If verbose is greater than 0, also print the process variables in each bucket.\n"
"Example: dbPvdDump pdbbase 1\n",
"Example: dbPvdDump pdbbase 1\n"
"If the last argument(s) are missing, dump all buckets as though verbose is 0.\n",
};
static void dbPvdDumpCallFunc(const iocshArgBuf *args)
{
@@ -247,7 +255,7 @@ static void dbCreateAliasCallFunc(const iocshArgBuf *args)
}
dbFinishEntry(&ent);
if(status) {
fprintf(stderr, "Error: %ld %s\n", status, errSymMsg(status));
fprintf(stderr, ERL_ERROR ": %ld %s\n", status, errSymMsg(status));
iocshSetError(1);
}
}

View File

@@ -57,10 +57,10 @@ static char *pNullString = "";
*/
STATIC_ASSERT(messagesize >= 21);
static char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"};
static char *msstring[4]={" NMS"," MS"," MSI"," MSS"};
static const char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"};
static const char *msstring[4]={" NMS"," MS"," MSI"," MSS"};
maplinkType pamaplinkType[LINK_NTYPES] = {
const maplinkType pamaplinkType[LINK_NTYPES] = {
{"CONSTANT",CONSTANT},
{"PV_LINK",PV_LINK},
{"VME_IO",VME_IO},
@@ -89,7 +89,7 @@ static FILE *openOutstream(const char *filename)
errno = 0;
stream = fopen(filename,"w");
if(!stream) {
fprintf(stderr,"error opening %s %s\n",filename,strerror(errno));
fprintf(stderr,ERL_ERROR " opening %s %s\n",filename,strerror(errno));
return 0;
}
return stream;
@@ -637,7 +637,7 @@ void dbFinishEntry(DBENTRY *pdbentry)
}
}
DBENTRY * dbCopyEntry(DBENTRY *pdbentry)
DBENTRY * dbCopyEntry(const DBENTRY *pdbentry)
{
DBENTRY *pnew;
@@ -647,7 +647,7 @@ DBENTRY * dbCopyEntry(DBENTRY *pdbentry)
return(pnew);
}
void dbCopyEntryContents(DBENTRY *pfrom,DBENTRY *pto)
void dbCopyEntryContents(const DBENTRY *pfrom,DBENTRY *pto)
{
*pto = *pfrom;
pto->message = NULL;
@@ -2204,11 +2204,11 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
*/
} else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
errlogPrintf("Error: %s.%s: can't initialize link type %d with \"%s\" (type %d)\n",
errlogPrintf(ERL_ERROR ": %s.%s: can't initialize link type %d with \"%s\" (type %d)\n",
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
} else if(dbSetLink(plink, &link_info, devsup)) {
errlogPrintf("Error: %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n",
errlogPrintf(ERL_ERROR ": %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n",
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
}
free(plink->text);

View File

@@ -51,9 +51,9 @@ DBCORE_API void dbInitEntry(DBBASE *pdbbase,
DBENTRY *pdbentry);
DBCORE_API void dbFinishEntry(DBENTRY *pdbentry);
DBCORE_API DBENTRY * dbCopyEntry(DBENTRY *pdbentry);
DBCORE_API void dbCopyEntryContents(DBENTRY *pfrom,
DBENTRY *pto);
DBCORE_API DBENTRY * dbCopyEntry(const DBENTRY *pdbentry);
DBCORE_API void dbCopyEntryContents(const DBENTRY *pfrom,
DBENTRY *pto);
DBCORE_API extern int dbBptNotMonotonic;

View File

@@ -143,7 +143,7 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName)
status = dbPutStringNum(pdbentry,pflddes->initial);
if(status)
epicsPrintf("Error initializing %s.%s initial %s\n",
epicsPrintf(ERL_ERROR " initializing %s.%s initial %s\n",
pdbRecordType->name,pflddes->name,pflddes->initial);
}
break;

View File

@@ -370,9 +370,9 @@ json_value: jsonNULL { $$ = dbmfStrdup("null"); }
static int yyerror(char *str)
{
if (str)
epicsPrintf("Error: %s\n", str);
epicsPrintf(ERL_ERROR ": %s\n", str);
else
epicsPrintf("Error");
epicsPrintf(ERL_ERROR "");
if (!yyFailed) { /* Only print this stuff once */
epicsPrintf(" at or before '%s'", yytext);
dbIncludePrint();

View File

@@ -43,11 +43,11 @@ extern "C" {
#define VXI_IO 15
#define LINK_NTYPES 16
typedef struct maplinkType {
char *strvalue;
const char *strvalue;
int value;
} maplinkType;
DBCORE_API extern maplinkType pamaplinkType[];
DBCORE_API extern const maplinkType pamaplinkType[LINK_NTYPES];
#define VXIDYNAMIC 0
#define VXISTATIC 1

View File

@@ -16,6 +16,7 @@
#include "osiUnistd.h"
#include "macLib.h"
#include "dbmf.h"
#include "errlog.h"
#include "epicsExport.h"
#include "dbAccess.h"
@@ -337,7 +338,7 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect)
if (dbTemplateMaxVars < 1)
{
fprintf(stderr,"Error: dbTemplateMaxVars = %d, must be +ve\n",
fprintf(stderr,ERL_ERROR ": dbTemplateMaxVars = %d, must be +ve\n",
dbTemplateMaxVars);
return -1;
}

View File

@@ -264,7 +264,7 @@ static void addMacroReplacements(MAC_HANDLE * const macPvt,
if (status) {
status = macInstallMacros(macPvt, pairs);
if (!status) {
fprintf(stderr, "Error from macInstallMacros\n");
fprintf(stderr, ERL_ERROR " from macInstallMacros\n");
usageExit(1);
}
free(pairs);
@@ -522,7 +522,7 @@ static void inputOpenFile(inputData *pinputData, const char * const filename)
}
if (!fp) {
fprintf(stderr, "msi: Can't open file '%s'\n", filename);
fprintf(stderr, ERL_ERROR " msi: Can't open file '%s'\n", filename);
inputErrPrint(pinputData);
abortExit(1);
}
@@ -672,7 +672,7 @@ static void substituteOpen(subInfo **ppvt, const std::string& substitutionName)
fp = fopen(substitutionName.c_str(), "r");
if (!fp) {
fprintf(stderr, "msi: Can't open file '%s'\n", substitutionName.c_str());
fprintf(stderr, ERL_ERROR " msi: Can't open file '%s'\n", substitutionName.c_str());
abortExit(1);
}

View File

@@ -173,7 +173,7 @@ static int iocBuild_2(void)
scanInit();
if (asInit()) {
errlogPrintf("iocBuild: asInit Failed.\n");
errlogPrintf(ERL_ERROR " iocBuild: asInit Failed.\n");
return -1;
}
dbProcessNotifyInit();

View File

@@ -38,7 +38,7 @@ static void iocBuildCallFunc(const iocshArgBuf *args)
/* iocRun */
static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL,
"Bring the IOC out of its initial quiescent state to the running state.\n"
"See more: iocBuild, iocPause"};
"See more: iocBuild, iocPause\n"};
static void iocRunCallFunc(const iocshArgBuf *args)
{
iocshSetError(iocRun());
@@ -47,7 +47,7 @@ static void iocRunCallFunc(const iocshArgBuf *args)
/* iocPause */
static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL,
"Brings a running IOC to a quiescent state with all record processing frozen.\n"
"See more: iocBuild, iocRub, iocInit"};
"See more: iocBuild, iocRub, iocInit\n"};
static void iocPauseCallFunc(const iocshArgBuf *args)
{
iocshSetError(iocPause());

View File

@@ -17,6 +17,7 @@
#include <epicsStdio.h>
#include <epicsFindSymbol.h>
#include <errlog.h>
#include <registryRecordType.h>
#include <registryDeviceSupport.h>
#include <registryDriverSupport.h>
@@ -248,7 +249,7 @@ registerAllRecordDeviceDrivers(DBBASE *pdbbase)
} catch(std::exception& e) {
dbFinishEntry(&entry);
fprintf(stderr, "Error: %s\n", e.what());
fprintf(stderr, ERL_ERROR ": %s\n", e.what());
return 2;
}
}

View File

@@ -51,6 +51,9 @@ static long readLocked(struct link *pinp, void *dummy)
if (status) return status;
if (prec->mask)
prec->rval &= prec->mask;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);

View File

@@ -17,6 +17,7 @@
#include <stdio.h>
#include "freeList.h"
#include "caeventmask.h"
#include "db_field_log.h"
#include "chfPlugin.h"
#include "epicsExit.h"
@@ -60,7 +61,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
myStruct *my = (myStruct*) pvt;
epicsInt32 i = my->i;
if (pfl->ctx == dbfl_context_read)
if (pfl->ctx == dbfl_context_read || (pfl->mask & DBE_PROPERTY))
return pfl;
if (i++ == 0)

View File

@@ -14,6 +14,7 @@
#include <stdio.h>
#include "freeList.h"
#include "caeventmask.h"
#include "db_field_log.h"
#include "chfPlugin.h"
#include "dbState.h"
@@ -94,7 +95,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
myStruct *my = (myStruct*) pvt;
int actstate;
if (pfl->ctx == dbfl_context_read)
if (pfl->ctx == dbfl_context_read || (pfl->mask & DBE_PROPERTY))
return pfl;
actstate = dbStateGet(my->id);

View File

@@ -60,8 +60,10 @@ this chapter for information on soft device support.
If the record gets its values from hardware or uses the C<Raw Soft Channel>
device support, the device support routines place the value in the RVAL
field which is then converted using the process described in the next
section.
field.
(Since 7.0.8) If the MASK field is non-zero, then this MASK is applied to RVAL.
The value from RVAL is then converted using the process described in the
next section.
=fields INP, DTYP, ZNAM, ONAM, RVAL, VAL

View File

@@ -36,7 +36,7 @@ The desired output needs to be in engineering units.
The first field that determines where the desired output originates is the
output mode select (OMSL) field, which can have two possible values:
C<losed_loop> or C<supervisory>. If C<supervisory> is specified, the value
C<closed_loop> or C<supervisory>. If C<supervisory> is specified, the value
in the VAL field can be set 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 Link (DOL) field which can be a

View File

@@ -158,7 +158,7 @@ CEIL: Ceiling (unary)
FLOOR: Floor (unary)
=item *
FMOD: Floating point modulo (binary) Added in UNRELEASED
FMOD: Floating point modulo (binary) Added in 7.0.8
=item *
LOG: Log base 10 (unary)
@@ -460,12 +460,17 @@ conditions.
The HYST field defines an alarm deadband for each limit.
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).
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
for a complete explanation of record alarms and of the standard fields.
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
to alarms that are common to all record types.
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC
=head3 Monitor Parameters
@@ -496,7 +501,7 @@ manner for the VAL field.
=cut
include "dbCommon.dbd"
include "dbCommon.dbd"
field(VAL,DBF_DOUBLE) {
prompt("Result")
promptgroup("50 - Output")

View File

@@ -184,7 +184,7 @@ CEIL: Ceiling (unary)
FLOOR: Floor (unary)
=item *
FMOD: Floating point modulo (binary) Added in UNRELEASED
FMOD: Floating point modulo (binary) Added in 7.0.8
=item *
LOG: Log base 10 (unary)

View File

@@ -70,6 +70,15 @@ The possible alarm conditions for long inputs are the SCAN, READ, and limit
alarms. The SCAN and READ alarms are called by the record or device support
routines.
The HYST field controls hysteresis to prevent alarm chattering from an input
signal that is close to one of the limits and suffers from significant readout
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).
The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW
fields using numerical values. For each of these fields, there is a
corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. The
@@ -77,7 +86,7 @@ HYST field can be used to specify a deadband around each limit.
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists the fields related to
alarms that are common to all record types.
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC
=head3 Monitor Parameters

View File

@@ -85,7 +85,7 @@ for information on the format of hardware addresses and database links.
=head4 Menu longoutOOPT
The OOPT field was added in EPICS UNRELEASED.
The OOPT field was added in EPICS 7.0.8.
It determines the condition that causes the output link to be
written to. It's a menu field that has six choices:
@@ -119,7 +119,7 @@ VAL is non-zero and last value was zero.
=head4 Changes in OUT field when OOPT = On Change
The OOCH field was added in EPICS UNRELEASED.
The OOCH field was added in EPICS 7.0.8.
If OOCH is C<YES> (its default value) and the OOPT field is C<On Change>,
the record will write to the device support the first time the record gets

View File

@@ -405,6 +405,11 @@ and state alarms. The state alarms are configured in the below severity fields.
These fields have the usual possible values for severity fields: NO_ALARM,
MINOR, and MAJOR.
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).
The unknown state severity (UNSV) field, if set to MINOR or MAJOR, triggers an
alarm when the record support routine cannot find a matching value in the state
value fields for C<<< rval >>>.
@@ -420,7 +425,7 @@ for a complete explanation of record alarms and of the standard fields.
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
to alarms that are common to all record types.
=fields UNSV, COSV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV
=fields UNSV, COSV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV, AFTC
=cut

View File

@@ -322,6 +322,7 @@ to alarms that are common to all record types.
field(B0,DBF_UCHAR) {
prompt("Bit 0")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -329,6 +330,7 @@ to alarms that are common to all record types.
field(B1,DBF_UCHAR) {
prompt("Bit 1")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -336,6 +338,7 @@ to alarms that are common to all record types.
field(B2,DBF_UCHAR) {
prompt("Bit 2")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -343,6 +346,7 @@ to alarms that are common to all record types.
field(B3,DBF_UCHAR) {
prompt("Bit 3")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -350,6 +354,7 @@ to alarms that are common to all record types.
field(B4,DBF_UCHAR) {
prompt("Bit 4")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -357,6 +362,7 @@ to alarms that are common to all record types.
field(B5,DBF_UCHAR) {
prompt("Bit 5")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -364,6 +370,7 @@ to alarms that are common to all record types.
field(B6,DBF_UCHAR) {
prompt("Bit 6")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -371,6 +378,7 @@ to alarms that are common to all record types.
field(B7,DBF_UCHAR) {
prompt("Bit 7")
promptgroup("51 - Output 0-7")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -378,6 +386,7 @@ to alarms that are common to all record types.
field(B8,DBF_UCHAR) {
prompt("Bit 8")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -385,6 +394,7 @@ to alarms that are common to all record types.
field(B9,DBF_UCHAR) {
prompt("Bit 9")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -392,6 +402,7 @@ to alarms that are common to all record types.
field(BA,DBF_UCHAR) {
prompt("Bit 10")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -399,6 +410,7 @@ to alarms that are common to all record types.
field(BB,DBF_UCHAR) {
prompt("Bit 11")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -406,6 +418,7 @@ to alarms that are common to all record types.
field(BC,DBF_UCHAR) {
prompt("Bit 12")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -413,6 +426,7 @@ to alarms that are common to all record types.
field(BD,DBF_UCHAR) {
prompt("Bit 13")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -420,6 +434,7 @@ to alarms that are common to all record types.
field(BE,DBF_UCHAR) {
prompt("Bit 14")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -427,6 +442,7 @@ to alarms that are common to all record types.
field(BF,DBF_UCHAR) {
prompt("Bit 15")
promptgroup("52 - Output 8-15")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -434,6 +450,7 @@ to alarms that are common to all record types.
field(B10,DBF_UCHAR) {
prompt("Bit 16")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -441,6 +458,7 @@ to alarms that are common to all record types.
field(B11,DBF_UCHAR) {
prompt("Bit 17")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -448,6 +466,7 @@ to alarms that are common to all record types.
field(B12,DBF_UCHAR) {
prompt("Bit 18")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -455,6 +474,7 @@ to alarms that are common to all record types.
field(B13,DBF_UCHAR) {
prompt("Bit 19")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -462,6 +482,7 @@ to alarms that are common to all record types.
field(B14,DBF_UCHAR) {
prompt("Bit 20")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -469,6 +490,7 @@ to alarms that are common to all record types.
field(B15,DBF_UCHAR) {
prompt("Bit 21")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -476,6 +498,7 @@ to alarms that are common to all record types.
field(B16,DBF_UCHAR) {
prompt("Bit 22")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -483,6 +506,7 @@ to alarms that are common to all record types.
field(B17,DBF_UCHAR) {
prompt("Bit 23")
promptgroup("53 - Output 16-23")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -490,6 +514,7 @@ to alarms that are common to all record types.
field(B18,DBF_UCHAR) {
prompt("Bit 24")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -497,6 +522,7 @@ to alarms that are common to all record types.
field(B19,DBF_UCHAR) {
prompt("Bit 25")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -504,6 +530,7 @@ to alarms that are common to all record types.
field(B1A,DBF_UCHAR) {
prompt("Bit 26")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -511,6 +538,7 @@ to alarms that are common to all record types.
field(B1B,DBF_UCHAR) {
prompt("Bit 27")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -518,6 +546,7 @@ to alarms that are common to all record types.
field(B1C,DBF_UCHAR) {
prompt("Bit 28")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -525,6 +554,7 @@ to alarms that are common to all record types.
field(B1D,DBF_UCHAR) {
prompt("Bit 29")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -532,6 +562,7 @@ to alarms that are common to all record types.
field(B1E,DBF_UCHAR) {
prompt("Bit 30")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)
@@ -539,6 +570,7 @@ to alarms that are common to all record types.
field(B1F,DBF_UCHAR) {
prompt("Bit 31")
promptgroup("54 - Output 24-31")
asl(ASL0)
special(SPC_MOD)
pp(TRUE)
interest(1)

View File

@@ -57,6 +57,14 @@
else \
flags |= F_BADLNK
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-security"
/* Intentionally passing non-const format string to epicsSnprintf() below.
* Older GCC does not allow pragma GCC within function body.
*/
#endif
static void doPrintf(printfRecord *prec)
{
const char *pfmt = prec->fmt;
@@ -169,7 +177,7 @@ static void doPrintf(printfRecord *prec)
precision = 0;
if (ch == '%') {
added = epicsSnprintf(pval, vspace + 1, "%s", format);
added = epicsSnprintf(pval, vspace + 1, format);
}
else if (linkn++ >= PRINTF_NLINKS) {
/* No more LNKn fields */
@@ -314,6 +322,9 @@ static void doPrintf(printfRecord *prec)
prec->len = pval - prec->val;
}
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
static long init_record(struct dbCommon *pcommon, int pass)
{

View File

@@ -20,10 +20,14 @@ use EPICS::Getopts;
use EPICS::Readfile;
use EPICS::macLib;
our ($opt_D, @opt_I, @opt_S, $opt_o);
our ($opt_D, $opt_A, @opt_I, @opt_S, $opt_o);
getopts('DI@S@o:') or
die "Usage: dbdExpand [-D] [-I dir] [-S macro=val] [-o out.dbd] in.dbd ...";
getopts('DAI@S@o:') or
die "Usage: dbdExpand [-D] [-A] [-I dir] [-S macro=val] [-o out.dbd] in.dbd ...";
if ($opt_A) {
$DBD::Parser::allowAutoDeclarations = 1;
}
my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32?
my $macros = EPICS::macLib->new(@opt_S);

View File

@@ -181,6 +181,8 @@ dbStaticTest_SRCS += dbStaticTest.c
dbStaticTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbStaticTest.c
TESTFILES += ../dbStaticTest.db
TESTFILES += ../dbStaticTestAlias1.db
TESTFILES += ../dbStaticTestAlias2.db
TESTS += dbStaticTest
# This runs all the test programs in a known working order:

View File

@@ -4,6 +4,8 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define EPICS_PRIVATE_API
#include <string.h>
#include <errlog.h>

View File

@@ -291,6 +291,18 @@ static void testDbVerify(const char *record)
dbFinishEntry(&entry);
}
static void testWrongAliasRecord(const char *filename)
{
FILE *fp = NULL;
dbPath(pdbbase,"." OSI_PATH_LIST_SEPARATOR "..");
dbOpenFile(pdbbase, filename, &fp);
if(!fp) {
testAbort("Unable to read %s", filename);
}
testOk(dbReadDatabaseFP(&pdbbase, fp, NULL, NULL) != 0,
"Wrong alias record in %s is expected to fail", filename);
}
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(dbStaticTest)
@@ -298,13 +310,14 @@ MAIN(dbStaticTest)
const char *ldir;
FILE *fp = NULL;
testPlan(310);
testPlan(312);
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
dbTestIoc_registerRecordDeviceDriver(pdbbase);
dbPath(pdbbase,"." OSI_PATH_LIST_SEPARATOR "..");
if(!(ldir = dbOpenFile(pdbbase, "dbStaticTest.db", &fp))) {
ldir = dbOpenFile(pdbbase, "dbStaticTest.db", &fp);
if(!fp) {
testAbort("Unable to read dbStaticTest.db");
}
if(dbReadDatabaseFP(&pdbbase, fp, NULL, NULL)) {
@@ -312,6 +325,9 @@ MAIN(dbStaticTest)
ldir, OSI_PATH_LIST_SEPARATOR);
}
testWrongAliasRecord("dbStaticTestAlias1.db");
testWrongAliasRecord("dbStaticTestAlias2.db");
testEntry("testrec.VAL");
testEntry("testalias.VAL");
testEntry("testalias2.VAL");

View File

@@ -0,0 +1,4 @@
record(x, "testrec2alias") {
}
alias("testrec2alias.NAME", "testalias4")

View File

@@ -0,0 +1,4 @@
record(x, "testrec2alias2") {
}
alias("testrec2alias2", "testalias5.NAME")

View File

@@ -23,6 +23,11 @@ PROD_LIBS = dbRecStdTest dbRecStd dbCore ca Com
TARGETS += $(COMMON_DIR)/recTestIoc.dbd
DBDDEPENDS_FILES += recTestIoc.dbd$(DEP)
recTestIoc_DBD = base.dbd
recTestIoc_DBD += bptTypeKdegC.dbd
recTestIoc_DBD += bptTypeKdegF.dbd
recTestIoc_DBD += bptTypeJdegF.dbd
recTestIoc_DBD += bptTypeJdegC.dbd
TESTFILES += $(COMMON_DIR)/recTestIoc.dbd
testHarness_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
@@ -93,6 +98,34 @@ testHarness_SRCS += longoutTest.c
TESTFILES += ../longoutTest.db
TESTS += longoutTest
TESTPROD_HOST += boTest
boTest_SRCS += boTest.c
boTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += boTest.c
TESTFILES += ../boTest.db
TESTS += boTest
TESTPROD_HOST += biTest
biTest_SRCS += biTest.c
biTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += biTest.c
TESTFILES += ../biTest.db
TESTS += biTest
TESTPROD_HOST += printfTest
printfTest_SRCS += printfTest.c
printfTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += printfTest.c
TESTFILES += ../printfTest.db
TESTS += printfTest
TESTPROD_HOST += aiTest
aiTest_SRCS += aiTest.c
aiTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += aiTest.c
TESTFILES += ../aiTest.db
TESTS += aiTest
TARGETS += $(COMMON_DIR)/asTestIoc.dbd
DBDDEPENDS_FILES += asTestIoc.dbd$(DEP)
asTestIoc_DBD += base.dbd

View File

@@ -0,0 +1,445 @@
/*************************************************************************\
* Copyright (c) 2023 Karl Vestin
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "dbUnitTest.h"
#include "testMain.h"
#include "errlog.h"
#include "dbAccess.h"
#include "menuAlarmSevr.h"
#include "menuConvert.h"
#include "epicsMath.h"
#include "menuScan.h"
#include "caeventmask.h"
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void test_soft_input(void){
double value = 543.123;
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set VAL to on linked record */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, value);
/* verify that this record VAL is updated but RVAL is not */
testdbGetFieldEqual("test_ai_rec.VAL", DBF_DOUBLE, value);
testdbGetFieldEqual("test_ai_rec.RVAL", DBF_DOUBLE, 0.0);
// number of tests = 6
}
static void test_raw_soft_input(void){
double value = -255;
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set VAL to on linked record */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, value);
/* verify that this record RVAL and VAL are updated */
testdbGetFieldEqual("test_ai_rec.VAL", DBF_DOUBLE, value);
testdbGetFieldEqual("test_ai_rec.RVAL", DBF_DOUBLE, value);
// number of tests = 6
}
static void test_operator_display(void){
const short hopr = 199;
const short lopr = 50;
const short prec = 2;
const char egu[] = "mm";
const char desc[] = "hmm?";
/* set operator display parameters */
testdbPutFieldOk("test_ai_rec.EGU", DBF_STRING, egu);
testdbPutFieldOk("test_ai_rec.DESC", DBF_STRING, desc);
testdbPutFieldOk("test_ai_rec.HOPR", DBF_SHORT, hopr);
testdbPutFieldOk("test_ai_rec.LOPR", DBF_SHORT, lopr);
testdbPutFieldOk("test_ai_rec.PREC", DBF_SHORT, prec);
/* verify operator display parameters read back */
testdbGetFieldEqual("test_ai_rec.NAME", DBF_STRING, "test_ai_rec");
testdbGetFieldEqual("test_ai_rec.EGU", DBF_STRING, egu);
testdbGetFieldEqual("test_ai_rec.DESC", DBF_STRING, desc);
testdbGetFieldEqual("test_ai_rec.HOPR", DBF_SHORT, hopr);
testdbGetFieldEqual("test_ai_rec.LOPR", DBF_SHORT, lopr);
testdbGetFieldEqual("test_ai_rec.PREC", DBF_SHORT, prec);
// number of tests = 7
}
static void test_no_linr_unit_conversion(void){
const short roff = 10;
const short aslo = 2;
const short aoff = 4;
const short rval = 9;
const short val = (((rval + roff) * aslo) + aoff);
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set unit conversion parameters */
testdbPutFieldOk("test_ai_rec.ROFF", DBF_SHORT, roff);
testdbPutFieldOk("test_ai_rec.ASLO", DBF_SHORT, aslo);
testdbPutFieldOk("test_ai_rec.AOFF", DBF_SHORT, aoff);
testdbPutFieldOk("test_ai_rec.LINR", DBF_LONG, menuConvertNO_CONVERSION);
/* verify conversion */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_SHORT, rval);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_SHORT, val);
testdbGetFieldEqual("test_ai_rec.RVAL", DBF_SHORT, rval);
// number of tests = 10
}
static void test_slope_linr_unit_conversion(void){
const short roff = 1;
const short aslo = 3;
const short aoff = 99;
const short eslo = 3;
const short eoff = 2;
const short rval = 7;
const short val = ((((rval + roff) * aslo) + aoff) * eslo) + eoff;
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set unit conversion parameters */
testdbPutFieldOk("test_ai_rec.ROFF", DBF_LONG, roff);
testdbPutFieldOk("test_ai_rec.ASLO", DBF_LONG, aslo);
testdbPutFieldOk("test_ai_rec.AOFF", DBF_LONG, aoff);
testdbPutFieldOk("test_ai_rec.ESLO", DBF_LONG, eslo);
testdbPutFieldOk("test_ai_rec.EOFF", DBF_LONG, eoff);
testdbPutFieldOk("test_ai_rec.LINR", DBF_LONG, menuConvertSLOPE);
/* verify conversion */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_LONG, rval);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_LONG, val);
testdbGetFieldEqual("test_ai_rec.RVAL", DBF_LONG, rval);
// number of tests = 12
}
static void test_linear_linr_unit_conversion(void){
const long roff = 6;
const long aslo = 2;
const long aoff = 19;
const long eslo = 4;
const long eoff = 1;
const long egul = 9999;
const long eguf = -1000;
const long rval = 2;
/* Since our raw soft input does not support EGUL and EGUF conversion LINEAR should work like SLOPE */
const long val = ((((rval + roff) * aslo) + aoff) * eslo) + eoff;
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set unit conversion parameters */
testdbPutFieldOk("test_ai_rec.ROFF", DBF_LONG, roff);
testdbPutFieldOk("test_ai_rec.ASLO", DBF_LONG, aslo);
testdbPutFieldOk("test_ai_rec.AOFF", DBF_LONG, aoff);
testdbPutFieldOk("test_ai_rec.ESLO", DBF_LONG, eslo);
testdbPutFieldOk("test_ai_rec.EOFF", DBF_LONG, eoff);
/* Since our raw soft input does not support EGUL and EGUF conversion we set them to lagre values here just to check they dont break anything */
testdbPutFieldOk("test_ai_rec.EGUL", DBF_LONG, egul);
testdbPutFieldOk("test_ai_rec.EGUF", DBF_LONG, eguf);
testdbPutFieldOk("test_ai_rec.LINR", DBF_LONG, menuConvertLINEAR);
/* verify conversion */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_LONG, rval);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_LONG, val);
testdbGetFieldEqual("test_ai_rec.RVAL", DBF_LONG, rval);
// number of tests = 14
}
static void test_bpt_conversion(void){
const float typeKdegFin = 699.550510;
const float typeKdegF = 3.427551e+02;
const float typeKdegCin = 2902.787322;
const float typeKdegC = 7.028131e+02;
const float typeJdegFin = 1218.865107;
const float typeJdegF = 3.897504e+02;
const float typeJdegCin = 4042.988372;
const float typeJdegC = 6.918437e+02;
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set unit conversion parameters */
testdbPutFieldOk("test_ai_rec.ROFF", DBF_LONG, 0);
testdbPutFieldOk("test_ai_rec.ASLO", DBF_LONG, 1);
testdbPutFieldOk("test_ai_rec.AOFF", DBF_LONG, 0);
/* Set type K deg F break point table and verify */
testdbPutFieldOk("test_ai_rec.LINR", DBF_SHORT, menuConverttypeKdegF);
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_FLOAT, typeKdegFin);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_FLOAT, typeKdegF);
/* Set type K deg C break point table and verify */
testdbPutFieldOk("test_ai_rec.LINR", DBF_SHORT, menuConverttypeKdegC);
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_FLOAT, typeKdegCin);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_FLOAT, typeKdegC);
/* Set type J deg F break point table and verify */
testdbPutFieldOk("test_ai_rec.LINR", DBF_SHORT, menuConverttypeJdegF);
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_FLOAT, typeJdegFin);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_FLOAT, typeJdegF);
/* Set type J deg C break point table and verify */
testdbPutFieldOk("test_ai_rec.LINR", DBF_SHORT, menuConverttypeJdegC);
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_FLOAT, typeJdegCin);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_FLOAT, typeJdegC);
// number of tests = 18
}
static void test_smoothing_filter(void){
const double smoo = 0.7;
const short roff = 1;
const short aslo = 3;
const short aoff = -2;
const short eslo = 2;
const short eoff = 6;
const short rval1 = 7;
const short val1 = ((((rval1 + roff) * aslo) + aoff) * eslo) + eoff;
const short rval2 = 9;
const short val2_pre_smoo = ((((rval2 + roff) * aslo) + aoff) * eslo) + eoff;
const float val2 = val1 * smoo + (1 - smoo) * val2_pre_smoo;
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set unit conversion parameters */
testdbPutFieldOk("test_ai_rec.ROFF", DBF_LONG, roff);
testdbPutFieldOk("test_ai_rec.ASLO", DBF_LONG, aslo);
testdbPutFieldOk("test_ai_rec.AOFF", DBF_LONG, aoff);
testdbPutFieldOk("test_ai_rec.ESLO", DBF_LONG, eslo);
testdbPutFieldOk("test_ai_rec.EOFF", DBF_LONG, eoff);
testdbPutFieldOk("test_ai_rec.LINR", DBF_LONG, menuConvertSLOPE);
/* set well known starting point (without smmothing) */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_SHORT, rval1);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_SHORT, val1);
/* set SMOO */
testdbPutFieldOk("test_ai_rec.SMOO", DBF_DOUBLE, smoo);
/* update value again and verify smoothing */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_SHORT, rval2);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_FLOAT, val2);
/* clear SMOO */
testdbPutFieldOk("test_ai_rec.SMOO", DBF_DOUBLE, 0.0);
// number of tests = 15
}
static void test_udf(void){
/* set soft channel */
testdbPutFieldOk("test_ai_rec2.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec2.INP", DBF_STRING, "test_ai_link_rec2.VAL");
testdbPutFieldOk("test_ai_link_rec2.FLNK", DBF_STRING, "test_ai_rec2");
/* verify UDF */
testdbGetFieldEqual("test_ai_rec2.UDF", DBF_CHAR, TRUE);
/* set VAL and verify UDF is cleared */
testdbPutFieldOk("test_ai_link_rec2.VAL", DBF_FLOAT, 7.0);
testdbGetFieldEqual("test_ai_rec2.UDF", DBF_CHAR, FALSE);
// number of tests = 6
}
static void test_alarm(void){
const double h = 5000;
const double hh = 7500;
const double l = 200;
const double ll = -20;
const double hyst = 5;
/* set soft channel */
testdbPutFieldOk("test_ai_rec.DTYP", DBF_STRING, "Soft Channel");
testdbPutFieldOk("test_ai_rec.INP", DBF_STRING, "test_ai_link_rec.VAL");
testdbPutFieldOk("test_ai_link_rec.FLNK", DBF_STRING, "test_ai_rec");
/* set alarm parameters */
testdbPutFieldOk("test_ai_rec.HIGH", DBF_DOUBLE, h);
testdbPutFieldOk("test_ai_rec.HIHI", DBF_DOUBLE, hh);
testdbPutFieldOk("test_ai_rec.LOW", DBF_DOUBLE, l);
testdbPutFieldOk("test_ai_rec.LOLO", DBF_DOUBLE, ll);
testdbPutFieldOk("test_ai_rec.HHSV", DBF_SHORT, menuAlarmSevrMAJOR);
testdbPutFieldOk("test_ai_rec.HSV", DBF_SHORT, menuAlarmSevrMINOR);
testdbPutFieldOk("test_ai_rec.LSV", DBF_SHORT, menuAlarmSevrMINOR);
testdbPutFieldOk("test_ai_rec.LLSV", DBF_SHORT, menuAlarmSevrMAJOR);
/* set non alarm VAL and verify */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, 400.0);
testdbGetFieldEqual("test_ai_rec.SEVR", DBF_SHORT, menuAlarmSevrNO_ALARM);
/* set LOW alarm VAL and verify */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, 190.0);
testdbGetFieldEqual("test_ai_rec.VAL", DBF_DOUBLE, 190.0);
testdbGetFieldEqual("test_ai_rec.SEVR", DBF_SHORT, menuAlarmSevrMINOR);
/* set LOLO alarm VAL and verify */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, -9998.0);
testdbGetFieldEqual("test_ai_rec.SEVR", DBF_SHORT, menuAlarmSevrMAJOR);
/* set HIGH alarm VAL and verify */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, 6111.0);
testdbGetFieldEqual("test_ai_rec.SEVR", DBF_SHORT, menuAlarmSevrMINOR);
/* set HIHI alarm VAL and verify */
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, 19998.0);
testdbGetFieldEqual("test_ai_rec.SEVR", DBF_SHORT, menuAlarmSevrMAJOR);
/* set HYST, verify and clear */
testdbPutFieldOk("test_ai_rec.HYST", DBF_DOUBLE, hyst);
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, hh - 1.0);
testdbGetFieldEqual("test_ai_rec.SEVR", DBF_SHORT, menuAlarmSevrMAJOR);
testdbPutFieldOk("test_ai_rec.HYST", DBF_DOUBLE, 0.0);
testdbPutFieldOk("test_ai_link_rec.VAL", DBF_DOUBLE, hh - 2.0);
testdbGetFieldEqual("test_ai_rec.SEVR", DBF_SHORT, menuAlarmSevrMINOR);
/* verify LALM */
testdbGetFieldEqual("test_ai_rec.LALM", DBF_DOUBLE, h);
// number of tests = 29
}
static void test_aftc(void){
const double h = 5000;
const double hh = 7500;
const double l = 200;
const double ll = -20;
const double aftc = 3;
testMonitor* test_mon = NULL;
epicsTimeStamp startTime;
epicsTimeStamp endTime;
double diffTime = 0;
/* set soft channel */
testdbPutFieldOk("test_ai_rec3.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_ai_rec3.INP", DBF_STRING, "test_ai_link_rec3.VAL");
testdbPutFieldOk("test_ai_link_rec3.FLNK", DBF_STRING, "test_ai_rec3");
/* set alarm parameters */
testdbPutFieldOk("test_ai_rec3.HIGH", DBF_DOUBLE, h);
testdbPutFieldOk("test_ai_rec3.HIHI", DBF_DOUBLE, hh);
testdbPutFieldOk("test_ai_rec3.LOW", DBF_DOUBLE, l);
testdbPutFieldOk("test_ai_rec3.LOLO", DBF_DOUBLE, ll);
testdbPutFieldOk("test_ai_rec3.HHSV", DBF_SHORT, menuAlarmSevrMAJOR);
testdbPutFieldOk("test_ai_rec3.HSV", DBF_SHORT, menuAlarmSevrMINOR);
testdbPutFieldOk("test_ai_rec3.LSV", DBF_SHORT, menuAlarmSevrMINOR);
testdbPutFieldOk("test_ai_rec3.LLSV", DBF_SHORT, menuAlarmSevrMAJOR);
/* test AFTC using a monitor and time stamps */
testdbPutFieldOk("test_ai_rec3.AFTC", DBF_DOUBLE, aftc);
testdbPutFieldOk("test_ai_rec3.SCAN", DBF_SHORT, menuScan_1_second);
/* set HIHI alarm VAL */
testdbPutFieldOk("test_ai_link_rec3.VAL", DBF_DOUBLE, 7550.0);
/* Create test monitor for alarm SEVR */
test_mon = testMonitorCreate("test_ai_rec3.VAL", DBE_ALARM, 0);
/* Get start time */
epicsTimeGetCurrent(&startTime);
/* wait for monitor to trigger on the new alarm status*/
testMonitorWait(test_mon);
epicsTimeGetCurrent(&endTime);
/* Verify that alarm status is now MAJOR */
testdbGetFieldEqual("test_ai_rec3.SEVR", DBF_SHORT, menuAlarmSevrMAJOR);
/* set HI alarm VAL */
testdbPutFieldOk("test_ai_link_rec3.VAL", DBF_DOUBLE, 5550.0);
/* Create test monitor for alarm SEVR */
test_mon = testMonitorCreate("test_ai_rec3.VAL", DBE_ALARM, 0);
/* Get start time */
epicsTimeGetCurrent(&startTime);
/* wait for monitor to trigger on the new alarm status*/
testMonitorWait(test_mon);
epicsTimeGetCurrent(&endTime);
/* Verify that alarm status is now MINOR */
testdbGetFieldEqual("test_ai_rec3.SEVR", DBF_SHORT, menuAlarmSevrMINOR);
/* Verify that time is at least equal to configured aftc */
diffTime = epicsTimeDiffInSeconds(&endTime, &startTime);
testOk(diffTime >= aftc, "ATFC time %lf", diffTime);
// number of tests = 18
}
MAIN(aiTest) {
#ifdef _WIN32
#if (defined(_MSC_VER) && _MSC_VER < 1900) || \
(defined(_MINGW) && defined(_TWO_DIGIT_EXPONENT))
_set_output_format(_TWO_DIGIT_EXPONENT);
#endif
#endif
testPlan(6+6+11+10+12+14+18+15+6+29+18);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("aiTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
test_soft_input();
test_raw_soft_input();
test_operator_display();
test_no_linr_unit_conversion();
test_slope_linr_unit_conversion();
test_linear_linr_unit_conversion();
test_bpt_conversion();
test_smoothing_filter();
test_udf();
test_alarm();
test_aftc();
testIocShutdownOk();
testdbCleanup();
return testDone();
}

View File

@@ -0,0 +1,20 @@
record(ai, "test_ai_rec") {
}
record(ao, "test_ai_link_rec") {
}
record(ai, "test_ai_rec2") {
}
record(ao, "test_ai_link_rec2") {
}
record(ai, "test_ai_rec3") {
}
record(ao, "test_ai_link_rec3") {
}

View File

@@ -0,0 +1,122 @@
/*************************************************************************\
* Copyright (c) 2023 Karl Vestin
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "dbUnitTest.h"
#include "testMain.h"
#include "errlog.h"
#include "dbAccess.h"
#include "menuAlarmSevr.h"
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void test_soft_input(void){
/* set soft channel */
testdbPutFieldOk("test_bi_rec.DTYP", DBF_STRING, "Soft Channel");
testdbPutFieldOk("test_bi_rec.INP", DBF_STRING, "test_bi_link_rec.VAL");
testdbPutFieldOk("test_bi_link_rec.FLNK", DBF_STRING, "test_bi_rec");
/* set VAL to on linked record */
testdbPutFieldOk("test_bi_link_rec.VAL", DBF_SHORT, TRUE);
/* verify that this record VAL is updated but RVAL is not */
testdbGetFieldEqual("test_bi_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bi_rec.RVAL", DBF_SHORT, FALSE);
// number of tests = 6
}
static void test_raw_soft_input(void){
/* set soft channel */
testdbPutFieldOk("test_bi_rec.DTYP", DBF_STRING, "Raw Soft Channel");
testdbPutFieldOk("test_bi_rec.INP", DBF_STRING, "test_bi_link_rec.VAL");
testdbPutFieldOk("test_bi_link_rec.FLNK", DBF_STRING, "test_bi_rec");
/* set VAL to on linked record */
testdbPutFieldOk("test_bi_link_rec.VAL", DBF_SHORT, TRUE);
/* verify that this record RVAL and VAL are updated */
testdbGetFieldEqual("test_bi_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bi_rec.RVAL", DBF_SHORT, TRUE);
// number of tests = 6
}
static void test_operator_display(void){
/* set operator display parameters */
testdbPutFieldOk("test_bi_rec.ZNAM", DBF_STRING, "ZNAM_TEST");
testdbPutFieldOk("test_bi_rec.ONAM", DBF_STRING, "ONAM_TEST");
testdbPutFieldOk("test_bi_rec.DESC", DBF_STRING, "DESC_TEST");
/* verify operator display parameters */
testdbGetFieldEqual("test_bi_rec.ZNAM", DBF_STRING, "ZNAM_TEST");
testdbGetFieldEqual("test_bi_rec.ONAM", DBF_STRING, "ONAM_TEST");
testdbGetFieldEqual("test_bi_rec.NAME", DBF_STRING, "test_bi_rec");
testdbGetFieldEqual("test_bi_rec.DESC", DBF_STRING, "DESC_TEST");
/* verify conversion */
testdbPutFieldOk("test_bi_link_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bi_rec.VAL", DBF_STRING, "ONAM_TEST");
testdbPutFieldOk("test_bi_link_rec.VAL", DBF_SHORT, FALSE);
testdbGetFieldEqual("test_bi_rec.VAL", DBF_STRING, "ZNAM_TEST");
// number of tests = 11
}
static void test_alarm(void){
/* set soft channel */
testdbPutFieldOk("test_bi_rec.DTYP", DBF_STRING, "Soft Channel");
testdbPutFieldOk("test_bi_rec.INP", DBF_STRING, "test_bi_link_rec.VAL");
testdbPutFieldOk("test_bi_link_rec.FLNK", DBF_STRING, "test_bi_rec");
/* set start VAL to FALSE*/
testdbPutFieldOk("test_bi_link_rec.VAL", DBF_SHORT, FALSE);
/* set alarm parameters */
testdbPutFieldOk("test_bi_rec.ZSV", DBF_SHORT, menuAlarmSevrNO_ALARM);
testdbPutFieldOk("test_bi_rec.OSV", DBF_SHORT, menuAlarmSevrMINOR);
testdbPutFieldOk("test_bi_rec.COSV", DBF_SHORT, menuAlarmSevrINVALID);
/* verify alarm status is NO_ALARM*/
testdbGetFieldEqual("test_bi_rec.SEVR", DBF_SHORT, menuAlarmSevrNO_ALARM);
/* set ZSV to MAJOR and verify that SEVR is now MAJOR */
testdbPutFieldOk("test_bi_rec.ZSV", DBF_SHORT, menuAlarmSevrMAJOR);
testdbGetFieldEqual("test_bi_rec.SEVR", DBF_SHORT, menuAlarmSevrMAJOR);
/* set VAL to 1 on linked record and verify that COSV now sets the SEVR to INVALID */
testdbPutFieldOk("test_bi_link_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bi_rec.SEVR", DBF_SHORT, menuAlarmSevrINVALID);
/* verify LAML */
testdbGetFieldEqual("test_bi_rec.LALM", DBF_SHORT, TRUE);
// number of tests = 13
}
MAIN(biTest) {
testPlan(6+6+11+13);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("biTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
test_soft_input();
test_raw_soft_input();
test_operator_display();
test_alarm();
testIocShutdownOk();
testdbCleanup();
return testDone();
}

View File

@@ -0,0 +1,6 @@
record(bi, "test_bi_rec") {
}
record(bo, "test_bi_link_rec") {
}

View File

@@ -0,0 +1,158 @@
/*************************************************************************\
* Copyright (c) 2023 Karl Vestin
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "dbUnitTest.h"
#include "testMain.h"
#include "errlog.h"
#include "dbAccess.h"
#include "menuAlarmSevr.h"
#include "menuIvoa.h"
#include "boRecord.h"
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void test_soft_output(void){
/* set soft channel */
testdbPutFieldOk("test_bo_rec.DTYP", DBF_STRING, "Soft Channel");
testdbPutFieldOk("test_bo_rec.OUT", DBF_STRING, "test_bo_link_rec");
/* set VAL to process record */
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, TRUE);
/* verify that OUT record is updated */
testdbGetFieldEqual("test_bo_link_rec.VAL", DBF_SHORT, TRUE);
// number of tests = 4
}
static void test_high(void){
const int high_time = 2;
testMonitor* test_mon = NULL;
epicsTimeStamp startTime;
epicsTimeStamp endTime;
double diffTime = 0;
double diffTimeTolerance = 0.1;
/* set soft channel */
testdbPutFieldOk("test_bo_rec.DTYP", DBF_STRING, "Soft Channel");
testdbPutFieldOk("test_bo_rec.OUT", DBF_STRING, "test_bo_link_rec");
/* set HIGH to 2 seconds */
testdbPutFieldOk("test_bo_rec.HIGH", DBF_SHORT, high_time);
/* Create test monitor */
test_mon = testMonitorCreate("test_bo_rec.VAL", DBR_SHORT, 0);
/* Get start time */
epicsTimeGetCurrent(&startTime);
/* set VAL to process record */
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, TRUE);
/* wait and verfiy time */
testMonitorWait(test_mon);
epicsTimeGetCurrent(&endTime);
/* EPICS timers have a tendency to trip slightly early, hence the test tolerance is added here to avoid false positives in testing */
diffTime = epicsTimeDiffInSeconds(&endTime, &startTime) + diffTimeTolerance;
testOk(diffTime >= high_time, "HIGH time %lf", diffTime);
/* verify that both records are set back to 0 */
testdbGetFieldEqual("test_bo_rec.VAL", DBF_SHORT, FALSE);
testdbGetFieldEqual("test_bo_link_rec.VAL", DBF_SHORT, FALSE);
testMonitorDestroy(test_mon);
// number of tests = 7
}
static void test_operator_display(void){
/* set operator display parameters */
testdbPutFieldOk("test_bo_rec.ZNAM", DBF_STRING, "ZNAM_TEST");
testdbPutFieldOk("test_bo_rec.ONAM", DBF_STRING, "ONAM_TEST");
testdbPutFieldOk("test_bo_rec.DESC", DBF_STRING, "DESC_TEST");
/* verify operator display parameters */
testdbGetFieldEqual("test_bo_rec.ZNAM", DBF_STRING, "ZNAM_TEST");
testdbGetFieldEqual("test_bo_rec.ONAM", DBF_STRING, "ONAM_TEST");
testdbGetFieldEqual("test_bo_rec.NAME", DBF_STRING, "test_bo_rec");
testdbGetFieldEqual("test_bo_rec.DESC", DBF_STRING, "DESC_TEST");
/* verify conversion */
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bo_rec.VAL", DBF_STRING, "ONAM_TEST");
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, FALSE);
testdbGetFieldEqual("test_bo_rec.VAL", DBF_STRING, "ZNAM_TEST");
// number of tests = 11
}
static void test_alarm(void){
/* set soft channel */
testdbPutFieldOk("test_bo_rec.DTYP", DBF_STRING, "Soft Channel");
testdbPutFieldOk("test_bo_rec.OUT", DBF_STRING, "test_bo_link_rec");
/* Set start VAL to FALSE*/
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, FALSE);
/* set alarm parameters */
testdbPutFieldOk("test_bo_rec.ZSV", DBF_SHORT, menuAlarmSevrNO_ALARM);
testdbPutFieldOk("test_bo_rec.OSV", DBF_SHORT, menuAlarmSevrMINOR);
testdbPutFieldOk("test_bo_rec.COSV", DBF_SHORT, menuAlarmSevrINVALID);
testdbPutFieldOk("test_bo_rec.IVOA", DBF_SHORT, menuIvoaSet_output_to_IVOV);
testdbPutFieldOk("test_bo_rec.IVOV", DBF_SHORT, FALSE);
/* Verify alarm status is NO_ALARM*/
testdbGetFieldEqual("test_bo_rec.SEVR", DBF_SHORT, menuAlarmSevrNO_ALARM);
/* Set ZSV to MAJOR and verify that SEVR is now MAJOR */
testdbPutFieldOk("test_bo_rec.ZSV", DBF_SHORT, menuAlarmSevrMAJOR);
testdbGetFieldEqual("test_bo_rec.SEVR", DBF_SHORT, menuAlarmSevrMAJOR);
/* Set VAL to 1 and verify that COSV now sets the SEVR to INVALID and in turn triggers the IVOV on output */
testdbPutFieldOk("test_bo_link_rec.VAL", DBF_SHORT, TRUE);
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bo_rec.SEVR", DBF_SHORT, menuAlarmSevrINVALID);
testdbGetFieldEqual("test_bo_link_rec.VAL", DBF_SHORT, FALSE);
/* verify IVOV continue normally action */
testdbPutFieldOk("test_bo_rec.IVOA", DBF_SHORT, menuIvoaContinue_normally);
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bo_link_rec.VAL", DBF_SHORT, TRUE);
/* verify IVOV dont drive outputs action */
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, FALSE);
testdbPutFieldOk("test_bo_rec.IVOA", DBF_SHORT, menuIvoaDon_t_drive_outputs);
testdbPutFieldOk("test_bo_rec.VAL", DBF_SHORT, TRUE);
testdbGetFieldEqual("test_bo_link_rec.VAL", DBF_SHORT, FALSE);
// number of tests = 22
}
MAIN(boTest) {
testPlan(4+7+11+22);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("boTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
test_soft_output();
test_high();
test_operator_display();
test_alarm();
testIocShutdownOk();
testdbCleanup();
return testDone();
}

View File

@@ -0,0 +1,6 @@
record(bo, "test_bo_rec") {
}
record(bi, "test_bo_link_rec") {
}

View File

@@ -24,6 +24,10 @@ int asyncSoftTest(void);
int simmTest(void);
int mbbioDirectTest(void);
int scanEventTest(void);
int boTest(void);
int biTest(void);
int printfTest(void);
int aiTest(void);
void epicsRunRecordTests(void)
{
@@ -51,5 +55,13 @@ void epicsRunRecordTests(void)
runTest(scanEventTest);
runTest(boTest);
runTest(biTest);
runTest(printfTest);
runTest(aiTest);
epicsExit(0); /* Trigger test harness */
}

View File

@@ -0,0 +1,577 @@
/*************************************************************************\
* Copyright (c) 2023 Karl Vestin
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "dbUnitTest.h"
#include "testMain.h"
#include "errlog.h"
#include "dbAccess.h"
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void test_double_percentile(void){
const char format_string[] = "Format test string %%d";
const char result_string[] = "Format test string %d";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 1);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_d_format(void){
const char format_string[] = "Format test string %d";
const char result_string[] = "Format test string 7";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 7);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_c_format(void){
const char format_string[] = "Format test string %c";
const char result_string[] = "Format test string R";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0, 82 is ASCII for R */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 82);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_i_format(void){
const char format_string[] = "Format test string %i";
const char result_string[] = "Format test string -27";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, -27);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_o_format(void){
const char format_string[] = "Format test string %o";
const char result_string[] = "Format test string 6777";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 06777);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_u_format(void){
const char format_string[] = "Format test string %u";
const char result_string[] = "Format test string 8009";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 8009);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_x_format(void){
const char format_string[] = "Format test string %x";
const char result_string[] = "Format test string fafa";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_LONG, 0xfafa);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_X_format(void){
const char format_string[] = "Format test string %X";
const char result_string[] = "Format test string BA";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 0x00ba);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_e_format(void){
const char format_string[] = "Format test string %e";
const char result_string[] = "Format test string -1.400000e+01";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, -14);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_E_format(void){
const char format_string[] = "Format test string %E";
const char result_string[] = "Format test string 1.992000E+03";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 1992);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_f_format(void){
const char format_string[] = "Format test string %f";
const char result_string[] = "Format test string -0.062000";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_DOUBLE, -0.062);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_F_format(void){
const char format_string[] = "Format test string %F";
const char result_string[] = "Format test string 6729982.999000";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_DOUBLE, 6729982.999);
/* verify that string is formatted as expected */
// visual studio less than 2015 does not support %F
// mingw/gcc also fails, suspect this may be gcc version
// related and checking __GNUC__ could resolve but
// initial attempts didn't work so excluding mingw entirely for now
#ifdef _WIN32
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_MINGW)
testTodoBegin("Fails on windows with old visual studio versions and mingw");
#endif
#endif
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
#ifdef _WIN32
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_MINGW)
testTodoEnd();
#endif
#endif
// number of tests = 3
}
static void test_g_format(void){
const char format_string[] = "Format test string %g";
const char result_string[] = "Format test string -0.093";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_DOUBLE, -93e-3);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_G_format(void){
const char format_string[] = "Format test string %G";
const char result_string[] = "Format test string 7.2884E+08";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_LONG, 728839938);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_s_format(void){
const char format_string[] = "Format test string %d %s";
const char result_string[] = "Format test string 7 Molly III";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 7);
/* set value on inp1 */
testdbPutFieldOk("test_printf_inp1_rec.VAL", DBF_STRING, "Molly III");
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 4
}
static void test_plus_flag(void){
const char format_string[] = "Format test string %+d";
const char result_string[] = "Format test string +7";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 7);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_minus_flag(void){
const char format_string[] = "Format test string %-10d";
const char result_string[] = "Format test string 18 ";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 18);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_space_flag(void){
const char format_string[] = "Format test string % d";
const char result_string[] = "Format test string 12";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 12);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_hash_flag(void){
const char format_string[] = "Format test string %#o";
const char result_string[] = "Format test string 014";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 014);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_min_width_flag(void){
const char format_string[] = "Format test string %04i";
const char result_string[] = "Format test string 0003";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 3);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_prec_flag(void){
const char format_string[] = "Format test string %.4f";
const char result_string[] = "Format test string 71.2000";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_DOUBLE, 71.2);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_h_flag(void){
const char format_string[] = "Format test string %hx";
const char result_string[] = "Format test string baba";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_LONG, 0xffbaba);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_hh_flag(void){
const char format_string[] = "Format test string %hhx";
const char result_string[] = "Format test string c1";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_LONG, 0xffc0c1);
/* verify that string is formatted as expected */
#ifdef __rtems__
testTodoBegin("Fails on UB-20 gcc-9 on RTEMS");
#endif
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
#ifdef __rtems__
testTodoEnd();
#endif
// number of tests = 3
}
static void test_l_flag(void){
const char format_string[] = "Format test string %lx";
const char result_string[] = "Format test string 70a1c0c1";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_LONG, 0x70a1c0c1);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 3
}
static void test_ll_flag(void){
const char format_string[] = "%d %s %llx";
const char result_string[] = "2 Reperbahn ba0110baa0a1c0c1";
const epicsInt64 value = 0xba0110baa0a1c0c1ull;
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 2);
/* set value on inp1 */
testdbPutFieldOk("test_printf_inp1_rec.VAL", DBF_STRING, "Reperbahn");
/* set value on inp2 */
testdbPutFieldOk("test_printf_inp2_rec.VAL", DBR_INT64, value);
testdbGetFieldEqual("test_printf_inp2_rec.VAL", DBR_INT64, value);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 6
}
static void test_sizv(void){
const char format_string[] = "%d %s %llx";
const char result_string[] = "99 123456789012345678901234567890 6640baa0a1";
const epicsInt64 value = 0x06640baa0a1c0c1ull;
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 99);
/* set value on inp1 */
testdbPutFieldOk("test_printf_inp1_rec.VAL", DBF_STRING, "123456789012345678901234567890");
/* set value on inp2 */
testdbPutFieldOk("test_printf_inp2_rec.VAL", DBR_INT64, value);
testdbGetFieldEqual("test_printf_inp2_rec.VAL", DBR_INT64, value);
/* verify that string is formatted as expected */
testdbGetArrFieldEqual("test_printf_rec.VAL$", DBF_CHAR, 45, 45, result_string);
// number of tests = 6
}
static void test_all_inputs(void){
const char format_string[] = "%d %s %i %i %i %i %i %i %i %i";
const char result_string[] = "0 One 2 3 4 5 6 7 8 9";
/* set format string */
testdbPutFieldOk("test_printf_rec.FMT", DBF_STRING, format_string);
/* set value on inp0 */
testdbPutFieldOk("test_printf_inp0_rec.VAL", DBF_SHORT, 0);
/* set value on inp1 */
testdbPutFieldOk("test_printf_inp1_rec.VAL", DBF_STRING, "One");
/* set value on inp2 */
testdbPutFieldOk("test_printf_inp2_rec.VAL", DBF_SHORT, 2);
/* set value on inp3 */
testdbPutFieldOk("test_printf_inp3_rec.VAL", DBF_SHORT, 3);
/* set value on inp4 */
testdbPutFieldOk("test_printf_inp4_rec.VAL", DBF_SHORT, 4);
/* set value on inp5 */
testdbPutFieldOk("test_printf_inp5_rec.VAL", DBF_SHORT, 5);
/* set value on inp6 */
testdbPutFieldOk("test_printf_inp6_rec.VAL", DBF_SHORT, 6);
/* set value on inp7 */
testdbPutFieldOk("test_printf_inp7_rec.VAL", DBF_SHORT, 7);
/* set value on inp8 */
testdbPutFieldOk("test_printf_inp8_rec.VAL", DBF_SHORT, 8);
/* set value on inp9 */
testdbPutFieldOk("test_printf_inp9_rec.VAL", DBF_SHORT, 9);
/* verify that string is formatted as expected */
testdbGetFieldEqual("test_printf_rec.VAL", DBF_STRING, result_string);
// number of tests = 12
}
MAIN(printfTest) {
#ifdef _WIN32
#if (defined(_MSC_VER) && _MSC_VER < 1900) || \
(defined(_MINGW) && defined(_TWO_DIGIT_EXPONENT))
_set_output_format(_TWO_DIGIT_EXPONENT);
#endif
#endif
testPlan(3+3+3+3+3+3+3+3+4+3+3+3+3+3+3+3+3+3+3+3+3+3+3+3+6+6+12);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("printfTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
test_double_percentile();
test_c_format();
test_d_format();
test_i_format();
test_o_format();
test_u_format();
test_x_format();
test_X_format();
test_e_format();
test_E_format();
test_f_format();
test_F_format();
test_g_format();
test_G_format();
test_s_format();
test_plus_flag();
test_minus_flag();
test_space_flag();
test_hash_flag();
test_min_width_flag();
test_prec_flag();
test_h_flag();
test_hh_flag();
test_l_flag();
test_ll_flag();
test_sizv();
test_all_inputs();
testIocShutdownOk();
testdbCleanup();
return testDone();
}

View File

@@ -0,0 +1,53 @@
record(printf, "test_printf_rec") {
field(SIZV, 45)
field(INP0, "test_printf_inp0_rec")
field(INP1, "test_printf_inp1_rec")
field(INP2, "test_printf_inp2_rec")
field(INP3, "test_printf_inp3_rec")
field(INP4, "test_printf_inp4_rec")
field(INP5, "test_printf_inp5_rec")
field(INP6, "test_printf_inp6_rec")
field(INP7, "test_printf_inp7_rec")
field(INP8, "test_printf_inp8_rec")
field(INP9, "test_printf_inp9_rec")
}
record(ai, "test_printf_inp0_rec") {
field(FLNK, "test_printf_rec")
}
record(stringin, "test_printf_inp1_rec") {
field(FLNK, "test_printf_rec")
}
record(int64in, "test_printf_inp2_rec") {
field(FLNK, "test_printf_rec")
}
record(ai, "test_printf_inp3_rec") {
field(FLNK, "test_printf_rec")
}
record(ai, "test_printf_inp4_rec") {
field(FLNK, "test_printf_rec")
}
record(ai, "test_printf_inp5_rec") {
field(FLNK, "test_printf_rec")
}
record(ai, "test_printf_inp6_rec") {
field(FLNK, "test_printf_rec")
}
record(ai, "test_printf_inp7_rec") {
field(FLNK, "test_printf_rec")
}
record(ai, "test_printf_inp8_rec") {
field(FLNK, "test_printf_rec")
}
record(ai, "test_printf_inp9_rec") {
field(FLNK, "test_printf_rec")
}

View File

@@ -37,7 +37,7 @@ int epicsNtpGetTime(char *ntpIp, struct timespec *now)
sockfd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); // Create a UDP socket.
if ( sockfd < 0 ) {
perror( "epicsNtpGetTime" );
perror( "epicsNtpGetTime creating socket" );
return -1;
}
@@ -51,24 +51,29 @@ int epicsNtpGetTime(char *ntpIp, struct timespec *now)
// Call up the server using its IP address and port number.
if ( connect( sockfd, ( struct sockaddr * ) &serv_addr, sizeof( serv_addr) ) < 0 ) {
perror( "epicsNtpGetTime" );
perror( "epicsNtpGetTime connecting socket" );
close( sockfd );
return -1;
}
// Send it the NTP packet it wants. If n == -1, it failed.
n = write( sockfd, ( char* ) &packet, sizeof( ntp_packet ) );
if ( n < 0 ) {
perror( "epicsNtpGetTime" );
perror( "epicsNtpGetTime sending NTP request" );
close( sockfd );
return -1;
}
// Wait and receive the packet back from the server. If n == -1, it failed.
// Wait and receive the packet back from the server. If n == -1, it failed.
n = read( sockfd, ( char* ) &packet, sizeof( ntp_packet ) );
if ( n < 0 ) {
perror( "epicsNtpGetTime" );
perror( "epicsNtpGetTime reading NTP reply" );
close( sockfd );
return -1;
}
close( sockfd );
// These two fields contain the time-stamp seconds as the packet left the NTP server.
// The number of seconds correspond to the seconds passed since 1900.
// ntohl() converts the bit/byte order from the network's to host's "endianness".

View File

@@ -209,7 +209,7 @@ static int yyerror(char *str)
if (strlen(str))
errlogPrintf("%s at line %d\n", str, line_num);
else
errlogPrintf("Error at line %d\n", line_num);
errlogPrintf(ERL_ERROR " at line %d\n", line_num);
yyFailed = TRUE;
return 0;
}

View File

@@ -176,12 +176,12 @@ long epicsStdCall asInitFile(const char *filename,const char *substitutions)
fp = fopen(filename,"r");
if(!fp) {
errlogPrintf("asInitFile: Can't open file '%s'\n", filename);
fprintf(stderr, ERL_ERROR " asInitFile: Can't open file '%s'\n", filename);
return(S_asLib_badConfig);
}
status = asInitFP(fp,substitutions);
if(fclose(fp)==EOF) {
errMessage(0,"asInitFile: fclose failed!");
fprintf(stderr, ERL_ERROR " asInitFile: fclose failed!");
if(!status) status = S_asLib_badConfig;
}
return(status);
@@ -359,7 +359,6 @@ void epicsStdCall asPutMemberPvt(ASMEMBERPVT asMemberPvt,void *userPvt)
if(!asActive) return;
if(!pasgmember) return;
pasgmember->userPvt = userPvt;
return;
}
long epicsStdCall asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,

View File

@@ -335,6 +335,10 @@ LIBCOM_API long
break;
case SEPERATOR:
if (pstacktop == stack) {
*perror = CALC_ERR_BAD_SEPERATOR;
goto bad;
}
/* Move operators to the output until open paren */
while (pstacktop->name[0] != '(') {
if (pstacktop <= stack+1) {
@@ -353,6 +357,10 @@ LIBCOM_API long
break;
case CLOSE_PAREN:
if (pstacktop == stack) {
*perror = CALC_ERR_PAREN_NOT_OPEN;
goto bad;
}
/* Move operators to the output until matching paren */
while (pstacktop->name[0] != '(') {
if (pstacktop <= stack+1) {

View File

@@ -222,7 +222,7 @@ extern "C" {
* - n parameter minimum value: min(a, b, ...)
* - Square root: sqr(a) or sqrt(a)
* - Floating point modulo: fmod(num, den)
* \since The fmod() function was added in UNRELEASED
* \since The fmod() function was added in 7.0.8
*
* -# ***Trigonometric Functions***
* Standard circular trigonometric functions, with angles expressed in radians:

View File

@@ -25,8 +25,8 @@
namespace {
static epicsThreadOnceId epicsSigletonOnceFlag ( EPICS_THREAD_ONCE_INIT );
static epicsMutex * pEPICSSigletonMutex = 0;
epicsThreadOnceId epicsSigletonOnceFlag ( EPICS_THREAD_ONCE_INIT );
epicsMutex * pEPICSSigletonMutex = 0;
extern "C" void SingletonMutexOnce ( void * /* pParm */ )
{

View File

@@ -34,8 +34,6 @@ void ellAdd (ELLLIST *pList, ELLNODE *pNode)
pList->node.previous = pNode;
pList->count++;
return;
}
/****************************************************************************
*
@@ -65,8 +63,6 @@ void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList)
pAddList->count = 0;
pAddList->node.next = NULL;
pAddList->node.previous = NULL;
return;
}
/****************************************************************************
*
@@ -86,8 +82,6 @@ void ellDelete (ELLLIST *pList, ELLNODE *pNode)
pNode->previous->next = pNode->next;
pList->count--;
return;
}
/****************************************************************************
*
@@ -136,8 +130,6 @@ void ellExtract (ELLLIST *pSrcList, ELLNODE *pStartNode, ELLNODE *pEndNode, ELLL
}
pSrcList->count -= count;
pDstList->count += count;
return;
}
/****************************************************************************
*
@@ -194,8 +186,6 @@ void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode)
pNode->next->previous = pNode;
plist->count++;
return;
}
/****************************************************************************
*

View File

@@ -26,6 +26,7 @@ ERR_S_FILES += $(LIBCOM)/as/asLib.h
ERR_S_FILES += $(LIBCOM)/misc/epicsStdlib.h
ERR_S_FILES += $(LIBCOM)/pool/epicsThreadPool.h
ERR_S_FILES += $(LIBCOM)/error/errMdef.h
ERR_S_FILES += $(LIBCOM)/error/errSymTbl.h
ERR_S_FILES += $(TOP)/modules/database/src/ioc/db/dbAccessDefs.h
ERR_S_FILES += $(TOP)/modules/database/src/ioc/dbStatic/dbStaticLib.h

View File

@@ -19,6 +19,7 @@
#define RTN_SUCCESS(STATUS) ((STATUS)==0)
/* Module numbers start above 500 for compatibility with vxWorks errnoLib */
#define MIN_MODULE_NUM 501
/* FIXME: M_xxx values could be declared as integer variables and set
* at runtime from registration routines; the S_xxx definitions would
@@ -32,6 +33,7 @@
#define M_stdlib (504 << 16) /* EPICS Standard library */
#define M_pool (505 << 16) /* Thread pool */
#define M_time (506 << 16) /* epicsTime */
#define M_err (507 << 16) /* Error */
/* ioc */
#define M_dbAccess (511 << 16) /* Database Access Routines */

View File

@@ -23,6 +23,9 @@
#include "cantProceed.h"
#include "epicsAssert.h"
#include "epicsStdio.h"
#include "epicsTypes.h"
#include "epicsMutex.h"
#include "epicsThread.h"
#include "errMdef.h"
#include "errSymTbl.h"
#include "ellLib.h"
@@ -33,69 +36,49 @@
static epicsUInt16 errhash(long errNum);
typedef struct errnumnode {
ELLNODE node;
long errNum;
struct errnumnode *hashnode;
const char *message;
long pad;
} ERRNUMNODE;
static ELLLIST errnumlist = ELLLIST_INIT;
static ERRNUMNODE **hashtable;
static int initialized = 0;
typedef struct {
ERRNUMNODE *table[NHASH * sizeof(ERRNUMNODE *)];
epicsMutexId tableMutexId;
} errHashTable_t;
static errHashTable_t errHashTable;
extern ERRSYMTAB_ID errSymTbl;
/****************************************************************
* ERRSYMBLD
*
* Create the normal ell LIST of sorted error messages nodes
* Followed by linked hash lists - that link together those
* ell nodes that have a common hash number.
* Populate EPICS error symbols
*
***************************************************************/
int errSymBld(void)
{
ERRSYMBOL *errArray = errSymTbl->symbols;
ERRNUMNODE *perrNumNode = NULL;
ERRNUMNODE *pNextNode = NULL;
ERRNUMNODE **phashnode = NULL;
int i;
int modnum;
if (initialized)
return(0);
hashtable = (ERRNUMNODE**)callocMustSucceed
(NHASH, sizeof(ERRNUMNODE*),"errSymBld");
ERRSYMBOL *errArray = errSymTbl->symbols;
int i;
for (i = 0; i < errSymTbl->nsymbols; i++, errArray++) {
modnum = errArray->errNum >> 16;
if (modnum < 501) {
fprintf(stderr, "errSymBld: ERROR - Module number in errSymTbl < 501 was Module=%lx Name=%s\n",
errArray->errNum, errArray->name);
continue;
}
if ((errSymbolAdd(errArray->errNum, errArray->name)) < 0) {
if (errSymbolAdd(errArray->errNum, errArray->name)) {
fprintf(stderr, "errSymBld: ERROR - errSymbolAdd() failed \n");
continue;
}
}
perrNumNode = (ERRNUMNODE *) ellFirst(&errnumlist);
while (perrNumNode) {
/* hash each perrNumNode->errNum */
epicsUInt16 hashInd = errhash(perrNumNode->errNum);
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
pNextNode = (ERRNUMNODE*) *phashnode;
/* search for last node (NULL) of hashnode linked list */
while (pNextNode) {
phashnode = &pNextNode->hashnode;
pNextNode = *phashnode;
}
*phashnode = perrNumNode;
perrNumNode = (ERRNUMNODE *) ellNext((ELLNODE *) perrNumNode);
}
initialized = 1;
return(0);
return 0;
}
static void _initErrorHashTable(void *_unused)
{
errHashTable.tableMutexId = epicsMutexMustCreate();
}
static void initErrorHashTable()
{
static epicsThreadOnceId initErrSymOnceFlag = EPICS_THREAD_ONCE_INIT;
epicsThreadOnce(&initErrSymOnceFlag, _initErrorHashTable, NULL);
}
/****************************************************************
@@ -109,21 +92,47 @@ static epicsUInt16 errhash(long errNum)
modnum = (unsigned short) (errNum >> 16);
errnum = (unsigned short) (errNum & 0xffff);
return (((modnum - 500) * 20) + errnum) % NHASH;
return ((modnum - (MIN_MODULE_NUM - 1)) * 20 + errnum) % NHASH;
}
/****************************************************************
* ERRSYMBOLADD
* adds symbols to the master errnumlist as compiled from errSymTbl.c
* adds symbols to the global error symbol hash table
***************************************************************/
int errSymbolAdd(long errNum, const char *name)
{
ERRNUMNODE *pNew = (ERRNUMNODE*) callocMustSucceed(1,
sizeof(ERRNUMNODE), "errSymbolAdd");
ERRNUMNODE *pNextNode = NULL;
ERRNUMNODE **phashnode = NULL;
ERRNUMNODE *pNew = NULL;
int modnum = (epicsUInt16) (errNum >> 16);
epicsUInt16 hashInd = errhash(errNum);
if (modnum < MIN_MODULE_NUM)
return S_err_invCode;
initErrorHashTable();
epicsMutexLock(errHashTable.tableMutexId);
phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd];
pNextNode = (ERRNUMNODE*) *phashnode;
/* search for last node (NULL) of hashnode linked list */
while (pNextNode) {
if (pNextNode->errNum == errNum) {
int notIdentical = strcmp(name, pNextNode->message);
epicsMutexUnlock(errHashTable.tableMutexId);
return notIdentical ? S_err_codeExists : 0;
}
phashnode = &pNextNode->hashnode;
pNextNode = *phashnode;
}
pNew = (ERRNUMNODE*) callocMustSucceed(
1, sizeof(ERRNUMNODE), "errSymbolAdd");
pNew->errNum = errNum;
pNew->message = name;
ellAdd(&errnumlist, (ELLNODE*)pNew);
*phashnode = pNew;
epicsMutexUnlock(errHashTable.tableMutexId);
return 0;
}
@@ -155,31 +164,31 @@ const char* errSymLookupInternal(long status)
if (!status)
return "Ok";
if (!initialized)
errSymBld();
initErrorHashTable();
modNum = (unsigned) status;
modNum >>= 16;
modNum &= 0xffff;
if (modNum <= 500) {
const char * pStr = strerror ((int) status);
if (pStr) {
return pStr;
}
if (modNum < MIN_MODULE_NUM) {
return strerror ((int) status);
}
else {
unsigned hashInd = errhash(status);
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
const char *result = NULL;
epicsMutexLock(errHashTable.tableMutexId);
phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd];
pNextNode = *phashnode;
while (pNextNode) {
if (pNextNode->errNum==status){
return pNextNode->message;
result = pNextNode->message;
break;
}
phashnode = &pNextNode->hashnode;
pNextNode = *phashnode;
}
epicsMutexUnlock(errHashTable.tableMutexId);
return result;
}
return NULL;
}
const char* errSymMsg(long status)
@@ -210,12 +219,12 @@ void errSymDump(void)
int i;
int msgcount = 0;
if (!initialized) errSymBld();
initErrorHashTable();
msgcount = 0;
printf("errSymDump: number of hash slots = %d\n", NHASH);
for (i = 0; i < NHASH; i++) {
ERRNUMNODE **phashnode = &hashtable[i];
ERRNUMNODE **phashnode = &errHashTable.table[i];
ERRNUMNODE *pNextNode = *phashnode;
int count = 0;
@@ -246,21 +255,21 @@ void errSymTestPrint(long errNum)
epicsUInt16 modnum;
epicsUInt16 errnum;
if (!initialized) errSymBld();
initErrorHashTable();
message[0] = '\0';
modnum = (epicsUInt16) (errNum >> 16);
errnum = (epicsUInt16) (errNum & 0xffff);
if (modnum < 501) {
if (modnum < MIN_MODULE_NUM) {
fprintf(stderr, "Usage: errSymTestPrint(long errNum) \n");
fprintf(stderr, "errSymTestPrint: module number < 501 \n");
fprintf(stderr,
"errSymTestPrint: module number < %d\n", MIN_MODULE_NUM);
return;
}
errSymLookup(errNum, message, sizeof(message));
if ( message[0] == '\0' ) return;
printf("module %hu number %hu message=\"%s\"\n",
modnum, errnum, message);
return;
}
/****************************************************************
@@ -272,10 +281,11 @@ void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
long errNum;
epicsUInt16 errnum;
if (!initialized) errSymBld();
if (modnum < 501)
if (modnum < MIN_MODULE_NUM)
return;
initErrorHashTable();
/* print range of error messages */
for (errnum = begErrNum; errnum <= endErrNum; errnum++) {
errNum = modnum << 16;

View File

@@ -16,6 +16,9 @@
#include "libComAPI.h"
#include "epicsTypes.h"
#define S_err_invCode (M_err | 1) /* Invalid error symbol code */
#define S_err_codeExists (M_err | 2) /* Error code already exists */
/* ERRSYMBOL - entry in symbol table */
typedef struct {
long errNum; /* errMessage symbol number */
@@ -35,13 +38,38 @@ typedef ERRSYMTAB *ERRSYMTAB_ID;
extern "C" {
#endif
/** \brief Lookup message from error/status code.
* \param status Input code
* \param pBuf Output string buffer
* \param bufLength Length of output buffer in bytes. Must be non-zero.
*
* Handles EPICS message codes, and "errno" codes.
*
* Copies in a mesage for any status code. Unknown status codes
* are printed numerically.
*/
LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength);
/** \brief Lookup message from error/status code.
* \param status Input code
* \returns A statically allocated message string. Never NULL.
*
* Handles EPICS message codes, and "errno" codes.
*
* For any unknown status codes, a generic "Unknown code" message is returned.
*
* \since 3.16.1
*/
LIBCOM_API const char* errSymMsg(long status);
LIBCOM_API void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
epicsUInt16 endErrNum);
LIBCOM_API void errSymTestPrint(long errNum);
LIBCOM_API int errSymBld(void);
LIBCOM_API int errSymbolAdd(long errNum, const char *name);
/** @brief Define new custom error code and associate message string.
* @param errNum New error code. Caller is reponsible for avoiding reuse of existing codes.
* @param message New message. Pointer stored. Caller must not free pointed storage.
* @return 0 on success
*/
LIBCOM_API int errSymbolAdd(long errNum, const char *message);
LIBCOM_API void errSymDump(void);
#ifdef __cplusplus

View File

@@ -246,7 +246,7 @@ int isATTY(FILE* fp)
else if(fp==stderr)
hand = GetStdHandle(STD_ERROR_HANDLE);
#ifdef ENABLE_VIRTUAL_TERMINAL_PROCESSING
if(hand && GetConsoleMode(hand, &mode)) {
if(hand!=INVALID_HANDLE_VALUE && GetConsoleMode(hand, &mode)) {
(void)SetConsoleMode(hand, mode|ENABLE_VIRTUAL_TERMINAL_PROCESSING);
mode = 0u;
if(GetConsoleMode(hand, &mode) && (mode&ENABLE_VIRTUAL_TERMINAL_PROCESSING))

View File

@@ -180,8 +180,8 @@ LIBCOM_API void errlogAddListener(errlogListener listener, void *pPrivate);
* \param listener Function pointer of type ::errlogListener
* \param pPrivate This will be passed as the first argument of listener()
*
* \since UNRELEASED Safe to call from a listener callback.
* \until UNRELEASED Self-removal from a listener callback caused corruption.
* \since 7.0.8 Safe to call from a listener callback.
* \until 7.0.8 Self-removal from a listener callback caused corruption.
*/
LIBCOM_API int errlogRemoveListeners(errlogListener listener,
void *pPrivate);
@@ -285,14 +285,16 @@ LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength);
#define ANSI_ESC_MAGENTA "\033[35;1m"
#define ANSI_ESC_CYAN "\033[36;1m"
#define ANSI_ESC_BOLD "\033[1m"
#define ANSI_ESC_UNDERLINE "\033[4m"
#define ANSI_ESC_RESET "\033[0m"
#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET
#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET
#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET
#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET
#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET
#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET
#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET
#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET
#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET
#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET
#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET
#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET
#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET
#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET
#define ANSI_UNDERLINE(STR) ANSI_ESC_UNDERLINE STR ANSI_ESC_RESET
#define ERL_ERROR ANSI_RED("ERROR")
#define ERL_WARNING ANSI_MAGENTA("WARNING")
/** @} */

View File

@@ -206,7 +206,6 @@ LIBCOM_API void fdManager::process (double delay)
this->pTimerQueue->process(epicsTime::getCurrent());
}
this->processInProg = false;
return;
}
//

View File

@@ -38,10 +38,9 @@ public:
// exceptions
//
class noFunctionSpecified {};
class doubleDelete {};
LIBCOM_API fdRegForOldFdmgr (const SOCKET fdIn, const fdRegType type,
const bool onceOnly, fdManager &manager, pCallBackFDMgr pFunc, void *pParam);
LIBCOM_API fdRegForOldFdmgr (SOCKET fdIn, fdRegType type,
bool onceOnly, fdManager &manager, pCallBackFDMgr pFunc, void *pParam);
LIBCOM_API ~fdRegForOldFdmgr ();
private:
@@ -66,7 +65,6 @@ public:
// exceptions
//
class noFunctionSpecified {};
class doubleDelete {};
private:
epicsTimer &timer;
oldFdmgr &fdmgr;
@@ -116,11 +114,7 @@ LIBCOM_API fdRegForOldFdmgr::fdRegForOldFdmgr
}
LIBCOM_API fdRegForOldFdmgr::~fdRegForOldFdmgr ()
{
if (this->pFunc==NULL) {
throwWithLocation ( doubleDelete () );
}
}
{}
LIBCOM_API void fdRegForOldFdmgr::callBack ()
{

View File

@@ -19,7 +19,7 @@ parse_CPPFLAGS = -DDEFAULT_SKELETON_FILE=$(SKELETON_FILE)
INC += flex.skel.static
# flex.c is included in parse.c
# flex.c, scan.c and yylex.c are #included by parse.c
e_flex_SRCS += ccl.c
e_flex_SRCS += dfa.c
e_flex_SRCS += ecs.c

View File

@@ -132,7 +132,6 @@ void cclnegate(int cclp)
void list_character_set(FILE *file, int cset[])
{
int i;
char *readable_form();
putc( '[', file );

View File

@@ -188,7 +188,6 @@ int main(int argc, char *argv[])
void flexend(int status)
{
int tblsiz;
char *flex_gettime();
if ( skelfile != NULL )
{
@@ -382,7 +381,7 @@ void flexend(int status)
void flexinit(int argc, char **argv)
{
int i, sawcmpflag;
char *arg, *flex_gettime(), *mktemp();
char *arg;
printstats = syntaxerror = trace = spprdflt = interactive = caseins = false;
backtrack_report = performance_report = ddebug = fulltbl = fullspd = false;

View File

@@ -567,8 +567,8 @@ extern int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs;
extern int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave;
extern int num_backtracking, bol_needed;
void *allocate_array(int size, int element_size);
void *reallocate_array(void *array, int size, int element_size);
extern void *allocate_array(int size, int element_size);
extern void *reallocate_array(void *array, int size, int element_size);
#define allocate_integer_array(size) \
(int *) allocate_array( size, sizeof( int ) )
@@ -677,10 +677,20 @@ extern int all_upper (Char *);
/* bubble sort an integer array */
extern void bubble (int [], int);
/* replace upper-case letter to lower-case */
extern Char clower(int c);
/* returns copy of a string */
extern char *copy_string(char *str);
/* returns copy of a (potentially) unsigned string */
extern Char *copy_unsigned_string(Char *str);
/* shell sort a character array */
extern void cshell (Char [], int, int);
extern void dataend (void); /* finish up a block of data declarations */
/* finish up a block of data declarations */
extern void dataend (void);
/* report an error message and terminate */
extern void flexerror (char[]) NORETURN;
@@ -688,6 +698,9 @@ extern void flexerror (char[]) NORETURN;
/* report a fatal error message and terminate */
extern void flexfatal (char[]);
/* return current time */
extern char *flex_gettime();
/* report an error message formatted with one integer argument */
extern void lerrif (char[], int);
@@ -700,11 +713,18 @@ extern void line_directive_out (FILE*);
/* generate a data statment for a two-dimensional array */
extern void mk2data (int);
extern void mkdata (int); /* generate a data statement */
/* generate a data statement */
extern void mkdata (int);
/* return the integer represented by a string of digits */
extern int myctoi (Char []);
/* return character corresponding to escape sequence */
extern Char myesc(Char *array);
/* return the the human-readable form of a character */
extern char *readable_form(int c);
/* write out one section of the skeleton file */
extern void skelout (void);
@@ -784,8 +804,14 @@ extern void cclinstal (Char [], int);
/* lookup the number associated with character class */
extern int ccllookup (Char []);
extern void ndinstal (char[], Char[]); /* install a name definition */
extern void scinstal (char[], int); /* make a start condition */
/* install a name definition */
extern void ndinstal (char[], Char[]);
/* lookup a name definition */
extern Char *ndlookup(char *nd);
/* make a start condition */
extern void scinstal (char[], int);
/* lookup the number associated with a start condition */
extern int sclookup (char[]);

View File

@@ -217,7 +217,6 @@ void genecs(void)
int i, j;
static char C_char_decl[] = "static const %s %s[%d] =\n { 0,\n";
int numrows;
Char clower();
if ( numecs < csize )
printf( C_char_decl, "YY_CHAR", "yy_ec", csize );
@@ -237,8 +236,6 @@ void genecs(void)
if ( trace )
{
char *readable_form();
fputs( "\n\nEquivalence Classes:\n\n", stderr );
numrows = csize / 8;

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