merged with upstream

This commit is contained in:
2019-02-20 10:51:02 +01:00
244 changed files with 11196 additions and 3586 deletions
+5 -18
View File
@@ -6,18 +6,9 @@ die() {
exit 1
}
ticker() {
while true
do
sleep 60
date -R
[ -r "$1" ] && tail -n10 "$1"
done
}
CACHEKEY=1
EPICS_HOST_ARCH=`sh startup/EpicsHostArch`
export EPICS_HOST_ARCH=`perl src/tools/EpicsHostArch.pl`
[ -e configure/os/CONFIG_SITE.Common.linux-x86 ] || die "Wrong location: $PWD"
@@ -57,28 +48,24 @@ EOF
fi
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
install -d /home/travis/.cache
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \
| tar -C /home/travis/.cache -xj
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
| tar -C / -xmj
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386
RTEMS_BASE=$HOME/.rtems
EOF
cat << EOF >> configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
EOF
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 $EXTRA
-46
View File
@@ -1,46 +0,0 @@
#!/bin/sh
set -e -x
die() {
echo "$1" >&2
exit 1
}
CURDIR="$PWD"
QDIR="$HOME/.cache/qemu"
if [ -n "$RTEMS" -a "$TEST" = "YES" ]
then
git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
cd "$HOME/.build/qemu"
HEAD=`git log -n1 --pretty=format:%H`
echo "HEAD revision $HEAD"
[ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
echo "Cached revision $BUILT"
if [ "$HEAD" != "$BUILT" ]
then
echo "Building QEMU"
git submodule --quiet update --init
install -d "$HOME/.build/qemu/build"
cd "$HOME/.build/qemu/build"
"$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
make -j2
make install
echo "$HEAD" > "$HOME/.cache/qemu/built"
fi
fi
cd "$CURDIR"
cat <<EOF >> configure/CONFIG_SITE
USR_CPPFLAGS += $USR_CPPFLAGS
USR_CFLAGS += $USR_CFLAGS
USR_CXXFLAGS += $USR_CXXFLAGS
EOF
+12 -18
View File
@@ -11,23 +11,17 @@ addons:
- perl
- clang
- g++-mingw-w64-i686
- bison
- flex
- texinfo
- install-info
cache:
directories:
- $HOME/.cache
install:
- ./.ci/travis-prepare.sh
- qemu-system-x86
script:
- ./.ci/travis-build.sh
- .ci/travis-build.sh
env:
- BRCORE=master BRLIBCOM=master BRCA=master
- CMPLR=clang
- USR_CXXFLAGS=-std=c++11
- CMPLR=clang USR_CXXFLAGS=-std=c++11
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=NO
- RTEMS=4.9 TEST=NO
- CMPLR=gcc
- CMPLR=clang
- CMPLR=gcc STATIC=YES
- CMPLR=clang STATIC=YES
- CMPLR=gcc EXTRA=CMD_CXXFLAGS=-std=c++11
- CMPLR=clang EXTRA=CMD_CXXFLAGS=-std=c++11
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=YES
- RTEMS=4.9 TEST=YES
+8 -5
View File
@@ -20,11 +20,14 @@ else
endif
# Provide a default if the user hasn't set EPICS_HOST_ARCH
ifeq ($(strip $(EPICS_HOST_ARCH)),)
# NB: We must set the environment variable for submodules to include
# the correct modules/RELEASE.<host>.local file to set EPICS_BASE,
# they can't do this for themselves since CONFIG is relative to it:
export EPICS_HOST_ARCH := $(shell $(CONFIG)/../startup/EpicsHostArch.pl)
#
ifeq ($(origin EPICS_HOST_ARCH), undefined)
# Bootstrapping ...
EHA := $(firstword $(wildcard $(EPICS_BASE)/lib/perl/EpicsHostArch.pl \
$(TOP)/src/tools/EpicsHostArch.pl))
# NB: We use a simply expanded variable here for performance:
export EPICS_HOST_ARCH := $(shell perl $(EHA))
EHA :=
endif
-include $(CONFIG)/RELEASE
+7
View File
@@ -24,9 +24,14 @@ LD = $(GNU_BIN)/$(CMPLR_PREFIX)ld$(CMPLR_SUFFIX) -r
CPP = $(CC) -x c -E
RANLIB = $(GNU_BIN)/$(CMPLR_PREFIX)ranlib$(CMPLR_SUFFIX)
# Requires at least GCC 4.8 or LLVM (clang) 3.1
ASAN_FLAGS_YES = -fsanitize=address
ASAN_LDFLAGS_YES = $(ASAN_FLAGS_YES)
PROF_CFLAGS_YES = -p
GPROF_CFLAGS_YES = -pg
CODE_CFLAGS = $(PROF_CFLAGS_$(PROFILE)) $(GPROF_CFLAGS_$(GPROF))
CODE_CFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
WARN_CFLAGS_YES = -Wall
WARN_CFLAGS_NO = -w
OPT_CFLAGS_YES = -O3
@@ -35,12 +40,14 @@ OPT_CFLAGS_NO = -g
PROF_CXXFLAGS_YES = -p
GPROF_CXXFLAGS_YES = -pg
CODE_CXXFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
CODE_CXXFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
WARN_CXXFLAGS_YES = -Wall
WARN_CXXFLAGS_NO = -w
OPT_CXXFLAGS_YES = -O3
OPT_CXXFLAGS_NO = -g
CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))
PIPE_CFLAGS_YES_YES = -pipe
PIPE_CFLAGS = $(PIPE_CFLAGS_$(GCC_PIPE)_$(GNU))
+1 -1
View File
@@ -42,7 +42,7 @@ PODTOHTML = $(PERL) $(TOOLS)/podToHtml.pl
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG)
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG)
#---------------------------------------------------------------
# tools for installing libraries and products
+14 -5
View File
@@ -15,17 +15,26 @@
# EPICS_SITE_VERSION is defined in CONFIG_SITE for sites that want a local
# version number to be included in the reported version string.
# We define BASE_3_14 and BASE_3_15 as NO and BASE_3_16 as YES, so
# We define convenience macros for our release series to be NO or YES, so
# Makefiles can detect 'Series X or later', or 'Series X only' like this:
#
# ifdef BASE_3_14
# true for 3.14 or later
# ifdef BASE_3_15
# true for 3.15 or later
# ifdef BASE_3_16
# true for 3.16 or later
# ifdef BASE_7_0
# true for 7.0 or later
#
# ifeq ($(BASE_3_14),YES)
# true for 3.14.x only
# ifeq ($(BASE_3_15),YES)
# true for 3.15 only
# true for 3.15.x only
# ifeq ($(BASE_3_16),YES)
# true for 3.16 only.
# true for 3.16.x only.
# ifeq ($(BASE_7_0),YES)
# true for 7.0.x only.
BASE_3_14 = NO
BASE_3_15 = NO
@@ -39,11 +48,11 @@ EPICS_VERSION = 7
EPICS_REVISION = 0
# EPICS_MODIFICATION must be a number >=0 and <256
EPICS_MODIFICATION = 1
EPICS_MODIFICATION = 2
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included if zero
EPICS_PATCH_LEVEL = 2
EPICS_PATCH_LEVEL = 0
# This will end in -DEV between official releases
EPICS_DEV_SNAPSHOT=-DEV
+8 -4
View File
@@ -76,10 +76,14 @@ COMMON_DIR = ../O.Common
IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
#-------------------------------------------------------
# Make echo output - suppress echoing if make's '-s' flag is set
# Silencing the build - suppress messages during 'make -s'
NOP = :
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
QUIET_FLAG := $(if $(findstring s,$(MAKEFLAGS)),-q,)
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
QUIET_FLAG := $(if $(findstring s,$(MFLAGS)),-q,)
#-------------------------------------------------------
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
QUESTION_FLAG := $(if $(findstring q,$(MFLAGS)),-i,)
#-------------------------------------------------------
ifdef T_A
@@ -89,7 +93,7 @@ INSTALL_SHRLIB = $(INSTALL_LOCATION_LIB)/$(T_A)
INSTALL_TCLLIB = $(INSTALL_LOCATION_LIB)/$(T_A)
INSTALL_BIN = $(INSTALL_LOCATION_BIN)/$(T_A)
#Directories for libraries
# Directories for libraries
SHRLIB_SEARCH_DIRS = $(INSTALL_LIB)
#-------------------------------------------------------
+3 -4
View File
@@ -1,11 +1,10 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7
# and higher are distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
ifndef T_A
+3 -2
View File
@@ -4,9 +4,10 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in the file LICENSE that is included with this distribution.
#*************************************************************************
#RULES.Db
# RULES.Db
# Set db substitutions and template file suffixes
SUBST_SUFFIX ?= .substitutions
+3 -2
View File
@@ -4,9 +4,10 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in the file LICENSE that is included with this distribution.
#*************************************************************************
#RULES.ioc
# RULES.ioc
include $(CONFIG)/RULES_DIRS
+1 -3
View File
@@ -90,6 +90,4 @@ realclean:
.PHONY : $(BUILD_ARCHS) rebuild archsCommonClean
.PHONY : $(ACTIONS) clean realclean archclean host all
# User specific rules
#
-include $(HOME)/configure/RULES_USER
include $(CONFIG)/RULES_COMMON
+34 -20
View File
@@ -6,11 +6,12 @@
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
# RULES_BUILD
# Rules for making things specified in a Makefile
#
# Rules for making things specified in Makefile
#
# we are in O.$(T_A), but most sources are elsewhere
#
# CWD is O.$(T_A), but most sources are elsewhere
ifndef BASE_RULES_BUILD
BASE_RULES_BUILD=1
@@ -42,6 +43,7 @@ LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_HOST)
OBJS += $(OBJS_HOST)
PROD += $(PROD_HOST)
SCRIPTS += $(SCRIPTS_HOST)
TARGETS += $(TARGETS_HOST)
TESTLIBRARY += $(TESTLIBRARY_HOST)
TESTSCRIPTS += $(TESTSCRIPTS_HOST)
TESTPROD += $(TESTPROD_HOST)
@@ -53,6 +55,7 @@ LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_IOC)
OBJS += $(OBJS_IOC)
PROD += $(PROD_IOC)
SCRIPTS += $(SCRIPTS_IOC)
TARGETS += $(TARGETS_IOC)
TESTLIBRARY += $(TESTLIBRARY_IOC)
TESTSCRIPTS += $(TESTSCRIPTS_IOC)
TESTPROD += $(TESTPROD_IOC)
@@ -79,9 +82,9 @@ else
host:
endif
-include $(CONFIG)/RULES_FILE_TYPE
include $(CONFIG)/RULES_FILE_TYPE
-include $(CONFIG)/RULES.Db
include $(CONFIG)/RULES.Db
#---------------------------------------------------------------
# Do not build anything if current path matches SKIP_BUILD
@@ -202,7 +205,7 @@ endif
# RELEASE file consistency checking
checkRelease:
$(CONVERTRELEASE) checkRelease
+$(CONVERTRELEASE) checkRelease
warnRelease:
-$(CONVERTRELEASE) checkRelease
noCheckRelease:
@@ -216,9 +219,9 @@ endif
$(TESTPRODNAME) $(PRODNAME): $(PRODUCT_OBJS) $(PROD_RESS) $(PROD_DEPLIBS)
$(TESTPRODNAME) $(PRODNAME): %$(EXE):
$(TESTPRODNAME) $(PRODNAME): %$(EXE): | $(INSTALL_LIB)
@$(RM) $@
$(DEBUGCMD) $(LINK.cpp)
$(LINK.cpp)
$(MT_EXE_COMMAND)
%_ctdt$(OBJ) : %_ctdt.c
@@ -273,15 +276,13 @@ YACCOPT ?= $($*_YACCOPT)
$(MV) $*.tab.c $*.c
$(if $(findstring -d, $(YACCOPT)),$(MV) $*.tab.h $*.h,)
# must be a seperate rule since when not using '-d' the
# must be a separate rule since when not using '-d' the
# prefix for .h will be different then .c
%.h : %.c %.y
%.c: %.l
@$(RM) $*.yy.c
$(LEX) $(LEXOPT) -t $< > $*.yy.c
@$(RM) $@
$(MV) $*.yy.c $@
$(LEX) $(LEXOPT) -o$@ $<
#---------------------------------------------------------------
# Libraries, shared/DLL and stubs
@@ -321,6 +322,10 @@ $(LOADABLE_SHRLIBNAME): $(LOADABLE_SHRLIB_PREFIX)%$(LOADABLE_SHRLIB_SUFFIX):
$(LINK.shrlib)
$(MT_DLL_COMMAND)
$(LIBNAME) $(SHRLIBNAME) $(LOADABLE_SHRLIBNAME): | $(INSTALL_LIB)
$(INSTALL_LIB):
@$(MKDIR) $@
#---------------------------------------------------------------
# C++ munching for VxWorks
@@ -378,14 +383,17 @@ ifneq ($(TAPFILES),)
ifdef RUNTESTS_ENABLED
prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES)
endif
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
CURRENT_JUNITFILES := $(wildcard $(JUNITFILES))
endif
clean-tests:
ifneq ($(TAPFILES),)
$(RM) $(TAPFILES)
ifneq ($(CURRENT_TAPFILES),)
$(RM) $(CURRENT_TAPFILES)
endif
ifneq ($(JUNITFILES),)
$(RM) $(JUNITFILES)
ifneq ($(CURRENT_JUNITFILES),)
$(RM) $(CURRENT_JUNITFILES)
endif
tapfiles: $(TESTSCRIPTS) $(TAPFILES)
@@ -409,7 +417,7 @@ endif
# Generate a perl program to exec the real test binary.
%.t: %$(EXE) $(TOOLS)/makeTestfile.pl
@$(RM) $@
$(PERL) $(TOOLS)/makeTestfile.pl $@ $<
$(PERL) $(TOOLS)/makeTestfile.pl $(T_A) $(EPICS_HOST_ARCH) $@ $<
#---------------------------------------------------------------
# Generate header with version number from VCS
@@ -480,9 +488,11 @@ $(INSTALL_TCLLIB)/%: ../%
@$(INSTALL) -d -m $(BIN_PERMISSIONS) $< $(INSTALL_TCLLIB)
endif
ifneq ($(TCLINDEX),)
$(INSTALL_TCLLIB)/$(TCLINDEX): $(INSTALL_TCLLIBS)
$(ECHO) "Updating $@"
$(ECHO) eval auto_mkindex $(INSTALL_TCLLIB) "$(TCLLIBNAME)" | tclsh
endif
$(INSTALL_LOADABLE_SHRLIBS): $(INSTALL_SHRLIB)/%: %
$(ECHO) "Installing loadable shared library $@"
@@ -548,7 +558,7 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
$(ECHO) "Installing $@"
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
-include $(CONFIG)/RULES_EXPAND
include $(CONFIG)/RULES_EXPAND
.PRECIOUS: %.i %.o %.c %.nm %.cpp %.cc
.PRECIOUS: $(COMMON_INC)
@@ -557,5 +567,9 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
.PHONY: runtests tapfiles clean-tests test-results junitfiles
.PHONY: checkRelease warnRelease noCheckRelease FORCE
include $(CONFIG)/RULES_COMMON
else
$(warning RULES_BUILD included more than once. \
Use 'make show-makefiles' to work out why.)
endif # BASE_RULES_BUILD
# EOF RULES_BUILD
+35
View File
@@ -0,0 +1,35 @@
#*************************************************************************
# Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
# These rules show the set of Makefiles, config files and
# rules files loaded by GNUmake.
# Protect against filenames containing colons (Windows)
SAFE_MAKEFILES = $(subst :,__colon__,$(MAKEFILE_LIST))
SHOW_MAKEFILES = $(SAFE_MAKEFILES:%=show-makefile.%)
show-makefiles: $(SHOW_MAKEFILES)
# The sort prevents warnings about duplicate targets:
$(sort $(SHOW_MAKEFILES)): show-makefile.%:
@echo " $(subst __colon__,:,$(@:show-makefile.%=%))"
.PHONY: show-makefiles show-makefile.%
# These rules support printing a Makefile variable values.
# Many variables are only set inside an O.<arch> build directory.
# make PRINT.T_A
PRINT_Var = $(@:PRINT.%=%)
PRINT.%:
@echo $(PRINT_Var) = '$($(PRINT_Var))'
.PHONY: PRINT PRINT.%
# User specific rules
#
-include $(HOME)/configure/RULES_USER
+1 -4
View File
@@ -92,7 +92,4 @@ $(ARCHS) $(ACTIONS) $(actionArchTargets) :%: \
.PHONY : $(dirActionArchTargets)
.PHONY : $(actionArchTargets)
# User specific rules
#
-include $(HOME)/configure/RULES_USER
include $(CONFIG)/RULES_COMMON
+10 -1
View File
@@ -1,4 +1,13 @@
# <top>/configure/RULES_EXPAND
#*************************************************************************
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
# RULES_EXPAND
vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
+5 -7
View File
@@ -7,9 +7,11 @@
# in the file LICENSE that is included with this distribution.
#*************************************************************************
# Include <top>/configure/RULES_BUILD from tops defined in RELEASE* files
# Include <top>/configure/RULES_BUILD from tops defined in RELEASE* files,
# excluding EPICS_BASE
#
RELEASE_RULES_BUILDS = $(foreach top, $(RELEASE_TOPS), \
RELEASE_RULES_BUILDS = $(foreach top, \
$(filter-out EPICS_BASE, $(RELEASE_TOPS)), \
$(wildcard $($(top))/configure/RULES_BUILD))
ifneq ($(RELEASE_RULES_BUILDS),)
include $(RELEASE_RULES_BUILDS)
@@ -23,7 +25,7 @@ ifneq ($(RELEASE_CFG_RULES),)
include $(RELEASE_CFG_RULES)
endif
# If this is not BASE then include <TOP>/configure/RULES_BUILD
# If this is not BASE then include <top>/configure/RULES_BUILD
#
ifeq ($(wildcard $(TOP)/configure/CONFIG_BASE_VERSION),)
TOP_RULES_BUILDS = $(wildcard $(TOP)/configure/RULES_BUILD)
@@ -67,7 +69,3 @@ file_type_clean:
@$(RM) $(foreach type, $(FILE_TYPE), $($(type)))
.PHONY : file_type_clean
# User specific rules
#
-include $(HOME)/configure/RULES_USER
+3 -4
View File
@@ -1,11 +1,10 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7
# and higher are distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
# Octave definitions and rules
+5 -10
View File
@@ -1,18 +1,13 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7
# and higher are distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
#
# RULES_TARGET
#
# This file is to be maintained by the community.
#
#-----------------------------------------------------------------------
# RULES_TARGET
define TARGET_template
$(1)_$(2) += $$(if $$(strip $$($(1)_$(2)_$$(OS_CLASS))), \
+7 -1
View File
@@ -15,6 +15,10 @@ CVSCLEAN = $(call FIND_TOOL,cvsclean.pl)
cvsclean:
$(PERL) $(CVSCLEAN)
DEPCLEAN = $(call FIND_TOOL,depclean.pl)
depclean:
$(PERL) $(DEPCLEAN)
realuninstall: uninstallDirs
$(RMDIR) $(INSTALL_LOCATION_BIN)
$(RMDIR) $(INSTALL_LOCATION_LIB)
@@ -73,12 +77,14 @@ help:
@echo " uninstall - Remove install directories created by this hostarch."
@echo " realuninstall - Removes ALL install dirs"
@echo " distclean - Same as realclean cvsclean realuninstall."
@echo " depclean - Removes all .d files from O.<arch> directories."
@echo " cvsclean - Removes cvs .#* files in all dirs of directory tree"
@echo " help - Prints this list of valid make targets "
@echo "Indiv. object targets are supported by O.<arch> level Makefile .e.g"
@echo " xxxRecord.o"
.PHONY: cleandirs distclean cvsclean realuninstall archuninstall uninstallDirs
.PHONY: cleandirs distclean cvsclean depclean
.PHONY: realuninstall archuninstall uninstallDirs
.PHONY: uninstall help
# Include <top>/cfg/TOP_RULES* files from tops defined in RELEASE* files
+6 -2
View File
@@ -27,9 +27,13 @@ ifneq ($(CONFIG),$(TOP)/configure)
-include $(TOP)/configure/CONFIG_SITE.Common.RTEMS
endif
#--------------------------------------------------
# Set RTEMS_BSP from T_A if not already done
RTEMS_BSP ?= $(subst RTEMS-,,$(T_A))
#-------------------------------------------------------
# Pick up the RTEMS tool/path definitions from the RTEMS BSP directory.
include $(RTEMS_BASE)/$(RTEMS_TARGET_CPU)-rtems$(RTEMS_VERSION)/$(subst RTEMS-,,$(T_A))/Makefile.inc
include $(RTEMS_BASE)/$(RTEMS_TARGET_CPU)-rtems$(RTEMS_VERSION)/$(RTEMS_BSP)/Makefile.inc
include $(RTEMS_CUSTOM)
include $(CONFIG.CC)
@@ -72,7 +76,7 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
#--------------------------------------------------
# Although RTEMS uses gcc, it wants to use gcc its own way
@@ -9,5 +9,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
RTEMS_TARGET_CPU=arm
RTEMS_BSP = at91rm9200ek
RTEMS_TARGET_CPU = arm
include $(CONFIG)/os/CONFIG.Common.RTEMS
+1
View File
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
RTEMS_BSP = beatnik
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
+2 -1
View File
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
RTEMS_TARGET_CPU=m68k
RTEMS_BSP = gen68360
RTEMS_TARGET_CPU = m68k
include $(CONFIG)/os/CONFIG.Common.RTEMS
+2 -1
View File
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
RTEMS_TARGET_CPU=ppc
RTEMS_BSP = mcp750
RTEMS_TARGET_CPU = ppc
include $(CONFIG)/os/CONFIG.Common.RTEMS
+2 -1
View File
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
RTEMS_TARGET_CPU=m68k
RTEMS_BSP = mvme167
RTEMS_TARGET_CPU = m68k
include $(CONFIG)/os/CONFIG.Common.RTEMS
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
RTEMS_BSP = mvme2100
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
@@ -1,6 +1,7 @@
#
# Author: Matt Rippa
#
RTEMS_BSP = mvme2700
RTEMS_TARGET_CPU = powerpc
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
ARCH_DEP_CFLAGS += -DHAVE_PPCBUG
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
RTEMS_BSP = mvme3100
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
@@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment
#
EXE = .elf
RTEMS_BSP = mvme5500
RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
+5 -4
View File
@@ -5,14 +5,15 @@
#
# All RTEMS targets use the same Makefile fragment
#
RTEMS_TARGET_CPU=i386
RTEMS_BSP = pc386
RTEMS_TARGET_CPU = i386
MUNCH_SUFFIX = .boot
define MUNCH_CMD
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< temp.bin
$(RM) $*.bin
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< $*.bin
$(BIN2BOOT) $@ 0x00097E00 \
$(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 temp.bin 0x00100000 0
rm -f temp.bin
$(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 $*.bin 0x00100000 0
endef
include $(CONFIG)/os/CONFIG.Common.RTEMS
@@ -0,0 +1,11 @@
# CONFIG.Common.RTEMS-pc386-qemu
#
# Definitions for the RTEMS-pc386-qemu target
# Site-specific overrides go in CONFIG_SITE.Common.RTEMS-pc386-qemu
#
#-------------------------------------------------------
# Include definitions from RTEMS-pc386
include $(CONFIG)/os/CONFIG.Common.RTEMS-pc386
RTEMS_QEMU_FIXUPS = YES
+2 -1
View File
@@ -5,5 +5,6 @@
#
# All RTEMS targets use the same Makefile fragment
#
RTEMS_TARGET_CPU=ppc
RTEMS_BSP = psim
RTEMS_TARGET_CPU = ppc
include $(CONFIG)/os/CONFIG.Common.RTEMS
+1
View File
@@ -5,6 +5,7 @@
#
# All RTEMS targets use the same Makefile fragment
#
RTEMS_BSP = uC5282
RTEMS_TARGET_CPU = m68k
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
+4 -2
View File
@@ -173,8 +173,10 @@ SHRLIB_CFLAGS =
SHRLIB_LDFLAGS =
#--------------------------------------------------
# Earlier versions of gcc don't understand -MF
HDEPENDS_COMPFLAGS = -MM > $@
# Don't use gcc 2.x for dependency generation
HDEPENDS_METHOD_2 = MKMF
HDEPENDS_METHOD = $(firstword $(HDEPENDS_METHOD_$(VX_GNU_MAJOR_VERSION)) COMP)
#--------------------------------------------------
# osithead use default stack, YES or NO override
@@ -65,14 +65,14 @@ GNU = NO
#
# Darwin shared libraries
#
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined suppress \
SHRLIB_LDFLAGS = -dynamiclib -undefined dynamic_lookup \
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
$(addprefix -current_version , $(SHRLIB_VERSION))
SHRLIB_SUFFIX_BASE = .dylib
SHRLIB_SUFFIX = $(addprefix ., $(SHRLIB_VERSION))$(SHRLIB_SUFFIX_BASE)
LOADABLE_SHRLIB_LDFLAGS = -bundle -flat_namespace -undefined suppress
LOADABLE_SHRLIB_LDFLAGS = -bundle -undefined dynamic_lookup
#
# Position-independent code is the default on Darwin.
+2
View File
@@ -26,3 +26,5 @@ endif
# Needed to find dlls for base installed build tools (antelope,eflex,...)
PATH := $(EPICS_BASE_BIN):$(PATH)
# Silence the tr1 namespace deprecation warnings
USR_CXXFLAGS_WIN32 += -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING
@@ -1,3 +0,0 @@
#
# Site-specific overrides for RTEMS-pc386 target
#
@@ -0,0 +1,9 @@
# CONFIG_SITE.Common.RTEMS-pc386-qemu
#
# Site-specific overrides for the RTEMS-pc386-qemu target
#
# If you're building this architecture you _probably_ want to
# run the tests for it under QEMU, but if not you can turn
# them off here by commenting out this line:
CROSS_COMPILER_RUNTEST_ARCHS += RTEMS-pc386-qemu
@@ -54,3 +54,7 @@ OPT_CXXFLAGS_YES += -g
# Tune GNU compiler output for a specific 32-bit cpu-type
# (e.g. generic, native, i386, i686, pentium2/3/4, prescott, k6, athlon etc.)
GNU_TUNE_CFLAGS = -mtune=generic
# Developers using a suitable compiler may enable its address sanitizer:
#ENABLE_ASAN = YES
@@ -50,3 +50,7 @@ OPT_CXXFLAGS_YES += -g
# Tune GNU compiler output for a specific 64-bit cpu-type
# (e.g. generic, native, core2, nocona, k8, opteron, athlon64, barcelona etc.)
GNU_TUNE_CFLAGS = -mtune=generic
# Developers using a suitable compiler may enable its address sanitizer:
#ENABLE_ASAN = YES
+4 -4
View File
@@ -4,17 +4,17 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Known Problems in EPICS 7.0.1</title>
<title>Known Problems in EPICS 7.0.2</title>
</head>
<body>
<h1 style="text-align: center">EPICS 7.0.1: Known Problems</h1>
<h1 style="text-align: center">EPICS 7.0.2: Known Problems</h1>
<p>Any patch files linked below should be applied at the root of the
base-7.0.1 tree. Download them, then use the GNU Patch program as
base-7.0.2 tree. Download them, then use the GNU Patch program as
follows:</p>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-7.0.1</b>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-7.0.2</b>
% <b>patch -p1 &lt; <i>/path/to/</i>file.patch</b></pre></blockquote>
<p>The following problems were known by the developers at the time of this
+6 -7
View File
@@ -1,6 +1,6 @@
Installation Instructions
EPICS Base Release 7.0.1.1
EPICS Base Release 7.0.2
--------------------------------------------------------------------------
@@ -164,12 +164,11 @@
base/startup directory - contains scripts to set environment and path
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable
Site.profile bourne shell script to set path and env variables
Site.cshrc c shell script to set path and env variables
cygwin.bat WIN32 bat file to set cygwin path and env variables
win32.bat WIN32 bat file to set path and env variables
EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
unix.csh C shell script to set path and env variables
unix.sh Bourne shell script to set path and env variables
win32.bat Bat file example to configure win32-x86 target
windows.bat Bat file example to configure windows-x64 target
base/configure directory - contains build definitions and rules
+1 -1
View File
@@ -21,7 +21,7 @@ of my Bash login script (~/.bash_login):
#
EPICS_BASE="${HOME}/src/EPICS/base"
EPICS_EXTENSIONS="${HOME}/src/EPICS/extensions"
<strong>.</strong> "${EPICS_BASE}"/startup/Site.profile
<strong>.</strong> "${EPICS_BASE}"/startup/unix.sh
</pre>
</li>
<li>
+6 -7
View File
@@ -9,7 +9,7 @@
<BODY>
<CENTER>
<H1>Installation Instructions</H1>
<H2>EPICS Base Release 7.0.1.1</H2><BR>
<H2>EPICS Base Release 7.0.2</H2><BR>
</CENTER>
<HR>
<H3> Table of Contents</H3>
@@ -176,12 +176,11 @@
<H4>base/startup directory - contains scripts to set environment and path</H4>
<PRE>
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable
Site.profile bourne shell script to set path and env variables
Site.cshrc c shell script to set path and env variables
cygwin.bat WIN32 bat file to set cygwin path and env variables
win32.bat WIN32 bat file to set path and env variables
EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
unix.csh C shell script to set path and env variables
unix.sh Bourne shell script to set path and env variables
win32.bat Bat file example to configure win32-x86 target
windows.bat Bat file example to configure windows-x64 target
</PRE>
<H4>base/configure directory - contains build definitions and rules</H4>
+335 -14
View File
@@ -8,7 +8,20 @@
<body lang="en">
<h1 align="center">EPICS Release 7.0.2.x</h1>
<p>These release notes describe changes that have been made since the previous
release of this series of EPICS Base. <b>Note that changes which were merged up
from commits to new releases in an older Base series are not described at the
top of this file but have entries that appear lower down, under the series to
which they were originally committed.</b> Thus it is important to read more than
just the first section to understand everything that has changed in each
release.</p>
<p>The external PVA submodules each have their own separate set of release notes
which should also be read to understand what has changed since an earlier
release.</p>
<h1 align="center">EPICS Release 7.0.3</h1>
<!-- Insert new items immediately below this template ...
@@ -28,6 +41,47 @@ CONFIG.Common.&lt;arch&gt; file for that architecture.
The builds for vxWorks 5 and up to 6.2 do that.
</p>
<h3>Old dbStaticLib APIs removed</h3>
<p>Support for some obsolete dbStaticLib Database Configuration Tool (DCT) APIs
was removed some time ago, but vestiges of them still remained. The following
routines and macros and have now finally been removed:</p>
<ul>
<li>int dbGetFieldType(DBENTRY *pdbentry)</li>
<li>int dbGetLinkType(DBENTRY *pdbentry)</li>
<li>DCT_STRING</li>
<li>DCT_INTEGER</li>
<li>DCT_REAL</li>
<li>DCT_MENU</li>
<li>DCT_MENUFORM</li>
<li>DCT_INLINK</li>
<li>DCT_OUTLINK</li>
<li>DCT_FWDLINK</li>
<li>DCT_NOACCESS</li>
<li>DCT_LINK_CONSTANT</li>
<li>DCT_LINK_FORM</li>
<li>DCT_LINK_PV</li>
</ul>
<h3>Fix for <tt>dbhcr</tt> before <tt>iocInit</tt></h3>
<p>The <tt>dbhcr</tt> command used to work before <tt>iocInit</tt> as well as
afterwards. It displays all records that have hardware addresses (VME_IO,
CAMAC_IO, GPIB_IO, INST_IO etc.) but stopped working if run before iocInit due
to the rewrite of the link address parser code in dbStaticLib. This release
fixes that issue, although in some cases the output may be slightly different
than it used to be.</p>
<h1 align="center">EPICS Release 7.0.2</h1>
<h3>Launchpad Bugs</h3>
<p>The list of tracked bugs fixed in this release can be found on the
<a href="https://launchpad.net/epics-base/+milestone/7.0.2">Launchpad Milestone
page for EPICS Base 7.0.2</a>.</p>
<h3>Git Branches Recombined</h3>
<p>The four separate Git branches <tt>core/master</tt>, <tt>libcom/master</tt>,
@@ -102,9 +156,139 @@ code than documentation. Send questions to the tech-talk mailing list and we'll
be happy to try and answer them!</p>
<h2 align="center">Changes from the 3.16 branch since 3.16.1</h2>
<h2 align="center">Changes between 3.16.1 and 3.16.2</h2>
<!-- Insert inherited items immediately below here ... -->
<p>The list of tracked bugs fixed in this release can be found on the
<a href="https://launchpad.net/epics-base/+milestone/3.16.2">Launchpad Milestone
page for EPICS Base 3.16.2</a>.</p>
<h3>Status reporting for the callback and scanOnce task queues</h3>
<p>Two new iocsh commands and some associated underlying APIs have been added to
show the state of the queues that feed the three callback tasks and the scanOnce
task, including a high-water mark which can optionally be reset. The new iocsh
commands are <tt>callbackQueueShow</tt> and <tt>scanOnceQueueShow</tt>; both
take an optional integer argument which must be non-zero to reset the
high-water mark.</p>
<h3>Support for event codes greater than or equal to NUM_TIME_EVENTS</h3>
<p>Event numbers greater than or equal to NUM_TIME_EVENTS are now allowed if
supported by the registered event time provider, which must provide its own
advancing timestamp validation for such events.</p>
<p>Time events numbered 0 through (NUM_TIME_EVENTS-1) are still validated by
code in epicsGeneralTime.c that checks for advancing timestamps and enforces
that restriction.</p>
<h3>Type-safe Device and Driver Support Tables</h3>
<p>Type-safe versions of the device and driver support structures <tt>dset</tt>
and <tt>drvet</tt> have been added to the devSup.h and drvSup.h headers
respectively. The original structure definitions have not been changed so
existing support modules will still build normally, but older modules can be
modified and new code written to be compatible with both.</p>
<p>The old structure definitions will be replaced by the new ones if the macros
<tt>USE_TYPED_DSET</tt> and/or <tt>USE_TYPED_DRVET</tt> are defined when the
appropriate header is included. The best place to define these is in the
Makefile, as with the <tt>USE_TYPED_RSET</tt> macro that was introduced in
Base-3.16.1 and described below. See the comments in devSup.h for a brief usage
example, or look at <a href="https://github.com/epics-modules/ipac/commit/a7e0ff4089b9aa39108bc8569e95ba7fcf07cee9">
this commit</a> to the ipac module to see a module conversion.</p>
<p>A helper function <tt>DBLINK* dbGetDevLink(dbCommon *prec)</tt> has also been
added to devSup.h which fetches a pointer to the INP or OUT field of the
record.</p>
<h3>RTEMS build configuration update, running tests under QEMU</h3>
<p>This release includes the ability to run the EPICS unit tests built for a
special version of the RTEMS-pc386 target architecture on systems that have an
appropriate QEMU emulator installed (<tt>qemu-system-i386</tt>). It is also now
possible to create sub-architectures of RTEMS targets, whereas previously the
EPICS target architecture name had to be <tt>RTEMS-$(RTEMS_BSP)</tt>.</p>
<p>The new target <tt>RTEMS-pc386-qemu</tt> builds binaries that can be run in
the <tt>qemu-system-i386</tt> PC System emulator. This target is a derivative of
the original <tt>RTEMS-pc386</tt> target but with additional software to build
an in-memory file-system, and some minor modifications to allow the unit tests
to work properly under QEMU. When this target is enabled, building any of the
make targets that cause the built-in self-tests to be run (such as
<tt>make&nbsp;runtests</tt>) will also run the tests for RTEMS using QEMU.</p>
<p>To allow the new 3-component RTEMS target name, the EPICS build system for
RTEMS was modified to allow a <tt>configure/os/CONFIG.Common.&lt;arch&gt;</tt>
file to set the <tt>RTEMS_BSP</tt> variable to inform the build what RTEMS BSP
to use. Previously this was inferred from the value of the <tt>T_A</tt> make
variable, but that prevents having multiple EPICS targets that build against the
same BSP. All the included RTEMS target configuration files have been updated;
build configuration files for out-of-tree RTEMS targets will continue to work as
the original rules are used to set <tt>RTEMS_BSP</tt> if it hasn't been set when
needed.</p>
<h3>Link type enhancements</h3>
<p>This release adds three new link types: "state", "debug" and "trace". The
"state" link type gets and puts boolean values from/to the dbState library that
was added in the 3.15.1 release. The "debug" link type sets the
<code>jlink::debug</code> flag in its child link, while the "trace" link type
also causes the arguments and return values for all calls to the child link's
jlif and lset routines to be printed on stdout. The debug flag can no longer be
set using an info tag. The addition of the "trace" link type has allowed over
200 lines of conditional diagnostic printf() calls to be removed from the other
link types.</p>
<p>The "calc" link type can now be used for output links as well as input links.
This allows modification of the output value and even combining it with values
from other input links. See the separate JSON Link types document for
details.</p>
<p>A new <code>start_child()</code> method was added to the end of the jlif
interface table.</p>
<p>The <code>lset</code> methods have now been properly documented in the
dbLink.h header file using Doxygen annotations, although we do not run Doxygen
on the source tree yet to generate API documentation.</p>
<p>Link types that utilize child links must now indicate whether the child will
be used for input, output or forward linking by the return value from its
<code>parse_start_map()</code> method. The <code>jlif_key_result</code> enum now
contains 3 values <code>jlif_key_child_inlink</code>,
<code>jlif_key_child_outlink</code> and <code>jlif_key_child_fwdlink</code>
instead of the single <code>jlif_key_child_link</code> that was previously used
for this.</p>
<h3>GNUmake targets for debugging</h3>
<p>Some additional build rules have been added to help debug configuration
problems with the build system. Run <tt>make show-makefiles</tt> to get a sorted
list of all the files that the build system includes when building in the
current directory.</p>
<p>A new pattern rule for <tt>PRINT.%</tt> can be used to show the value of any
GNUmake variable for the current build directory (make sure you are in the right
directory though, many variables are only set when inside the
<tt>O.<i>arch</i></tt> build directory). For example <tt>make PRINT.T_A</tt>
will display the build target architecture name from inside a
<tt>O.<i>arch</i></tt> directory but the variable will be empty from an
application top or src directory. <tt>make PRINT.EPICS_BASE</tt> will show the
path to Base from any EPICS application directory though.</p>
<h3>Propagate PUTF across Asynchronous record processing</h3>
<p>The IOC contains a mechanism involving the PUTF and RPRO fields of each
record to ensure that if a record is busy when it receives a put to one of its
fields, the record will be processed again to ensure that the new field value
has been correctly acted on. Until now that mechanism only worked if the put was
to the asynchronous record itself, so puts that were chained from some other
record via a DB link did not cause reprocessing.</p>
<p>In this release the mechanism has been extended to propagate the PUTF state
across DB links until all downstream records have been reprocessed. Some
additional information about the record state can be shown by setting the TPRO
field of an upstream record, and even more trace data is displayed if the
debugging variable <tt>dbAccessDebugPUTF</tt> is set in addition to TPRO.</p>
<h3>Finding info fields</h3>
@@ -122,15 +306,18 @@ release also includes additional protection against buffer overflows while
printing long links in <tt>dbpr</tt>, and corrects the output of long strings
from the <tt>dbgf</tt> command.</p>
<h3>Record types mbbiDirect and mbboDirect extended to 32 bit</h3>
<h3>Record types mbbiDirect and mbboDirect upgraded to 32 bit</h3>
<p>The VAL fields of mbbiDirect and mbboDirect records have
been extended from <tt>DBF_USHORT</tt> (16 bit) to <tt>DBF_LONG</tt> (32 bit).
New bit fields <tt>B10</tt>...<tt>B1F</tt> have been added.</p>
<p>The VAL fields and related fields of these records are now <tt>DBF_LONG</tt>.
(Not <tt>DBF_ULONG</tt> in order to prevent Channel Access from promoting them
to <tt>DBF_DOUBLE</tt>.) Additional bit fields <tt>B10</tt>...<tt>B1F</tt> have
been added.</p>
<p>Device support which accesses the bit fields can test if the macro
<tt>mbbiDirectRecord1BF</tt> or <tt>mbboDirectRecord1BF</tt> is
defined. Device support which only accesses RVAL needs no modification.</p>
<p>Device support that accesses <tt>VAL</tt> or the bit fields directly (most
don't) and aims for compatibility with old and new versions of these records
should use at least 32 bit integer types to avoid bit loss. The number of bit
fields can be calculated using <code>8&nbsp;*&nbsp;sizeof(prec->val)</code>
which is correct in both versions.</p>
<h3>Restore use of ledlib for VxWorks command editing</h3>
@@ -772,11 +959,76 @@ the stdout stream, making it hard to parse.</p>
callback.h header and removed the need for dbScan.c to reach into the internals
of its CALLBACK objects.</p>
<h2 align="center">Changes from the 3.15 branch since 3.15.5</h2>
<h2 align="center">Changes from the 3.15 branch since 3.15.6</h2>
<!-- Insert inherited items immediately below here ... -->
<h3>Routine <tt>epicsTempName()</tt> removed from libCom</h3>
<p>This routine was a simple wrapper around the C89 function <tt>tmpnam()</tt>
which is now seen as unsafe and causes warning messages to be generated by
most modern compilers. The two internal uses of this function have been
modified to call <tt>epicsTempFile()</tt> instead. We were unable to find any
published code that used this function, so it was removed immediately instead
of being deprecated.</p>
<h3>DBD Parsing of Record Types</h3>
<p>The Perl DBD file parser has been made slightly more liberal; the order in
which DBD files must be parsed is now more flexible, so that a record type
definition can now be parsed after a device support that referred to that
record type. A warning message will be displayed when the device support is
seen, but the subsequent loading of the record type will be accepted without
triggering an error. See
<a href="https://bugs.launchpad.net/epics-base/+bug/1801145">Launchpad bug
#1801145</a>.</p>
<h3>menuScan and several record types documented with POD</h3>
<p>The EPICS Wiki pages describing a number of standard record types has been
converted into the Perl POD documentation format and added to the DBD files,
so at build-time an HTML version of these documents is generated and installed
into the htmls directory. Thanks to Tony Pietryla.</p>
<h3>CA client tools learned <tt>-V</tt> option</h3>
<p>This displays the version numbers of EPICS Base and the CA protocol.</p>
<h2 align="center">Changes made between 3.15.5 and 3.15.6</h2>
<h3>Unsetting environment variables</h3>
<p>The new command <code>epicsEnvUnset <i>varname</i></code> can be used to
unset an environment variable.</p>
<h3>Warning indicators in msi (and macLib) output</h3>
<p>The libCom macro expansion library has been modified so that when the
SUPPRESS_WARNINGS flag is set it will no longer include any <tt>,undefined</tt>
or <tt>,recursive</tt> indicators in its output when undefined or recursive
macros are encountered. These indicators were harmless when the output was fed
into an IOC along with a definition for the macro, but when the <tt>msi</tt>
tool was used to generate other kinds of files they caused problems. If the
<tt>msi -V</tt> flag is used the markers will still be present in the output
whenever the appropriate condition is seen.</p>
<h3>Improvements to msi</h3>
<p>In addition to fixing its response to discovering parsing errors in its
substitution input file (reported as Launchpad
<a href="https://bugs.launchpad.net/epics-base/+bug/1503661">bug #1503661</a>)
so it now deletes the incomplete output file, the msi program has been cleaned
up a little bit internally.</p>
<h3>All array records now post monitors on their array-length fields</h3>
<p>The waveform record has been posting monitors on its NORD field since Base
3.15.0.1; we finally got around to doing the equivalent in all the other
built-in record types, which even required modifying device support in some
cases. This fixes <a href="https://bugs.launchpad.net/epics-base/+bug/1730727">
Launchpad bug #1730727</a>.</p>
<h3>HOWTO: Converting Wiki Record Reference to POD</h3>
<p>Some documentation has been added to the <tt>dbdToHtml.pl</tt> script
@@ -808,15 +1060,84 @@ of having go modify or replace the original. A new .gitignore pattern
tells git to ignore all configure/*.local files.</p>
<h2 align="center">Changes from the 3.14 branch since 3.15.5</h2>
<h2 align="center">Changes from the 3.14 branch between 3.15.5 and 3.15.6</h2>
<!-- Insert inherited items immediately below here ... -->
<h3>Fix broken <tt>EPICS_IOC_LOG_FILE_LIMIT=0</tt> setting</h3>
<p>The Application Developers' Guide says this is allowed and disables the
limit on the log-file, but it hasn't actually worked for some time (if ever).
Note that the iocLogServer will be removed from newer Base release sometime
soon as its functionality can be implemented by other dedicated log servers
such as logstash or syslog-ng.</p>
<p>Fixes <a href="https://bugs.launchpad.net/bugs/1786858">lp:1786858</a>
and part of <a href="https://bugs.launchpad.net/bugs/1786966">lp:1786966</a>.
</p>
<h3>Cleanup of startup directory</h3>
<p>The files in the startup directory have not been maintained in recent years
and have grown crufty (technical term). This release includes the following
updates to these files:</p>
<ul>
<li>The Perl <tt>EpicsHostArch.pl</tt> script has been rewritten, and support
for a few previously missing host architectures has been added to it.</li>
<li>The <tt>EpicsHostArch.pl</tt> script has also been moved into the standard
<tt>src/tools</tt> directory, from where it will be installed into
<tt>lib/perl</tt>. In this new location it is no longer executable, so it must
be run by the <tt>perl</tt> executable.</li>
<li>The build system has been adjusted to look for <tt>EpicsHostArch.pl</tt> in
both places if the <tt>EPICS_HOST_ARCH</tt> environment variable has not been
set at build-time.</li>
<li>Sites that used the original Perl script to set <tt>EPICS_HOST_ARCH</tt> as
part of their standard environment will need to adjust their scripts when they
upgrade to this release.</li>
<li>The <tt>EpicsHostArch</tt> shell script has been replaced with a wrapper
routine that calls the Perl <tt>EpicsHostArch.pl</tt> script. Sites that rely on
this script to set <tt>EPICS_HOST_ARCH</tt> should consider switching to the
Perl script instead.</li>
<li>The <tt>Site.cshrc</tt> and <tt>Site.profile</tt> files have been renamed to
<tt>unix.csh</tt> and <tt>unix.sh</tt>, respectively.</li>
<li>The existing <tt>win32.bat</tt> file has been cleaned up and a new
<tt>windows.bat</tt> file added for 64-bit targets. The contents of these files
should be seen as examples, don't uncomment or install parts for software that
you don't explicitly know that you need.</li>
</ul>
<h3>Recent Apple XCode Build Issues</h3>
<p>The latest version of XCode will not compile calls to <tt>system()</tt> or
<tt>clock_settime()</tt> for iOS targets. There were several places in Base
where these were being compiled, although there were probably never called. The
code has now been modified to permit iOS builds to complete again.</p>
<h3>Prevent illegal alarm severities</h3>
<p>A check has been added to <tt>recGblResetAlarms()</tt> that prevents records
from getting an alarm severity higher than INVALID_ALARM. It is still possible
for a field like HSV to get set to a value that is not a legal alarm severity,
but the core IOC code should never copy such a value into a record's SEVR or
ACKS fields. With this fix the record's alarm severity will be limited to
INVALID_ALARM.</p>
<h3>Fixes for Launchpad bugs</h3>
<p>The following launchpad bugs have fixes included:</p>
<ul>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1786320">
lp: #1786320</a>, dbCa subscribes twice to ENUM</li>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/541221">
lp: #541221</a>, 'assert (pca->pgetNative)' failed in ../dbCa.c</li>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1747091">
lp: #1747091</a>, epicsTimeGetEvent() / generalTime bug</li>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1743076">
+45 -21
View File
@@ -133,20 +133,20 @@ made.</p>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Tag the module in Git using these tag conventions:
<td>Tag the module in Git, using these tag conventions:
<ul>
<li>
<tt>R7.1.1-pre<i>n</i></tt>
<tt>R7.0.2-pre<i>n</i></tt>
&mdash; pre-release tag
</li>
<li>
<tt>R7.1.1-rc<i>n</i></tt>
<tt>R7.0.2-rc<i>n</i></tt>
&mdash; release candidate tag
</li>
</ul>
</ul>
<blockquote><tt>
cd base-7.1<br />
git tag -m 'ANJ: Tagged for 7.1.1-rc1' R7.1.1-rc1
cd base-7.0<br />
git tag -m 'ANJ: Tagged for 7.0.2-rc1' R7.0.2-rc1
</tt></blockquote>
Note that submodules must <em>not</em> be tagged with the version used
for the top-level, they each have their own separate version numbers
@@ -159,12 +159,12 @@ made.</p>
script generates a gzipped tarfile directly from the tag, excluding the
files and directories that are only used for continuous integration:
<blockquote><tt>
cd base-7.1<br />
.ci/make-tar.sh R7.1.1-rc1 base-7.1.1-rc1.tar.gz base-7.1.1-rc1/
cd base-7.0<br />
./.tools/make-tar.sh R7.0.2-rc1 base-7.0.2-rc1.tar.gz base-7.0.2-rc1/
</tt></blockquote>
Create a GPG signature file of the tarfile as follows:
<blockquote><tt>
gpg --armor --sign --detach-sig base-7.1.1-rc1.tar.gz
gpg --armor --sign --detach-sig base-7.0.2-rc1.tar.gz
</tt></blockquote>
</td>
</tr>
@@ -247,6 +247,7 @@ made.</p>
</ul>
</td>
</tr>
<tr>
<th colspan="3">Release Approval</th>
</tr>
@@ -263,18 +264,36 @@ made.</p>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Edit and commit changes to the EPICS version number file
configure/CONFIG_BASE_VERSION.</td>
<td>
<p>For each external submodule, check if the module's release version
number (and SHRLIB_VERSION setting) has been updated if appropriate,
and that its Release Notes have been updated to cover any changes.
Commit any fixes and tag the module if that hasn't already been
done.</p>
<p>Update all external submodules on the Base-7.0 branch and
commit.</p></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Tag the module in Git:
<td>Edit and commit changes to the EPICS Base version number file and
the embedded module version files:
<ul>
<li>configure/CONFIG_BASE_VERSION </li>
<li>modules/libcom/configure/CONFIG_LIBCOM_VERSION</li>
<li>modules/ca/configure/CONFIG_CA_VERSION</li>
<li>modules/database/configure/CONFIG_DATABASE_VERSION</li>
</ul></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Tag the epics-base module in Git:
<blockquote><tt>
cd base-7.1<br />
git tag -m 'ANJ: Tagged for 7.1.1' R7.1.1</i>
cd base-7.0<br />
git tag -m 'ANJ: Tagged for 7.0.2' R7.0.2</i>
</tt></blockquote>
</td>
Don't push the new tag to the Launchpad repository yet.</td>
</tr>
<tr>
<td>&nbsp;</td>
@@ -283,12 +302,12 @@ made.</p>
script generates a gzipped tarfile directly from the tag, excluding the
files and directories that are only used for continuous integration:
<blockquote><tt>
cd base-7.1<br />
.ci/make-tar.sh R7.1.1 base-7.1.1.tar.gz base-7.1.1/
cd base-7.0<br />
./.tools/make-tar.sh R7.0.2 base-7.0.2.tar.gz base-7.0.2/
</tt></blockquote>
Create a GPG signature file of the tarfile as follows:
<blockquote><tt>
gpg --armor --sign --detach-sig base-7.1.1.tar.gz
gpg --armor --sign --detach-sig base-7.0.2.tar.gz
</tt></blockquote>
</td>
</tr>
@@ -296,7 +315,12 @@ made.</p>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Test the tar file by extracting its contents and building it on at
least one supported platform</td>
least one supported platform. When this succeeds the new git tag can be
pushed to the Launchpad repository:
<blockquote><tt>
git push --follow-tags upstream 7.0
</tt></blockquote>
</td>
</tr>
<tr>
<td>&nbsp;</td>
@@ -316,8 +340,8 @@ made.</p>
<tr>
<td>&nbsp;</td>
<td>Website Manager</td>
<td>Copy the tar file and its <tt>.asc</tt> signature file to the Base
download area of the website.</td>
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
Launchpad milestone for this release version.</td>
</tr>
<tr>
<td>&nbsp;</td>
+1 -1
View File
@@ -55,4 +55,4 @@ $(RELEASE_LOCAL):
$(ECHO) Creating $@, EPICS_BASE = $(INSTALL_LOCATION_ABS)
@echo EPICS_BASE = $(INSTALL_LOCATION_ABS)> $@
realclean:
$(RM) $(RELEASE_LOCAL)
$(RM) $(wildcard RELEASE.*.local)
+2 -2
View File
@@ -1,4 +1,4 @@
EPICS_CA_MAJOR_VERSION = 4
EPICS_CA_MINOR_VERSION = 13
EPICS_CA_MAINTENANCE_VERSION = 2
EPICS_CA_DEVELOPMENT_FLAG = 1
EPICS_CA_MAINTENANCE_VERSION = 3
EPICS_CA_DEVELOPMENT_FLAG = 0
+1 -1
View File
@@ -126,7 +126,7 @@ EXPANDVARS += EPICS_CA_DEVELOPMENT_FLAG
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
# shared library ABI version.
SHRLIB_VERSION = 4.13.1
SHRLIB_VERSION = $(EPICS_CA_MAJOR_VERSION).$(EPICS_CA_MINOR_VERSION).$(EPICS_CA_MAINTENANCE_VERSION)
include $(TOP)/configure/RULES
+14 -3
View File
@@ -193,7 +193,7 @@ udpiiu::udpiiu (
#ifdef IP_MULTICAST_TTL
{
int ttl;
osiSockOptMcastTTL_t ttl;
long val;
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
val =1;
@@ -961,7 +961,7 @@ bool udpiiu::pushDatagramMsg ( epicsGuard < epicsMutex > & guard,
udpiiu :: SearchDestUDP :: SearchDestUDP (
const osiSockAddr & destAddr, udpiiu & udpiiuIn ) :
_destAddr ( destAddr ), _udpiiu ( udpiiuIn )
_lastError (0u), _destAddr ( destAddr ), _udpiiu ( udpiiuIn )
{
}
@@ -976,6 +976,13 @@ void udpiiu :: SearchDestUDP :: searchRequest (
int status = sendto ( _udpiiu.sock, const_cast<char *>(pBuf), bufSizeAsInt, 0,
& _destAddr.sa, sizeof ( _destAddr.sa ) );
if ( status == bufSizeAsInt ) {
if ( _lastError ) {
char buf[64];
sockAddrToDottedIP ( &_destAddr.sa, buf, sizeof ( buf ) );
errlogPrintf (
"CAC: ok sending UDP msg to %s\n", buf);
}
_lastError = 0;
break;
}
if ( status >= 0 ) {
@@ -1002,7 +1009,9 @@ void udpiiu :: SearchDestUDP :: searchRequest (
else if ( localErrno == SOCK_EBADF ) {
break;
}
else {
else if ( localErrno == _lastError) {
break;
} else {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
@@ -1011,6 +1020,8 @@ void udpiiu :: SearchDestUDP :: searchRequest (
errlogPrintf (
"CAC: error = \"%s\" sending UDP msg to %s\n",
sockErrBuf, buf);
_lastError = localErrno;
break;
}
}
+1
View File
@@ -123,6 +123,7 @@ private:
void show (
epicsGuard < epicsMutex > &, unsigned level ) const;
private:
int _lastError;
osiSockAddr _destAddr;
udpiiu & _udpiiu;
};
@@ -143,6 +143,10 @@ sub display {
printf " Lo ctrl limit: %g\n", $data->{lower_ctrl_limit};
printf " Hi ctrl limit: %g\n", $data->{upper_ctrl_limit};
}
if (exists $data->{ackt}) {
printf " Ack transients: %s\n", $data->{ackt} ? 'YES' : 'NO';
printf " Ack severity: %s\n", $data->{acks};
}
} else {
my $value = format_number($data, $type);
if ($opt_t) {
+6 -1
View File
@@ -34,6 +34,7 @@
#include <alarm.h>
#include <cadef.h>
#include <epicsGetopt.h>
#include "epicsVersion.h"
#include "tool_lib.h"
@@ -55,6 +56,7 @@ static void usage (void)
{
fprintf (stderr, "\nUsage: caget [options] <PV name> ...\n\n"
" -h: Help: Print this message\n"
" -V: Version: Show EPICS and CA versions\n"
"Channel Access options:\n"
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
" -c: Asynchronous get (use ca_get_callback and wait for completion)\n"
@@ -389,11 +391,14 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
while ((opt = getopt(argc, argv, ":taicnhsSe:f:g:l:#:d:0:w:p:F:")) != -1) {
while ((opt = getopt(argc, argv, ":taicnhsSVe:f:g:l:#:d:0:w:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage();
return 0;
case 'V':
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
return 0;
case 't': /* Terse output mode */
complainIfNotPlainAndSet(&format, terse);
break;
+7 -1
View File
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <epicsStdlib.h>
#include "epicsVersion.h"
#include <cadef.h>
#include <epicsGetopt.h>
@@ -36,12 +37,14 @@ void usage (void)
{
fprintf (stderr, "\nUsage: cainfo [options] <PV name> ...\n\n"
" -h: Help: Print this message\n"
" -V: Version: Show EPICS and CA versions\n"
"Channel Access options:\n"
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
" -s <level>: Call ca_client_status with the specified interest level\n"
" -p <prio>: CA priority (0-%u, default 0=lowest)\n"
"\nExample: cainfo my_channel another_channel\n\n"
, DEFAULT_TIMEOUT, CA_PRIORITY_MAX);
fprintf (stderr, "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
}
@@ -137,11 +140,14 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
while ((opt = getopt(argc, argv, ":nhw:s:p:")) != -1) {
while ((opt = getopt(argc, argv, ":nhVw:s:p:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage();
return 0;
case 'V':
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
return 0;
case 'w': /* Set CA timeout value */
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
+7 -2
View File
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <epicsStdlib.h>
#include <string.h>
#include "epicsVersion.h"
#include <cadef.h>
#include <epicsGetopt.h>
@@ -44,7 +45,8 @@ void usage (void)
{
fprintf (stderr, "\nUsage: camonitor [options] <PV name> ...\n"
"\n"
" -h: Help; Print this message\n"
" -h: Help: Print this message\n"
" -V: Version: Show EPICS and CA versions\n"
"Channel Access options:\n"
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
" -m <msk>: Specify CA event mask to use. <msk> is any combination of\n"
@@ -209,11 +211,14 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
while ((opt = getopt(argc, argv, ":nhm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
while ((opt = getopt(argc, argv, ":nhVm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage();
return 0;
case 'V':
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
return 0;
case 'n': /* Print ENUM as index numbers */
enumAsNr=1;
break;
+6 -1
View File
@@ -37,6 +37,7 @@
#include <epicsGetopt.h>
#include <epicsEvent.h>
#include <epicsString.h>
#include "epicsVersion.h"
#include "tool_lib.h"
@@ -59,6 +60,7 @@ void usage (void)
fprintf (stderr, "\nUsage: caput [options] <PV name> <PV value> ...\n"
" caput -a [options] <PV name> <no of values> <PV value> ...\n\n"
" -h: Help: Print this message\n"
" -V: Version: Show EPICS and CA versions\n"
"Channel Access options:\n"
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
" -c: Asynchronous put (use ca_put_callback and wait for completion)\n"
@@ -281,11 +283,14 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */
while ((opt = getopt(argc, argv, ":cnlhatsS#:w:p:F:")) != -1) {
while ((opt = getopt(argc, argv, ":cnlhatsVS#:w:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage();
return 0;
case 'V':
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
return 0;
case 'n': /* Force interpret ENUM as index number */
enumAsNr = 1;
enumAsString = 0;
+1 -1
View File
@@ -25,7 +25,7 @@ INSTALL_LOCATION = $(TOP)
BASE_CPPFLAGS += -DUSE_TYPED_RSET
# Shared library ABI version.
SHRLIB_VERSION = 3.17.0
SHRLIB_VERSION = $(EPICS_DATABASE_MAJOR_VERSION).$(EPICS_DATABASE_MINOR_VERSION).$(EPICS_DATABASE_MAINTENANCE_VERSION)
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
@@ -1,4 +1,4 @@
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 17
EPICS_DATABASE_MAINTENANCE_VERSION = 1
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
EPICS_DATABASE_MAINTENANCE_VERSION = 2
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
-5
View File
@@ -25,11 +25,6 @@ INC += databaseVersionNum.h
PROD_LIBS = Com
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 17
EPICS_DATABASE_MAINTENANCE_VERSION = 0
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
include $(IOCDIR)/as/Makefile
include $(IOCDIR)/bpt/Makefile
include $(IOCDIR)/db/Makefile
+1 -3
View File
@@ -35,7 +35,6 @@ INC += dbTest.h
INC += dbCaTest.h
INC += db_test.h
INC += db_field_log.h
INC += initHooks.h
INC += recGbl.h
INC += dbIocRegister.h
INC += chfPlugin.h
@@ -63,7 +62,7 @@ DBDINC += menuScan
DBDINC += dbCommon
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
HTMLS += $(patsubst %.dbd.pod,%.html,$(menusPod))
HTMLS += $(patsubst %.dbd.pod,%.html,$(dbMenusPod))
dbCore_SRCS += dbLock.c
dbCore_SRCS += dbAccess.c
@@ -87,7 +86,6 @@ dbCore_SRCS += recGbl.c
dbCore_SRCS += callback.c
dbCore_SRCS += dbCa.c
dbCore_SRCS += dbCaTest.c
dbCore_SRCS += initHooks.c
dbCore_SRCS += cvtBpt.c
dbCore_SRCS += dbContext.cpp
dbCore_SRCS += dbChannelIO.cpp
+47
View File
@@ -54,6 +54,7 @@ typedef struct cbQueueSet {
epicsEventId semWakeUp;
epicsRingPointerId queue;
int queueOverflow;
int queueOverflows;
int shutdown;
int threadsConfigured;
int threadsRunning;
@@ -103,6 +104,51 @@ int callbackSetQueueSize(int size)
return 0;
}
int callbackQueueStatus(const int reset, callbackQueueStats *result)
{
int ret;
if (!callbackIsInit) return -1;
if (result) {
int prio;
result->size = callbackQueueSize;
for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
epicsRingPointerId qId = callbackQueue[prio].queue;
result->numUsed[prio] = epicsRingPointerGetUsed(qId);
result->maxUsed[prio] = epicsRingPointerGetHighWaterMark(qId);
result->numOverflow[prio] = epicsAtomicGetIntT(&callbackQueue[prio].queueOverflows);
}
ret = 0;
} else {
ret = -2;
}
if (reset) {
int prio;
for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
epicsRingPointerResetHighWaterMark(callbackQueue[prio].queue);
}
}
return ret;
}
void callbackQueueShow(const int reset)
{
callbackQueueStats stats;
if (callbackQueueStatus(reset, &stats) == -1) {
fprintf(stderr, "Callback system not initialized, yet. Please run "
"iocInit before using this command.\n");
} else {
int prio;
printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n");
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
double qusage = 100.0 * stats.numUsed[prio] / stats.size;
printf("%8s %15d %10d %6d %6.1f %11d\n",
threadNamePrefix[prio], stats.maxUsed[prio],
stats.numUsed[prio], stats.size, qusage,
stats.numOverflow[prio]);
}
}
}
int callbackParallelThreads(int count, const char *prio)
{
if (callbackIsInit) {
@@ -290,6 +336,7 @@ int callbackRequest(CALLBACK *pcallback)
if (!pushOK) {
epicsInterruptContextMessage(fullMessage[priority]);
mySet->queueOverflow = TRUE;
epicsAtomicIncrIntT(&mySet->queueOverflows);
return S_db_bufFull;
}
epicsEventSignal(mySet->semWakeUp);
+9
View File
@@ -48,6 +48,13 @@ typedef epicsCallback CALLBACK;
typedef void (*CALLBACKFUNC)(struct callbackPvt*);
typedef struct callbackQueueStats {
int size;
int numUsed[NUM_CALLBACK_PRIORITIES];
int maxUsed[NUM_CALLBACK_PRIORITIES];
int numOverflow[NUM_CALLBACK_PRIORITIES];
} callbackQueueStats;
#define callbackSetCallback(PFUN, PCALLBACK) \
( (PCALLBACK)->callback = (PFUN) )
#define callbackSetPriority(PRIORITY, PCALLBACK) \
@@ -73,6 +80,8 @@ epicsShareFunc void callbackCancelDelayed(CALLBACK *pcallback);
epicsShareFunc void callbackRequestProcessCallbackDelayed(
CALLBACK *pCallback, int Priority, void *pRec, double seconds);
epicsShareFunc int callbackSetQueueSize(int size);
epicsShareFunc int callbackQueueStatus(const int reset, callbackQueueStats *result);
epicsShareFunc void callbackQueueShow(const int reset);
epicsShareFunc int callbackParallelThreads(int count, const char *prio);
#ifdef __cplusplus
+57 -52
View File
@@ -34,7 +34,7 @@
#include "errlog.h"
#include "errMdef.h"
#define epicsExportSharedSymbols
#include "epicsExport.h" /* #define epicsExportSharedSymbols */
#include "caeventmask.h"
#include "callback.h"
#include "dbAccessDefs.h"
@@ -65,6 +65,9 @@
epicsShareDef struct dbBase *pdbbase = 0;
epicsShareDef volatile int interruptAccept=FALSE;
epicsShareDef int dbAccessDebugPUTF = 0;
epicsExportAddress(int, dbAccessDebugPUTF);
/* Hook Routines */
epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
@@ -446,22 +449,6 @@ int dbGetFieldIndex(const struct dbAddr *paddr)
return paddr->pfldDes->indRecordType;
}
/*
* Process a record if its scan field is passive.
* Will notify if processing is complete by callback.
* (only if you are interested in completion)
*/
long dbScanPassive(dbCommon *pfrom, dbCommon *pto)
{
/* if not passive just return success */
if (pto->scan != 0)
return 0;
if (pfrom && pfrom->ppn)
dbNotifyAdd(pfrom,pto);
return dbProcess(pto);
}
/*
* Process the record.
* 1. Check for breakpoints.
@@ -527,7 +514,8 @@ long dbProcess(dbCommon *precord)
unsigned short monitor_mask;
if (*ptrace)
printf("%s: Active %s\n", context, precord->name);
printf("%s: dbProcess of Active '%s' with RPRO=%d\n",
context, precord->name, precord->rpro);
/* raise scan alarm after MAX_LOCK times */
if ((precord->stat == SCAN_ALARM) ||
@@ -556,7 +544,8 @@ long dbProcess(dbCommon *precord)
/* if disabled check disable alarm severity and return success */
if (precord->disa == precord->disv) {
if (*ptrace)
printf("%s: Disabled %s\n", context, precord->name);
printf("%s: dbProcess of Disabled '%s'\n",
context, precord->name);
/*take care of caching and notifyCompletion*/
precord->rpro = FALSE;
@@ -593,7 +582,7 @@ long dbProcess(dbCommon *precord)
}
if (*ptrace)
printf("%s: Process %s\n", context, precord->name);
printf("%s: dbProcess of '%s'\n", context, precord->name);
/* process record */
status = prset->process(precord);
@@ -612,6 +601,31 @@ all_done:
return status;
}
long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr)
{
dbFldDes *pflddes = pdbentry->pflddes;
short dbfType = pflddes->field_type;
paddr->precord = pdbentry->precnode->precord;
paddr->pfield = pdbentry->pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
const rset *prset = dbGetRset(paddr);
/* Let record type modify paddr */
if (prset && prset->cvt_dbaddr) {
return prset->cvt_dbaddr(paddr);
}
}
return 0;
}
/*
* Fill out a database structure (*paddr) for
* a record given by the name "pname."
@@ -622,9 +636,7 @@ all_done:
long dbNameToAddr(const char *pname, DBADDR *paddr)
{
DBENTRY dbEntry;
dbFldDes *pflddes;
long status = 0;
short dbfType;
if (!pname || !*pname || !pdbbase)
return S_db_notFound;
@@ -639,46 +651,28 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
status = dbGetAttributePart(&dbEntry, &pname);
if (status) goto finish;
pflddes = dbEntry.pflddes;
dbfType = pflddes->field_type;
paddr->precord = dbEntry.precnode->precord;
paddr->pfield = dbEntry.pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
rset *prset = dbGetRset(paddr);
/* Let record type modify paddr */
if (prset && prset->cvt_dbaddr) {
status = prset->cvt_dbaddr(paddr);
if (status)
goto finish;
dbfType = paddr->field_type;
}
}
status = dbEntryToAddr(&dbEntry, paddr);
if (status) goto finish;
/* Handle field modifiers */
if (*pname++ == '$') {
short dbfType = paddr->field_type;
/* Some field types can be accessed as char arrays */
if (dbfType == DBF_STRING) {
paddr->no_elements = paddr->field_size;
paddr->field_type = DBF_CHAR;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
}
else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
}
else {
status = S_dbLib_fieldNotFound;
goto finish;
}
}
@@ -713,6 +707,18 @@ void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
pdbentry->precnode = ppvt->recnode;
}
struct link* dbGetDevLink(struct dbCommon* prec)
{
DBLINK *plink = 0;
DBENTRY entry;
dbInitEntryFromRecord(prec, &entry);
if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) {
plink = (DBLINK*)entry.pfield;
}
dbFinishEntry(&entry);
return plink;
}
long dbValueSize(short dbr_type)
{
/* sizes for value associated with each DBR request type */
@@ -1049,7 +1055,7 @@ static long dbPutFieldLink(DBADDR *paddr,
return S_db_badDbrtype;
}
status = dbParseLink(pstring, pfldDes->field_type, &link_info, 0);
status = dbParseLink(pstring, pfldDes->field_type, &link_info);
if (status)
return status;
@@ -1222,8 +1228,8 @@ long dbPutField(DBADDR *paddr, short dbrType,
precord->scan == 0 &&
dbrType < DBR_PUT_ACKT)) {
if (precord->pact) {
if (precord->tpro)
printf("%s: Active %s\n",
if (dbAccessDebugPUTF && precord->tpro)
printf("%s: dbPutField to Active '%s', setting RPRO=1\n",
epicsThreadGetNameSelf(), precord->name);
precord->rpro = TRUE;
} else {
@@ -1356,4 +1362,3 @@ done:
paddr->pfield = pfieldsave;
return status;
}
+26 -2
View File
@@ -34,6 +34,7 @@ extern "C" {
epicsShareExtern struct dbBase *pdbbase;
epicsShareExtern volatile int interruptAccept;
epicsShareExtern int dbAccessDebugPUTF;
/* The database field and request types are defined in dbFldTypes.h*/
/* Data Base Request Options */
@@ -203,6 +204,8 @@ struct dbr_alDouble {DBRalDouble};
#define S_db_notInit (M_dbAccess|67) /*Not initialized*/
#define S_db_bufFull (M_dbAccess|68) /*Buffer full*/
struct dbEntry;
epicsShareFunc long dbPutSpecial(struct dbAddr *paddr,int pass);
epicsShareFunc rset * dbGetRset(const struct dbAddr *paddr);
epicsShareFunc long dbPutAttribute(
@@ -212,8 +215,29 @@ epicsShareFunc int dbGetFieldIndex(const struct dbAddr *paddr);
epicsShareFunc long dbScanPassive(
struct dbCommon *pfrom,struct dbCommon *pto);
epicsShareFunc long dbProcess(struct dbCommon *precord);
epicsShareFunc long dbNameToAddr(
const char *pname,struct dbAddr *);
epicsShareFunc long dbNameToAddr(const char *pname, struct dbAddr *paddr);
/** Initialize DBADDR from a dbEntry
* Also handles SPC_DBADDR processing. This is really an internal
* routine for use by dbNameToAddr() and dbChannelCreate().
*/
epicsShareFunc long dbEntryToAddr(const struct dbEntry *pdbentry,
struct dbAddr *paddr);
/** Initialize DBENTRY from a valid dbAddr*
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias().
*/
epicsShareFunc void dbInitEntryFromAddr(struct dbAddr *paddr,
struct dbEntry *pdbentry);
/** Initialize DBENTRY from a valid record (dbCommon*)
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias() when no field is specified.
*/
epicsShareFunc void dbInitEntryFromRecord(struct dbCommon *prec,
struct dbEntry *pdbentry);
epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset);
epicsShareFunc long dbGetField(
+12 -3
View File
@@ -703,7 +703,12 @@ static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
caLink *pca;
long status;
pcaGetCheck
assert(plink);
if (plink->type != CA_LINK) return -1;
pca = (caLink *)plink->value.pv_link.pvt;
assert(pca);
epicsMutexMustLock(pca->lock);
assert(pca->plink);
status = rtn(plink, priv);
epicsMutexUnlock(pca->lock);
return status;
@@ -842,6 +847,7 @@ static void eventCallback(struct event_handler_args arg)
struct dbr_time_double *pdbr_time_double;
dbCaCallback monitor = 0;
void *userPvt = 0;
int doScan = 1;
assert(pca);
epicsMutexMustLock(pca->lock);
@@ -872,10 +878,13 @@ static void eventCallback(struct event_handler_args arg)
memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size);
pca->gotInString = TRUE;
} else switch (arg.type){
case DBR_TIME_ENUM:
/* Disable the record scan if we also have a string monitor */
doScan = !(plink->value.pv_link.pvlMask & pvlOptInpString);
/* fall through */
case DBR_TIME_STRING:
case DBR_TIME_SHORT:
case DBR_TIME_FLOAT:
case DBR_TIME_ENUM:
case DBR_TIME_CHAR:
case DBR_TIME_LONG:
case DBR_TIME_DOUBLE:
@@ -893,7 +902,7 @@ static void eventCallback(struct event_handler_args arg)
pca->sevr = pdbr_time_double->severity;
pca->stat = pdbr_time_double->status;
memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp));
if (precord) {
if (doScan && precord) {
struct pv_link *ppv_link = &plink->value.pv_link;
if ((ppv_link->pvlMask & pvlOptCP) ||
+10 -27
View File
@@ -20,6 +20,7 @@
#include "cantProceed.h"
#include "epicsAssert.h"
#include "epicsString.h"
#include "epicsStdio.h"
#include "errlog.h"
#include "freeList.h"
#include "gpHash.h"
@@ -472,9 +473,7 @@ dbChannel * dbChannelCreate(const char *name)
dbChannel *chan = NULL;
char *cname;
dbAddr *paddr;
dbFldDes *pflddes;
long status;
short dbfType;
if (!name || !*name || !pdbbase)
return NULL;
@@ -497,32 +496,14 @@ dbChannel * dbChannelCreate(const char *name)
ellInit(&chan->post_chain);
paddr = &chan->addr;
pflddes = dbEntry.pflddes;
dbfType = pflddes->field_type;
paddr->precord = dbEntry.precnode->precord;
paddr->pfield = dbEntry.pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
rset *prset = dbGetRset(paddr);
/* Let record type modify paddr */
if (prset && prset->cvt_dbaddr) {
status = prset->cvt_dbaddr(paddr);
if (status)
goto finish;
dbfType = paddr->field_type;
}
}
status = dbEntryToAddr(&dbEntry, paddr);
if (status)
goto finish;
/* Handle field modifiers */
if (*pname) {
short dbfType = paddr->field_type;
if (*pname == '$') {
/* Some field types can be accessed as char arrays */
if (dbfType == DBF_STRING) {
@@ -530,12 +511,14 @@ dbChannel * dbChannelCreate(const char *name)
paddr->field_type = DBF_CHAR;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
}
else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
}
else {
status = S_dbLib_fieldNotFound;
goto finish;
}
+104 -20
View File
@@ -12,6 +12,29 @@
* Current Author: Andrew Johnson
*/
/* The PUTF and RPRO fields in dbCommon are flags that indicate when a record
* is being processed as a result of an external put (i.e. some server process
* calling dbPutField()), ensuring that the record and its successors will
* eventually get processed even if they happen to be busy at the time of the
* put. From Base-3.16.2 and 7.0.2 the code ensures that all records downstream
* from the original are processed even if a busy asynchronous device appears
* in the processing chain (this breaks the chain in older versions).
*
* PUTF - This field is set in dbPutField() prior to it calling dbProcess().
* It is normally cleared at the end of processing in recGblFwdLink().
* It may also be cleared in dbProcess() if DISA==DISV (scan disabled),
* or by the processTarget() function below.
*
* If PUTF is TRUE before a call to dbProcess(prec), then after it returns
* either PACT is TRUE, or PUTF will be FALSE.
*
* RPRO - This field is set by dbPutField() or by the processTarget() function
* below when a record to be processed is found to be busy (PACT==1).
* It is normally cleared in recGblFwdLink() when the record is queued
* for re-processing, or in dbProcess() if DISA==DISV (scan disabled).
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -43,17 +66,22 @@
#include "dbNotify.h"
#include "dbScan.h"
#include "dbStaticLib.h"
#include "dbServer.h"
#include "devSup.h"
#include "link.h"
#include "recGbl.h"
#include "recSup.h"
#include "special.h"
#include "dbDbLink.h"
/***************************** Database Links *****************************/
/* Forward definition */
/* Forward definitions */
static lset dbDb_lset;
static long processTarget(dbCommon *psrc, dbCommon *pdst);
long dbDbInitLink(struct link *plink, short dbfType)
{
DBADDR dbaddr;
@@ -138,11 +166,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
/* scan passive records if link is process passive */
if (ppv_link->pvlMask & pvlOptPP) {
unsigned char pact = precord->pact;
precord->pact = TRUE;
status = dbScanPassive(precord, paddr->precord);
precord->pact = pact;
if (status)
return status;
}
@@ -311,22 +335,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
return status;
if (paddr->pfield == (void *) &pdest->proc ||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
/* if dbPutField caused asyn record to process */
/* ask for reprocessing*/
if (pdest->putf) {
pdest->rpro = TRUE;
} else { /* process dest record with source's PACT true */
unsigned char pact;
if (psrce && psrce->ppn)
dbNotifyAdd(psrce, pdest);
pact = psrce->pact;
psrce->pact = TRUE;
status = dbProcess(pdest);
psrce->pact = pact;
}
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
status = processTarget(psrce, pdest);
}
return status;
}
@@ -356,3 +368,75 @@ static lset dbDb_lset = {
dbDbPutValue, NULL,
dbDbScanFwdLink, doLocked
};
/*
* Process a record if its scan field is passive.
*/
long dbScanPassive(dbCommon *pfrom, dbCommon *pto)
{
/* if not passive we're done */
if (pto->scan != 0)
return 0;
return processTarget(pfrom, pto);
}
static long processTarget(dbCommon *psrc, dbCommon *pdst)
{
char context[40] = "";
int trace = dbAccessDebugPUTF && *dbLockSetAddrTrace(psrc);
long status;
epicsUInt8 pact = psrc->pact;
psrc->pact = TRUE;
if (psrc && psrc->ppn)
dbNotifyAdd(psrc, pdst);
if (trace && dbServerClient(context, sizeof(context))) {
/* No client, use thread name */
strncpy(context, epicsThreadGetNameSelf(), sizeof(context));
context[sizeof(context) - 1] = 0;
}
if (!pdst->pact) {
/* Normal propagation of PUTF from src to dst */
if (trace)
printf("%s: '%s' -> '%s' with PUTF=%u\n",
context, psrc->name, pdst->name, psrc->putf);
if (pdst->putf)
errlogPrintf("Warning: '%s.PUTF' found true with PACT false\n",
pdst->name);
pdst->putf = psrc->putf;
}
else if (psrc->putf) {
/* The dst record is busy (awaiting async reprocessing) and
* we were originally triggered by a call to dbPutField(),
* so we mark the dst record for reprocessing once the async
* completion is over.
*/
if (trace)
printf("%s: '%s' -> Active '%s', setting RPRO=1\n",
context, psrc->name, pdst->name);
pdst->putf = FALSE;
pdst->rpro = TRUE;
}
else {
/* The dst record is busy, but we weren't triggered by a call
* to dbPutField(). Do nothing.
*/
if (trace)
printf("%s: '%s' -> Active '%s', done\n",
context, psrc->name, pdst->name);
}
status = dbProcess(pdst);
psrc->pact = pact;
return status;
}
@@ -296,6 +296,17 @@ static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
scanOnceSetQueueSize(args[0].ival);
}
/* scanOnceQueueShow */
static const iocshArg scanOnceQueueShowArg0 = { "reset",iocshArgInt};
static const iocshArg * const scanOnceQueueShowArgs[1] =
{&scanOnceQueueShowArg0};
static const iocshFuncDef scanOnceQueueShowFuncDef =
{"scanOnceQueueShow",1,scanOnceQueueShowArgs};
static void scanOnceQueueShowCallFunc(const iocshArgBuf *args)
{
scanOnceQueueShow(args[0].ival);
}
/* scanppl */
static const iocshArg scanpplArg0 = { "rate",iocshArgDouble};
static const iocshArg * const scanpplArgs[1] = {&scanpplArg0};
@@ -335,6 +346,17 @@ static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
callbackSetQueueSize(args[0].ival);
}
/* callbackQueueShow */
static const iocshArg callbackQueueShowArg0 = { "reset", iocshArgInt};
static const iocshArg * const callbackQueueShowArgs[1] =
{&callbackQueueShowArg0};
static const iocshFuncDef callbackQueueShowFuncDef =
{"callbackQueueShow",1,callbackQueueShowArgs};
static void callbackQueueShowCallFunc(const iocshArgBuf *args)
{
callbackQueueShow(args[0].ival);
}
/* callbackParallelThreads */
static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgInt};
static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString};
@@ -441,12 +463,14 @@ void dbIocRegister(void)
iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc);
iocshRegister(&scanOnceSetQueueSizeFuncDef,scanOnceSetQueueSizeCallFunc);
iocshRegister(&scanOnceQueueShowFuncDef,scanOnceQueueShowCallFunc);
iocshRegister(&scanpplFuncDef,scanpplCallFunc);
iocshRegister(&scanpelFuncDef,scanpelCallFunc);
iocshRegister(&postEventFuncDef,postEventCallFunc);
iocshRegister(&scanpiolFuncDef,scanpiolCallFunc);
iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc);
iocshRegister(&callbackQueueShowFuncDef,callbackQueueShowCallFunc);
iocshRegister(&callbackParallelThreadsFuncDef,callbackParallelThreadsCallFunc);
/* Needed before callback system is initialized */
+107 -53
View File
@@ -2,7 +2,7 @@
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbJLink.c */
@@ -25,19 +25,33 @@
#include "dbLock.h"
#include "dbStaticLib.h"
#include "link.h"
#include "epicsExport.h"
#define IFDEBUG(n) if(parser->parse_debug)
epicsShareDef int dbJLinkDebug = 0;
epicsExportAddress(int, dbJLinkDebug);
#define IFDEBUG(n) if (dbJLinkDebug >= (n))
typedef struct parseContext {
jlink *pjlink;
jlink *product;
short dbfType;
short jsonDepth;
unsigned key_is_link:1;
unsigned parse_debug:1;
unsigned lset_debug:1;
} parseContext;
epicsShareDef const char *jlif_result_name[2] = {
"jlif_stop",
"jlif_continue",
};
epicsShareDef const char *jlif_key_result_name[5] = {
"jlif_key_stop",
"jlif_key_continue",
"jlif_key_child_inlink",
"jlif_key_child_outlink",
"jlif_key_child_fwdlink"
};
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
static int dbjl_return(parseContext *parser, jlif_result result) {
@@ -45,8 +59,8 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
IFDEBUG(10) {
printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
}
if (result == jlif_stop && pjlink) {
@@ -59,6 +73,9 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
pjlink->pif->free_jlink(pjlink);
}
IFDEBUG(10)
printf(" returning %d %s\n", result,
result == jlif_stop ? "*** STOP ***" : "Continue");
return result;
}
@@ -68,8 +85,8 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
IFDEBUG(10) {
printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
}
if (result == jlif_stop || pjlink->parseDepth > 0)
@@ -81,7 +98,6 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
} else if (parent->pif->end_child) {
parent->pif->end_child(parent, pjlink);
}
pjlink->debug = 0;
parser->pjlink = parent;
@@ -159,29 +175,46 @@ static int dbjl_start_map(void *ctx) {
if (!pjlink) {
IFDEBUG(10) {
printf("dbjl_start_map(NULL)\t");
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
parser->jsonDepth, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
parser->jsonDepth, parser->dbfType);
}
assert(parser->jsonDepth == 0);
parser->jsonDepth++;
parser->key_is_link = 1;
return jlif_continue; /* Opening '{' */
}
IFDEBUG(10) {
printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
}
pjlink->parseDepth++;
parser->jsonDepth++;
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
if (result == jlif_key_child_link) {
parser->key_is_link = 1;
switch (result) {
case jlif_key_child_inlink:
parser->dbfType = DBF_INLINK;
result = jlif_continue;
break;
case jlif_key_child_outlink:
parser->dbfType = DBF_OUTLINK;
result = jlif_continue;
break;
case jlif_key_child_fwdlink:
parser->dbfType = DBF_FWDLINK;
result = jlif_continue;
break;
case jlif_key_stop:
case jlif_key_continue:
break;
default:
errlogPrintf("dbJLinkInit: Bad return %d from '%s'::parse_start_map()\n",
result, pjlink->pif->name);
result = jlif_stop;
break;
}
IFDEBUG(10)
@@ -196,8 +229,9 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
char *link_name;
linkSup *linkSup;
jlif *pjlif;
jlink *child;
if (!parser->key_is_link) {
if (parser->dbfType == 0) {
if (!pjlink) {
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
(int) len, key);
@@ -207,8 +241,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
IFDEBUG(10) {
printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
pjlink->pif->name, pjlink, (int) len, key);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
}
assert(pjlink->parseDepth > 0);
@@ -219,8 +253,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
IFDEBUG(10) {
printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key);
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
parser->jsonDepth, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
parser->jsonDepth, parser->dbfType);
}
link_name = dbmfStrndup((const char *) key, len);
@@ -241,27 +275,35 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
return dbjl_return(parser, jlif_stop);
}
dbmfFree(link_name);
pjlink = pjlif->alloc_jlink(parser->dbfType);
if (!pjlink) {
errlogPrintf("dbJLinkInit: Out of memory\n");
child = pjlif->alloc_jlink(parser->dbfType);
if (!child) {
errlogPrintf("dbJLinkInit: Link type '%s' allocation failed. \n",
link_name);
dbmfFree(link_name);
return dbjl_return(parser, jlif_stop);
}
pjlink->pif = pjlif;
pjlink->parent = NULL;
pjlink->parseDepth = 0;
pjlink->debug = !!parser->lset_debug;
child->pif = pjlif;
child->parseDepth = 0;
child->debug = 0;
if (parser->pjlink) {
/* We're starting a child link, save its parent */
pjlink->parent = parser->pjlink;
child->parent = pjlink;
if (pjlink->pif->start_child)
pjlink->pif->start_child(pjlink, child);
}
parser->pjlink = pjlink;
parser->key_is_link = 0;
else
child->parent = NULL;
parser->pjlink = child;
parser->dbfType = 0;
dbmfFree(link_name);
IFDEBUG(8)
printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink);
printf("dbjl_map_key: New %s@%p\n", child ? child->pif->name : "", child);
return jlif_continue;
}
@@ -274,9 +316,9 @@ static int dbjl_end_map(void *ctx) {
IFDEBUG(10) {
printf("dbjl_end_map(%s@%p)\t",
pjlink ? pjlink->pif->name : "NULL", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0,
parser->key_is_link);
parser->dbfType);
}
parser->jsonDepth--;
@@ -298,8 +340,8 @@ static int dbjl_start_array(void *ctx) {
IFDEBUG(10) {
printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
}
assert(pjlink);
@@ -316,8 +358,8 @@ static int dbjl_end_array(void *ctx) {
IFDEBUG(10) {
printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
}
assert(pjlink);
@@ -335,7 +377,7 @@ static yajl_callbacks dbjl_callbacks = {
};
long dbJLinkParse(const char *json, size_t jlen, short dbfType,
jlink **ppjlink, unsigned opts)
jlink **ppjlink)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbjl_allocs;
@@ -347,17 +389,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
parser->product = NULL;
parser->dbfType = dbfType;
parser->jsonDepth = 0;
parser->key_is_link = 0;
parser->parse_debug = !!(opts&LINK_DEBUG_JPARSE);
parser->lset_debug = !!(opts&LINK_DEBUG_LSET);
IFDEBUG(10)
printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
(int) jlen, json, dbfType, ppjlink);
IFDEBUG(10)
printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n",
parser->jsonDepth, parser->key_is_link);
printf("dbJLinkInit: jsonDepth=%d, dbfType=%d\n",
parser->jsonDepth, parser->dbfType);
yajl_set_default_alloc_funcs(&dbjl_allocs);
yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser);
@@ -365,8 +404,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
if (ys == yajl_status_ok)
IFDEBUG(10)
printf("dbJLinkInit: yajl_parse() returned %d\n", ys);
if (ys == yajl_status_ok) {
ys = yajl_complete_parse(yh);
IFDEBUG(10)
printf("dbJLinkInit: yajl_complete_parse() returned %d\n", ys);
}
switch (ys) {
unsigned char *err;
@@ -378,6 +423,9 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
break;
case yajl_status_error:
IFDEBUG(10)
printf(" jsonDepth=%d, product=%p, pjlink=%p\n",
parser->jsonDepth, parser->product, parser->pjlink);
err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
errlogPrintf("dbJLinkInit: %s\n", err);
yajl_free_error(yh, err);
@@ -389,18 +437,24 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
}
yajl_free(yh);
IFDEBUG(10)
printf("dbJLinkInit: returning status=0x%lx\n\n",
status);
return status;
}
long dbJLinkInit(struct link *plink)
{
jlink *pjlink;
assert(plink);
pjlink = plink->value.json.jlink;
if (pjlink)
plink->lset = pjlink->pif->get_lset(pjlink);
if (plink->type == JSON_LINK) {
jlink *pjlink = plink->value.json.jlink;
if (pjlink)
plink->lset = pjlink->pif->get_lset(pjlink);
}
dbLinkOpen(plink);
return 0;
+20 -9
View File
@@ -2,7 +2,7 @@
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbJLink.h */
@@ -21,12 +21,16 @@ typedef enum {
jlif_continue = 1
} jlif_result;
epicsShareExtern const char *jlif_result_name[2];
typedef enum {
jlif_key_stop = jlif_stop,
jlif_key_continue = jlif_continue,
jlif_key_child_link
jlif_key_child_inlink, jlif_key_child_outlink, jlif_key_child_fwdlink
} jlif_key_result;
epicsShareExtern const char *jlif_key_result_name[5];
struct link;
struct lset;
struct jlif;
@@ -35,7 +39,7 @@ typedef struct jlink {
struct jlif *pif; /* Link methods */
struct jlink *parent; /* NULL for top-level links */
int parseDepth; /* Used by parser, unused afterwards */
unsigned debug:1; /* set by caller of jlif operations to request debug output to console */
unsigned debug:1; /* Set to request debug output to console */
/* Link types extend or embed this structure for private storage */
} jlink;
@@ -72,8 +76,9 @@ typedef struct jlif {
/* Optional, parser saw a string value */
jlif_key_result (*parse_start_map)(jlink *);
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_link
* to expect a child link next (extra key/value pairs may follow).
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_inlink,
* jlif_key_child_outlink, or jlif_key_child_fwdlink to expect a child
* link next (extra key/value pairs may follow)
*/
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
@@ -90,7 +95,8 @@ typedef struct jlif {
void (*end_child)(jlink *parent, jlink *child);
/* Optional, called with pointer to the new child link after
* parse_start_map() returned jlif_key_child_link */
* the child link has finished parsing successfully
*/
struct lset* (*get_lset)(const jlink *);
/* Required, return lset for this link instance */
@@ -98,7 +104,7 @@ typedef struct jlif {
void (*report)(const jlink *, int level, int indent);
/* Optional, print status information about this link instance, then
* if (level > 0) print a link identifier (at indent+2) and call
* dbJLinkReport(child, level-1, indent+4)
* dbJLinkReport(child, level-1, indent+4)
* for each child.
*/
@@ -107,13 +113,19 @@ typedef struct jlif {
* Stop immediately and return status if non-zero.
*/
void (*start_child)(jlink *parent, jlink *child);
/* Optional, called with pointer to the new child link after
* parse_start_map() returned a jlif_key_child_link value and
* the child link has been allocated (but not parsed yet)
*/
/* Link types must NOT extend this table with their own routines,
* this space is reserved for extensions to the jlink interface.
*/
} jlif;
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
jlink **ppjlink, unsigned opts);
jlink **ppjlink);
epicsShareFunc long dbJLinkInit(struct link *plink);
epicsShareFunc void dbJLinkFree(jlink *);
@@ -130,4 +142,3 @@ epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx);
#endif
#endif /* INC_dbJLink_H */
+12 -1
View File
@@ -265,8 +265,19 @@ int dbIsLinkConnected(const struct link *plink)
{
lset *plset = plink->lset;
if (!plset || !plset->isConnected)
if (!plset)
return FALSE;
if (!plset->isVolatile)
return TRUE;
if (!plset->isConnected) {
struct dbCommon *precord = plink->precord;
errlogPrintf("dbLink: Link type for '%s.%s' is volatile but has no"
" lset::isConnected() method\n",
precord->name, dbLinkFieldName(plink));
return FALSE;
}
return plset->isConnected(plink);
}
+288 -5
View File
@@ -27,54 +27,337 @@ extern "C" {
struct dbLocker;
/** @file dbLink.h
* @brief Link Support API
*
* Link support run-time API, all link types provide an lset which is used by
* the IOC database to control and operate the link. This file also declares the
* dbLink routines that IOC, record and device code can call to perform link
* operations.
*/
/** @brief callback routine for locked link operations
*
* Called by the lset::doLocked method to permit multiple link operations
* while the link instance is locked.
*
* @param plink the link
* @param priv context for the callback routine
*/
typedef long (*dbLinkUserCallback)(struct link *plink, void *priv);
/** @brief Link Support Entry Table
*
* This structure provides information about and methods for an individual link
* type. A pointer to this structure is included in every link's lset field, and
* is used to perform operations on the link. For JSON links the pointer is
* obtained by calling pjlink->pif->get_lset() at link initialization time,
* immediately before calling dbLinkOpen() to activate the link.
*/
typedef struct lset {
/* Characteristics of the link type */
/** @brief link constancy
*
* 1 means this is a constant link type whose value doesn't change.
* The link's value will be obtained using one of the methods loadScalar,
* loadLS or loadArray.
*/
const unsigned isConstant:1;
/** @brief link volatility
*
* 0 means the link is always connected.
*/
const unsigned isVolatile:1;
/* Activation */
/** @brief activate link
*
* Optional, called whenever a JSON link is initialized or added at runtime.
*
* @param plink the link
*/
void (*openLink)(struct link *plink);
/* Destructor */
/** @brief deactivate link
*
* Optional, called whenever a link address is changed at runtime, or the
* IOC is shutting down.
*
* @param locker
* @param plink the link
*/
void (*removeLink)(struct dbLocker *locker, struct link *plink);
/* Const init, data type hinting */
/* Constant link initialization and data type hinting */
/** @brief load constant scalar from link type
*
* Usually called during IOC initialization, constant link types must copy a
* scalar value of the indicated data type to the buffer provided and return
* 0. A non-constant link type can use this method call as an early hint
* that subsequent calls to dbGetLink() will request scalar data of the
* indicated type, although the type might change.
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @returns 0 if a value was loaded, non-zero otherwise
*/
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
/** @brief load constant long string from link type
*
* Usually called during IOC initialization, constant link types must copy a
* nil-terminated string up to size characters long to the buffer provided,
* and write the length of that string to the plen location. A non-constant
* link type can use this as an early hint that subsequent calls to
* dbGetLink() will request long string data, although this might change.
*
* @param plink the link
* @param pbuffer where to put the string
* @param size length of pbuffer in chars
* @param plen set to number of chars written
* @returns status value
*/
long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen);
/** @brief load constant array from link type
*
* Usually called during IOC initialization, constant link types must copy
* an array value of the indicated data type to the buffer provided, update
* the pnRequest location to indicate how many elements were loaded, and
* return 0. A non-constant link type can use this method call as an early
* hint that subsequent calls to dbGetLink() will request array data of the
* indicated type and max size, although the request might change.
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param pnRequest Max elements on entry, actual on exit
* @returns 0 if elements were loaded, non-zero otherwise
*/
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest);
/* Metadata */
/** @brief return link connection status
*
* Return an indication whether this link is connected or not. This routine
* is polled by the calcout and some external record types. Not required for
* non-volatile link types, which are by definition always connected.
*
* @param plink the link
* @returns 1 if connected, 0 if disconnected
*/
int (*isConnected)(const struct link *plink);
/** @brief get data type of link destination
*
* Called on both input and output links by long string support code to
* decide whether to use DBR_CHAR/DBR_UCHAR or DBR_STRING for a subsequent
* dbPutLink() or dbGetLink() call. Optional, but if not provided long
* strings cannot be transported over this link type, and no warning or
* error will appear to explain why. Not required for constant link types.
*
* @param plink the link
* @returns DBF_* type code, or -1 on error/disconnected link
*/
int (*getDBFtype)(const struct link *plink);
long (*getElements)(const struct link *plink, long *nelements);
/* Get data */
/** @brief get array size of an input link
*
* Called on input links by the compress record type for memory allocation
* purposes, before using the dbGetLink() routine to fetch the actual
* array data.
*
* @param plink the link
* @param pnElements where to put the answer
* @returns status value
*/
long (*getElements)(const struct link *plink, long *pnElements);
/** @brief get value from an input link
*
* Called to fetch data from the link, which must be converted into the
* given data type and placed in the buffer indicated. The actual number of
* elements retrieved should be updated in the pnRequest location. If this
* method returns an error status value, the link's record will be placed
* into an Invalid severity / Link Alarm state by the dbGetLink() routine
* that calls this method.
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param pnRequest max elements on entry, actual on exit
* @returns status value
*/
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest);
/** @brief get the control range for an output link
*
* Called to fetch the control range for the link target, as a pair of
* double values for the lowest and highest values that the target will
* accept. This method is not used at all by the IOC or built-in record
* types, although external record types may require it.
*
* @param plink the link
* @param lo lowest accepted value
* @param hi highest accepted value
* @returns status value
*/
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
/** @brief get the display range from an input link
*
* Called to fetch the display range for an input link target, as a pair of
* double values for the lowest and highest values that the PV expects to
* return. This method is used by several built-in record types to obtain
* the display range for their generic input links.
*
* @param plink the link
* @param lo lowest accepted value
* @param hi highest accepted value
* @returns status value
*/
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
/** @brief get the alarm limits from an input link
*
* Called to fetch the alarm limits for an input link target, as four
* double values for the warning and alarm levels that the PV checks its
* value against. This method is used by several built-in record types to
* obtain the alarm limits for their generic input links.
*
* @param plink the link
* @param lolo low alarm value
* @param lo low warning value
* @param hi high warning value
* @param hihi high alarm value
* @returns status value
*/
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
double *hi, double *hihi);
/** @brief get the precision from an input link
*
* Called to fetch the precision for an input link target. This method is
* used by several built-in record types to obtain the precision for their
* generic input links.
*
* @param plink the link
* @param precision where to put the answer
* @returns status value
*/
long (*getPrecision)(const struct link *plink, short *precision);
/** @brief get the units string from an input link
*
* Called to fetch the units string for an input link target. This method is
* used by several built-in record types to obtain the units string for
* their generic input links.
*
* @param plink the link
* @param units where to put the answer
* @param unitsSize buffer size for the answer
* @returns status value
*/
long (*getUnits)(const struct link *plink, char *units, int unitsSize);
/** @brief get the alarm condition from an input link
*
* Called to fetch the alarm status and severity for an input link target.
* Either status or severity pointers may be NULL when that value is not
* needed by the calling code. This method is used by several built-in
* record types to obtain the alarm condition for their generic input links.
*
* @param plink the link
* @param status where to put the alarm status (or NULL)
* @param severity where to put the severity (or NULL)
* @returns status value
*/
long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity);
/** @brief get the time-stamp from an input link
*
* Called to fetch the time-stamp for an input link target. This method is
* used by many built-in device supports to obtain the precision for their
* generic input links.
*
* @param plink the link
* @param pstamp where to put the answer
* @returns status value
*/
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
/* Put data */
/** @brief put a value to an output link
*
* Called to send nRequest elements of type dbrType found at pbuffer to an
* output link target.
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param nRequest number of elements to send
* @returns status value
*/
long (*putValue)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
/** @brief put a value to an output link with asynchronous completion
*
* Called to send nRequest elements of type dbrType found at pbuffer to an
* output link target. If the return status is zero, the link type will
* later indicate the put has completed by calling dbLinkAsyncComplete()
* from a background thread, which will be used to continue the record
* process operation from where it left off.
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param nRequest number of elements to send
* @returns status value
*/
long (*putAsync)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
/* Process */
/** @brief trigger processing of a forward link
*
* Called to trigger processing of the record pointed to by a forward link.
* This routine is optional, but if not provided no warning message will be
* shown when called by dbScanFwdLink(). JSON link types that do not support
* this operation should return NULL from their jlif::alloc_jlink() method
* if it gets called with a dbfType of DBF_FWDLINK.
*
* @param plink the link
*/
void (*scanForward)(struct link *plink);
/* Atomicity */
/** @brief execute a callback routine with link locked
*
* Called on an input link when multiple link attributes need to be fetched
* in an atomic fashion. The link type must call the callback routine and
* prevent any background I/O from updating any cached link data until that
* routine returns. This method is used by most input device support to
* fetch the timestamp along with the value when the record's TSE field is
* set to epicsTimeEventDeviceTime.
*
* @param plink the link
* @param rtn routine to execute
* @returns status value
*/
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
} lset;
@@ -99,7 +382,7 @@ epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
long *pnRequest);
epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
epicsShareFunc long dbGetNelements(const struct link *plink, long *pnElements);
epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
epicsShareFunc long dbTryGetLink(struct link *, short dbrType, void *pbuffer,
+2
View File
@@ -13,6 +13,8 @@
#ifndef INCdbLockh
#define INCdbLockh
#include <stddef.h>
#include "ellLib.h"
#include "shareLib.h"
+37
View File
@@ -24,6 +24,7 @@
#include "cantProceed.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsAtomic.h"
#include "epicsEvent.h"
#include "epicsMutex.h"
#include "epicsPrint.h"
@@ -63,6 +64,7 @@ static volatile enum ctl scanCtl;
static int onceQueueSize = 1000;
static epicsEventId onceSem;
static epicsRingBytesId onceQ;
static int onceQOverruns = 0;
static epicsThreadId onceTaskId;
static void *exitOnce;
@@ -676,6 +678,7 @@ int scanOnceCallback(struct dbCommon *precord, once_complete cb, void *usr)
if (!pushOK) {
if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n");
newOverflow = FALSE;
epicsAtomicIncrIntT(&onceQOverruns);
} else {
newOverflow = TRUE;
}
@@ -722,6 +725,40 @@ int scanOnceSetQueueSize(int size)
return 0;
}
int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result)
{
int ret;
if (!onceQ) return -1;
if (result) {
result->size = epicsRingBytesSize(onceQ) / sizeof(onceEntry);
result->numUsed = epicsRingBytesUsedBytes(onceQ) / sizeof(onceEntry);
result->maxUsed = epicsRingBytesHighWaterMark(onceQ) / sizeof(onceEntry);
result->numOverflow = epicsAtomicGetIntT(&onceQOverruns);
ret = 0;
} else {
ret = -2;
}
if (reset) {
epicsRingBytesResetHighWaterMark(onceQ);
}
return ret;
}
void scanOnceQueueShow(const int reset)
{
scanOnceQueueStats stats;
if (scanOnceQueueStatus(reset, &stats) == -1) {
fprintf(stderr, "scanOnce system not initialized, yet. Please run "
"iocInit before using this command.\n");
} else {
double qusage = 100.0 * stats.numUsed / stats.size;
printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n");
printf("%8s %15d %10d %6d %6.1f %11d\n", "scanOnce", stats.maxUsed,
stats.numUsed, stats.size, qusage,
epicsAtomicGetIntT(&onceQOverruns));
}
}
static void initOnce(void)
{
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
+11 -3
View File
@@ -19,6 +19,7 @@
#include "menuScan.h"
#include "shareLib.h"
#include "compilerDependencies.h"
#include "devSup.h"
#ifdef __cplusplus
extern "C" {
@@ -33,9 +34,7 @@ extern "C" {
#define MIN_PHASE SHRT_MIN
/*definitions for I/O Interrupt Scanning */
struct ioscan_head;
typedef struct ioscan_head *IOSCANPVT;
/* IOSCANPVT now defined in devSup.h */
typedef struct event_list *EVENTPVT;
struct dbCommon;
@@ -43,6 +42,13 @@ struct dbCommon;
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
typedef void (*once_complete)(void *usr, struct dbCommon*);
typedef struct scanOnceQueueStats {
int size;
int numUsed;
int maxUsed;
int numOverflow;
} scanOnceQueueStats;
epicsShareFunc long scanInit(void);
epicsShareFunc void scanRun(void);
epicsShareFunc void scanPause(void);
@@ -58,6 +64,8 @@ epicsShareFunc double scanPeriod(int scan);
epicsShareFunc int scanOnce(struct dbCommon *);
epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
epicsShareFunc int scanOnceSetQueueSize(int size);
epicsShareFunc int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result);
epicsShareFunc void scanOnceQueueShow(const int reset);
/*print periodic lists*/
epicsShareFunc int scanppl(double rate);
+10 -4
View File
@@ -12,6 +12,7 @@
#include <stddef.h>
#include <string.h>
#include "dbDefs.h"
#include "ellLib.h"
#include "envDefs.h"
#include "epicsStdio.h"
@@ -29,6 +30,7 @@ static char *stateNames[] = {
int dbRegisterServer(dbServer *psrv)
{
const char * ignore = envGetConfigParamPtr(&EPICS_IOC_IGNORE_SERVERS);
ELLNODE *node;
if (!psrv || !psrv->name || state != registering)
return -1;
@@ -55,10 +57,14 @@ int dbRegisterServer(dbServer *psrv)
}
}
if (ellNext(&psrv->node) || ellLast(&serverList) == &psrv->node) {
fprintf(stderr, "dbRegisterServer: '%s' registered twice?\n",
psrv->name);
return -1;
for(node=ellFirst(&serverList); node; node = ellNext(node)) {
dbServer *cur = CONTAINER(node, dbServer, node);
if(cur==psrv) {
return 0; /* already registered identically. */
} else if(strcmp(cur->name, psrv->name)==0) {
fprintf(stderr, "dbRegisterServer: Can't redefine '%s'.\n", cur->name);
return -1;
}
}
ellAdd(&serverList, &psrv->node);
+9
View File
@@ -15,6 +15,10 @@
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @file dbState.h
* @brief Generic IOC state facility
*
@@ -89,4 +93,9 @@ epicsShareFunc void dbStateShow(dbStateId id, unsigned int level);
*/
epicsShareFunc void dbStateShowAll(unsigned int level);
#ifdef __cplusplus
}
#endif
#endif // INCdbStateH
@@ -1,11 +1,48 @@
#*************************************************************************
# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
# Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Menu menuScan
This menu is used for the C<SCAN> field of all record types.
The set of periodic scan rates may be modified for an individual IOC by
copying the F<menuScan.dbd> file from Base into the IOC's source
directory and changing it to contain the desired scan rates.
The scan periods are extracted from the choice strings at runtime, which
must be expressed as a number with any of the following units appended:
=over 4
second
seconds
minute
minutes
hour
hours
Hertz
Hz
=back
At IOC start-up a separate scan thread will be created for each period,
with thread priority increasing further down the list, so faster periods
should appear after slower ones.
Scan rates that cannot be achieved will generate a warning message from
the C<iocInit> command.
=menu menuScan
=cut
menu(menuScan) {
choice(menuScanPassive,"Passive")
choice(menuScanEvent,"Event")
+4
View File
@@ -19,6 +19,7 @@
#include "alarm.h"
#include "dbDefs.h"
#include "alarm.h"
#include "epicsMath.h"
#include "epicsPrint.h"
#include "epicsStdlib.h"
@@ -180,6 +181,9 @@ unsigned short recGblResetAlarms(void *precord)
epicsEnum16 val_mask = 0;
epicsEnum16 stat_mask = 0;
if (new_sevr > INVALID_ALARM)
new_sevr = INVALID_ALARM;
pdbc->stat = new_stat;
pdbc->sevr = new_sevr;
pdbc->nsta = 0;
+120 -169
View File
@@ -79,16 +79,6 @@ epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = {
{"VXI_IO",VXI_IO}
};
static int mapDBFtoDCT[DBF_NOACCESS+1] = {
DCT_STRING,
DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,
DCT_REAL,DCT_REAL,
DCT_INTEGER,
DCT_MENU,
DCT_MENUFORM,
DCT_INLINK,DCT_OUTLINK,DCT_FWDLINK,
DCT_NOACCESS};
/*forward references for private routines*/
static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
EPICS_PRINTF_STYLE(2,3);
@@ -166,38 +156,6 @@ void dbFreePath(DBBASE *pdbbase)
}
static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess)
{
char message[200];
char *pmessage=&message[0];
dbRecordNode *precnode = pdbentry->precnode;
dbFldDes *pflddes = pdbentry->pflddes;
char *pname = NULL;
*pmessage=0;
if(pdbentry->precordType) pname = pdbentry->precordType->name;
if(pname) {
strcat(pmessage,"RecordType:");
strcat(pmessage,pname);
}
if(precnode){
if (dbIsAlias(pdbentry))
strcat(pmessage," Record Alias:");
else
strcat(pmessage," Record:");
strcat(pmessage,(char *)precnode->precord);
}
if(pflddes) {
char *pstr=pflddes->name;
strcat(pmessage," Field:");
strcat(pmessage,pstr);
}
strcat(pmessage,"\n");
strcat(pmessage,mess);
errMessage(status,pmessage);
}
static void zeroDbentry(DBENTRY *pdbentry)
{
/*NOTE that pdbbase and message MUST NOT be set to NULL*/
@@ -1398,19 +1356,6 @@ long dbNextField(DBENTRY *pdbentry,int dctonly)
}
}
int dbGetFieldType(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
long status;
if(!pflddes){
status = S_dbLib_flddesNotFound;
entryErrMessage(pdbentry,status,"dbGetFieldType");
return(status);
}
return(mapDBFtoDCT[pflddes->field_type]);
}
int dbGetNFields(DBENTRY *pdbentry,int dctonly)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -2241,7 +2186,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
if(!plink->text)
continue;
if(dbParseLink(plink->text, pflddes->field_type, &link_info, 0)!=0) {
if(dbParseLink(plink->text, pflddes->field_type, &link_info)!=0) {
/* This was already parsed once when ->text was set.
* Any syntax error messages were printed at that time.
*/
@@ -2270,7 +2215,7 @@ void dbFreeLinkInfo(dbLinkInfo *pinfo)
pinfo->target = NULL;
}
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
{
char *pstr;
size_t len;
@@ -2306,7 +2251,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
if (dbJLinkParse(str, len, ftype, &pinfo->jlink, opts))
if (dbJLinkParse(str, len, ftype, &pinfo->jlink))
goto fail;
pinfo->ltype = JSON_LINK;
@@ -2353,9 +2298,13 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
else if (strcmp(pinfo->hwid, "VS")==0) pinfo->ltype = VXI_IO;
else goto fail;
if (parm && pinfo->ltype != RF_IO) {
/* move parm string to beginning of buffer */
memmove(pinfo->target, parm, len + 1);
if (pinfo->ltype != RF_IO) {
if (!parm) {
pinfo->target[0] = '\0';
} else {
/* move parm string to beginning of buffer */
memmove(pinfo->target, parm, len + 1);
}
} else if (!parm && pinfo->ltype == RF_IO) {
/* RF_IO, the string isn't needed at all */
free(pinfo->target);
@@ -2641,21 +2590,8 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
case DBF_FWDLINK: {
dbLinkInfo link_info;
DBLINK *plink = (DBLINK *)pfield;
DBENTRY infoentry;
unsigned opts = 0;
if(pdbentry->precnode && ellCount(&pdbentry->precnode->infoList)) {
dbCopyEntryContents(pdbentry, &infoentry);
if(dbFindInfo(&infoentry, "base:lsetDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
opts |= LINK_DEBUG_LSET;
if(dbFindInfo(&infoentry, "base:jlinkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
opts |= LINK_DEBUG_JPARSE;
dbFinishEntry(&infoentry);
}
status = dbParseLink(pstring, pflddes->field_type, &link_info, opts);
status = dbParseLink(pstring, pflddes->field_type, &link_info);
if (status) break;
if (plink->type==CONSTANT && plink->value.constantStr==NULL) {
@@ -3225,48 +3161,21 @@ int dbGetNLinks(DBENTRY *pdbentry)
return((int)precordType->no_links);
}
long dbGetLinkField(DBENTRY *pdbentry,int index)
long dbGetLinkField(DBENTRY *pdbentry, int index)
{
dbRecordType *precordType = pdbentry->precordType;
dbFldDes *pflddes;
dbRecordType *precordType = pdbentry->precordType;
dbFldDes *pflddes;
if (!precordType)
return S_dbLib_recordTypeNotFound;
if (index < 0 || index >= precordType->no_links)
return S_dbLib_badLink;
if(!precordType) return(S_dbLib_recordTypeNotFound);
if(index<0 || index>=precordType->no_links) return(S_dbLib_badLink);
pdbentry->indfield = precordType->link_ind[index];
pdbentry->pflddes = pflddes = precordType->papFldDes[pdbentry->indfield];
dbGetFieldAddress(pdbentry);
return(0);
}
int dbGetLinkType(DBENTRY *pdbentry)
{
dbFldDes *pflddes;
DBLINK *plink;
int field_type;
dbGetFieldAddress(pdbentry);
pflddes = pdbentry->pflddes;
if(!pflddes) return(-1);
plink = (DBLINK *)pdbentry->pfield;
if(!plink) return(-1);
field_type = pflddes->field_type;
switch (field_type) {
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_FWDLINK:
switch(plink->type) {
case CONSTANT:
return(DCT_LINK_CONSTANT);
case PV_LINK:
case PN_LINK:
case DB_LINK:
case CA_LINK:
return(DCT_LINK_PV);
default:
return(DCT_LINK_FORM);
}
}
return(-1);
return 0;
}
void dbDumpPath(DBBASE *pdbbase)
@@ -3565,68 +3474,110 @@ void dbDumpBreaktable(DBBASE *pdbbase,const char *name)
return;
}
static char *bus[VXI_IO+1] = {"","","VME","CAMAC","AB",
"GPIB","BITBUS","","","","","","INST","BBGPIB","VXI"};
void dbReportDeviceConfig(dbBase *pdbbase,FILE *report)
static char *bus[LINK_NTYPES] = {
"", /* CONSTANT */
NULL, /* PV_LINK */
"VME",
"CAMAC",
"AB",
"GPIB",
"BITBUS",
NULL, /* MACRO_LINK */
NULL, /* JSON_LINK */
NULL, /* PN_LINK */
NULL, /* DB_LINK */
NULL, /* CA_LINK */
"INST",
"BBGPIB",
"VXI"
};
void dbReportDeviceConfig(dbBase *pdbbase, FILE *report)
{
DBENTRY dbentry;
DBENTRY *pdbentry=&dbentry;
long status;
char linkValue[messagesize];
char dtypValue[50];
char cvtValue[40];
int ilink,nlinks;
struct link *plink;
int linkType;
FILE *stream = (report==0) ? stdout : report;
DBENTRY dbentry, *pdbentry = &dbentry;
long status;
FILE *stream = report ? report : stdout;
if(!pdbbase) {
fprintf(stderr,"pdbbase not specified\n");
return;
if (!pdbbase) {
fprintf(stderr, "dbReportDeviceConfig: pdbbase not specified\n");
return;
}
dbInitEntry(pdbbase,pdbentry);
status = dbFirstRecordType(pdbentry);
while(!status) {
status = dbFirstRecord(pdbentry);
while(!status) {
nlinks = dbGetNLinks(pdbentry);
for(ilink=0; ilink<nlinks; ilink++) {
status = dbGetLinkField(pdbentry,ilink);
if(status || dbGetLinkType(pdbentry)!=DCT_LINK_FORM) continue;
plink = pdbentry->pfield;
linkType = plink->type;
if(bus[linkType][0]==0) continue;
strncpy(linkValue, dbGetString(pdbentry), NELEMENTS(linkValue)-1);
linkValue[NELEMENTS(linkValue)-1] = '\0';
status = dbFindField(pdbentry,"DTYP");
if(status) break;
strcpy(dtypValue,dbGetString(pdbentry));
status = dbFindField(pdbentry,"LINR");
if(status) {
cvtValue[0] = 0;
} else {
if(strcmp(dbGetString(pdbentry),"LINEAR")!=0) {
cvtValue[0] = 0;
} else {
strcpy(cvtValue,"cvt(");
status = dbFindField(pdbentry,"EGUL");
if(!status) strcat(cvtValue,dbGetString(pdbentry));
status = dbFindField(pdbentry,"EGUF");
if(!status) {
strcat(cvtValue,",");
strcat(cvtValue,dbGetString(pdbentry));
}
strcat(cvtValue,")");
}
}
fprintf(stream,"%-8s %-20s %-20s %-20s %-s\n",
bus[linkType],linkValue,dtypValue,
dbGetRecordName(pdbentry),cvtValue);
break;
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
while (!status) {
const int nlinks = dbGetNLinks(pdbentry);
status = dbFirstRecord(pdbentry);
while (!status) {
int ilink;
for (ilink=0; ilink<nlinks; ilink++) {
char linkValue[messagesize];
char dtypValue[50];
char cvtValue[40];
struct link *plink;
int linkType;
status = dbGetLinkField(pdbentry, ilink);
if (status)
continue;
plink = pdbentry->pfield;
linkType = plink->type;
if (plink->text) { /* Not yet parsed */
dbLinkInfo linfo;
if (dbParseLink(plink->text, pdbentry->pflddes->field_type, &linfo))
continue;
linkType = linfo.ltype;
if (linkType && bus[linkType])
strncpy(linkValue, plink->text, messagesize-1);
dbFreeLinkInfo(&linfo);
}
else {
strncpy(linkValue, dbGetString(pdbentry), messagesize-1);
}
if (!linkType || !bus[linkType])
continue;
linkValue[messagesize-1] = '\0';
status = dbFindField(pdbentry, "DTYP");
if (status)
break; /* Next record type */
strcpy(dtypValue, dbGetString(pdbentry));
status = dbFindField(pdbentry, "LINR");
if (status) {
cvtValue[0] = 0;
}
else {
if (strcmp(dbGetString(pdbentry), "LINEAR") != 0) {
cvtValue[0] = 0;
}
else {
strcpy(cvtValue,"cvt(");
status = dbFindField(pdbentry, "EGUL");
if (!status)
strcat(cvtValue, dbGetString(pdbentry));
status = dbFindField(pdbentry, "EGUF");
if (!status) {
strcat(cvtValue, ",");
strcat(cvtValue, dbGetString(pdbentry));
}
strcat(cvtValue, ")");
}
}
fprintf(stream,"%-8s %-20s %-20s %-20s %-s\n",
bus[linkType], linkValue, dtypValue,
dbGetRecordName(pdbentry), cvtValue);
break;
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
}
dbFinishEntry(pdbentry);
finishOutstream(stream);
@@ -28,25 +28,9 @@
extern "C" {
#endif
/*Field types as seen by static database access clients*/
#define DCT_STRING 0
#define DCT_INTEGER 1
#define DCT_REAL 2
#define DCT_MENU 3
#define DCT_MENUFORM 4
#define DCT_INLINK 5
#define DCT_OUTLINK 6
#define DCT_FWDLINK 7
#define DCT_NOACCESS 8
/*Link types as seen by static database access clients*/
#define DCT_LINK_CONSTANT 0
#define DCT_LINK_FORM 1
#define DCT_LINK_PV 2
typedef dbBase DBBASE;
typedef struct{
typedef struct dbEntry {
DBBASE *pdbbase;
dbRecordType *precordType;
dbFldDes *pflddes;
@@ -57,9 +41,6 @@ typedef struct{
short indfield;
} DBENTRY;
struct dbAddr;
struct dbCommon;
/* Static database access routines*/
epicsShareFunc DBBASE * dbAllocBase(void);
epicsShareFunc void dbFreeBase(DBBASE *pdbbase);
@@ -68,18 +49,6 @@ epicsShareFunc void dbFreeEntry(DBENTRY *pdbentry);
epicsShareFunc void dbInitEntry(DBBASE *pdbbase,
DBENTRY *pdbentry);
/** Initialize DBENTRY from a valid dbAddr*.
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias()
*/
epicsShareFunc void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry);
/** Initialize DBENTRY from a valid record (dbCommon*).
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias() when no field is specified.
*/
epicsShareFunc void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry);
epicsShareFunc void dbFinishEntry(DBENTRY *pdbentry);
epicsShareFunc DBENTRY * dbCopyEntry(DBENTRY *pdbentry);
epicsShareFunc void dbCopyEntryContents(DBENTRY *pfrom,
@@ -139,7 +108,6 @@ epicsShareFunc long dbGetAttributePart(DBENTRY *pdbentry,
epicsShareFunc long dbFirstField(DBENTRY *pdbentry, int dctonly);
epicsShareFunc long dbNextField(DBENTRY *pdbentry, int dctonly);
epicsShareFunc int dbGetFieldType(DBENTRY *pdbentry);
epicsShareFunc int dbGetNFields(DBENTRY *pdbentry, int dctonly);
epicsShareFunc char * dbGetFieldName(DBENTRY *pdbentry);
epicsShareFunc char * dbGetDefault(DBENTRY *pdbentry);
@@ -231,7 +199,6 @@ epicsShareFunc linkSup * dbFindLinkSup(dbBase *pdbbase,
epicsShareFunc int dbGetNLinks(DBENTRY *pdbentry);
epicsShareFunc long dbGetLinkField(DBENTRY *pdbentry, int index);
epicsShareFunc int dbGetLinkType(DBENTRY *pdbentry);
/* Dump routines */
epicsShareFunc void dbDumpPath(DBBASE *pdbbase);
@@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbStaticPvt.h */
/*
@@ -59,13 +59,10 @@ typedef struct dbLinkInfo {
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
#define LINK_DEBUG_LSET 1
#define LINK_DEBUG_JPARSE 2
/* Parse link string. no record locks needed.
* on success caller must free pinfo->target
*/
epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts);
epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo);
/* Check if link type allow the parsed link value pinfo
* to be assigned to the given link.
* Record containing plink must be locked.
+121 -6
View File
@@ -6,7 +6,11 @@
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* devSup.h Device Support */
/** @file devSup.h
*
* @brief Device support routines
*/
/*
* Author: Marty Kraimer
* Date: 6-1-90
@@ -21,6 +25,111 @@
/* structures defined elsewhere */
struct dbCommon;
struct devSup;
typedef struct ioscan_head *IOSCANPVT;
struct link; /* aka DBLINK */
/** Type safe version of 'struct dset'
*
* Recommended usage:
*
* In Makefile:
@code
USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET
@endcode
*
* In C source file:
@code
#include <devSup.h>
#include <dbScan.h> // For IOCSCANPVT
...
#include <epicsExport.h> // defines epicsExportSharedSymbols
...
static long init_record(dbCommon *prec);
static long get_iointr_info(int detach, dbCommon *prec, IOCSCANPVT* pscan);
static long longin_read(longinRecord *prec);
const struct {
dset common;
long (*read)(longinRecord *prec);
} devLiDevName = {
{
5, // 4 from dset + 1 from longinRecord
NULL,
NULL,
&init_record,
&get_iointr_info
},
&longin_read
};
epicsExportAddress(dset, devLiDevName);
@endcode
*/
typedef struct typed_dset {
/** Number of function pointers which follow.
* The value depends on the recordtype, but must be >=4 */
long number;
/** Called from dbior() */
long (*report)(int lvl);
/** Called twice during iocInit().
* First with @a after = 0 before init_record() or array field allocation.
* Again with @a after = 1 after init_record() has finished.
*/
long (*init)(int after);
/** Called once per record instance */
long (*init_record)(struct dbCommon *prec);
/** Called when SCAN="I/O Intr" on startup, or after SCAN is changed.
*
* Caller must assign the third arguement (IOCSCANPVT*). eg.
@code
struct mpvt {
IOSCANPVT drvlist;
};
...
// init_record() routine calls
scanIoInit(&pvt->drvlist);
...
static long get_ioint_info(int detach, struct dbCommon *prec, IOCSCANPVT* pscan) {
if(prec->dpvt)
*pscan = &((mypvt*)prec->dpvt)->drvlist;
@endcode
*
* When a particular record instance can/will only used a single scan list,
* the @a detach argument can be ignored.
*
* If this is not the case, then the following should be noted.
* + get_ioint_info() is called with @a detach = 0 to fetch the scan list to
* which this record will be added.
* + get_ioint_info() is called later with @a detach = 1 to fetch the scan
* list from which this record should be removed.
* + Calls will be balanced, so a call with @a detach = 0 will be followed
* by one with @a detach = 1.
*
* @note get_ioint_info() will be called during IOC shutdown if the
* dsxt::del_record() extended callback is defined. (from 3.15.0.1)
*/
long (*get_ioint_info)(int detach, struct dbCommon *prec, IOSCANPVT* pscan);
/* Any further functions are specified by the record type. */
} typed_dset;
/** Device support extension table.
*
* Optional routines to allow run-time address modifications to be communicated
* to device support, which must register a struct dsxt by calling devExtend()
* from its init() routine.
*/
typedef struct dsxt {
/** Optional, called to offer device support a new record to control.
*
* Routine may return a non-zero error code to refuse record.
*/
long (*add_record)(struct dbCommon *precord);
/** Optional, called to remove record from device support control.
*
* Routine return a non-zero error code to refuse record removal.
*/
long (*del_record)(struct dbCommon *precord);
/* Only future Base releases may extend this table. */
} dsxt;
#ifdef __cplusplus
extern "C" {
@@ -29,6 +138,8 @@ extern "C" {
typedef long (*DEVSUPFUN)(); /* ptr to device support function*/
#endif
#ifndef USE_TYPED_DSET
typedef struct dset { /* device support entry table */
long number; /*number of support routines*/
DEVSUPFUN report; /*print report*/
@@ -38,11 +149,15 @@ typedef struct dset { /* device support entry table */
/*other functions are record dependent*/
} dset;
typedef struct dsxt { /* device support extension table */
long (*add_record)(struct dbCommon *precord);
long (*del_record)(struct dbCommon *precord);
/* Recordtypes are *not* allowed to extend this table */
} dsxt;
#else
typedef typed_dset dset;
#endif /* USE_TYPED_DSET */
/** Fetch INP or OUT link (or NULL if record type has neither).
*
* Recommended for use in device support init_record()
*/
epicsShareFunc struct link* dbGetDevLink(struct dbCommon* prec);
epicsShareExtern dsxt devSoft_DSXT; /* Allow anything table */
+33 -8
View File
@@ -6,7 +6,10 @@
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* drvSup.h Driver Support */
/** @file drvSup.h
*
* @brief Driver support routines.
*/
/*
* Author: Marty Kraimer
@@ -18,16 +21,38 @@
#include "errMdef.h"
typedef long (*DRVSUPFUN) (); /* ptr to driver support function*/
/** Driver entry table */
typedef struct typed_drvet {
/** Number of function pointers which follow. Must be >=2 */
long number;
/** Called from dbior() */
long (*report)(int lvl);
/** Called during iocInit() */
long (*init)(void);
/* Any further functions are driver-specific */
} typed_drvet;
#ifdef USE_TYPED_DRVET
typedef typed_drvet drvet;
#else
/* These interfaces may eventually get deprecated */
typedef long (*DRVSUPFUN) (); /* ptr to driver support function */
typedef struct drvet { /* driver entry table */
long number; /* number of support routines */
DRVSUPFUN report; /* print report */
DRVSUPFUN init; /* init support */
/* Any further functions are driver-specific */
} drvet;
typedef struct drvet { /* driver entry table */
long number; /*number of support routines*/
DRVSUPFUN report; /*print report*/
DRVSUPFUN init; /*init support*/
/*other functions are device dependent*/
}drvet;
#define DRVETNUMBER ( (sizeof(struct drvet) -sizeof(long))/sizeof(DRVSUPFUN) )
#endif /* USE_TYPED_DRVET */
#define S_drv_noDrvSup (M_drvSup| 1) /*SDR_DRVSUP: Driver support missing*/
#define S_drv_noDrvet (M_drvSup| 3) /*Missing driver support entry table*/
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -34,10 +34,10 @@ be written to stdout unless the -o option is given.</p>
<dl>
<dt><tt>-V</tt></dt>
<dd>Verbose warnings; if this parameter is specified then any undefined
macro discovered in the template file which does not have an associated
default value is considered an error. An error message is generated, and
when msi terminates it will do so with an exit status of 2.</dd>
<dd>Verbose warnings; if this parameter is specified then any undefined or
recursive macros discovered in the template will be considered an error and
will be marked in the output file. An error message will be shown, and when
msi terminates it will do so with an exit status of 2.</dd>
<dt><tt>-g</tt></dt>
<dd>When this flag is given all macros defined in a substitution file will
+1
View File
@@ -26,3 +26,4 @@ dbCore_SRCS += miscIocRegister.c
dbCore_SRCS += dlload.c
dbCore_SRCS += iocshRegisterCommon.c
miscIocRegister_CFLAGS_iOS = -DSYSTEM_UNAVAILABLE
+7
View File
@@ -12,6 +12,9 @@ variable(asCaDebug,int)
# CA server debug flag (very verbose) range[0,5]
variable(CASDEBUG,int)
# Link parsing debug
variable(dbJLinkDebug,int)
# Static database access variables
variable(dbRecordsOnceOnly,int)
variable(dbRecordsAbcSorted,int)
@@ -19,8 +22,12 @@ variable(dbBptNotMonotonic,int)
variable(dbQuietMacroWarnings,int)
variable(dbConvertStrict,int)
# PUTF/RPRO tracing; set TPRO on records to trace
variable(dbAccessDebugPUTF,int)
# dbLoadTemplate settings
variable(dbTemplateMaxVars,int)
# Default number of parallel callback threads
variable(callbackParallelThreadsDefault,int)
@@ -66,10 +66,12 @@ void miscIocRegister(void)
/* system -- escape to system command interpreter.
*
* Disabled by default, for security reasons. To enable this command, add
* Disabled by default for security reasons, not available on all OSs.
* To enable this command, add
* registrar(iocshSystemCommand)
* to an application dbd file.
* to an application dbd file, or include system.dbd
*/
#ifndef SYSTEM_UNAVAILABLE
static const iocshArg systemArg0 = { "command string",iocshArgString};
static const iocshArg * const systemArgs[] = {&systemArg0};
static const iocshFuncDef systemFuncDef = {"system",1,systemArgs};
@@ -77,12 +79,15 @@ static void systemCallFunc(const iocshArgBuf *args)
{
system(args[0].sval);
}
#endif
static void iocshSystemCommand(void)
{
#ifndef SYSTEM_UNAVAILABLE
if (system(NULL))
iocshRegister(&systemFuncDef, systemCallFunc);
else
#endif
errlogPrintf ("Can't register 'system' command -- no command interpreter available.\n");
}
epicsExportRegistrar(iocshSystemCommand);
+12 -18
View File
@@ -83,20 +83,22 @@ static void req_server (void *pParm)
while (TRUE) {
SOCKET clientSock;
struct sockaddr sockAddr;
osiSockAddr sockAddr;
osiSocklen_t addLen = sizeof(sockAddr);
while (castcp_ctl == ctlPause) {
epicsThreadSleep(0.1);
}
clientSock = epicsSocketAccept ( IOC_sock, &sockAddr, &addLen );
if ( clientSock == INVALID_SOCKET ) {
clientSock = epicsSocketAccept ( IOC_sock, &sockAddr.sa, &addLen );
if ( clientSock == INVALID_SOCKET ||
sockAddr.sa.sa_family != AF_INET ||
addLen < sizeof(sockAddr.ia) ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf("CAS: Client accept error: %s\n",
sockErrBuf );
errlogPrintf("CAS: Client accept error: %s (%d)\n",
sockErrBuf, (int)addLen );
epicsThreadSleep(15.0);
continue;
}
@@ -105,7 +107,7 @@ static void req_server (void *pParm)
struct client *pClient;
/* socket passed in is closed if unsuccessful here */
pClient = create_tcp_client ( clientSock );
pClient = create_tcp_client ( clientSock, &sockAddr );
if ( ! pClient ) {
epicsThreadSleep ( 15.0 );
continue;
@@ -324,7 +326,7 @@ void rsrv_build_addr_lists(void)
#ifdef IP_MULTICAST_TTL
{
int ttl;
osiSockOptMcastTTL_t ttl;
long val;
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
val =1;
@@ -1405,12 +1407,11 @@ void casExpandRecvBuffer ( struct client *pClient, ca_uint32_t size )
/*
* create_tcp_client ()
*/
struct client *create_tcp_client ( SOCKET sock )
struct client *create_tcp_client (SOCKET sock , const osiSockAddr *peerAddr)
{
int status;
struct client *client;
int intTrue = TRUE;
osiSocklen_t addrSize;
unsigned priorityOfEvents;
/* socket passed in is destroyed here if unsuccessful */
@@ -1419,6 +1420,8 @@ struct client *create_tcp_client ( SOCKET sock )
return NULL;
}
client->addr = peerAddr->ia;
/*
* see TCP(4P) this seems to make unsolicited single events much
* faster. I take care of queue up as load increases.
@@ -1470,15 +1473,6 @@ struct client *create_tcp_client ( SOCKET sock )
}
#endif
addrSize = sizeof ( client->addr );
status = getpeername ( sock, (struct sockaddr *)&client->addr,
&addrSize );
if ( status < 0 ) {
epicsPrintf ("CAS: peer address fetch failed\n");
destroy_tcp_client (client);
return NULL;
}
client->evuser = (struct event_user *) db_init_events ();
if ( ! client->evuser ) {
errlogPrintf ("CAS: unable to init the event facility\n");
+27 -7
View File
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <cantProceed.h>
#include "addrList.h"
#include "dbDefs.h"
@@ -45,6 +46,7 @@ void rsrv_online_notify_task(void *pParm)
caHdr msg;
int status;
ca_uint32_t beaconCounter = 0;
int *lastError;
taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL);
@@ -70,29 +72,45 @@ void rsrv_online_notify_task(void *pParm)
msg.m_count = htons (ca_server_port);
msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION);
/* beaconAddrList should not change after rsrv_init(), which then starts this thread */
lastError = callocMustSucceed(ellCount(&beaconAddrList), sizeof(*lastError), "rsrv_online_notify_task lastError");
epicsEventSignal(beacon_startStopEvent);
while (TRUE) {
ELLNODE *cur;
unsigned i;
/* send beacon to each interface */
for(cur=ellFirst(&beaconAddrList); cur; cur=ellNext(cur))
for(i=0, cur=ellFirst(&beaconAddrList); cur; i++, cur=ellNext(cur))
{
osiSockAddrNode *pAddr = CONTAINER(cur, osiSockAddrNode, node);
status = sendto (beaconSocket, (char *)&msg, sizeof(msg), 0,
&pAddr->addr.sa, sizeof(pAddr->addr));
if (status < 0) {
char sockErrBuf[64];
char sockDipBuf[22];
int err = SOCKERRNO;
if(err != lastError[i]) {
char sockErrBuf[64];
char sockDipBuf[22];
epicsSocketConvertErrnoToString(sockErrBuf, sizeof(sockErrBuf));
ipAddrToDottedIP(&pAddr->addr.ia, sockDipBuf, sizeof(sockDipBuf));
errlogPrintf ( "CAS: CA beacon send to %s error: %s\n",
sockDipBuf, sockErrBuf);
epicsSocketConvertErrorToString(sockErrBuf, sizeof(sockErrBuf), err);
ipAddrToDottedIP(&pAddr->addr.ia, sockDipBuf, sizeof(sockDipBuf));
errlogPrintf ( "CAS: CA beacon send to %s error: %s\n",
sockDipBuf, sockErrBuf);
lastError[i] = err;
}
}
else {
assert (status == sizeof(msg));
if(lastError[i]) {
char sockDipBuf[22];
ipAddrToDottedIP(&pAddr->addr.ia, sockDipBuf, sizeof(sockDipBuf));
errlogPrintf ( "CAS: CA beacon send to %s ok\n",
sockDipBuf);
}
lastError[i] = 0;
}
}
@@ -111,6 +129,8 @@ void rsrv_online_notify_task(void *pParm)
delay = 0.02; /* Restart beacon timing if paused */
}
}
free(lastError);
}
+1 -1
View File
@@ -230,7 +230,7 @@ void rsrv_online_notify_task (void *);
void cast_server (void *);
struct client *create_client ( SOCKET sock, int proto );
void destroy_client ( struct client * );
struct client *create_tcp_client ( SOCKET sock );
struct client *create_tcp_client ( SOCKET sock, const osiSockAddr* peerAddr );
void destroy_tcp_client ( struct client * );
void casAttachThreadToClient ( struct client * );
int camessage ( struct client *client );
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbConstLink.h"
#include "dbEvent.h"
#include "recGbl.h"
#include "devSup.h"
#include "cantProceed.h"
@@ -96,11 +97,15 @@ static long readLocked(struct link *pinp, void *dummy)
static long read_aai(aaiRecord *prec)
{
epicsUInt32 nord = prec->nord;
struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp;
long status = dbLinkDoLocked(pinp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(pinp, NULL);
if (!status && nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return status;
}
+8 -2
View File
@@ -4,7 +4,7 @@
* Copyright (c) 2002 Lawrence Berkeley Laboratory,The Control Systems
* Group, Systems Engineering Department
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -19,6 +19,7 @@
#include "alarm.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "recGbl.h"
#include "devSup.h"
#include "subArrayRecord.h"
@@ -101,6 +102,7 @@ static long read_sa(subArrayRecord *prec)
{
long status;
struct sart rt;
epicsUInt32 nord = prec->nord;
rt.nRequest = prec->indx + prec->nelm;
if (rt.nRequest > prec->malm)
@@ -123,8 +125,12 @@ static long read_sa(subArrayRecord *prec)
status = readLocked(&prec->inp, &rt);
}
if (!status && rt.nRequest > 0)
if (!status && rt.nRequest > 0) {
subset(prec, rt.nRequest);
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
}
return status;
}
+4 -1
View File
@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -81,6 +81,7 @@ static long read_wf(waveformRecord *prec)
{
long status;
struct wfrt rt;
epicsUInt32 nord = prec->nord;
rt.nRequest = prec->nelm;
rt.ptime = (dbLinkIsConstant(&prec->tsel) &&
@@ -93,6 +94,8 @@ static long read_wf(waveformRecord *prec)
if (!status && rt.nRequest > 0) {
prec->nord = rt.nRequest;
prec->udf = FALSE;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
}
return status;
+3 -2
View File
@@ -2,7 +2,7 @@
# Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/std/Makefile.
@@ -13,6 +13,7 @@ DBD += links.dbd
dbRecStd_SRCS += lnkConst.c
dbRecStd_SRCS += lnkCalc.c
dbRecStd_SRCS += lnkState.c
dbRecStd_SRCS += lnkDebug.c
HTMLS += links.html
+113 -9
View File
@@ -13,6 +13,12 @@ The following additional link types are available in this release:
=item * L<Calc|/"Calculation Link calc">
=item * L<dbState|/"dbState Link state">
=item * L<Debug|/"Debug Link debug">
=item * L<Trace|/"Trace Link trace">
=back
=head2 Using JSON Links
@@ -31,15 +37,16 @@ database file syntax.
=cut
link(const, lnkConstIf)
=head3 Constant Link C<"const">
Constant links provide one or more values at link initalization time, but do not
return any data when their C<getValue()> routine is called. Most record types
support the use of constant links by calling C<recGblInitConstantLink()> at
record initialization, which results in the constant value being loaded into the
target field at that time.
Constant links are input links that provide literal values at link initalization
time, but do not return any data when their C<getValue()> routine is called.
Most record types support the use of constant links on their input links by
calling C<recGblInitConstantLink()> at record initialization, which results in
the constant value being loaded into the target field at that time.
Note that for most record types (the C<printf> and C<calcout> records are the
main exceptions) it is pointless to set an input link to a constant link at
@@ -70,14 +77,35 @@ converted to the desired double value at initialization, for example:
=cut
link(calc, lnkCalcIf)
=head3 Calculation Link C<"calc">
Calculation links can perform simple mathematical expressions on scalar
(double-precision floating-point) values obtained from other link types and
return a single double-precision floating-point result. The expressions are
evaluated by the EPICS Calc engine, and up to 12 inputs can be provided.
A calculation link is an input link that can evaluate mathematical expressions
on scalar (double-precision floating-point) values obtained from up to 12 child
input links, and returns a double-precision floating-point result. The
expression is evaluated by the EPICS Calc engine, and the result is returned as
the value of the link.
Two additional expressions may also be provided and are evaluated to determine
whether the record owning the link should be placed in alarm state. In both
cases the result of the main calculation is available to these expressions as
C<VAL> (attempts to assign to C<VAL> inside either expression will have no
lasting effect). If the C<major> expression evaluates to a non-zero value the
record will be placed in C<LINK/MAJOR> alarm. If not and the C<minor> expression
evaluates to non-zero the record will be placed in C<LINK/MINOR> alarm state.
A calculation link can also be an output link, with the scalar output value
being converted to a double and provided to the expression as C<VAL>. Up to 12
additional input links can also be read and provided to the expression as above.
The result of the calculation is forwarded to a child output link specified in
the link's C<out> parameter.
For an output link the main expression is actually optional; if not provided the
converted value will be forwarded to the output link unchanged. The two alarm
expressions may still be used to put the output link into alarm state as
described above.
=head4 Parameters
@@ -88,6 +116,7 @@ The link address is a JSON map with the following keys:
=item expr
The primary expression to be evaluated, given as a string.
This is optional for output links, required for input links.
=item major
@@ -104,6 +133,12 @@ to the inputs C<A>, C<B>, C<C>, ... C<L>. Each input argument may be either a
numeric literal or an embedded JSON link inside C<{}> braces. The same input
values are provided to the two alarm expressions as to the primary expression.
=item out
A JSON link inside C<{}> braces which specifies the destination of C<putValue>
operations after any expressions have been evaluated.
This key is required for output links, not used by input links.
=item units
An optional string specifying the engineering units for the result of the
@@ -129,3 +164,72 @@ atomically with the value of the input argument.
{calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5], prec:3}}
=cut
link(state, lnkStateIf)
=head3 dbState Link C<"state">
A dbState link is one that gets or puts a boolean value from/to a named global
flag as implemented by the dbState facility in C<dbstate.h>. The link type can
invert the sense of the dbState flag during the get or put if desired.
The value of the named flag is read or written at the time of the link I/O
operation. When reading a flag, the value returned by the link will be zero or
one converted to the requested data type. When writing to a flag the boolean
value of the data written is determined in the originating data type. All
strings are regarded as true other than C<""> and C<"0"> which are both false.
A link can be configured to invert the sense of the flag data by putting an
exclamation mark C<!> before the first character of the flag's name in the link
address.
These dbState flags can be accessed from the IOC Shell with various dbState
commands, and are also used by the C<"sync"> Channel-Access server-side filter
mechanism.
=head4 Parameters
The link takes a single parameter which must be a string, providing the name of
the dbState object, with an optional leading C<!> character to indicate that the
flag's value should be inverted. The dbState object will be created when the
link is initialized if it doesn't already exist.
=head4 Examples
{state:"redBeam"}
{state:"!simEnable"}
=cut
link(debug, lnkDebugIf)
variable(lnkDebug_debug, int)
=head3 Debug Link C<"debug">
The debug link type exists to enable debugging of other link types; it provides
no functionality itself other than to turn on the debug flag for the child link
that is its only parameter and pass all link operations down to that link.
=head4 Example
{debug:{state:"redBeam"}}
=cut
link(trace, lnkTraceIf)
=head3 Trace Link C<"trace">
The trace link type is a relative of the debug link type that also traces the
operation of its child link. At creation it turns on the debug flag of its child
link, then it prints the method arguments and return values of all link
operations before / after passing control down to the child link.
=head4 Example
{trace:{state:"redBeam"}}
=cut
+191 -117
View File
@@ -6,13 +6,9 @@
\*************************************************************************/
/* lnkCalc.c */
/* Current usage
* {calc:{expr:"A", args:[{...}, ...]}}
/* Usage
* {calc:{expr:"A*B", args:[{...}, ...], units:"mm"}}
* First link in 'args' is 'A', second is 'B', and so forth.
*
* TODO:
* Support setting individual input links instead of the args list.
* {calc:{expr:"K", K:{...}}}
*/
#include <string.h>
@@ -26,6 +22,7 @@
#include "epicsAssert.h"
#include "epicsString.h"
#include "epicsTypes.h"
#include "epicsTime.h"
#include "dbAccessDefs.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
@@ -40,15 +37,14 @@
typedef long (*FASTCONVERT)();
#define IFDEBUG(n) if(clink->jlink.debug)
typedef struct calc_link {
jlink jlink; /* embedded object */
int nArgs;
short dbfType;
enum {
ps_init,
ps_expr, ps_major, ps_minor,
ps_args,
ps_args, ps_out,
ps_prec,
ps_units,
ps_time,
@@ -66,7 +62,9 @@ typedef struct calc_link {
char *units;
short tinp;
struct link inp[CALCPERFORM_NARGS];
struct link out;
double arg[CALCPERFORM_NARGS];
epicsTimeStamp time;
double val;
} calc_link;
@@ -77,19 +75,25 @@ static lset lnkCalc_lset;
static jlink* lnkCalc_alloc(short dbfType)
{
calc_link *clink = calloc(1, sizeof(struct calc_link));
calc_link *clink;
IFDEBUG(10)
printf("lnkCalc_alloc()\n");
if (dbfType == DBF_FWDLINK) {
errlogPrintf("lnkCalc: No support for forward links\n");
return NULL;
}
clink = calloc(1, sizeof(struct calc_link));
if (!clink) {
errlogPrintf("lnkCalc: calloc() failed.\n");
return NULL;
}
clink->nArgs = 0;
clink->dbfType = dbfType;
clink->pstate = ps_init;
clink->prec = 15; /* standard value for a double */
clink->tinp = -1;
IFDEBUG(10)
printf("lnkCalc_alloc -> calc@%p\n", clink);
return &clink->jlink;
}
@@ -98,12 +102,11 @@ static void lnkCalc_free(jlink *pjlink)
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_free(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++)
dbJLinkFree(clink->inp[i].value.json.jlink);
dbJLinkFree(clink->out.value.json.jlink);
free(clink->expr);
free(clink->major);
free(clink->minor);
@@ -118,9 +121,6 @@ static jlif_result lnkCalc_integer(jlink *pjlink, long long num)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_integer(calc@%p, %lld)\n", clink, num);
if (clink->pstate == ps_prec) {
clink->prec = num;
return jlif_continue;
@@ -146,9 +146,6 @@ static jlif_result lnkCalc_double(jlink *pjlink, double num)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_double(calc@%p, %g)\n", clink, num);
if (clink->pstate != ps_args) {
return jlif_stop;
errlogPrintf("lnkCalc: Unexpected double %g\n", num);
@@ -171,9 +168,6 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
char *inbuf, *postbuf;
short err;
IFDEBUG(10)
printf("lnkCalc_string(calc@%p, \"%.*s\")\n", clink, (int) len, val);
if (clink->pstate == ps_units) {
clink->units = epicsStrnDup(val, len);
return jlif_continue;
@@ -181,7 +175,8 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
if (clink->pstate == ps_time) {
char tinp;
if (len != 1 || (tinp = toupper(val[0])) < 'A' || tinp > 'L') {
if (len != 1 || (tinp = toupper((int) val[0])) < 'A' || tinp > 'L') {
errlogPrintf("lnkCalc: Bad 'time' parameter \"%.*s\"\n", (int) len, val);
return jlif_stop;
}
@@ -234,11 +229,10 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_start_map(calc@%p)\n", clink);
if (clink->pstate == ps_args)
return jlif_key_child_link;
return jlif_key_child_inlink;
if (clink->pstate == ps_out)
return jlif_key_child_outlink;
if (clink->pstate != ps_init) {
errlogPrintf("lnkCalc: Unexpected map\n");
@@ -252,10 +246,21 @@ static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n", pjlink, (int) len, key);
/* FIXME: These errors messages are wrong when a key is duplicated.
* The key is known, we just don't allow it more than once.
*/
if (len == 4) {
if (len == 3) {
if (!strncmp(key, "out", len) &&
clink->dbfType == DBF_OUTLINK &&
clink->out.type == 0)
clink->pstate = ps_out;
else {
errlogPrintf("lnkCalc: Unknown key \"%.3s\"\n", key);
return jlif_stop;
}
}
else if (len == 4) {
if (!strncmp(key, "expr", len) && !clink->post_expr)
clink->pstate = ps_expr;
else if (!strncmp(key, "args", len) && !clink->nArgs)
@@ -293,13 +298,16 @@ static jlif_result lnkCalc_end_map(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_end_map(calc@%p)\n", clink);
if (clink->pstate == ps_error)
return jlif_stop;
else if (!clink->post_expr) {
errlogPrintf("lnkCalc: no expression ('expr' key)\n");
else if (clink->dbfType == DBF_INLINK &&
!clink->post_expr) {
errlogPrintf("lnkCalc: No expression ('expr' key)\n");
return jlif_stop;
}
else if (clink->dbfType == DBF_OUTLINK &&
clink->out.type != JSON_LINK) {
errlogPrintf("lnkCalc: No output link ('out' key)\n");
return jlif_stop;
}
@@ -310,9 +318,6 @@ static jlif_result lnkCalc_start_array(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_start_array(calc@%p)\n", clink);
if (clink->pstate != ps_args) {
errlogPrintf("lnkCalc: Unexpected array\n");
return jlif_stop;
@@ -325,9 +330,6 @@ static jlif_result lnkCalc_end_array(jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_end_array(calc@%p)\n", clink);
if (clink->pstate == ps_error)
return jlif_stop;
@@ -339,15 +341,27 @@ static void lnkCalc_end_child(jlink *parent, jlink *child)
calc_link *clink = CONTAINER(parent, struct calc_link, jlink);
struct link *plink;
if (clink->nArgs == CALCPERFORM_NARGS) {
dbJLinkFree(child);
errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
CALCPERFORM_NARGS);
if (clink->pstate == ps_args) {
if (clink->nArgs == CALCPERFORM_NARGS) {
errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
CALCPERFORM_NARGS);
goto errOut;
}
plink = &clink->inp[clink->nArgs++];
}
else if (clink->pstate == ps_out) {
plink = &clink->out;
}
else {
errlogPrintf("lnkCalc: Unexpected child link, parser state = %d\n",
clink->pstate);
errOut:
clink->pstate = ps_error;
dbJLinkFree(child);
return;
}
plink = &clink->inp[clink->nArgs++];
plink->type = JSON_LINK;
plink->value.json.string = NULL;
plink->value.json.jlink = child;
@@ -355,11 +369,6 @@ static void lnkCalc_end_child(jlink *parent, jlink *child)
static struct lset* lnkCalc_get_lset(const jlink *pjlink)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_get_lset(calc@%p)\n", pjlink);
return &lnkCalc_lset;
}
@@ -368,9 +377,6 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_report(calc@%p)\n", clink);
printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "",
clink->expr, clink->prec, clink->val,
clink->units ? clink->units : "");
@@ -388,9 +394,13 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
printf("%*s Minor expression: \"%s\"\n", indent, "",
clink->minor);
if (clink->tinp >= 0 && clink->tinp < clink->nArgs)
printf("%*s Timestamp input \"%c\"\n", indent, "",
clink->tinp + 'A');
if (clink->tinp >= 0) {
char timeStr[40];
epicsTimeToStrftime(timeStr, 40, "%Y-%m-%d %H:%M:%S.%09f",
&clink->time);
printf("%*s Timestamp input %c: %s\n", indent, "",
clink->tinp + 'A', timeStr);
}
for (i = 0; i < clink->nArgs; i++) {
struct link *plink = &clink->inp[i];
@@ -403,17 +413,20 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
if (child)
dbJLinkReport(child, level - 1, indent + 4);
}
if (clink->out.type == JSON_LINK) {
printf("%*s Output:\n", indent, "");
dbJLinkReport(clink->out.value.json.jlink, level - 1, indent + 4);
}
}
}
long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
static long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_map_children(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
long status = dbJLinkMapChildren(child, rtn, ctx);
@@ -421,6 +434,10 @@ long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
if (status)
return status;
}
if (clink->out.type == JSON_LINK) {
return dbJLinkMapChildren(&clink->out, rtn, ctx);
}
return 0;
}
@@ -432,9 +449,6 @@ static void lnkCalc_open(struct link *plink)
struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_open(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
@@ -442,6 +456,10 @@ static void lnkCalc_open(struct link *plink)
dbJLinkInit(child);
dbLoadLink(child, DBR_DOUBLE, &clink->arg[i]);
}
if (clink->out.type == JSON_LINK) {
dbJLinkInit(&clink->out);
}
}
static void lnkCalc_remove(struct dbLocker *locker, struct link *plink)
@@ -450,15 +468,16 @@ static void lnkCalc_remove(struct dbLocker *locker, struct link *plink)
struct calc_link, jlink);
int i;
IFDEBUG(10)
printf("lnkCalc_remove(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
dbRemoveLink(locker, child);
}
if (clink->out.type == JSON_LINK) {
dbRemoveLink(locker, &clink->out);
}
free(clink->expr);
free(clink->major);
free(clink->minor);
@@ -477,9 +496,6 @@ static int lnkCalc_isConn(const struct link *plink)
int connected = 1;
int i;
IFDEBUG(10)
printf("lnkCalc_isConn(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
@@ -488,37 +504,24 @@ static int lnkCalc_isConn(const struct link *plink)
connected = 0;
}
if (clink->out.type == JSON_LINK) {
struct link *child = &clink->out;
if (dbLinkIsVolatile(child) &&
!dbIsLinkConnected(child))
connected = 0;
}
return connected;
}
static int lnkCalc_getDBFtype(const struct link *plink)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10) {
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
printf("lnkCalc_getDBFtype(calc@%p)\n", clink);
}
return DBF_DOUBLE;
}
static long lnkCalc_getElements(const struct link *plink, long *nelements)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10) {
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
printf("lnkCalc_getElements(calc@%p, (%ld))\n",
clink, *nelements);
}
*nelements = 1;
return 0;
}
@@ -551,23 +554,22 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
long status;
FASTCONVERT conv = dbFastPutConvertRoutine[DBR_DOUBLE][dbrType];
IFDEBUG(10)
printf("lnkCalc_getValue(calc@%p, %d, ...)\n",
clink, dbrType);
/* Any link errors will trigger a LINK/INVALID alarm in the child link */
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
long nReq = 1;
if (i == clink->tinp &&
dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
struct lcvt vt = {&clink->arg[i], &prec->time};
if (i == clink->tinp) {
struct lcvt vt = {&clink->arg[i], &clink->time};
status = dbLinkDoLocked(child, readLocked, &vt);
if (status == S_db_noLSET)
status = readLocked(child, &vt);
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
prec->time = clink->time;
}
}
else
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
@@ -599,7 +601,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
}
}
if (!status && clink->post_minor) {
if (!status && !clink->sevr && clink->post_minor) {
double alval = clink->val;
status = calcPerform(clink->arg, &alval, clink->post_minor);
@@ -613,14 +615,79 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
return status;
}
static long lnkCalc_putValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
dbCommon *prec = plink->precord;
int i;
long status;
FASTCONVERT conv = dbFastGetConvertRoutine[dbrType][DBR_DOUBLE];
/* Any link errors will trigger a LINK/INVALID alarm in the child link */
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
long nReq = 1;
if (i == clink->tinp) {
struct lcvt vt = {&clink->arg[i], &clink->time};
status = dbLinkDoLocked(child, readLocked, &vt);
if (status == S_db_noLSET)
status = readLocked(child, &vt);
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
prec->time = clink->time;
}
}
else
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
}
clink->stat = 0;
clink->sevr = 0;
/* Get the value being output as VAL */
status = conv(pbuffer, &clink->val, NULL);
if (!status && clink->post_expr)
status = calcPerform(clink->arg, &clink->val, clink->post_expr);
if (!status && clink->post_major) {
double alval = clink->val;
status = calcPerform(clink->arg, &alval, clink->post_major);
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MAJOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
}
}
if (!status && !clink->sevr && clink->post_minor) {
double alval = clink->val;
status = calcPerform(clink->arg, &alval, clink->post_minor);
if (!status && alval) {
clink->stat = LINK_ALARM;
clink->sevr = MINOR_ALARM;
recGblSetSevr(prec, clink->stat, clink->sevr);
}
}
if (!status) {
status = dbPutLink(&clink->out, DBR_DOUBLE, &clink->val, 1);
}
return status;
}
static long lnkCalc_getPrecision(const struct link *plink, short *precision)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getPrecision(calc@%p)\n", clink);
*precision = clink->prec;
return 0;
}
@@ -630,9 +697,6 @@ static long lnkCalc_getUnits(const struct link *plink, char *units, int len)
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getUnits(calc@%p)\n", clink);
if (clink->units) {
strncpy(units, clink->units, --len);
units[len] = '\0';
@@ -648,9 +712,6 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getAlarm(calc@%p)\n", clink);
if (status)
*status = clink->stat;
if (severity)
@@ -659,6 +720,19 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
return 0;
}
static long lnkCalc_getTimestamp(const struct link *plink, epicsTimeStamp *pstamp)
{
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
if (clink->tinp >= 0) {
*pstamp = clink->time;
return 0;
}
return -1;
}
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
{
return rtn(plink, priv);
@@ -675,8 +749,8 @@ static lset lnkCalc_lset = {
lnkCalc_getValue,
NULL, NULL, NULL,
lnkCalc_getPrecision, lnkCalc_getUnits,
lnkCalc_getAlarm, NULL,
NULL, NULL,
lnkCalc_getAlarm, lnkCalc_getTimestamp,
lnkCalc_putValue, NULL,
NULL, doLocked
};
@@ -686,6 +760,6 @@ static jlif lnkCalcIf = {
lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map,
lnkCalc_start_array, lnkCalc_end_array,
lnkCalc_end_child, lnkCalc_get_lset,
lnkCalc_report, lnkCalc_map_children
lnkCalc_report, lnkCalc_map_children, NULL
};
epicsExportAddress(jlif, lnkCalcIf);
+33 -93
View File
@@ -2,7 +2,7 @@
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* lnkConst.c */
@@ -22,8 +22,6 @@
#include "epicsExport.h"
#define IFDEBUG(n) if (clink->jlink.debug)
typedef long (*FASTCONVERT)();
typedef struct const_link {
@@ -48,18 +46,23 @@ static lset lnkConst_lset;
static jlink* lnkConst_alloc(short dbfType)
{
const_link *clink = calloc(1, sizeof(*clink));
const_link *clink;
IFDEBUG(10)
printf("lnkConst_alloc()\n");
if (dbfType != DBF_INLINK) {
errlogPrintf("lnkConst: Only works with input links\n");
return NULL;
}
clink = calloc(1, sizeof(*clink));
if (!clink) {
errlogPrintf("lnkConst: calloc() failed.\n");
return NULL;
}
clink->type = s0;
clink->nElems = 0;
clink->value.pmem = NULL;
IFDEBUG(10)
printf("lnkConst_alloc -> const@%p\n", clink);
return &clink->jlink;
}
@@ -67,9 +70,6 @@ static void lnkConst_free(jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_free(const@%p) type=%d\n", pjlink, clink->type);
switch (clink->type) {
int i;
case ac40:
@@ -95,16 +95,13 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_integer(const@%p, %lld)\n", pjlink, num);
switch (clink->type) {
void *buf;
case s0:
clink->type = si64;
clink->value.scalar_integer = num;
IFDEBUG(12)
if (pjlink->debug)
printf(" si64 := %lld\n", num);
break;
@@ -118,7 +115,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
clink->value.pmem = buf;
clink->value.pintegers[clink->nElems] = num;
IFDEBUG(12)
if (pjlink->debug)
printf(" ai64 += %lld\n", num);
break;
@@ -129,7 +126,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
clink->value.pmem = buf;
clink->value.pdoubles[clink->nElems] = num;
IFDEBUG(12)
if (pjlink->debug)
printf(" af64 += %lld\n", num);
break;
@@ -146,10 +143,6 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
static jlif_result lnkConst_boolean(jlink *pjlink, int val)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_boolean(const@%p, %d)\n", pjlink, val);
return lnkConst_integer(pjlink, val);
}
@@ -158,9 +151,6 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_double(const@%p, %g)\n", pjlink, num);
switch (clink->type) {
epicsFloat64 *f64buf;
int i;
@@ -212,9 +202,6 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
switch (clink->type) {
char **vec, *str;
@@ -262,9 +249,6 @@ static jlif_result lnkConst_start_array(jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_start_array(const@%p)\n", pjlink);
if (clink->type != s0) {
errlogPrintf("lnkConst: Embedded array value\n");
return jlif_stop;
@@ -276,21 +260,11 @@ static jlif_result lnkConst_start_array(jlink *pjlink)
static jlif_result lnkConst_end_array(jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_end_array(const@%p)\n", pjlink);
return jlif_continue;
}
static struct lset* lnkConst_get_lset(const jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_get_lset(const@%p)\n", pjlink);
return &lnkConst_lset;
}
@@ -318,9 +292,6 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent)
};
const char * const dtype = type_names[clink->type & 3];
IFDEBUG(10)
printf("lnkConst_report(const@%p)\n", clink);
if (clink->type > a0) {
const char * const plural = clink->nElems > 1 ? "s" : "";
@@ -382,11 +353,6 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent)
static void lnkConst_remove(struct dbLocker *locker, struct link *plink)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_remove(const@%p)\n", clink);
lnkConst_free(plink->value.json.jlink);
}
@@ -395,55 +361,51 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
long status;
IFDEBUG(10)
printf("lnkConst_loadScalar(const@%p, %d, %p)\n",
clink, dbrType, pbuffer);
switch (clink->type) {
case si64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" si64 %lld\n", clink->value.scalar_integer);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(&clink->value.scalar_integer, pbuffer, NULL);
break;
case sf64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sf64 %g\n", clink->value.scalar_double);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(&clink->value.scalar_double, pbuffer, NULL);
break;
case sc40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
break;
case ai64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(clink->value.pintegers, pbuffer, NULL);
break;
case af64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(clink->value.pdoubles, pbuffer, NULL);
break;
case ac40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.pstrings[0], pbuffer, NULL);
break;
default:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type);
status = S_db_badField;
break;
@@ -458,27 +420,23 @@ static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
const char *pstr;
IFDEBUG(10)
printf("lnkConst_loadLS(const@%p, %p, %d, %d)\n",
clink, pbuffer, size, *plen);
if(!size) return 0;
switch (clink->type) {
case sc40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
pstr = clink->value.scalar_string;
break;
case ac40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
pstr = clink->value.pstrings[0];
break;
default:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type);
return S_db_badField;
}
@@ -499,10 +457,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
FASTCONVERT conv;
long status;
IFDEBUG(10)
printf("lnkConst_loadArray(const@%p, %d, %p, (%ld))\n",
clink, dbrType, pbuffer, *pnReq);
if (nElems > *pnReq)
nElems = *pnReq;
@@ -510,28 +464,28 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
int i;
case si64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" si64 %lld\n", clink->value.scalar_integer);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(&clink->value.scalar_integer, pdest, NULL);
break;
case sf64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sf64 %g\n", clink->value.scalar_double);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(&clink->value.scalar_double, pdest, NULL);
break;
case sc40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
break;
case ai64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
conv = dbFastPutConvertRoutine[DBF_INT64][dbrType];
for (i = 0; i < nElems; i++) {
@@ -542,7 +496,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break;
case af64:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType];
for (i = 0; i < nElems; i++) {
@@ -553,7 +507,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break;
case ac40:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
conv = dbFastPutConvertRoutine[DBF_STRING][dbrType];
for (i = 0; i < nElems; i++) {
@@ -564,7 +518,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break;
default:
IFDEBUG(12)
if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type);
status = S_db_badField;
}
@@ -574,12 +528,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
static long lnkConst_getNelements(const struct link *plink, long *nelements)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_getNelements(const@%p, (%ld))\n",
plink->value.json.jlink, *nelements);
*nelements = 0;
return 0;
}
@@ -587,13 +535,6 @@ static long lnkConst_getNelements(const struct link *plink, long *nelements)
static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_getValue(const@%p, %d, %p, ... (%ld))\n",
plink->value.json.jlink, dbrType, pbuffer,
pnRequest ? *pnRequest : 0);
if (pnRequest)
*pnRequest = 0;
return 0;
@@ -626,7 +567,6 @@ static jlif lnkConstIf = {
NULL, NULL, NULL,
lnkConst_start_array, lnkConst_end_array,
NULL, lnkConst_get_lset,
lnkConst_report, NULL
lnkConst_report, NULL, NULL
};
epicsExportAddress(jlif, lnkConstIf);

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