Compare commits
129 Commits
PSI-7.0.7.
...
PSI-7.0.7.
| Author | SHA1 | Date | |
|---|---|---|---|
| e2bb42d8d3 | |||
| abcada0d85 | |||
| 2c35d60a64 | |||
| af1b77eb0f | |||
| 93947eb027 | |||
| 961671259f | |||
|
|
db2482117d | ||
| a66caa5985 | |||
| 4803aae904 | |||
| 427be18e2e | |||
| fff690a449 | |||
| 428b836500 | |||
| 6c74507b11 | |||
| 122ca4e1d3 | |||
|
|
ba1bf00ce7 | ||
|
|
68fea5c2ca | ||
|
|
3f03efe7fe | ||
|
|
98dc97022a | ||
|
|
5d01b637a7 | ||
|
|
69a184ee1d | ||
|
|
aebacff3db | ||
|
|
27ad623d68 | ||
|
|
1b23701946 | ||
|
|
0502fe25e4 | ||
|
|
77a37781af | ||
|
|
ba21e655df | ||
|
|
2e727a0262 | ||
|
|
f4cb31d5d5 | ||
|
|
ab4e687816 | ||
|
|
1d1926eaf3 | ||
|
|
d31ba6ade3 | ||
| 609147dad0 | |||
|
|
5a5535aa5b | ||
|
|
de61390049 | ||
|
|
304d8217d9 | ||
|
|
2c95dc91e9 | ||
|
|
8cc15c6e68 | ||
|
|
680e1734a4 | ||
| 4aea7de032 | |||
|
|
bddbc38e0b | ||
|
|
67e669c5e5 | ||
|
|
e291ca0a03 | ||
|
|
5b84a86ccd | ||
|
|
cb6442da71 | ||
|
|
49b9573f3a | ||
|
|
42dfca2b54 | ||
|
|
3fd79a21a2 | ||
|
|
12f311b780 | ||
|
|
8abc9f8d03 | ||
|
|
ae6f01b8ee | ||
| 1d3a2defa2 | |||
| 43f6fd5060 | |||
|
|
ca9c957e62 | ||
|
|
8488c9e891 | ||
|
|
1f2edb69d2 | ||
|
|
fe3ee85aee | ||
|
|
c8d596034a | ||
|
|
1d3459982c | ||
|
|
9934242ccf | ||
|
|
e6dab90bf4 | ||
|
|
c680b9bebd | ||
|
|
9555ca05b8 | ||
|
|
0cd56fa40b | ||
|
|
485ac85fa5 | ||
| 1148931226 | |||
|
|
a74789d9c0 | ||
|
|
7830345e59 | ||
|
|
1595ed8860 | ||
|
|
d97943b697 | ||
|
|
f8f4376594 | ||
|
|
df397f4ade | ||
|
|
7fd690e53e | ||
|
|
bc5d347bb2 | ||
|
|
3ea29f581b | ||
|
|
6de82bb0fd | ||
| e1a51e2839 | |||
|
|
0f59d823d3 | ||
| 73f80cced9 | |||
| 152c72bab0 | |||
|
|
00dc55b8a2 | ||
|
|
524f81b8bd | ||
|
|
80e62031e9 | ||
|
|
d87fd0db01 | ||
|
|
6636b4b9e7 | ||
|
|
b51d1de283 | ||
|
|
38c99df2e0 | ||
|
|
688195a273 | ||
|
|
d691acc001 | ||
|
|
059d32a975 | ||
|
|
5c99031157 | ||
|
|
a01c671399 | ||
|
|
b2c80efd33 | ||
|
|
39b6fa26da | ||
|
|
3ee6097ab7 | ||
|
|
500a57738b | ||
|
|
f488765631 | ||
|
|
3a2d225682 | ||
|
|
1d056c6fe4 | ||
| 0f086126b7 | |||
| 5b058d7d27 | |||
|
|
42604fc794 | ||
|
|
4ecc0daa79 | ||
|
|
5a1f3ecc8b | ||
|
|
cb97d662a7 | ||
|
|
d4fab0d20e | ||
|
|
0c13e6ba6c | ||
|
|
8f1243da40 | ||
|
|
fe9995c0b5 | ||
|
|
f56412d6a5 | ||
|
|
07d18c55ba | ||
|
|
9f97f25669 | ||
| 912a82c0b5 | |||
| acf2241fd0 | |||
|
|
b878295d06 | ||
| f41f11c7f6 | |||
|
|
216359974c | ||
|
|
17ad04505e | ||
|
|
3500a02034 | ||
|
|
52b18d56a0 | ||
|
|
5507646ce7 | ||
|
|
625c2ef159 | ||
|
|
bdaca51d96 | ||
|
|
9655b78e11 | ||
|
|
e11f88017d | ||
|
|
8a3020033e | ||
|
|
bd1af9ac95 | ||
|
|
d5959ca20a | ||
|
|
e10dcede7d | ||
|
|
c042b08ab0 |
@@ -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 #
|
||||
#---------------------------------#
|
||||
|
||||
@@ -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
2
.ci
Submodule .ci updated: 1e0e326f74...130e88b709
45
.github/workflows/ci-scripts-build.yml
vendored
45
.github/workflows/ci-scripts-build.yml
vendored
@@ -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
|
||||
@@ -133,13 +152,15 @@ jobs:
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: default
|
||||
configuration: debug
|
||||
name: "Win2019 MSC-19"
|
||||
extra: "CMD_CXXFLAGS=-analysis"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: static
|
||||
configuration: static-debug
|
||||
name: "Win2019 MSC-19, static"
|
||||
extra: "CMD_CXXFLAGS=-analysis"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
@@ -151,6 +172,26 @@ jobs:
|
||||
configuration: default
|
||||
name: "Win2019 mingw"
|
||||
|
||||
# Cross builds
|
||||
|
||||
- os: ubuntu-latest
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
name: "Cross linux-aarch64"
|
||||
cross: linux-aarch64
|
||||
|
||||
- os: ubuntu-latest
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
name: "Cross linux-arm gnueabi"
|
||||
cross: linux-arm@arm-linux-gnueabi
|
||||
|
||||
- os: ubuntu-latest
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
name: "Cross linux-arm gnueabihf"
|
||||
cross: linux-arm@arm-linux-gnueabihf
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -17,3 +17,6 @@ O.*/
|
||||
*.log
|
||||
.*.swp
|
||||
.DS_Store
|
||||
.iocsh_history
|
||||
RPMS
|
||||
SRPMS
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,7 @@
|
||||
[submodule "modules/pvData"]
|
||||
path = modules/pvData
|
||||
url = https://github.com/epics-base/pvDataCPP
|
||||
# url = https://github.com/epics-base/pvDataCPP
|
||||
url = git@git.psi.ch:epics_base/pvData.git
|
||||
branch = master
|
||||
[submodule "modules/pvAccess"]
|
||||
path = modules/pvAccess
|
||||
|
||||
@@ -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.
|
||||
|
||||
3
Makefile
3
Makefile
@@ -30,3 +30,6 @@ copysrc:
|
||||
|
||||
tar:
|
||||
tar cfjP epics_base-$(EPICS_VERSION_NUMBER).tar.bz2 $(INSTALL_LOCATION)
|
||||
|
||||
rpm:
|
||||
rpmbuild -bb epics-base.spec
|
||||
|
||||
@@ -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))))
|
||||
|
||||
18
configure/os/CONFIG.Common.RHEL9-x86_64
Normal file
18
configure/os/CONFIG.Common.RHEL9-x86_64
Normal file
@@ -0,0 +1,18 @@
|
||||
# Include definitions common to linux pentium targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-x86_64
|
||||
|
||||
TOOLSET_LOCATION = /opt/rh
|
||||
TOOLSET = gcc-toolset-12
|
||||
STD_CXXFLAGS = -std=c++20
|
||||
|
||||
# Fix bug in gcc-toolset-11 calling the old assembler
|
||||
ifneq ($(filter %-11,$(TOOLSET)),)
|
||||
TARGET_CPPFLAGS += $(TOOLSET_DIR:%=-B$(SYSROOT)%/bin)
|
||||
TARGET_LDFLAGS += $(TOOLSET_DIR:%=-B$(SYSROOT)%/bin)
|
||||
endif
|
||||
|
||||
ifneq (($(TOOLSET)),)
|
||||
# Perl requests (native) annobin incompatible with the annobin from any TOOLSET
|
||||
# Disable Perl specific CFLAGS
|
||||
override Cap5_CFLAGS=
|
||||
endif
|
||||
3
configure/os/CONFIG.Common.RHEL9-x86_64-clang
Normal file
3
configure/os/CONFIG.Common.RHEL9-x86_64-clang
Normal file
@@ -0,0 +1,3 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-clang
|
||||
|
||||
STD_CXXFLAGS = -std=c++2a
|
||||
@@ -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))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.vxWorks-ppc604_long
|
||||
VXWORKS_VERSION = 5.5.1
|
||||
WIND_BASE = /afs/psi.ch/project/vxworks/Tornado2.2.1
|
||||
WIND_BASE = /opt/VxWorks/Tornado2.2.1
|
||||
|
||||
#there is a problem with our ccppc and optimization
|
||||
# -O0 works, -O and -O1 and higher are buggy
|
||||
|
||||
@@ -12,7 +12,7 @@ SDK_DIR = /opt/xgcc/gcc-8.3.0-deb10
|
||||
GNU_ARCH = x86_64-deb10-linux-gnu
|
||||
SDKTARGETSYSROOT=$(SDK_DIR)/$(GNU_ARCH)/sys-root/
|
||||
GNU_DIR = $(SDK_DIR)
|
||||
GNU_BIN = $(GNU_DIR)/bin/
|
||||
GNU_BIN = $(GNU_DIR)/bin
|
||||
GNU_TARGET_INCLUDE_DIR =
|
||||
GNU_TARGET=x86_64-deb10-linux-gnu
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
# Include definitions common to all Unix targets
|
||||
include $(CONFIG)/os/CONFIG.Common.UnixCommon
|
||||
GNU = NO
|
||||
CMPLR_CLASS = clang
|
||||
CC = clang
|
||||
CCC = clang++
|
||||
|
||||
OS_CLASS = freebsd
|
||||
|
||||
|
||||
@@ -24,17 +24,23 @@ STATIC_LDFLAGS_NO=
|
||||
STATIC_LDLIBS_YES= -Wl,-Bdynamic
|
||||
|
||||
# Set runtime path for shared libraries if LINKER_USE_RPATH=YES
|
||||
SHRLIBDIR_RPATH_LDFLAGS_YES = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
SHRLIBDIR_RPATH_LDFLAGS_YES = $(subst $(abspath $(LINKER_ORIGIN_ROOT)),$(FINAL_LOCATION),$(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%))
|
||||
SHRLIBDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(SHRLIB_DEPLIB_DIRS))
|
||||
SHRLIBDIR_LDFLAGS += \
|
||||
$(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
# Set runtime path for products if LINKER_USE_RPATH=YES
|
||||
PRODDIR_RPATH_LDFLAGS_YES = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
PRODDIR_RPATH_LDFLAGS_YES = $(subst $(abspath $(LINKER_ORIGIN_ROOT)),$(FINAL_LOCATION),$(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%))
|
||||
PRODDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(PROD_DEPLIB_DIRS))
|
||||
PRODDIR_LDFLAGS += \
|
||||
$(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
ifneq ($(LINKER_USE_RPATH:NO=),)
|
||||
ifeq ($(T_A),$(EPICS_HOST_ARCH))
|
||||
LD_LIBRARY_PATH:=$(LD_LIBRARY_PATH:%=%:)$(INSTALL_LIB)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Link libraries controlled by COMMANDLINE_LIBRARY
|
||||
# The newest Linux versions only need readline, older ones need both
|
||||
# readline and ncurses, and the oldest need readline and curses
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Include definitions common to all Linux ARM targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-arm
|
||||
|
||||
GNU_DIR=/afs/psi.ch/project/embeddedlinux/moxa/arm-linux-4.4.2-v4
|
||||
GNU_DIR=/opt/moxa/arm-linux-4.4.2-v4
|
||||
GNU_TARGET=arm
|
||||
ARCH_DEP_LDFLAGS+=-Wl,-rpath-link,$(GNU_DIR)/arm-none-linux-gnueabi/lib
|
||||
ARCH_DEP_LDFLAGS+=-Wl,-rpath-link,$(INSTALL_LIB)
|
||||
|
||||
@@ -7,7 +7,7 @@ COMMANDLINE_LIBRARY = READLINE_CURSES
|
||||
|
||||
ARCH_CLASS = xscale
|
||||
|
||||
GNU_DIR=/afs/psi.ch/project/embeddedlinux/moxa/xscale_be/armv5teb-montavista-linuxeabi
|
||||
GNU_DIR=/opt/moxa/xscale_be/armv5teb-montavista-linuxeabi
|
||||
|
||||
ARCH_DEP_CFLAGS += -funwind-tables
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# National Instruments CompactRIO running LabView RT 19.5.1
|
||||
# requires RPM gcc-c++-arm-linux-gnu
|
||||
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
@@ -8,10 +9,11 @@ ARCH_CLASS = arm
|
||||
GNU_TARGET = arm-linux-gnu
|
||||
|
||||
SYSROOT = /opt/LabVIEW-RT-19.5.1/arm/sysroots/armv7a-vfp-neon-nilrt-linux-gnueabi
|
||||
GNU_BIN = /bin
|
||||
GNU_BIN = /opt/RHEL7/bin
|
||||
LD_LIBRARY_PATH=/usr/$$LIB:/opt/RHEL7/$$LIB
|
||||
|
||||
ARCH_DEP_CPPFLAGS += -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon
|
||||
ARCH_DEP_CXXFLAGS += -I$(SYSROOT)/usr/include/c++/4.7.2/arm-nilrt-linux-gnueabi/
|
||||
ARCH_DEP_CXXFLAGS += -I$(SYSROOT)/usr/include/c++/4.7.2/
|
||||
ARCH_DEP_CXXFLAGS += -I=/usr/include/c++/4.7.2/arm-nilrt-linux-gnueabi
|
||||
ARCH_DEP_CXXFLAGS += -I=/usr/include/c++/4.7.2
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE_NCURSES
|
||||
|
||||
@@ -10,13 +10,13 @@ include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
# Due to missing/messed up libs in the toolchain, readline needs copies of
|
||||
# libtinfo.so.5.9 and libreadline.so.6.2 from a Raspbian 7 rootfs
|
||||
# /lib/arm-linux-gnueabihf/ to the toolchain, e.g.
|
||||
# $(SDK_DIR)/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/lib/arm-linux-gnueabihf/
|
||||
# $(SDK_DIR)/$(SDK_TARGET)/arm-linux-gnueabihf/libc/lib/arm-linux-gnueabihf/
|
||||
# and manually created links libtinfo.so.5 and libreadline.so.
|
||||
# For gcc-linaro-arm-linux-gnueabihf-raspbian, an existing incompatible
|
||||
# libtinfo.so.5 is in the way. Remove it.
|
||||
# (Built with glibc 2.16 like installed on Raspbian 9 but toolchain uses glibc 2.13.)
|
||||
# Also copy /usr/include/readline/ directory from some readline 6 installation
|
||||
# to $(SDK_DIR)/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/usr/include/
|
||||
# to $(SDK_DIR)/$(SDK_TARGET)/arm-linux-gnueabihf/libc/usr/include/
|
||||
|
||||
ARCH_CLASS = arm
|
||||
|
||||
@@ -25,10 +25,10 @@ SDK_DIR = /opt/raspberrypi/arm-bcm2708
|
||||
# Available SDK_TARGETs:
|
||||
|
||||
# gcc 4.8.3 for 32 bit hosts with GLIBC 2.3 or higher
|
||||
SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian
|
||||
# SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian
|
||||
|
||||
# gcc 4.8.3 for 64 bit hosts with GLIBC 2.14 or higher
|
||||
# SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian-x64
|
||||
SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian-x64
|
||||
|
||||
# gcc 4.7.1 for 64 bit hosts with GLIBC 2.8 or higher
|
||||
# SDK_TARGET = arm-linux-gnueabihf
|
||||
|
||||
@@ -2,5 +2,9 @@ include $(CONFIG)/os/CONFIG.windows-x64.windows-x64
|
||||
|
||||
VALID_BUILDS = Ioc Command
|
||||
|
||||
PATH := /opt/wine-msvc-2017/bin/x64:$(PATH)
|
||||
MSVC_VERSION ?= 2019
|
||||
PATH := /opt/gfa-wine/bin:/opt/wine-msvc-$(MSVC_VERSION)/bin/x64:$(PATH)
|
||||
export WINEPREFIX = $(HOME)/.wine-$(EPICS_HOST_ARCH)
|
||||
export WINEDEBUG=fixme-all
|
||||
export WINEDLLOVERRIDES="mscoree,mshtml="
|
||||
export WINE = wine64
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
# MSVC_VERSION 2019 in wine 4 for on RHEL7 would require winetricks
|
||||
MSVC_VERSION = 2017
|
||||
include $(CONFIG)/os/CONFIG.Linux.windows-x64
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
GNU_BIN = /opt/RHEL7/bin
|
||||
3
configure/os/CONFIG.RHEL9-x86_64.Common
Normal file
3
configure/os/CONFIG.RHEL9-x86_64.Common
Normal file
@@ -0,0 +1,3 @@
|
||||
#CONFIG.$(EPICS_HOST_ARCH).Common is required by build system
|
||||
#Include definitions common to linux hosts
|
||||
include $(CONFIG)/os/CONFIG.linux-x86_64.Common
|
||||
18
configure/os/CONFIG.RHEL9-x86_64.RHEL7-x86_64
Normal file
18
configure/os/CONFIG.RHEL9-x86_64.RHEL7-x86_64
Normal file
@@ -0,0 +1,18 @@
|
||||
# Include common linux definitions
|
||||
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86
|
||||
|
||||
# "Cross compile" for RHEL7-x86_64
|
||||
# Expects RHEL7 RPMs c++ and readline-devel installed
|
||||
# in $(SYSROOT)
|
||||
# This can be installed on RHEL7 with:
|
||||
# yum install --installroot=$(SYSROOT) <packages>
|
||||
# (Assuming $(SYSROOT) is on a shared network volume.)
|
||||
# Optionally use a newer TOOLSET (installed on $(SYSROOT)).
|
||||
|
||||
SYSROOT = /opt/RHEL7
|
||||
|
||||
# "Cross" TOOLSET progs need to find their libraries
|
||||
LD_LIBRARY_PATH = $(TOOLSET_DIR:%=$(SYSROOT)%/usr/$$LIB:)/usr/$$LIB:$(SYSROOT)/usr/$$LIB
|
||||
|
||||
# The linker has problems to find indirectly referenced libraries
|
||||
PROD_LDLIBS += $(LDLIBS)
|
||||
23
configure/os/CONFIG.RHEL9-x86_64.RHEL8-x86_64
Normal file
23
configure/os/CONFIG.RHEL9-x86_64.RHEL8-x86_64
Normal file
@@ -0,0 +1,23 @@
|
||||
# Include common linux definitions
|
||||
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86
|
||||
|
||||
# "Cross compile" for RHEL8-x86_64
|
||||
# Expects RHEL8 RPMs gcc-toolset-12-gcc-c++ and readline-devel
|
||||
# to be installed in $(SYSROOT)
|
||||
# These can be installed on RHEL8 with:
|
||||
# yum install --installroot=$(SYSROOT) <packages>
|
||||
# (Assuming $(SYSROOT) is on a shared network volume.)
|
||||
|
||||
SYSROOT = /opt/RHEL8
|
||||
|
||||
# "Cross" TOOLSET progs need to find their libraries.
|
||||
# But linker gets confused with LD_LIBRARY_PATH.
|
||||
# Thus only wrap the compiler.
|
||||
WRAPPER = -wrapper env,LD_LIBRARY_PATH=$(TOOLSET_DIR:%=$(SYSROOT)%/usr/lib64:)/usr/lib64:$(SYSROOT)/usr/lib64
|
||||
TARGET_CPPFLAGS += $(WRAPPER)
|
||||
TARGET_PROD_LDFLAGS += $(WRAPPER)
|
||||
|
||||
# These programs as cross tools would also need LD_LIBRARY_PATH.
|
||||
# But but our host versions work just fine.
|
||||
AR = ar -rc
|
||||
RANLIB = ranlib
|
||||
2
configure/os/CONFIG.RHEL9-x86_64.RHEL9-x86_64
Normal file
2
configure/os/CONFIG.RHEL9-x86_64.RHEL9-x86_64
Normal file
@@ -0,0 +1,2 @@
|
||||
# Include common linux definitions
|
||||
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86
|
||||
1
configure/os/CONFIG.RHEL9-x86_64.windows-x64
Normal file
1
configure/os/CONFIG.RHEL9-x86_64.windows-x64
Normal file
@@ -0,0 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.Linux.windows-x64
|
||||
@@ -5,3 +5,4 @@
|
||||
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
CMPLR_CLASS = clang
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Definitions for freebsd-x86 host - freebsd-x86 target builds
|
||||
# Sites may override these definitions in CONFIG_SITE.freebsd-x86.freebsd-x86
|
||||
#-------------------------------------------------------
|
||||
GNU_DIR=/usr/local
|
||||
|
||||
# Include common gnu compiler definitions
|
||||
include $(CONFIG)/CONFIG.gnuCommon
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Definitions for freebsd-x86_64 host - freebsd-x86_64 target builds
|
||||
# Sites may override these definitions in CONFIG_SITE.freebsd-x86_64.freebsd-x86_64
|
||||
#-------------------------------------------------------
|
||||
GNU_DIR=/usr/local
|
||||
|
||||
# Include common gnu compiler definitions
|
||||
include $(CONFIG)/CONFIG.gnuCommon
|
||||
|
||||
@@ -16,7 +16,7 @@ OPT_WHOLE_PROGRAM = YES
|
||||
|
||||
WINLINK = link
|
||||
|
||||
RCCMD = rc -l 0x409 $(INCLUDES) -fo $@ $<
|
||||
RCCMD = rc -nologo -l 0x409 $(INCLUDES) -fo $@ $<
|
||||
|
||||
ARCMD = lib -nologo -verbose -out:$@ $(LIB_OPT_LDFLAGS) $(LIBRARY_LD_OBJS)
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
SHRLIB_SUFFIX = $(SHRLIB_SUFFIX_BASE)
|
||||
LOADABLE_SHRLIB_SUFFIX = $(SHRLIB_SUFFIX_BASE)
|
||||
@@ -87,7 +87,7 @@ CODE_CXXFLAGS =
|
||||
#WIND_BASE = /usr/local/vw/tornado22-$(ARCH_CLASS)
|
||||
#WIND_BASE = /usr/local/vw/vxWorks-$(VXWORKS_VERSION)
|
||||
#WIND_BASE = /ade/vxWorks/$(VXWORKS_VERSION)
|
||||
WIND_BASE = /afs/psi.ch/project/vxworks/VxWorks$(VXWORKS_VERSION)
|
||||
WIND_BASE = /opt/VxWorks/VxWorks$(VXWORKS_VERSION)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Modules we cannot build with old compiler
|
||||
|
||||
@@ -3,8 +3,3 @@ include $(CONFIG)/os/CONFIG_SITE.linux-x86_64.Common
|
||||
# Improved error checking with clang
|
||||
CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64-clang
|
||||
CROSS_COMPILER_RUNTEST_ARCHS += RHEL7-x86_64-clang
|
||||
|
||||
# NI Linux Real-Time 7.x
|
||||
# requires RPM gcc-c++-arm-linux-gnu
|
||||
# Not available on RHEL8
|
||||
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a
|
||||
|
||||
@@ -5,7 +5,3 @@ CROSS_COMPILER_TARGET_ARCHS += RHEL8-x86_64-clang
|
||||
|
||||
# Build for old RHEL7 64 bit
|
||||
CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64
|
||||
|
||||
# NI Linux Real-Time 7.x
|
||||
# requires RPM gcc-c++-arm-linux-gnu
|
||||
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a
|
||||
|
||||
10
configure/os/CONFIG_SITE.RHEL9-x86_64.Common
Normal file
10
configure/os/CONFIG_SITE.RHEL9-x86_64.Common
Normal file
@@ -0,0 +1,10 @@
|
||||
include $(CONFIG)/os/CONFIG_SITE.linux-x86_64.Common
|
||||
|
||||
# Improved error checking with clang
|
||||
CROSS_COMPILER_TARGET_ARCHS += RHEL9-x86_64-clang
|
||||
|
||||
# Build for old RHEL8 64 bit
|
||||
CROSS_COMPILER_TARGET_ARCHS += RHEL8-x86_64
|
||||
|
||||
# Build for old RHEL7 64 bit
|
||||
CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64
|
||||
@@ -38,7 +38,7 @@ CROSS_COMPILER_TARGET_ARCHS += eldk52-e500v2
|
||||
|
||||
# DeltaTau PowerPMAC
|
||||
CROSS_COMPILER_TARGET_ARCHS += eldk42-ppc4xxFP
|
||||
#CROSS_COMPILER_TARGET_ARCHS += eldk53-ppc4xxFP
|
||||
CROSS_COMPILER_TARGET_ARCHS += eldk53-ppc4xxFP
|
||||
|
||||
# Test other vxWorks versions
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V66-ppc603
|
||||
@@ -48,9 +48,6 @@ CROSS_COMPILER_TARGET_ARCHS += eldk42-ppc4xxFP
|
||||
# (No PVA because of old compiler)
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V62-ppc604
|
||||
|
||||
# Raspberry Pi
|
||||
CROSS_COMPILER_TARGET_ARCHS += raspbian-arm
|
||||
|
||||
# RTEMS (Can only have 1 RTEMS major version in 1 EPICS installation
|
||||
# because they overwrite their header files.)
|
||||
#CROSS_COMPILER_TARGET_ARCHS += RTEMS49-pc386
|
||||
|
||||
@@ -25,4 +25,10 @@ CROSS_COMPILER_TARGET_ARCHS += yocto40-aarch64
|
||||
CROSS_COMPILER_TARGET_ARCHS += deb10-x86_64
|
||||
|
||||
# Newer DeltaTau PowerPMAC
|
||||
#CROSS_COMPILER_TARGET_ARCHS += gcc8-ppc4xxFP
|
||||
CROSS_COMPILER_TARGET_ARCHS += gcc8-ppc4xxFP
|
||||
|
||||
# Raspberry Pi
|
||||
CROSS_COMPILER_TARGET_ARCHS += raspbian-arm
|
||||
|
||||
# NI Linux Real-Time 7.x
|
||||
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a
|
||||
|
||||
@@ -9,12 +9,105 @@ 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:
|
||||
|
||||
- [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)
|
||||
|
||||
**This version of EPICS has not been released yet.**
|
||||
|
||||
## Changes made on the 7.0 branch since 7.0.7
|
||||
|
||||
### PROC field changed to ASL0
|
||||
|
||||
The PROC field has been changed from access security level ASL1 to ASL0.
|
||||
This allows users to trigger processing a record without having the rights
|
||||
to reconfigure the records.
|
||||
|
||||
### 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
|
||||
|
||||
On Windows targets, if a thread not created by `epicsThreadCreate*()` directly
|
||||
or indirectly calls an `epicsThread*()` function, a specific tracking struct
|
||||
is allocated. Prior to this release the allocation would not be `free()`d,
|
||||
resulting in a memory leak.
|
||||
|
||||
A similar issue on POSIX targets was previously fixed.
|
||||
|
||||
### Change compiler for FreeBSD to clang
|
||||
|
||||
The default compiler for FreeBSD targets changes from GCC to clang.
|
||||
|
||||
### Expose `dbCreateAlias` in IOC shell
|
||||
|
||||
Add a new IOC shell command `dbCreateAlias` allow record aliases to be added.
|
||||
Intended for use before `iocInit`. eg. to add an alias "bar" for a record "foo".
|
||||
|
||||
```
|
||||
dbLoadRecords("some.db") # includes: record(ai, "foo") { ...
|
||||
dbCreateAlias("foo", "bar")
|
||||
iocInit()
|
||||
```
|
||||
|
||||
### dbEvent eventsRemaining missed on cancel
|
||||
|
||||
In some cases, RSRV may queue a subscription update, but not flush it.
|
||||
@@ -26,7 +119,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.
|
||||
|
||||
@@ -48,6 +141,27 @@ The compress record now supports the use of partially-filled buffers when using
|
||||
any of the N-to-one algorithms. This is achieved by setting the new field `PBUF`
|
||||
to `YES`.
|
||||
|
||||
### Extended timestamp channel filter
|
||||
|
||||
The `"ts"` filter can now retrieve the record's timestamp in several numeric
|
||||
and string formats, some of which support full nanosecond precision.
|
||||
|
||||
Hal$ caget -a test:channel
|
||||
test:channel 2021-03-11 18:23:48.265386 42
|
||||
Hal$ caget -f9 'test:channel.{"ts": {"num": "dbl"}}'
|
||||
test:channel.{"ts": {"num": "dbl"}} 984331428.265386105
|
||||
Hal$ caget 'test:channel.{"ts": {"str": "iso"}}'
|
||||
test:channel.{"ts": {"str": "iso"}} 2021-03-11T18:23:48.265386+0100
|
||||
Hal$ caget -f1 'test:channel.{"ts": {"num": "ts"}}'
|
||||
test:channel.{"ts": {"num": "ts"}} 2 984331428.0 265386163.0
|
||||
|
||||
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
|
||||
@@ -60,7 +174,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
|
||||
@@ -72,14 +188,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
|
||||
@@ -227,6 +354,32 @@ This release fixed the leak on POSIX targets.
|
||||
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
|
||||
for WIN32 status.
|
||||
|
||||
### Fixed leak from a non-EPICS thread
|
||||
|
||||
On some targets, if a thread not created by `epicsThreadCreate*()` directly
|
||||
or indirectly calls an `epicsThread*()` function, a specific tracking struct
|
||||
is allocated.
|
||||
|
||||
Prior to this release, on POSIX and WIN32 targets, this
|
||||
allocation would not be `free()`d, resulting in a memory leak.
|
||||
|
||||
This release fixed the leak on POSIX and WIN32 targets (excluding
|
||||
MSVC before vs2012, and the WINE runtime).
|
||||
|
||||
### Fixed leak from a non-EPICS thread
|
||||
|
||||
On some targets, if a thread not created by `epicsThreadCreate*()` directly
|
||||
or indirectly calls an `epicsThread*()` function, a specific tracking struct
|
||||
is allocated.
|
||||
|
||||
Prior to this release, on POSIX and WIN32 targets, this
|
||||
struct would not be `free()`d, resulting in a memory leak.
|
||||
|
||||
This release fixed the leak on POSIX targets.
|
||||
|
||||
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
|
||||
for WIN32 status.
|
||||
|
||||
### Fix `CHECK_RELEASE = WARN`
|
||||
|
||||
This now works again, it was broken in 2019 (7.0.3.1) by an errant commit.
|
||||
|
||||
8
epics-base.sh
Normal file
8
epics-base.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
_OLD_EXTGLOB=$(shopt -p extglob)
|
||||
shopt -s extglob
|
||||
test -n "$EPICS_BASE" || export EPICS_BASE=$(ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/ | head -n1)
|
||||
test -n "$EPICS_HOST_ARCH" || export EPICS_HOST_ARCH=$(/bin/sed "s%cpe:/o:redhat:enterprise_linux:\([0-9]*\).*%RHEL\1-`/bin/uname -m`%" /etc/system-release-cpe)
|
||||
PATH=${PATH//\/usr\/local\/epics\/base-+([0-9]).+([0-9]).+([0-9])\/bin\/$EPICS_HOST_ARCH}:$(echo $(ls -dvr /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/$EPICS_HOST_ARCH) | tr ' ' :)
|
||||
eval $_OLD_EXTGLOB
|
||||
unset _OLD_EXTGLOB
|
||||
|
||||
385
epics-base.spec
Normal file
385
epics-base.spec
Normal file
@@ -0,0 +1,385 @@
|
||||
# Always make sure EpicsVersion.Version-Release matches the git tag!
|
||||
|
||||
%define EpicsVersion 7.0.7
|
||||
|
||||
Name: epics-base-%{EpicsVersion}
|
||||
Summary: EPICS Base %{EpicsVersion}
|
||||
Version: 1
|
||||
Release: 4%{?dist}
|
||||
License: EPICS Open License
|
||||
Group: Development/Languages
|
||||
URL: https://git.psi.ch/epics_base/base-7.0
|
||||
|
||||
Obsoletes: caRepeater
|
||||
|
||||
%define module_name %{name}
|
||||
%define prog_folder /usr/local/epics/base-%{EpicsVersion}
|
||||
|
||||
%define debug_package %{nil}
|
||||
|
||||
# do not strip libraries
|
||||
%global __strip /bin/true
|
||||
%undefine __brp_strip
|
||||
|
||||
%undefine __brp_mangle_shebangs
|
||||
%undefine __brp_ldconfig
|
||||
%define _binaries_in_noarch_packages_terminate_build 0
|
||||
|
||||
%if %{defined rhel}
|
||||
%global epics_host_arch RHEL%{rhel}-%{_host_cpu}
|
||||
%endif
|
||||
|
||||
%description
|
||||
EPICS is a set of Open Source software tools, libraries and applications
|
||||
developed collaboratively and used worldwide to create distributed soft
|
||||
real-time control systems for scientific instruments such as a particle
|
||||
accelerators, telescopes and other large scientific experiments.
|
||||
This RPM is a binary-only package.
|
||||
|
||||
###########################################
|
||||
|
||||
%package host-devel
|
||||
Requires: make >= 3.80
|
||||
BuildRequires: make >= 3.80
|
||||
|
||||
Summary: Minimal stuff needed to build EPICS host apps
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
|
||||
# This EPICS installation uses the toolset 12 compiler
|
||||
%if 0%{?rhel} == 7
|
||||
Requires: devtoolset-12-gcc-c++
|
||||
BuildRequires: devtoolset-12-gcc-c++
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} >= 8
|
||||
Requires: gcc-toolset-12-gcc-c++
|
||||
BuildRequires: gcc-toolset-12-gcc-c++
|
||||
%endif
|
||||
|
||||
# The perl stuff we need
|
||||
Requires: perl-interpreter >= 5.10.1
|
||||
BuildRequires: perl-interpreter >= 5.10.1
|
||||
|
||||
%if 0%{?rhel} >= 7
|
||||
Requires: perl-File-Path perl-Getopt-Long perl-Pod-Usage perl-Time-HiRes perl-Data-Dumper perl-Scalar-List-Utils
|
||||
BuildRequires: perl-File-Path perl-Getopt-Long perl-Pod-Usage perl-Time-HiRes perl-Data-Dumper perl-Scalar-List-Utils
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} >= 8
|
||||
Requires: perl-Text-Tabs+Wrap
|
||||
BuildRequires: perl-Text-Tabs+Wrap
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} >= 9
|
||||
Requires: perl-File-Find perl-File-Basename perl-File-Copy perl-FindBin perl-Getopt-Std perl-POSIX
|
||||
BuildRequires: perl-File-Find perl-File-Basename perl-File-Copy perl-FindBin perl-Getopt-Std perl-POSIX
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} == 7
|
||||
# Perl auto-detection is broken
|
||||
# It does not find all EPICS internal packages
|
||||
%global __requires_exclude_from ^%{prog_folder}/bin/.*\\.pl$
|
||||
%endif
|
||||
|
||||
%description host-devel
|
||||
Contains headers etc to build EPICS host applications.
|
||||
|
||||
###########################################
|
||||
|
||||
%package compat
|
||||
Summary: EPICS base %{EpicsVersion} for other RHEL versions
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
AutoReqProv: no
|
||||
|
||||
%description compat
|
||||
Contains EPICS binaries that run on other RHEL versions.
|
||||
|
||||
###########################################
|
||||
|
||||
%package wine
|
||||
Summary: EPICS base %{EpicsVersion} for wine
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
Requires: wine
|
||||
BuildRequires: wine
|
||||
|
||||
%description wine
|
||||
Allows to run EPICS in wine.
|
||||
|
||||
###########################################
|
||||
|
||||
%package boot
|
||||
Summary: EPICS base %{EpicsVersion} for boot servers
|
||||
BuildArch: noarch
|
||||
AutoReqProv: no
|
||||
Prefix: /usr/local/epics
|
||||
|
||||
%description boot
|
||||
Contains files needed on NFS server to boot EPICS targets from.
|
||||
This package can be relocated.
|
||||
|
||||
###########################################
|
||||
|
||||
%package devel
|
||||
Summary: EPICS base %{EpicsVersion} for development environments
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
Requires: %{name}-host-devel = %{version}-%{release}
|
||||
Requires: %{name}-boot = %{version}-%{release}
|
||||
Requires: gfa-cross-compiler-links
|
||||
BuildArch: noarch
|
||||
AutoReqProv: no
|
||||
|
||||
%description devel
|
||||
All what is needed to develop EPICS for different target architectures.
|
||||
|
||||
###########################################
|
||||
|
||||
%package devel-static
|
||||
Summary: EPICS base %{EpicsVersion} for development environments including static libraries
|
||||
Requires: %{name}-devel = %{version}-%{release}
|
||||
BuildArch: noarch
|
||||
AutoReqProv: no
|
||||
|
||||
%description devel-static
|
||||
Contains the static libraries (*.a) for EPICS development systems.
|
||||
Only needed to build statically linked applications.
|
||||
|
||||
###########################################
|
||||
|
||||
%package src
|
||||
Summary: Sources code of EPICS base %{EpicsVersion}
|
||||
BuildArch: noarch
|
||||
AutoReqProv: no
|
||||
Prefix: /usr/local/epics
|
||||
|
||||
%description src
|
||||
The source code of EPICS base %{EpicsVersion}.
|
||||
May help when debugging
|
||||
|
||||
###########################################
|
||||
|
||||
%package doc
|
||||
Summary: EPICS base %{EpicsVersion} documentation
|
||||
BuildArch: noarch
|
||||
AutoReqProv: no
|
||||
Prefix: /usr/local/epics
|
||||
|
||||
%description doc
|
||||
The documentation of EPICS base %{EpicsVersion}.
|
||||
|
||||
###########################################
|
||||
|
||||
# Our sources are locally in this directory
|
||||
# and here we also build
|
||||
# RPMS and SRPMS will be stored here, too
|
||||
%define _topdir %(pwd)
|
||||
%define _sourcedir %{_topdir}
|
||||
%define _builddir %{_topdir}
|
||||
|
||||
%prep
|
||||
%{__rm} -rf %{buildroot}/usr/lib
|
||||
%{__rm} -f modules/RELEASE.*.local
|
||||
git submodule update --init modules
|
||||
%{__mkdir_p} RPMS
|
||||
|
||||
%build
|
||||
%if %{defined epics_host_arch}
|
||||
export EPICS_HOST_ARCH=%{epics_host_arch}
|
||||
%endif
|
||||
%{__make} -j $RPM_BUILD_NCPUS INSTALL_LOCATION=%{buildroot}/%{prog_folder} FINAL_LOCATION=%{prog_folder}
|
||||
%{__make} INSTALL_LOCATION=%{buildroot}/%{prog_folder} copysrc
|
||||
|
||||
# remove files we do not need
|
||||
shopt -s extglob
|
||||
%{__rm} -f %{buildroot}/%{prog_folder}/bin/{V,RTEMS}*/{*Harness,softIoc,softIocPVA}
|
||||
%{__rm} -f %{buildroot}/%{prog_folder}/bin/RTEMS*/TEMP.*
|
||||
|
||||
# install the profile script
|
||||
%{__install} epics-base.sh %{buildroot}/%{prog_folder}/bin
|
||||
|
||||
# Do not use install section because build already installed
|
||||
# and install will delete our buildroot!
|
||||
|
||||
%clean
|
||||
%{__make} realclean
|
||||
%{__rm} -f modules/RELEASE.*.local
|
||||
|
||||
# Link caRepeater and profile script to highest installed EPICS version after install and uninstall
|
||||
%post
|
||||
shopt -s extglob
|
||||
|
||||
if [ -e /etc/profile.d/epics-base.sh ]
|
||||
then
|
||||
%{__rm} -f /etc/profile.d/epics-base.sh
|
||||
fi
|
||||
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/epics-base.sh | /usr/bin/head -n1)" /etc/profile.d/
|
||||
|
||||
SYSTEMD_DIR=$(pkg-config systemd --variable=systemdsystemunitdir)
|
||||
if [ -n "$SYSTEMD_DIR" ]
|
||||
then
|
||||
systemctl is-enabled caRepeater.service 2>/dev/null && systemctl disable --now caRepeater.service
|
||||
test -e $SYSTEMD_DIR/caRepeater.service && %{__rm} $SYSTEMD_DIR/caRepeater.service
|
||||
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/%{epics_host_arch}/caRepeater.service | /usr/bin/head -n1)" $SYSTEMD_DIR/
|
||||
systemctl daemon-reload
|
||||
killall caRepeater 2>/dev/null
|
||||
systemctl enable --now caRepeater.service
|
||||
fi
|
||||
|
||||
%postun
|
||||
shopt -s extglob
|
||||
|
||||
if [ -e /etc/profile.d/epics-base.sh ]
|
||||
then
|
||||
%{__rm} -f /etc/profile.d/epics-base.sh
|
||||
fi
|
||||
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/epics-base.sh 2>/dev/null | /usr/bin/head -n1)" /etc/profile.d/ 2>/dev/null
|
||||
|
||||
SYSTEMD_DIR=$(pkg-config systemd --variable=systemdsystemunitdir)
|
||||
if [ -n "$SYSTEMD_DIR" ]
|
||||
then
|
||||
systemctl disable --now caRepeater.service
|
||||
%{__rm} -f $SYSTEMD_DIR/caRepeater.service
|
||||
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/%{epics_host_arch}/caRepeater.service 2>/dev/null | /usr/bin/head -n1)" $SYSTEMD_DIR/ 2>/dev/null
|
||||
systemctl daemon-reload
|
||||
if [ -e $SYSTEMD_DIR/caRepeater.service ]
|
||||
then
|
||||
killall caRepeater 2>/dev/null
|
||||
systemctl enable --now caRepeater.service
|
||||
fi
|
||||
fi
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%dir %{prog_folder}
|
||||
%dir %{prog_folder}/configure
|
||||
%{prog_folder}/configure/CONFIG_BASE_VERSION
|
||||
|
||||
%dir %{prog_folder}/dbd
|
||||
%{prog_folder}/dbd/softIoc*.dbd
|
||||
|
||||
%dir %{prog_folder}/bin
|
||||
%dir %{prog_folder}/lib
|
||||
%{prog_folder}/db
|
||||
|
||||
%{prog_folder}/bin/epics-base.sh
|
||||
|
||||
# Install host binaries but avoid installing *.pl scripts
|
||||
# and other development tools
|
||||
|
||||
%if %{defined rhel}
|
||||
%dir %{prog_folder}/bin/RHEL%{rhel}*
|
||||
%{prog_folder}/bin/RHEL%{rhel}*/[Scips]*[^.]??
|
||||
%{prog_folder}/bin/RHEL%{rhel}*/p2p
|
||||
%{prog_folder}/bin/RHEL%{rhel}*/msi
|
||||
%dir %{prog_folder}/lib/RHEL%{rhel}*
|
||||
%{prog_folder}/lib/RHEL%{rhel}*/*.so*
|
||||
%endif
|
||||
|
||||
###########################################
|
||||
|
||||
%files compat
|
||||
%if %{?rhel} > 7
|
||||
%{prog_folder}/bin/RHEL7*
|
||||
%dir %{prog_folder}/lib/RHEL7*
|
||||
%{prog_folder}/lib/RHEL7*/*.so*
|
||||
%endif
|
||||
|
||||
%if %{?rhel} > 8
|
||||
%{prog_folder}/bin/RHEL8*
|
||||
%dir %{prog_folder}/lib/RHEL8*
|
||||
%{prog_folder}/lib/RHEL8*/*.so*
|
||||
%endif
|
||||
|
||||
%if %{?rhel} > 9
|
||||
%{prog_folder}/bin/RHEL9*
|
||||
%dir %{prog_folder}/lib/RHEL9*
|
||||
%{prog_folder}/lib/RHEL9*/*.so*
|
||||
%endif
|
||||
|
||||
###########################################
|
||||
|
||||
%files wine
|
||||
%{prog_folder}/bin/win*
|
||||
|
||||
###########################################
|
||||
|
||||
%files boot
|
||||
%defattr(-,root,root,-)
|
||||
%dir %{prog_folder}/configure
|
||||
%{prog_folder}/configure/CONFIG_BASE_VERSION
|
||||
|
||||
%dir %{prog_folder}/dbd
|
||||
%{prog_folder}/dbd/softIoc*.dbd
|
||||
%{prog_folder}/db
|
||||
|
||||
%dir %{prog_folder}/lib
|
||||
# avoid pulling in pkgconfig and perl
|
||||
%dir %{prog_folder}/lib/[a-z]*-*
|
||||
%{prog_folder}/lib/[a-z]*-*/*.so*
|
||||
|
||||
%dir %{prog_folder}/bin
|
||||
# avoid pulling in host files again
|
||||
# but get all cross architectures (mostly lower case)
|
||||
# including all Windows dlls (hence listed twice: here and in wine)
|
||||
%dir %{prog_folder}/bin/[a-z]*
|
||||
%{prog_folder}/bin/[a-z]*/[Scips]*[^.]??
|
||||
%{prog_folder}/bin/[a-z]*/msi*
|
||||
%{prog_folder}/bin/[a-z]*/*.dll
|
||||
|
||||
# vxWorks and RTEMS
|
||||
%dir %{prog_folder}/bin/V*
|
||||
%{prog_folder}/bin/V*/*.munch
|
||||
%{prog_folder}/bin/V*/*.o
|
||||
%dir %{prog_folder}/bin/RTEMS*
|
||||
%{prog_folder}/bin/RTEMS*/*.boot
|
||||
|
||||
###########################################
|
||||
|
||||
%files host-devel
|
||||
%defattr(-,root,root,-)
|
||||
%{prog_folder}/configure
|
||||
%{prog_folder}/cfg
|
||||
%{prog_folder}/include
|
||||
%{prog_folder}/templates
|
||||
%if %{defined rhel}
|
||||
%{prog_folder}/bin/RHEL%{rhel}*/[^Scips]*[^.]??
|
||||
%{prog_folder}/bin/RHEL%{rhel}*/*.??
|
||||
%endif
|
||||
%{prog_folder}/lib/pkgconfig
|
||||
%{prog_folder}/lib/perl
|
||||
%{prog_folder}/lib/win*
|
||||
%{prog_folder}/lib/RTEMS*
|
||||
%{prog_folder}/dbd
|
||||
|
||||
###########################################
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
|
||||
%{prog_folder}/bin/[a-z]*/[^Scips]*[^.]??
|
||||
|
||||
# VxWorks and RTEMS need static libs
|
||||
%{prog_folder}/lib/V*
|
||||
|
||||
###########################################
|
||||
|
||||
%files devel-static
|
||||
%defattr(-,root,root,-)
|
||||
|
||||
# Install bulky static libs for Linux targets only on request
|
||||
%{prog_folder}/lib/RHEL*/*.a
|
||||
%{prog_folder}/lib/[a-z]*/*.a
|
||||
|
||||
###########################################
|
||||
|
||||
%files src
|
||||
%defattr(-,root,root,-)
|
||||
%dir %{prog_folder}
|
||||
%{prog_folder}/modules
|
||||
|
||||
###########################################
|
||||
|
||||
%files doc
|
||||
%defattr(-,root,root,-)
|
||||
%dir %{prog_folder}
|
||||
%docdir %{prog_folder}/html
|
||||
%{prog_folder}/html
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
};
|
||||
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);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -73,7 +73,7 @@ epicsExportAddress(int, dbAccessDebugPUTF);
|
||||
|
||||
DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
|
||||
|
||||
static short mapDBFToDBR[DBF_NTYPES] = {
|
||||
static const short mapDBFToDBR[DBF_NTYPES] = {
|
||||
/* DBF_STRING => */ DBR_STRING,
|
||||
/* DBF_CHAR => */ DBR_CHAR,
|
||||
/* DBF_UCHAR => */ DBR_UCHAR,
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -235,6 +240,7 @@ The B<SPVT> field is for internal use by the scanning system.
|
||||
}
|
||||
field(PROC,DBF_UCHAR) {
|
||||
prompt("Force Processing")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
interest(3)
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -410,8 +412,21 @@ DBCORE_API long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
|
||||
DBCORE_API long dbGetNelements(const struct link *plink, long *pnElements);
|
||||
DBCORE_API int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
|
||||
DBCORE_API int dbGetLinkDBFtype(const struct link *plink);
|
||||
/** \brief Fetch current value from link.
|
||||
* \param dbrType Database DBR code
|
||||
* \param pbuffer Destination buffer
|
||||
* \param nRequest If !NULL. Caller initializes with number of elements requested,
|
||||
* On success, set to number of elements written to pbuffer.
|
||||
* \return 0 on success
|
||||
*
|
||||
* When called with `nRequest==NULL`, treated as a request for one (1)
|
||||
* element.
|
||||
*
|
||||
* see lset::getValue
|
||||
*/
|
||||
DBCORE_API long dbTryGetLink(struct link *, short dbrType, void *pbuffer,
|
||||
long *nRequest);
|
||||
/** see dbTryGetLink() */
|
||||
DBCORE_API long dbGetLink(struct link *, short dbrType, void *pbuffer,
|
||||
long *options, long *nRequest);
|
||||
DBCORE_API long dbGetControlLimits(const struct link *plink, double *low,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define DBLOCKPVT_H
|
||||
|
||||
#include "dbLock.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
/* Define to enable additional error checking */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -39,12 +39,17 @@ extern "C" {
|
||||
* will adjust automatically, it just compares field sizes.
|
||||
*/
|
||||
union native_value {
|
||||
epicsInt8 dbf_char;
|
||||
epicsInt16 dbf_short;
|
||||
epicsEnum16 dbf_enum;
|
||||
epicsInt32 dbf_long;
|
||||
epicsFloat32 dbf_float;
|
||||
epicsFloat64 dbf_double;
|
||||
epicsInt8 dbf_char;
|
||||
epicsUInt8 dbf_uchar;
|
||||
epicsInt16 dbf_short;
|
||||
epicsUInt16 dbf_ushort;
|
||||
epicsEnum16 dbf_enum;
|
||||
epicsInt32 dbf_long;
|
||||
epicsUInt32 dbf_ulong;
|
||||
epicsInt64 dbf_int64;
|
||||
epicsUInt64 dbf_uint64;
|
||||
epicsFloat32 dbf_float;
|
||||
epicsFloat64 dbf_double;
|
||||
#ifdef DB_EVENT_LOG_STRINGS
|
||||
char dbf_string[MAX_STRING_SIZE];
|
||||
#endif
|
||||
|
||||
@@ -75,7 +75,7 @@ DBCORE_API void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
|
||||
epicsEnum16 sevr);
|
||||
DBCORE_API int recGblSetSevrMsg(void *precord, epicsEnum16 new_stat,
|
||||
epicsEnum16 new_sevr,
|
||||
const char *msg, ...) EPICS_PRINTF_STYLE(4,5);
|
||||
EPICS_PRINTF_FMT(const char *msg), ...) EPICS_PRINTF_STYLE(4,5);
|
||||
DBCORE_API int recGblSetSevrVMsg(void *precord, epicsEnum16 new_stat,
|
||||
epicsEnum16 new_sevr,
|
||||
const char *msg, va_list args);
|
||||
|
||||
@@ -139,14 +139,16 @@ char** dbCompleteRecord(const char *cword)
|
||||
|
||||
if(!prefix.empty() || !suggestions.empty()) {
|
||||
ret = (char**)malloc(sizeof(*ret)*(2u + suggestions.size()));
|
||||
ret[0] = prefix.dup();
|
||||
size_t n=1u;
|
||||
for(suggestions_t::iterator it(suggestions.begin()), end(suggestions.end());
|
||||
it!=end; ++it)
|
||||
{
|
||||
ret[n++] = it->dup();
|
||||
if(ret) {
|
||||
ret[0] = prefix.dup();
|
||||
size_t n=1u;
|
||||
for(suggestions_t::iterator it(suggestions.begin()), end(suggestions.end());
|
||||
it!=end; ++it)
|
||||
{
|
||||
ret[n++] = it->dup();
|
||||
}
|
||||
ret[n] = NULL;
|
||||
}
|
||||
ret[n] = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
\*************************************************************************/
|
||||
|
||||
#include "iocsh.h"
|
||||
#include "errSymTbl.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#include "dbStaticIocRegister.h"
|
||||
#include "dbStaticLib.h"
|
||||
@@ -23,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);
|
||||
@@ -98,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);
|
||||
@@ -123,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);
|
||||
@@ -133,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);
|
||||
@@ -143,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);
|
||||
@@ -158,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)
|
||||
{
|
||||
@@ -175,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)
|
||||
{
|
||||
@@ -217,6 +226,40 @@ static void dbReportDeviceConfigCallFunc(const iocshArgBuf *args)
|
||||
dbReportDeviceConfig(*iocshPpdbbase,stdout);
|
||||
}
|
||||
|
||||
|
||||
static const iocshArg dbCreateAliasArg0 = { "record",iocshArgStringRecord};
|
||||
static const iocshArg dbCreateAliasArg1 = { "alias",iocshArgStringRecord};
|
||||
static const iocshArg * const dbCreateAliasArgs[] = {&argPdbbase,&dbCreateAliasArg0, &dbCreateAliasArg1};
|
||||
static const iocshFuncDef dbCreateAliasFuncDef = {
|
||||
"dbCreateAlias",
|
||||
3,
|
||||
dbCreateAliasArgs,
|
||||
"Add a new record alias.\n"
|
||||
"\n"
|
||||
"Example: dbCreateAlias pdbbase record:name new:alias\n",
|
||||
};
|
||||
static void dbCreateAliasCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
DBENTRY ent;
|
||||
long status;
|
||||
|
||||
dbInitEntry(*iocshPpdbbase, &ent);
|
||||
if(!args[1].sval || !args[2].sval) {
|
||||
status = S_dbLib_recNotFound;
|
||||
|
||||
} else {
|
||||
status = dbFindRecord(&ent, args[1].sval);
|
||||
if(!status) {
|
||||
status = dbCreateAlias(&ent, args[2].sval);
|
||||
}
|
||||
}
|
||||
dbFinishEntry(&ent);
|
||||
if(status) {
|
||||
fprintf(stderr, ERL_ERROR ": %ld %s\n", status, errSymMsg(status));
|
||||
iocshSetError(1);
|
||||
}
|
||||
}
|
||||
|
||||
void dbStaticIocRegister(void)
|
||||
{
|
||||
iocshRegister(&dbDumpPathFuncDef, dbDumpPathCallFunc);
|
||||
@@ -234,4 +277,5 @@ void dbStaticIocRegister(void)
|
||||
iocshRegister(&dbPvdDumpFuncDef, dbPvdDumpCallFunc);
|
||||
iocshRegister(&dbPvdTableSizeFuncDef,dbPvdTableSizeCallFunc);
|
||||
iocshRegister(&dbReportDeviceConfigFuncDef, dbReportDeviceConfigCallFunc);
|
||||
iocshRegister(&dbCreateAliasFuncDef, dbCreateAliasCallFunc);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -1652,6 +1652,7 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
|
||||
dbRecordNode *pnewnode;
|
||||
DBENTRY tempEntry;
|
||||
PVDENTRY *ppvd;
|
||||
long status;
|
||||
|
||||
if (!precordType)
|
||||
return S_dbLib_recordTypeNotFound;
|
||||
@@ -1664,9 +1665,10 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
|
||||
return S_dbLib_recNotFound;
|
||||
|
||||
dbInitEntry(pdbentry->pdbbase, &tempEntry);
|
||||
if (!dbFindRecord(&tempEntry, alias))
|
||||
return S_dbLib_recExists;
|
||||
status = dbFindRecord(&tempEntry, alias);
|
||||
dbFinishEntry(&tempEntry);
|
||||
if (!status)
|
||||
return S_dbLib_recExists;
|
||||
|
||||
pnewnode = dbCalloc(1, sizeof(dbRecordNode));
|
||||
pnewnode->recordname = epicsStrDup(alias);
|
||||
@@ -1676,15 +1678,16 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
|
||||
precnode->flags |= DBRN_FLAGS_HASALIAS;
|
||||
ellInit(&pnewnode->infoList);
|
||||
|
||||
ellAdd(&precordType->recList, &pnewnode->node);
|
||||
precordType->no_aliases++;
|
||||
|
||||
ppvd = dbPvdAdd(pdbentry->pdbbase, precordType, pnewnode);
|
||||
if (!ppvd) {
|
||||
errMessage(-1, "dbCreateAlias: Add to PVD failed");
|
||||
free(pnewnode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ellAdd(&precordType->recList, &pnewnode->node);
|
||||
precordType->no_aliases++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2201,12 +2204,12 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
|
||||
*/
|
||||
|
||||
} else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
|
||||
errlogPrintf("Error: %s.%s: can't initialize link type %s with \"%s\" (type %s)\n",
|
||||
prec->name, pflddes->name, pamaplinkType[plink->type].strvalue, plink->text, pamaplinkType[link_info.ltype].strvalue);
|
||||
errlogPrintf(ERL_ERROR ": %s.%s: can't initialize link type %d with \"%s\" (type %s)\n",
|
||||
prec->name, pflddes->name, plink->type, plink->text, pamaplinkType[link_info.ltype].strvalue);
|
||||
|
||||
} else if(dbSetLink(plink, &link_info, devsup)) {
|
||||
errlogPrintf("Error: %s.%s: failed to initialize link type %s with \"%s\" (type %s)\n",
|
||||
prec->name, pflddes->name, pamaplinkType[plink->type].strvalue, plink->text, pamaplinkType[link_info.ltype].strvalue);
|
||||
errlogPrintf(ERL_ERROR ": %s.%s: failed to initialize link type %d with \"%s\" (type %s)\n",
|
||||
prec->name, pflddes->name, plink->type, plink->text, pamaplinkType[link_info.ltype].strvalue);
|
||||
}
|
||||
free(plink->text);
|
||||
plink->text = NULL;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -39,7 +39,9 @@ char *dbRecordName(DBENTRY *pdbentry);
|
||||
char *dbGetStringNum(DBENTRY *pdbentry);
|
||||
long dbPutStringNum(DBENTRY *pdbentry,const char *pstring);
|
||||
|
||||
void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) EPICS_PRINTF_STYLE(2,3);
|
||||
void dbMsgPrint(
|
||||
DBENTRY *pdbentry, EPICS_PRINTF_FMT(const char *fmt), ...
|
||||
) EPICS_PRINTF_STYLE(2,3);
|
||||
|
||||
void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
SRC_DIRS += $(IOCDIR)/dbtemplate
|
||||
|
||||
PROD_HOST += msi
|
||||
PROD_CMD += msi
|
||||
|
||||
msi_SRCS = msi.cpp
|
||||
msi_LIBS += Com
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -216,22 +216,96 @@ registrar(tsInitialize)
|
||||
|
||||
=head3 TimeStamp Filter C<"ts">
|
||||
|
||||
This filter replaces the timestamp in the data fetched through the channel with
|
||||
the time the value was fetched (or an update was sent). The record's timestamp
|
||||
This filter is used for two purposes:
|
||||
|
||||
=over
|
||||
|
||||
=item * to retrieve the timestamp of the record as a value in several different
|
||||
formats;
|
||||
|
||||
=item * to retrieve the record value as normal, but replace the timestamp with
|
||||
the time the value was fetched.
|
||||
|
||||
=back
|
||||
|
||||
=head4 Parameters
|
||||
|
||||
=head4 No parameters (an empty pair of braces)
|
||||
|
||||
Retrieve the record value as normal, but replace the timestamp with the time the
|
||||
value was fetched (or an update was sent). This is useful for clients that can't
|
||||
handle timestamps that are far in the past. Normally, the record's timestamp
|
||||
indicates when the record last processed, which could have been days or even
|
||||
weeks ago for some records, or set to the EPICS epoch if the record has never
|
||||
processed.
|
||||
|
||||
=head4 Parameters
|
||||
=head4 Numeric type C<"num">
|
||||
|
||||
None, use an empty pair of braces.
|
||||
The following values are accepted for this parameter:
|
||||
|
||||
=head4 Example
|
||||
=over
|
||||
|
||||
Hal$ caget -a 'test:channel.{"ts":{}}'
|
||||
test:channel.{"ts":{}} 2012-08-28 22:10:31.192547 0 UDF INVALID
|
||||
Hal$ caget -a 'test:channel'
|
||||
test:channel <undefined> 0 UDF INVALID
|
||||
=item * C<"dbl"> requests the timestamp as C<epicsFloat64> representing the
|
||||
non-integral number of seconds since epoch. This format is convenient,
|
||||
but loses precision, depending on which epoch is used.
|
||||
|
||||
=item * C<"sec"> requests the number of seconds since epoch as C<epicsUInt32>.
|
||||
|
||||
=item * C<"nsec"> requests the number of nanoseconds since epoch as
|
||||
C<epicsUInt32>.
|
||||
|
||||
=item * C<"ts"> requests the entire timestamp. It is provided as a two-element
|
||||
array of C<epicsUInt32> representing seconds and nanoseconds.
|
||||
|
||||
=back
|
||||
|
||||
Note that C<epicsUInt32> cannot be transferred over Channel Access; in that
|
||||
case, the value will be converted to C<epicsFloat64>.
|
||||
|
||||
=head4 String type C<"str">
|
||||
|
||||
The following values are accepted for this parameter:
|
||||
|
||||
=over
|
||||
|
||||
=item * C<"epics"> requests the timestamp as a string in the format used by
|
||||
tools such as C<caget>.
|
||||
|
||||
=item * C<"iso"> requests the timestamp as a string in the ISO8601 format.
|
||||
|
||||
=back
|
||||
|
||||
=head4 Epoch adjustment C<"epoch">
|
||||
|
||||
The following values are accepted for this parameter:
|
||||
|
||||
=over
|
||||
|
||||
=item * C<"epics"> keeps the EPICS epoch (1990-01-01) and is the default if the
|
||||
C<"epoch"> parameter is not specified.
|
||||
|
||||
=item * C<"unix"> converts the timestamp to the UNIX/POSIX epoch (1970-01-01).
|
||||
|
||||
=back
|
||||
|
||||
=head4 Examples
|
||||
|
||||
Hal$ caget -a 'test:invalid_ts.{"ts":{}}'
|
||||
test:invalid_ts.{"ts":{}} 2012-08-28 22:10:31.192547 0 UDF INVALID
|
||||
Hal$ caget -a 'test:invalid_ts'
|
||||
test:invalid_ts <undefined> 0 UDF INVALID
|
||||
Hal$ caget -a test:channel
|
||||
test:channel 2021-03-11 18:23:48.265386 42
|
||||
Hal$ caget 'test:channel.{"ts": {"str": "epics"}}'
|
||||
test:channel.{"ts": {"str": "epics"}} 2021-03-11 18:23:48.265386
|
||||
Hal$ caget 'test:channel.{"ts": {"str": "iso"}}'
|
||||
test:channel.{"ts": {"str": "iso"}} 2021-03-11T18:23:48.265386+0100
|
||||
Hal$ caget -f9 'test:channel.{"ts": {"num": "dbl"}}'
|
||||
test:channel.{"ts": {"num": "dbl"}} 984331428.265386105
|
||||
Hal$ caget -f1 'test:channel.{"ts": {"num": "ts"}}'
|
||||
test:channel.{"ts": {"num": "ts"}} 2 984331428.0 265386163.0
|
||||
Hal$ caget -f1 'test:channel.{"ts": {"num": "ts", "epoch": "unix"}}'
|
||||
test:channel.{"ts": {"num": "ts", "epoch": "unix"}} 2 1615483428.0 265386163.0
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2021 Cosylab d.d
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
@@ -9,6 +10,7 @@
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
* Author: Jure Varlec <jure.varlec@cosylab.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -16,20 +18,124 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "chfPlugin.h"
|
||||
#include "db_field_log.h"
|
||||
#include "dbExtractArray.h"
|
||||
#include "dbLock.h"
|
||||
#include "db_field_log.h"
|
||||
#include "epicsExport.h"
|
||||
#include "freeList.h"
|
||||
#include "errlog.h"
|
||||
|
||||
/*
|
||||
* The size of the data is different for each channel, and can even
|
||||
* change at runtime, so a freeList doesn't make much sense here.
|
||||
*/
|
||||
/* Allocation size for freelists */
|
||||
#define ALLOC_NUM_ELEMENTS 32
|
||||
|
||||
#define logicErrorMessage() \
|
||||
errMessage(-1, "Logic error: invalid state encountered in ts filter")
|
||||
|
||||
/* Filter settings */
|
||||
|
||||
enum tsMode {
|
||||
tsModeInvalid = 0,
|
||||
tsModeGenerate = 1,
|
||||
tsModeDouble = 2,
|
||||
tsModeSec = 3,
|
||||
tsModeNsec = 4,
|
||||
tsModeArray = 5,
|
||||
tsModeString = 6,
|
||||
};
|
||||
|
||||
static const chfPluginEnumType ts_numeric_enum[] = {
|
||||
{"dbl", 2}, {"sec", 3}, {"nsec", 4}, {"ts", 5}};
|
||||
|
||||
enum tsEpoch {
|
||||
tsEpochEpics = 0,
|
||||
tsEpochUnix = 1,
|
||||
};
|
||||
|
||||
static const chfPluginEnumType ts_epoch_enum[] = {{"epics", 0}, {"unix", 1}};
|
||||
|
||||
enum tsString {
|
||||
tsStringInvalid = 0,
|
||||
tsStringEpics = 1,
|
||||
tsStringIso = 2,
|
||||
};
|
||||
|
||||
static const chfPluginEnumType ts_string_enum[] = {{"epics", 1}, {"iso", 2}};
|
||||
|
||||
typedef struct tsPrivate {
|
||||
enum tsMode mode;
|
||||
enum tsEpoch epoch;
|
||||
enum tsString str;
|
||||
} tsPrivate;
|
||||
|
||||
static const chfPluginArgDef ts_args[] = {
|
||||
chfEnum(tsPrivate, mode, "num", 0, 0, ts_numeric_enum),
|
||||
chfEnum(tsPrivate, epoch, "epoch", 0, 0, ts_epoch_enum),
|
||||
chfEnum(tsPrivate, str, "str", 0, 0, ts_string_enum),
|
||||
chfPluginArgEnd
|
||||
};
|
||||
|
||||
static int parse_finished(void *pvt) {
|
||||
tsPrivate *settings = (tsPrivate *)pvt;
|
||||
if (settings->str != tsStringInvalid) {
|
||||
settings->mode = tsModeString;
|
||||
#if defined _MSC_VER && _MSC_VER <= 1700
|
||||
// VS 2012 crashes in ISO mode, doesn't support timezones
|
||||
if (settings->str == tsStringIso) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
} else if (settings->mode == tsModeInvalid) {
|
||||
settings->mode = tsModeGenerate;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Allocation of filter settings */
|
||||
static void *private_free_list;
|
||||
|
||||
static void * allocPvt() {
|
||||
return freeListCalloc(private_free_list);
|
||||
}
|
||||
|
||||
static void freePvt(void *pvt) {
|
||||
freeListFree(private_free_list, pvt);
|
||||
}
|
||||
|
||||
|
||||
/* Allocation of two-element arrays for second+nanosecond pairs */
|
||||
static void *ts_array_free_list;
|
||||
|
||||
static void *allocTsArray() {
|
||||
return freeListCalloc(ts_array_free_list);
|
||||
}
|
||||
|
||||
static void freeTsArray(db_field_log *pfl) {
|
||||
freeListFree(ts_array_free_list, pfl->u.r.field);
|
||||
}
|
||||
|
||||
/* Allocation of strings */
|
||||
static void *string_free_list;
|
||||
|
||||
static void *allocString() {
|
||||
return freeListCalloc(string_free_list);
|
||||
}
|
||||
|
||||
static void freeString(db_field_log *pfl) {
|
||||
freeListFree(string_free_list, pfl->u.r.field);
|
||||
}
|
||||
|
||||
|
||||
/* The dtor for waveform data for the case when we have to copy it. */
|
||||
static void freeArray(db_field_log *pfl) {
|
||||
/*
|
||||
* The size of the data is different for each channel, and can even
|
||||
* change at runtime, so a freeList doesn't make much sense here.
|
||||
*/
|
||||
free(pfl->u.r.field);
|
||||
}
|
||||
|
||||
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
static db_field_log* generate(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
epicsTimeStamp now;
|
||||
epicsTimeGetCurrent(&now);
|
||||
|
||||
@@ -44,7 +150,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
dbScanLock(dbChannelRecord(chan));
|
||||
dbChannelGetArrayInfo(chan, &pSource, &nSource, &offset);
|
||||
dbExtractArray(pSource, pTarget, pfl->field_size,
|
||||
nSource, pfl->no_elements, offset, 1);
|
||||
nSource, pfl->no_elements, offset, 1);
|
||||
pfl->u.r.field = pTarget;
|
||||
pfl->dtor = freeArray;
|
||||
pfl->u.r.pvt = pvt;
|
||||
@@ -56,34 +162,246 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
return pfl;
|
||||
}
|
||||
|
||||
static void channelRegisterPre(dbChannel *chan, void *pvt,
|
||||
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
|
||||
{
|
||||
static db_field_log *replace_fl_value(tsPrivate const *pvt,
|
||||
db_field_log *pfl,
|
||||
int (*func)(tsPrivate const *,
|
||||
db_field_log *)) {
|
||||
/* Get rid of the old value */
|
||||
if (pfl->type == dbfl_type_ref && pfl->dtor) {
|
||||
pfl->dtor(pfl);
|
||||
pfl->dtor = NULL;
|
||||
}
|
||||
pfl->no_elements = 1;
|
||||
pfl->type = dbfl_type_val;
|
||||
|
||||
if (func(pvt, pfl)) {
|
||||
db_delete_field_log(pfl);
|
||||
pfl = NULL;
|
||||
}
|
||||
|
||||
return pfl;
|
||||
}
|
||||
|
||||
static void ts_to_array(tsPrivate const *settings,
|
||||
epicsTimeStamp const *ts,
|
||||
epicsUInt32 arr[2]) {
|
||||
arr[0] = ts->secPastEpoch;
|
||||
arr[1] = ts->nsec;
|
||||
if (settings->epoch == tsEpochUnix) {
|
||||
/* Cannot use epicsTimeToWhatever because Whatever uses signed ints */
|
||||
arr[0] += POSIX_TIME_AT_EPICS_EPOCH;
|
||||
}
|
||||
}
|
||||
|
||||
static int ts_seconds(tsPrivate const *settings, db_field_log *pfl) {
|
||||
epicsUInt32 arr[2];
|
||||
ts_to_array(settings, &pfl->time, arr);
|
||||
pfl->field_type = DBF_ULONG;
|
||||
pfl->field_size = sizeof(epicsUInt32);
|
||||
pfl->u.v.field.dbf_ulong = arr[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts_nanos(tsPrivate const *settings, db_field_log *pfl) {
|
||||
epicsUInt32 arr[2];
|
||||
ts_to_array(settings, &pfl->time, arr);
|
||||
pfl->field_type = DBF_ULONG;
|
||||
pfl->field_size = sizeof(epicsUInt32);
|
||||
pfl->u.v.field.dbf_ulong = arr[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts_double(tsPrivate const *settings, db_field_log *pfl) {
|
||||
epicsUInt32 arr[2];
|
||||
ts_to_array(settings, &pfl->time, arr);
|
||||
pfl->field_type = DBF_DOUBLE;
|
||||
pfl->field_size = sizeof(epicsFloat64);
|
||||
pfl->u.v.field.dbf_double = arr[0] + arr[1] * 1e-9;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts_array(tsPrivate const *settings, db_field_log *pfl) {
|
||||
pfl->field_type = DBF_ULONG;
|
||||
pfl->field_size = sizeof(epicsUInt32);
|
||||
pfl->type = dbfl_type_ref;
|
||||
pfl->u.r.pvt = NULL;
|
||||
pfl->u.r.field = allocTsArray();
|
||||
if (pfl->u.r.field) {
|
||||
pfl->no_elements = 2;
|
||||
pfl->dtor = freeTsArray;
|
||||
ts_to_array(settings, &pfl->time, (epicsUInt32*)pfl->u.r.field);
|
||||
} else {
|
||||
pfl->no_elements = 0;
|
||||
pfl->dtor = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts_string(tsPrivate const *settings, db_field_log *pfl) {
|
||||
char const *fmt;
|
||||
char *field;
|
||||
size_t n;
|
||||
|
||||
switch (settings->str) {
|
||||
case tsStringEpics:
|
||||
fmt = "%Y-%m-%d %H:%M:%S.%06f";
|
||||
break;
|
||||
case tsStringIso:
|
||||
fmt = "%Y-%m-%dT%H:%M:%S.%06f%z";
|
||||
break;
|
||||
case tsStringInvalid:
|
||||
default:
|
||||
logicErrorMessage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
pfl->field_type = DBF_STRING;
|
||||
pfl->field_size = MAX_STRING_SIZE;
|
||||
pfl->type = dbfl_type_ref;
|
||||
pfl->u.r.pvt = NULL;
|
||||
pfl->u.r.field = allocString();
|
||||
|
||||
if (!pfl->u.r.field) {
|
||||
pfl->no_elements = 0;
|
||||
pfl->dtor = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pfl->dtor = freeString;
|
||||
|
||||
field = (char *)pfl->u.r.field;
|
||||
n = epicsTimeToStrftime(field, MAX_STRING_SIZE, fmt, &pfl->time);
|
||||
if (!n) {
|
||||
field[0] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static db_field_log *filter(void *pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
tsPrivate *settings = (tsPrivate *)pvt;
|
||||
(void)chan;
|
||||
|
||||
switch (settings->mode) {
|
||||
case tsModeDouble:
|
||||
return replace_fl_value(pvt, pfl, ts_double);
|
||||
case tsModeSec:
|
||||
return replace_fl_value(pvt, pfl, ts_seconds);
|
||||
case tsModeNsec:
|
||||
return replace_fl_value(pvt, pfl, ts_nanos);
|
||||
case tsModeArray:
|
||||
return replace_fl_value(pvt, pfl, ts_array);
|
||||
case tsModeString:
|
||||
return replace_fl_value(pvt, pfl, ts_string);
|
||||
case tsModeGenerate:
|
||||
case tsModeInvalid:
|
||||
default:
|
||||
logicErrorMessage();
|
||||
db_delete_field_log(pfl);
|
||||
pfl = NULL;
|
||||
}
|
||||
|
||||
return pfl;
|
||||
}
|
||||
|
||||
|
||||
/* Only the "generate" mode is registered for the pre-queue chain as it creates
|
||||
it's own timestamp which should be as close to the event as possible */
|
||||
static void channelRegisterPre(dbChannel * chan, void *pvt,
|
||||
chPostEventFunc **cb_out, void **arg_out,
|
||||
db_field_log *probe) {
|
||||
tsPrivate *settings = (tsPrivate *)pvt;
|
||||
(void)chan;
|
||||
(void)arg_out;
|
||||
(void)probe;
|
||||
|
||||
*cb_out = settings->mode == tsModeGenerate ? generate : NULL;
|
||||
}
|
||||
|
||||
/* For other modes, the post-chain is fine as they only manipulate existing
|
||||
timestamps */
|
||||
static void channelRegisterPost(dbChannel *chan, void *pvt,
|
||||
chPostEventFunc **cb_out, void **arg_out,
|
||||
db_field_log *probe) {
|
||||
tsPrivate *settings = (tsPrivate *)pvt;
|
||||
(void)chan;
|
||||
|
||||
if (settings->mode == tsModeGenerate || settings->mode == tsModeInvalid) {
|
||||
*cb_out = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
*cb_out = filter;
|
||||
*arg_out = pvt;
|
||||
|
||||
/* Get rid of the value of the probe because we will be changing the
|
||||
datatype */
|
||||
if (probe->type == dbfl_type_ref && probe->dtor) {
|
||||
probe->dtor(probe);
|
||||
probe->dtor = NULL;
|
||||
}
|
||||
probe->no_elements = 1;
|
||||
probe->type = dbfl_type_val;
|
||||
|
||||
switch (settings->mode) {
|
||||
case tsModeArray:
|
||||
probe->no_elements = 2;
|
||||
/* fallthrough */
|
||||
case tsModeSec:
|
||||
case tsModeNsec:
|
||||
probe->field_type = DBF_ULONG;
|
||||
probe->field_size = sizeof(epicsUInt32);
|
||||
break;
|
||||
case tsModeDouble:
|
||||
probe->field_type = DBF_DOUBLE;
|
||||
probe->field_size = sizeof(epicsFloat64);
|
||||
break;
|
||||
case tsModeString:
|
||||
probe->field_type = DBF_STRING;
|
||||
probe->field_size = MAX_STRING_SIZE;
|
||||
break;
|
||||
case tsModeGenerate:
|
||||
case tsModeInvalid:
|
||||
// Already handled above, added here for completeness.
|
||||
default:
|
||||
logicErrorMessage();
|
||||
*cb_out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent)
|
||||
{
|
||||
printf("%*sTimestamp (ts)\n", indent, "");
|
||||
tsPrivate *settings = (tsPrivate *)pvt;
|
||||
(void)chan;
|
||||
(void)level;
|
||||
|
||||
printf("%*sTimestamp (ts): mode: %d, epoch: %d, str: %d\n",
|
||||
indent, "", settings->mode, settings->epoch, settings->str);
|
||||
}
|
||||
|
||||
static chfPluginIf pif = {
|
||||
NULL, /* allocPvt, */
|
||||
NULL, /* freePvt, */
|
||||
allocPvt,
|
||||
freePvt,
|
||||
|
||||
NULL, /* parse_error, */
|
||||
NULL, /* parse_ok, */
|
||||
NULL, /* parse_error, */
|
||||
parse_finished,
|
||||
|
||||
NULL, /* channel_open, */
|
||||
channelRegisterPre,
|
||||
NULL, /* channelRegisterPost, */
|
||||
channelRegisterPost,
|
||||
channel_report,
|
||||
NULL /* channel_close */
|
||||
};
|
||||
|
||||
static void tsInitialize(void)
|
||||
{
|
||||
chfPluginRegister("ts", &pif, NULL);
|
||||
freeListInitPvt(&private_free_list, sizeof(tsPrivate),
|
||||
ALLOC_NUM_ELEMENTS);
|
||||
freeListInitPvt(&ts_array_free_list, 2 * sizeof(epicsUInt32),
|
||||
ALLOC_NUM_ELEMENTS);
|
||||
freeListInitPvt(&string_free_list, MAX_STRING_SIZE,
|
||||
ALLOC_NUM_ELEMENTS);
|
||||
chfPluginRegister("ts", &pif, ts_args);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(tsInitialize);
|
||||
|
||||
@@ -42,6 +42,8 @@ value is non-zero.
|
||||
|
||||
=back
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.14.10 .
|
||||
|
||||
=head2 Record-specific Menus
|
||||
|
||||
=head3 Menu aSubLFLG
|
||||
|
||||
@@ -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 UNRELEASED) If the MASK field is non-zero, then this MASK is applied to RVAL.
|
||||
The value of RVAL is then converted using the process described in the
|
||||
next section.
|
||||
|
||||
=fields INP, DTYP, ZNAM, ONAM, RVAL, VAL
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -13,6 +13,8 @@ The histogram record is used to store frequency counts of a signal into an array
|
||||
of arbitrary length. The user can configure the range of the signal value that
|
||||
the array will store. Anything outside this range will be ignored.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.1 .
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The record-specific fields are described below.
|
||||
|
||||
@@ -14,6 +14,8 @@ from a hardware input.
|
||||
The record supports alarm limits, alarm filtering, graphics and control
|
||||
limits.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.16.1 .
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The record-specific fields are described below.
|
||||
|
||||
@@ -13,6 +13,8 @@ This record type is normally used to send an integer value of up to 64 bits
|
||||
to an output device.
|
||||
The record supports alarm, drive, graphics and control limits.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.16.1 .
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The record-specific fields are described below.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
The long string input record is used to retrieve an arbitrary ASCII string with
|
||||
a maximum length of 65535 characters.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The record-specific fields are described below, grouped by functionality.
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
The long string output record is used to write an arbitrary ASCII string with a
|
||||
maximum length of 65535 characters.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The record-specific fields are described below, grouped by functionality.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -323,6 +323,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)
|
||||
@@ -330,6 +331,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)
|
||||
@@ -337,6 +339,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)
|
||||
@@ -344,6 +347,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)
|
||||
@@ -351,6 +355,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)
|
||||
@@ -358,6 +363,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)
|
||||
@@ -365,6 +371,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)
|
||||
@@ -372,6 +379,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)
|
||||
@@ -379,6 +387,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)
|
||||
@@ -386,6 +395,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)
|
||||
@@ -393,6 +403,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)
|
||||
@@ -400,6 +411,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)
|
||||
@@ -407,6 +419,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)
|
||||
@@ -414,6 +427,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)
|
||||
@@ -421,6 +435,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)
|
||||
@@ -428,6 +443,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)
|
||||
@@ -435,6 +451,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)
|
||||
@@ -442,6 +459,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)
|
||||
@@ -449,6 +467,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)
|
||||
@@ -456,6 +475,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)
|
||||
@@ -463,6 +483,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)
|
||||
@@ -470,6 +491,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)
|
||||
@@ -477,6 +499,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)
|
||||
@@ -484,6 +507,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)
|
||||
@@ -491,6 +515,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)
|
||||
@@ -498,6 +523,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)
|
||||
@@ -505,6 +531,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)
|
||||
@@ -512,6 +539,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)
|
||||
@@ -519,6 +547,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)
|
||||
@@ -526,6 +555,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)
|
||||
@@ -533,6 +563,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)
|
||||
@@ -540,6 +571,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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
The printf record is used to generate and write a string using a format
|
||||
specification and parameters, analogous to the C C<printf()> function.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The record-specific fields are described below, grouped by functionality.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user