Merge 3.16 (after 3.16.2-rc1) into 7.0

This commit is contained in:
Andrew Johnson
2018-10-26 17:04:53 -05:00
157 changed files with 5520 additions and 1623 deletions

View File

@ -6,18 +6,9 @@ die() {
exit 1 exit 1
} }
ticker() {
while true
do
sleep 60
date -R
[ -r "$1" ] && tail -n10 "$1"
done
}
CACHEKEY=1 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" [ -e configure/os/CONFIG_SITE.Common.linux-x86 ] || die "Wrong location: $PWD"
@ -57,28 +48,24 @@ EOF
fi fi
# set RTEMS to eg. "4.9" or "4.10" # set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ] if [ -n "$RTEMS" ]
then then
echo "Cross RTEMS${RTEMS} for pc386" echo "Cross RTEMS${RTEMS} for pc386"
install -d /home/travis/.cache curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \ | tar -C / -xmj
| tar -C /home/travis/.cache -xj
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS RTEMS_VERSION=$RTEMS
RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 RTEMS_BASE=$HOME/.rtems
EOF EOF
cat << EOF >> configure/CONFIG_SITE cat << EOF >> configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
EOF EOF
# find local qemu-system-i386 # find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: " echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu" type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi fi
make -j2 $EXTRA make -j2 $EXTRA
@ -86,5 +73,5 @@ make -j2 $EXTRA
if [ "$TEST" != "NO" ] if [ "$TEST" != "NO" ]
then then
make -j2 tapfiles make -j2 tapfiles
make -s test-results make -j2 -s test-results
fi fi

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

View File

@ -11,23 +11,17 @@ addons:
- perl - perl
- clang - clang
- g++-mingw-w64-i686 - g++-mingw-w64-i686
- bison - qemu-system-x86
- flex
- texinfo
- install-info
cache:
directories:
- $HOME/.cache
install:
- ./.ci/travis-prepare.sh
script: script:
- ./.ci/travis-build.sh - .ci/travis-build.sh
env: env:
- BRCORE=master BRLIBCOM=master BRCA=master - CMPLR=gcc
- CMPLR=clang - CMPLR=clang
- USR_CXXFLAGS=-std=c++11 - CMPLR=gcc STATIC=YES
- CMPLR=clang USR_CXXFLAGS=-std=c++11 - CMPLR=clang STATIC=YES
- WINE=32 TEST=NO STATIC=YES - CMPLR=gcc EXTRA=CMD_CXXFLAGS=-std=c++11
- WINE=32 TEST=NO STATIC=NO - CMPLR=clang EXTRA=CMD_CXXFLAGS=-std=c++11
- RTEMS=4.10 TEST=NO - WINE=32 TEST=NO STATIC=YES
- RTEMS=4.9 TEST=NO - WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=YES
- RTEMS=4.9 TEST=YES

View File

@ -20,11 +20,14 @@ else
endif endif
# Provide a default if the user hasn't set EPICS_HOST_ARCH # 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 ifeq ($(origin EPICS_HOST_ARCH), undefined)
# the correct modules/RELEASE.<host>.local file to set EPICS_BASE, # Bootstrapping ...
# they can't do this for themselves since CONFIG is relative to it: EHA := $(firstword $(wildcard $(EPICS_BASE)/lib/perl/EpicsHostArch.pl \
export EPICS_HOST_ARCH := $(shell $(CONFIG)/../startup/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 endif
-include $(CONFIG)/RELEASE -include $(CONFIG)/RELEASE

View File

@ -42,7 +42,7 @@ PODTOHTML = $(PERL) $(TOOLS)/podToHtml.pl
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl) CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.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 # tools for installing libraries and products

View File

@ -80,6 +80,7 @@ IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
NOP = : NOP = :
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo) ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
QUIET_FLAG := $(if $(findstring s,$(MAKEFLAGS)),-q,) QUIET_FLAG := $(if $(findstring s,$(MAKEFLAGS)),-q,)
QUESTION_FLAG := $(if $(findstring q,$(MAKEFLAGS)),-i,)
#------------------------------------------------------- #-------------------------------------------------------
ifdef T_A ifdef T_A

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. # National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as # Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory. # Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7 # EPICS BASE is distributed subject to a Software License Agreement found
# and higher are distributed subject to a Software License Agreement found # in the file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#************************************************************************* #*************************************************************************
ifndef T_A ifndef T_A

View File

@ -4,9 +4,10 @@
# Copyright (c) 2002 The Regents of the University of California, as # Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory. # Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found # 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 # Set db substitutions and template file suffixes
SUBST_SUFFIX ?= .substitutions SUBST_SUFFIX ?= .substitutions

View File

@ -4,9 +4,10 @@
# Copyright (c) 2002 The Regents of the University of California, as # Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory. # Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found # 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 include $(CONFIG)/RULES_DIRS

View File

@ -90,6 +90,4 @@ realclean:
.PHONY : $(BUILD_ARCHS) rebuild archsCommonClean .PHONY : $(BUILD_ARCHS) rebuild archsCommonClean
.PHONY : $(ACTIONS) clean realclean archclean host all .PHONY : $(ACTIONS) clean realclean archclean host all
# User specific rules include $(CONFIG)/RULES_COMMON
#
-include $(HOME)/configure/RULES_USER

View File

@ -6,11 +6,12 @@
# EPICS BASE is distributed subject to a Software License Agreement found # EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution. # in the file LICENSE that is included with this distribution.
#************************************************************************* #*************************************************************************
# RULES_BUILD
# Rules for making things specified in a Makefile
# #
# Rules for making things specified in Makefile # CWD is O.$(T_A), but most sources are elsewhere
#
# we are in O.$(T_A), but most sources are elsewhere
#
ifndef BASE_RULES_BUILD ifndef BASE_RULES_BUILD
BASE_RULES_BUILD=1 BASE_RULES_BUILD=1
@ -79,9 +80,9 @@ else
host: host:
endif endif
-include $(CONFIG)/RULES_FILE_TYPE include $(CONFIG)/RULES_FILE_TYPE
-include $(CONFIG)/RULES.Db include $(CONFIG)/RULES.Db
#--------------------------------------------------------------- #---------------------------------------------------------------
# Include defines and rules for prod, library and test* targets # Include defines and rules for prod, library and test* targets
@ -185,7 +186,7 @@ endif
# RELEASE file consistency checking # RELEASE file consistency checking
checkRelease: checkRelease:
$(CONVERTRELEASE) checkRelease +$(CONVERTRELEASE) checkRelease
warnRelease: warnRelease:
-$(CONVERTRELEASE) checkRelease -$(CONVERTRELEASE) checkRelease
noCheckRelease: noCheckRelease:
@ -256,15 +257,13 @@ YACCOPT ?= $($*_YACCOPT)
$(MV) $*.tab.c $*.c $(MV) $*.tab.c $*.c
$(if $(findstring -d, $(YACCOPT)),$(MV) $*.tab.h $*.h,) $(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 # prefix for .h will be different then .c
%.h : %.c %.y %.h : %.c %.y
%.c: %.l %.c: %.l
@$(RM) $*.yy.c
$(LEX) $(LEXOPT) -t $< > $*.yy.c
@$(RM) $@ @$(RM) $@
$(MV) $*.yy.c $@ $(LEX) $(LEXOPT) -o$@ $<
#--------------------------------------------------------------- #---------------------------------------------------------------
# Libraries, shared/DLL and stubs # Libraries, shared/DLL and stubs
@ -392,7 +391,7 @@ endif
# Generate a perl program to exec the real test binary. # Generate a perl program to exec the real test binary.
%.t: %$(EXE) $(TOOLS)/makeTestfile.pl %.t: %$(EXE) $(TOOLS)/makeTestfile.pl
@$(RM) $@ @$(RM) $@
$(PERL) $(TOOLS)/makeTestfile.pl $@ $< $(PERL) $(TOOLS)/makeTestfile.pl $(T_A) $(EPICS_HOST_ARCH) $@ $<
#--------------------------------------------------------------- #---------------------------------------------------------------
# Generate header with version number from VCS # Generate header with version number from VCS
@ -531,7 +530,7 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
$(ECHO) "Installing $@" $(ECHO) "Installing $@"
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
-include $(CONFIG)/RULES_EXPAND include $(CONFIG)/RULES_EXPAND
.PRECIOUS: %.i %.o %.c %.nm %.cpp %.cc .PRECIOUS: %.i %.o %.c %.nm %.cpp %.cc
.PRECIOUS: $(COMMON_INC) .PRECIOUS: $(COMMON_INC)
@ -540,5 +539,9 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
.PHONY: runtests tapfiles clean-tests test-results junitfiles .PHONY: runtests tapfiles clean-tests test-results junitfiles
.PHONY: checkRelease warnRelease noCheckRelease FORCE .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 endif # BASE_RULES_BUILD
# EOF RULES_BUILD

35
configure/RULES_COMMON Normal file
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

View File

@ -92,7 +92,4 @@ $(ARCHS) $(ACTIONS) $(actionArchTargets) :%: \
.PHONY : $(dirActionArchTargets) .PHONY : $(dirActionArchTargets)
.PHONY : $(actionArchTargets) .PHONY : $(actionArchTargets)
include $(CONFIG)/RULES_COMMON
# User specific rules
#
-include $(HOME)/configure/RULES_USER

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) vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)

View File

@ -7,9 +7,11 @@
# in the file LICENSE that is included with this distribution. # 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)) $(wildcard $($(top))/configure/RULES_BUILD))
ifneq ($(RELEASE_RULES_BUILDS),) ifneq ($(RELEASE_RULES_BUILDS),)
include $(RELEASE_RULES_BUILDS) include $(RELEASE_RULES_BUILDS)
@ -23,7 +25,7 @@ ifneq ($(RELEASE_CFG_RULES),)
include $(RELEASE_CFG_RULES) include $(RELEASE_CFG_RULES)
endif 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),) ifeq ($(wildcard $(TOP)/configure/CONFIG_BASE_VERSION),)
TOP_RULES_BUILDS = $(wildcard $(TOP)/configure/RULES_BUILD) TOP_RULES_BUILDS = $(wildcard $(TOP)/configure/RULES_BUILD)
@ -67,7 +69,3 @@ file_type_clean:
@$(RM) $(foreach type, $(FILE_TYPE), $($(type))) @$(RM) $(foreach type, $(FILE_TYPE), $($(type)))
.PHONY : file_type_clean .PHONY : file_type_clean
# User specific rules
#
-include $(HOME)/configure/RULES_USER

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. # National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as # Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory. # Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7 # EPICS BASE is distributed subject to a Software License Agreement found
# and higher are distributed subject to a Software License Agreement found # in the file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#************************************************************************* #*************************************************************************
# Octave definitions and rules # Octave definitions and rules

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. # National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as # Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory. # Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7 # EPICS BASE is distributed subject to a Software License Agreement found
# and higher are distributed subject to a Software License Agreement found # in the file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#************************************************************************* #*************************************************************************
#
# RULES_TARGET # RULES_TARGET
#
# This file is to be maintained by the community.
#
#-----------------------------------------------------------------------
define TARGET_template define TARGET_template
$(1)_$(2) += $$(if $$(strip $$($(1)_$(2)_$$(OS_CLASS))), \ $(1)_$(2) += $$(if $$(strip $$($(1)_$(2)_$$(OS_CLASS))), \

View File

@ -27,9 +27,13 @@ ifneq ($(CONFIG),$(TOP)/configure)
-include $(TOP)/configure/CONFIG_SITE.Common.RTEMS -include $(TOP)/configure/CONFIG_SITE.Common.RTEMS
endif 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. # 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 $(RTEMS_CUSTOM)
include $(CONFIG.CC) include $(CONFIG.CC)

View File

@ -9,5 +9,6 @@
# #
# All RTEMS targets use the same Makefile fragment # 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 include $(CONFIG)/os/CONFIG.Common.RTEMS

View File

@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment # All RTEMS targets use the same Makefile fragment
# #
EXE = .elf EXE = .elf
RTEMS_BSP = beatnik
RTEMS_TARGET_CPU = powerpc RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL

View File

@ -5,5 +5,6 @@
# #
# All RTEMS targets use the same Makefile fragment # 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 include $(CONFIG)/os/CONFIG.Common.RTEMS

View File

@ -5,5 +5,6 @@
# #
# All RTEMS targets use the same Makefile fragment # 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 include $(CONFIG)/os/CONFIG.Common.RTEMS

View File

@ -5,5 +5,6 @@
# #
# All RTEMS targets use the same Makefile fragment # 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 include $(CONFIG)/os/CONFIG.Common.RTEMS

View File

@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment # All RTEMS targets use the same Makefile fragment
# #
EXE = .elf EXE = .elf
RTEMS_BSP = mvme2100
RTEMS_TARGET_CPU = powerpc RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL

View File

@ -1,6 +1,7 @@
# #
# Author: Matt Rippa # Author: Matt Rippa
# #
RTEMS_BSP = mvme2700
RTEMS_TARGET_CPU = powerpc RTEMS_TARGET_CPU = powerpc
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
ARCH_DEP_CFLAGS += -DHAVE_PPCBUG ARCH_DEP_CFLAGS += -DHAVE_PPCBUG

View File

@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment # All RTEMS targets use the same Makefile fragment
# #
EXE = .elf EXE = .elf
RTEMS_BSP = mvme3100
RTEMS_TARGET_CPU = powerpc RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL

View File

@ -5,6 +5,7 @@
# All RTEMS targets use the same Makefile fragment # All RTEMS targets use the same Makefile fragment
# #
EXE = .elf EXE = .elf
RTEMS_BSP = mvme5500
RTEMS_TARGET_CPU = powerpc RTEMS_TARGET_CPU = powerpc
GNU_TARGET = powerpc-rtems GNU_TARGET = powerpc-rtems
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL

View File

@ -5,14 +5,15 @@
# #
# All RTEMS targets use the same Makefile fragment # All RTEMS targets use the same Makefile fragment
# #
RTEMS_TARGET_CPU=i386 RTEMS_BSP = pc386
RTEMS_TARGET_CPU = i386
MUNCH_SUFFIX = .boot MUNCH_SUFFIX = .boot
define MUNCH_CMD 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 \ $(BIN2BOOT) $@ 0x00097E00 \
$(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 temp.bin 0x00100000 0 $(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 $*.bin 0x00100000 0
rm -f temp.bin
endef endef
include $(CONFIG)/os/CONFIG.Common.RTEMS include $(CONFIG)/os/CONFIG.Common.RTEMS

View File

@ -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

View File

@ -5,5 +5,6 @@
# #
# All RTEMS targets use the same Makefile fragment # 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 include $(CONFIG)/os/CONFIG.Common.RTEMS

View File

@ -5,6 +5,7 @@
# #
# All RTEMS targets use the same Makefile fragment # All RTEMS targets use the same Makefile fragment
# #
RTEMS_BSP = uC5282
RTEMS_TARGET_CPU = m68k RTEMS_TARGET_CPU = m68k
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL

View File

@ -65,14 +65,14 @@ GNU = NO
# #
# Darwin shared libraries # Darwin shared libraries
# #
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined suppress \ SHRLIB_LDFLAGS = -dynamiclib -undefined dynamic_lookup \
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \ -install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \ $(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
$(addprefix -current_version , $(SHRLIB_VERSION)) $(addprefix -current_version , $(SHRLIB_VERSION))
SHRLIB_SUFFIX_BASE = .dylib SHRLIB_SUFFIX_BASE = .dylib
SHRLIB_SUFFIX = $(addprefix ., $(SHRLIB_VERSION))$(SHRLIB_SUFFIX_BASE) 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. # Position-independent code is the default on Darwin.

View File

@ -1,3 +0,0 @@
#
# Site-specific overrides for RTEMS-pc386 target
#

View File

@ -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

View File

@ -164,12 +164,11 @@
base/startup directory - contains scripts to set environment and path base/startup directory - contains scripts to set environment and path
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable unix.csh C shell script to set path and env variables
Site.profile bourne shell script to set path and env variables unix.sh Bourne shell script to set path and env variables
Site.cshrc c shell script to set path and env variables win32.bat Bat file example to configure win32-x86 target
cygwin.bat WIN32 bat file to set cygwin path and env variables windows.bat Bat file example to configure windows-x64 target
win32.bat WIN32 bat file to set path and env variables
base/configure directory - contains build definitions and rules base/configure directory - contains build definitions and rules

View File

@ -21,7 +21,7 @@ of my Bash login script (~/.bash_login):
# #
EPICS_BASE="${HOME}/src/EPICS/base" EPICS_BASE="${HOME}/src/EPICS/base"
EPICS_EXTENSIONS="${HOME}/src/EPICS/extensions" EPICS_EXTENSIONS="${HOME}/src/EPICS/extensions"
<strong>.</strong> "${EPICS_BASE}"/startup/Site.profile <strong>.</strong> "${EPICS_BASE}"/startup/unix.sh
</pre> </pre>
</li> </li>
<li> <li>

View File

@ -176,12 +176,11 @@
<H4>base/startup directory - contains scripts to set environment and path</H4> <H4>base/startup directory - contains scripts to set environment and path</H4>
<PRE> <PRE>
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable unix.csh C shell script to set path and env variables
Site.profile bourne shell script to set path and env variables unix.sh Bourne shell script to set path and env variables
Site.cshrc c shell script to set path and env variables win32.bat Bat file example to configure win32-x86 target
cygwin.bat WIN32 bat file to set cygwin path and env variables windows.bat Bat file example to configure windows-x64 target
win32.bat WIN32 bat file to set path and env variables
</PRE> </PRE>
<H4>base/configure directory - contains build definitions and rules</H4> <H4>base/configure directory - contains build definitions and rules</H4>

View File

@ -97,6 +97,115 @@ be happy to try and answer them!</p>
<!-- Insert inherited items immediately below here ... --> <!-- Insert inherited items immediately below here ... -->
<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> <h3>Finding info fields</h3>
<p>A new iocsh command <code>dbli</code> lists the info fields defined in the <p>A new iocsh command <code>dbli</code> lists the info fields defined in the
@ -113,15 +222,18 @@ release also includes additional protection against buffer overflows while
printing long links in <tt>dbpr</tt>, and corrects the output of long strings printing long links in <tt>dbpr</tt>, and corrects the output of long strings
from the <tt>dbgf</tt> command.</p> 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 <p>The VAL fields and related fields of these records are now <tt>DBF_LONG</tt>.
been extended from <tt>DBF_USHORT</tt> (16 bit) to <tt>DBF_LONG</tt> (32 bit). (Not <tt>DBF_ULONG</tt> in order to prevent Channel Access from promoting them
New bit fields <tt>B10</tt>...<tt>B1F</tt> have been added.</p> 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 <p>Device support that accesses <tt>VAL</tt> or the bit fields directly (most
<tt>mbbiDirectRecord1BF</tt> or <tt>mbboDirectRecord1BF</tt> is don't) and aims for compatibility with old and new versions of these records
defined. Device support which only accesses RVAL needs no modification.</p> 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> <h3>Restore use of ledlib for VxWorks command editing</h3>
@ -763,11 +875,45 @@ the stdout stream, making it hard to parse.</p>
callback.h header and removed the need for dbScan.c to reach into the internals callback.h header and removed the need for dbScan.c to reach into the internals
of its CALLBACK objects.</p> of its CALLBACK objects.</p>
<h2 align="center">Changes from the 3.15 branch since 3.15.6</h2>
<h2 align="center">Changes from the 3.15 branch since 3.15.5</h2>
<!-- Insert inherited items immediately below here ... --> <!-- Insert inherited items immediately below here ... -->
<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> <h3>HOWTO: Converting Wiki Record Reference to POD</h3>
<p>Some documentation has been added to the <tt>dbdToHtml.pl</tt> script <p>Some documentation has been added to the <tt>dbdToHtml.pl</tt> script
@ -799,15 +945,84 @@ of having go modify or replace the original. A new .gitignore pattern
tells git to ignore all configure/*.local files.</p> 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> <h3>Fixes for Launchpad bugs</h3>
<p>The following launchpad bugs have fixes included:</p> <p>The following launchpad bugs have fixes included:</p>
<ul> <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"> <li><a href="https://bugs.launchpad.net/epics-base/+bug/1747091">
lp: #1747091</a>, epicsTimeGetEvent() / generalTime bug</li> lp: #1747091</a>, epicsTimeGetEvent() / generalTime bug</li>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1743076"> <li><a href="https://bugs.launchpad.net/epics-base/+bug/1743076">

View File

@ -133,7 +133,7 @@ made.</p>
<tr> <tr>
<td>&nbsp;</td> <td>&nbsp;</td>
<td>Release Manager</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> <ul>
<li> <li>
<tt>R7.1.1-pre<i>n</i></tt> <tt>R7.1.1-pre<i>n</i></tt>
@ -143,7 +143,7 @@ made.</p>
<tt>R7.1.1-rc<i>n</i></tt> <tt>R7.1.1-rc<i>n</i></tt>
&mdash; release candidate tag &mdash; release candidate tag
</li> </li>
</ul> </ul>
<blockquote><tt> <blockquote><tt>
cd base-7.1<br /> cd base-7.1<br />
git tag -m 'ANJ: Tagged for 7.1.1-rc1' R7.1.1-rc1 git tag -m 'ANJ: Tagged for 7.1.1-rc1' R7.1.1-rc1

View File

@ -193,7 +193,7 @@ udpiiu::udpiiu (
#ifdef IP_MULTICAST_TTL #ifdef IP_MULTICAST_TTL
{ {
int ttl; osiSockOptMcastTTL_t ttl;
long val; long val;
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val)) if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
val =1; val =1;

View File

@ -143,6 +143,10 @@ sub display {
printf " Lo ctrl limit: %g\n", $data->{lower_ctrl_limit}; printf " Lo ctrl limit: %g\n", $data->{lower_ctrl_limit};
printf " Hi ctrl limit: %g\n", $data->{upper_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 { } else {
my $value = format_number($data, $type); my $value = format_number($data, $type);
if ($opt_t) { if ($opt_t) {

View File

@ -34,7 +34,7 @@
#include "errlog.h" #include "errlog.h"
#include "errMdef.h" #include "errMdef.h"
#define epicsExportSharedSymbols #include "epicsExport.h" /* #define epicsExportSharedSymbols */
#include "caeventmask.h" #include "caeventmask.h"
#include "callback.h" #include "callback.h"
#include "dbAccessDefs.h" #include "dbAccessDefs.h"
@ -65,6 +65,9 @@
epicsShareDef struct dbBase *pdbbase = 0; epicsShareDef struct dbBase *pdbbase = 0;
epicsShareDef volatile int interruptAccept=FALSE; epicsShareDef volatile int interruptAccept=FALSE;
epicsShareDef int dbAccessDebugPUTF = 0;
epicsExportAddress(int, dbAccessDebugPUTF);
/* Hook Routines */ /* Hook Routines */
epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL; epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
@ -446,22 +449,6 @@ int dbGetFieldIndex(const struct dbAddr *paddr)
return paddr->pfldDes->indRecordType; 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. * Process the record.
* 1. Check for breakpoints. * 1. Check for breakpoints.
@ -527,7 +514,8 @@ long dbProcess(dbCommon *precord)
unsigned short monitor_mask; unsigned short monitor_mask;
if (*ptrace) 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 */ /* raise scan alarm after MAX_LOCK times */
if ((precord->stat == SCAN_ALARM) || if ((precord->stat == SCAN_ALARM) ||
@ -556,7 +544,8 @@ long dbProcess(dbCommon *precord)
/* if disabled check disable alarm severity and return success */ /* if disabled check disable alarm severity and return success */
if (precord->disa == precord->disv) { if (precord->disa == precord->disv) {
if (*ptrace) 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*/ /*take care of caching and notifyCompletion*/
precord->rpro = FALSE; precord->rpro = FALSE;
@ -593,7 +582,7 @@ long dbProcess(dbCommon *precord)
} }
if (*ptrace) if (*ptrace)
printf("%s: Process %s\n", context, precord->name); printf("%s: dbProcess of '%s'\n", context, precord->name);
/* process record */ /* process record */
status = prset->process(precord); status = prset->process(precord);
@ -713,6 +702,18 @@ void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
pdbentry->precnode = ppvt->recnode; 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) long dbValueSize(short dbr_type)
{ {
/* sizes for value associated with each DBR request type */ /* sizes for value associated with each DBR request type */
@ -1040,7 +1041,7 @@ static long dbPutFieldLink(DBADDR *paddr,
return S_db_badDbrtype; return S_db_badDbrtype;
} }
status = dbParseLink(pstring, pfldDes->field_type, &link_info, 0); status = dbParseLink(pstring, pfldDes->field_type, &link_info);
if (status) if (status)
return status; return status;
@ -1213,8 +1214,8 @@ long dbPutField(DBADDR *paddr, short dbrType,
precord->scan == 0 && precord->scan == 0 &&
dbrType < DBR_PUT_ACKT)) { dbrType < DBR_PUT_ACKT)) {
if (precord->pact) { if (precord->pact) {
if (precord->tpro) if (dbAccessDebugPUTF && precord->tpro)
printf("%s: Active %s\n", printf("%s: dbPutField to Active '%s', setting RPRO=1\n",
epicsThreadGetNameSelf(), precord->name); epicsThreadGetNameSelf(), precord->name);
precord->rpro = TRUE; precord->rpro = TRUE;
} else { } else {
@ -1347,4 +1348,3 @@ done:
paddr->pfield = pfieldsave; paddr->pfield = pfieldsave;
return status; return status;
} }

View File

@ -34,6 +34,7 @@ extern "C" {
epicsShareExtern struct dbBase *pdbbase; epicsShareExtern struct dbBase *pdbbase;
epicsShareExtern volatile int interruptAccept; epicsShareExtern volatile int interruptAccept;
epicsShareExtern int dbAccessDebugPUTF;
/* The database field and request types are defined in dbFldTypes.h*/ /* The database field and request types are defined in dbFldTypes.h*/
/* Data Base Request Options */ /* Data Base Request Options */

View File

@ -842,6 +842,7 @@ static void eventCallback(struct event_handler_args arg)
struct dbr_time_double *pdbr_time_double; struct dbr_time_double *pdbr_time_double;
dbCaCallback monitor = 0; dbCaCallback monitor = 0;
void *userPvt = 0; void *userPvt = 0;
int doScan = 1;
assert(pca); assert(pca);
epicsMutexMustLock(pca->lock); epicsMutexMustLock(pca->lock);
@ -872,10 +873,13 @@ static void eventCallback(struct event_handler_args arg)
memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size); memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size);
pca->gotInString = TRUE; pca->gotInString = TRUE;
} else switch (arg.type){ } 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_STRING:
case DBR_TIME_SHORT: case DBR_TIME_SHORT:
case DBR_TIME_FLOAT: case DBR_TIME_FLOAT:
case DBR_TIME_ENUM:
case DBR_TIME_CHAR: case DBR_TIME_CHAR:
case DBR_TIME_LONG: case DBR_TIME_LONG:
case DBR_TIME_DOUBLE: case DBR_TIME_DOUBLE:
@ -893,7 +897,7 @@ static void eventCallback(struct event_handler_args arg)
pca->sevr = pdbr_time_double->severity; pca->sevr = pdbr_time_double->severity;
pca->stat = pdbr_time_double->status; pca->stat = pdbr_time_double->status;
memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp)); memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp));
if (precord) { if (doScan && precord) {
struct pv_link *ppv_link = &plink->value.pv_link; struct pv_link *ppv_link = &plink->value.pv_link;
if ((ppv_link->pvlMask & pvlOptCP) || if ((ppv_link->pvlMask & pvlOptCP) ||

View File

@ -12,6 +12,29 @@
* Current Author: Andrew Johnson * 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 <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
@ -43,17 +66,22 @@
#include "dbNotify.h" #include "dbNotify.h"
#include "dbScan.h" #include "dbScan.h"
#include "dbStaticLib.h" #include "dbStaticLib.h"
#include "dbServer.h"
#include "devSup.h" #include "devSup.h"
#include "link.h" #include "link.h"
#include "recGbl.h" #include "recGbl.h"
#include "recSup.h" #include "recSup.h"
#include "special.h" #include "special.h"
#include "dbDbLink.h"
/***************************** Database Links *****************************/ /***************************** Database Links *****************************/
/* Forward definition */ /* Forward definitions */
static lset dbDb_lset; static lset dbDb_lset;
static long processTarget(dbCommon *psrc, dbCommon *pdst);
long dbDbInitLink(struct link *plink, short dbfType) long dbDbInitLink(struct link *plink, short dbfType)
{ {
DBADDR dbaddr; DBADDR dbaddr;
@ -138,11 +166,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
/* scan passive records if link is process passive */ /* scan passive records if link is process passive */
if (ppv_link->pvlMask & pvlOptPP) { if (ppv_link->pvlMask & pvlOptPP) {
unsigned char pact = precord->pact;
precord->pact = TRUE;
status = dbScanPassive(precord, paddr->precord); status = dbScanPassive(precord, paddr->precord);
precord->pact = pact;
if (status) if (status)
return status; return status;
} }
@ -311,22 +335,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
return status; return status;
if (paddr->pfield == (void *) &pdest->proc || if (paddr->pfield == (void *) &pdest->proc ||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) { (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
/* if dbPutField caused asyn record to process */ status = processTarget(psrce, pdest);
/* 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;
}
} }
return status; return status;
} }
@ -356,3 +368,75 @@ static lset dbDb_lset = {
dbDbPutValue, NULL, dbDbPutValue, NULL,
dbDbScanFwdLink, doLocked 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;
}

View File

@ -2,7 +2,7 @@
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne * Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory. * National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found * 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 */ /* dbJLink.c */
@ -25,19 +25,33 @@
#include "dbLock.h" #include "dbLock.h"
#include "dbStaticLib.h" #include "dbStaticLib.h"
#include "link.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 { typedef struct parseContext {
jlink *pjlink; jlink *pjlink;
jlink *product; jlink *product;
short dbfType; short dbfType;
short jsonDepth; short jsonDepth;
unsigned key_is_link:1;
unsigned parse_debug:1;
unsigned lset_debug:1;
} parseContext; } 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) #define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
static int dbjl_return(parseContext *parser, jlif_result result) { static int dbjl_return(parseContext *parser, jlif_result result) {
@ -45,8 +59,8 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result); printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
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->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
} }
if (result == jlif_stop && pjlink) { if (result == jlif_stop && pjlink) {
@ -59,6 +73,9 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
pjlink->pif->free_jlink(pjlink); pjlink->pif->free_jlink(pjlink);
} }
IFDEBUG(10)
printf(" returning %d %s\n", result,
result == jlif_stop ? "*** STOP ***" : "Continue");
return result; return result;
} }
@ -68,8 +85,8 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result); printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
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->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
} }
if (result == jlif_stop || pjlink->parseDepth > 0) 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) { } else if (parent->pif->end_child) {
parent->pif->end_child(parent, pjlink); parent->pif->end_child(parent, pjlink);
} }
pjlink->debug = 0;
parser->pjlink = parent; parser->pjlink = parent;
@ -159,29 +175,46 @@ static int dbjl_start_map(void *ctx) {
if (!pjlink) { if (!pjlink) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_start_map(NULL)\t"); printf("dbjl_start_map(NULL)\t");
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n", printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
parser->jsonDepth, parser->key_is_link); parser->jsonDepth, parser->dbfType);
} }
assert(parser->jsonDepth == 0); assert(parser->jsonDepth == 0);
parser->jsonDepth++; parser->jsonDepth++;
parser->key_is_link = 1;
return jlif_continue; /* Opening '{' */ return jlif_continue; /* Opening '{' */
} }
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink); printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", 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->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
} }
pjlink->parseDepth++; pjlink->parseDepth++;
parser->jsonDepth++; parser->jsonDepth++;
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink); result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
if (result == jlif_key_child_link) { switch (result) {
parser->key_is_link = 1; case jlif_key_child_inlink:
parser->dbfType = DBF_INLINK;
result = jlif_continue; 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) IFDEBUG(10)
@ -196,8 +229,9 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
char *link_name; char *link_name;
linkSup *linkSup; linkSup *linkSup;
jlif *pjlif; jlif *pjlif;
jlink *child;
if (!parser->key_is_link) { if (parser->dbfType == 0) {
if (!pjlink) { if (!pjlink) {
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n", errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
(int) len, key); (int) len, key);
@ -207,8 +241,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_map_key(%s@%p, \"%.*s\")\t", printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
pjlink->pif->name, pjlink, (int) len, key); pjlink->pif->name, pjlink, (int) len, key);
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->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
} }
assert(pjlink->parseDepth > 0); assert(pjlink->parseDepth > 0);
@ -219,8 +253,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key); printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key);
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n", printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
parser->jsonDepth, parser->key_is_link); parser->jsonDepth, parser->dbfType);
} }
link_name = dbmfStrndup((const char *) key, len); 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); return dbjl_return(parser, jlif_stop);
} }
dbmfFree(link_name); child = pjlif->alloc_jlink(parser->dbfType);
if (!child) {
pjlink = pjlif->alloc_jlink(parser->dbfType); errlogPrintf("dbJLinkInit: Link type '%s' allocation failed. \n",
if (!pjlink) { link_name);
errlogPrintf("dbJLinkInit: Out of memory\n"); dbmfFree(link_name);
return dbjl_return(parser, jlif_stop); return dbjl_return(parser, jlif_stop);
} }
pjlink->pif = pjlif;
pjlink->parent = NULL; child->pif = pjlif;
pjlink->parseDepth = 0; child->parseDepth = 0;
pjlink->debug = !!parser->lset_debug; child->debug = 0;
if (parser->pjlink) { if (parser->pjlink) {
/* We're starting a child link, save its parent */ /* 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; else
parser->key_is_link = 0; child->parent = NULL;
parser->pjlink = child;
parser->dbfType = 0;
dbmfFree(link_name);
IFDEBUG(8) 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; return jlif_continue;
} }
@ -274,9 +316,9 @@ static int dbjl_end_map(void *ctx) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_end_map(%s@%p)\t", printf("dbjl_end_map(%s@%p)\t",
pjlink ? pjlink->pif->name : "NULL", pjlink); 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->jsonDepth, pjlink ? pjlink->parseDepth : 0,
parser->key_is_link); parser->dbfType);
} }
parser->jsonDepth--; parser->jsonDepth--;
@ -298,8 +340,8 @@ static int dbjl_start_array(void *ctx) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink); printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", 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->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
} }
assert(pjlink); assert(pjlink);
@ -316,8 +358,8 @@ static int dbjl_end_array(void *ctx) {
IFDEBUG(10) { IFDEBUG(10) {
printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink); printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", 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->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
} }
assert(pjlink); assert(pjlink);
@ -335,7 +377,7 @@ static yajl_callbacks dbjl_callbacks = {
}; };
long dbJLinkParse(const char *json, size_t jlen, short dbfType, long dbJLinkParse(const char *json, size_t jlen, short dbfType,
jlink **ppjlink, unsigned opts) jlink **ppjlink)
{ {
parseContext context, *parser = &context; parseContext context, *parser = &context;
yajl_alloc_funcs dbjl_allocs; yajl_alloc_funcs dbjl_allocs;
@ -347,17 +389,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
parser->product = NULL; parser->product = NULL;
parser->dbfType = dbfType; parser->dbfType = dbfType;
parser->jsonDepth = 0; parser->jsonDepth = 0;
parser->key_is_link = 0;
parser->parse_debug = !!(opts&LINK_DEBUG_JPARSE);
parser->lset_debug = !!(opts&LINK_DEBUG_LSET);
IFDEBUG(10) IFDEBUG(10)
printf("dbJLinkInit(\"%.*s\", %d, %p)\n", printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
(int) jlen, json, dbfType, ppjlink); (int) jlen, json, dbfType, ppjlink);
IFDEBUG(10) IFDEBUG(10)
printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n", printf("dbJLinkInit: jsonDepth=%d, dbfType=%d\n",
parser->jsonDepth, parser->key_is_link); parser->jsonDepth, parser->dbfType);
yajl_set_default_alloc_funcs(&dbjl_allocs); yajl_set_default_alloc_funcs(&dbjl_allocs);
yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser); 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; return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, jlen); 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); ys = yajl_complete_parse(yh);
IFDEBUG(10)
printf("dbJLinkInit: yajl_complete_parse() returned %d\n", ys);
}
switch (ys) { switch (ys) {
unsigned char *err; unsigned char *err;
@ -378,6 +423,9 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
break; break;
case yajl_status_error: 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); err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
errlogPrintf("dbJLinkInit: %s\n", err); errlogPrintf("dbJLinkInit: %s\n", err);
yajl_free_error(yh, err); yajl_free_error(yh, err);
@ -389,18 +437,24 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
} }
yajl_free(yh); yajl_free(yh);
IFDEBUG(10)
printf("dbJLinkInit: returning status=0x%lx\n\n",
status);
return status; return status;
} }
long dbJLinkInit(struct link *plink) long dbJLinkInit(struct link *plink)
{ {
jlink *pjlink;
assert(plink); assert(plink);
pjlink = plink->value.json.jlink;
if (pjlink) if (plink->type == JSON_LINK) {
plink->lset = pjlink->pif->get_lset(pjlink); jlink *pjlink = plink->value.json.jlink;
if (pjlink)
plink->lset = pjlink->pif->get_lset(pjlink);
}
dbLinkOpen(plink); dbLinkOpen(plink);
return 0; return 0;

View File

@ -2,7 +2,7 @@
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne * Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory. * National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found * 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 */ /* dbJLink.h */
@ -21,12 +21,16 @@ typedef enum {
jlif_continue = 1 jlif_continue = 1
} jlif_result; } jlif_result;
epicsShareExtern const char *jlif_result_name[2];
typedef enum { typedef enum {
jlif_key_stop = jlif_stop, jlif_key_stop = jlif_stop,
jlif_key_continue = jlif_continue, jlif_key_continue = jlif_continue,
jlif_key_child_link jlif_key_child_inlink, jlif_key_child_outlink, jlif_key_child_fwdlink
} jlif_key_result; } jlif_key_result;
epicsShareExtern const char *jlif_key_result_name[5];
struct link; struct link;
struct lset; struct lset;
struct jlif; struct jlif;
@ -35,7 +39,7 @@ typedef struct jlink {
struct jlif *pif; /* Link methods */ struct jlif *pif; /* Link methods */
struct jlink *parent; /* NULL for top-level links */ struct jlink *parent; /* NULL for top-level links */
int parseDepth; /* Used by parser, unused afterwards */ 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 */ /* Link types extend or embed this structure for private storage */
} jlink; } jlink;
@ -72,8 +76,9 @@ typedef struct jlif {
/* Optional, parser saw a string value */ /* Optional, parser saw a string value */
jlif_key_result (*parse_start_map)(jlink *); jlif_key_result (*parse_start_map)(jlink *);
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_link /* Optional, parser saw an open-brace '{'. Return jlif_key_child_inlink,
* to expect a child link next (extra key/value pairs may follow). * 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); 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); void (*end_child)(jlink *parent, jlink *child);
/* Optional, called with pointer to the new child link after /* 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 *); struct lset* (*get_lset)(const jlink *);
/* Required, return lset for this link instance */ /* Required, return lset for this link instance */
@ -98,7 +104,7 @@ typedef struct jlif {
void (*report)(const jlink *, int level, int indent); void (*report)(const jlink *, int level, int indent);
/* Optional, print status information about this link instance, then /* Optional, print status information about this link instance, then
* if (level > 0) print a link identifier (at indent+2) and call * 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. * for each child.
*/ */
@ -107,13 +113,19 @@ typedef struct jlif {
* Stop immediately and return status if non-zero. * 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, /* Link types must NOT extend this table with their own routines,
* this space is reserved for extensions to the jlink interface. * this space is reserved for extensions to the jlink interface.
*/ */
} jlif; } jlif;
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType, epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
jlink **ppjlink, unsigned opts); jlink **ppjlink);
epicsShareFunc long dbJLinkInit(struct link *plink); epicsShareFunc long dbJLinkInit(struct link *plink);
epicsShareFunc void dbJLinkFree(jlink *); epicsShareFunc void dbJLinkFree(jlink *);
@ -130,4 +142,3 @@ epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx);
#endif #endif
#endif /* INC_dbJLink_H */ #endif /* INC_dbJLink_H */

View File

@ -265,8 +265,19 @@ int dbIsLinkConnected(const struct link *plink)
{ {
lset *plset = plink->lset; lset *plset = plink->lset;
if (!plset || !plset->isConnected) if (!plset)
return FALSE; 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); return plset->isConnected(plink);
} }

View File

@ -27,54 +27,337 @@ extern "C" {
struct dbLocker; 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); 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 { typedef struct lset {
/* Characteristics of the link type */ /* 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; const unsigned isConstant:1;
/** @brief link volatility
*
* 0 means the link is always connected.
*/
const unsigned isVolatile:1; 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); 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); 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); 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, long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen); 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 (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest); long *pnRequest);
/* Metadata */ /* 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); 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); int (*getDBFtype)(const struct link *plink);
long (*getElements)(const struct link *plink, long *nelements);
/* Get data */ /* 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 (*getValue)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest); 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); 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); 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, long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
double *hi, double *hihi); 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); 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); 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, long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity); 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); long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
/* Put data */ /* 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, long (*putValue)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest); 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, long (*putAsync)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest); const void *pbuffer, long nRequest);
/* Process */ /* 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); void (*scanForward)(struct link *plink);
/* Atomicity */ /* 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); long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
} lset; } lset;
@ -99,7 +382,7 @@ epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer, epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
long *pnRequest); 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 dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink); epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
epicsShareFunc long dbTryGetLink(struct link *, short dbrType, void *pbuffer, epicsShareFunc long dbTryGetLink(struct link *, short dbrType, void *pbuffer,

View File

@ -13,6 +13,8 @@
#ifndef INCdbLockh #ifndef INCdbLockh
#define INCdbLockh #define INCdbLockh
#include <stddef.h>
#include "ellLib.h" #include "ellLib.h"
#include "shareLib.h" #include "shareLib.h"

View File

@ -19,6 +19,7 @@
#include "menuScan.h" #include "menuScan.h"
#include "shareLib.h" #include "shareLib.h"
#include "compilerDependencies.h" #include "compilerDependencies.h"
#include "devSup.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -33,9 +34,7 @@ extern "C" {
#define MIN_PHASE SHRT_MIN #define MIN_PHASE SHRT_MIN
/*definitions for I/O Interrupt Scanning */ /*definitions for I/O Interrupt Scanning */
struct ioscan_head; /* IOSCANPVT now defined in devSup.h */
typedef struct ioscan_head *IOSCANPVT;
typedef struct event_list *EVENTPVT; typedef struct event_list *EVENTPVT;
struct dbCommon; struct dbCommon;

View File

@ -15,6 +15,10 @@
#include "shareLib.h" #include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @file dbState.h /** @file dbState.h
* @brief Generic IOC state facility * @brief Generic IOC state facility
* *
@ -89,4 +93,9 @@ epicsShareFunc void dbStateShow(dbStateId id, unsigned int level);
*/ */
epicsShareFunc void dbStateShowAll(unsigned int level); epicsShareFunc void dbStateShowAll(unsigned int level);
#ifdef __cplusplus
}
#endif
#endif // INCdbStateH #endif // INCdbStateH

View File

@ -19,6 +19,7 @@
#include "alarm.h" #include "alarm.h"
#include "dbDefs.h" #include "dbDefs.h"
#include "alarm.h"
#include "epicsMath.h" #include "epicsMath.h"
#include "epicsPrint.h" #include "epicsPrint.h"
#include "epicsStdlib.h" #include "epicsStdlib.h"
@ -180,6 +181,9 @@ unsigned short recGblResetAlarms(void *precord)
epicsEnum16 val_mask = 0; epicsEnum16 val_mask = 0;
epicsEnum16 stat_mask = 0; epicsEnum16 stat_mask = 0;
if (new_sevr > INVALID_ALARM)
new_sevr = INVALID_ALARM;
pdbc->stat = new_stat; pdbc->stat = new_stat;
pdbc->sevr = new_sevr; pdbc->sevr = new_sevr;
pdbc->nsta = 0; pdbc->nsta = 0;

View File

@ -2241,7 +2241,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
if(!plink->text) if(!plink->text)
continue; 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. /* This was already parsed once when ->text was set.
* Any syntax error messages were printed at that time. * Any syntax error messages were printed at that time.
*/ */
@ -2270,7 +2270,7 @@ void dbFreeLinkInfo(dbLinkInfo *pinfo)
pinfo->target = NULL; 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; char *pstr;
size_t len; size_t len;
@ -2306,7 +2306,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
/* Check for braces => JSON */ /* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') { if (*str == '{' && str[len-1] == '}') {
if (dbJLinkParse(str, len, ftype, &pinfo->jlink, opts)) if (dbJLinkParse(str, len, ftype, &pinfo->jlink))
goto fail; goto fail;
pinfo->ltype = JSON_LINK; pinfo->ltype = JSON_LINK;
@ -2353,9 +2353,13 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
else if (strcmp(pinfo->hwid, "VS")==0) pinfo->ltype = VXI_IO; else if (strcmp(pinfo->hwid, "VS")==0) pinfo->ltype = VXI_IO;
else goto fail; else goto fail;
if (parm && pinfo->ltype != RF_IO) { if (pinfo->ltype != RF_IO) {
/* move parm string to beginning of buffer */ if (!parm) {
memmove(pinfo->target, parm, len + 1); 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) { } else if (!parm && pinfo->ltype == RF_IO) {
/* RF_IO, the string isn't needed at all */ /* RF_IO, the string isn't needed at all */
free(pinfo->target); free(pinfo->target);
@ -2641,21 +2645,8 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
case DBF_FWDLINK: { case DBF_FWDLINK: {
dbLinkInfo link_info; dbLinkInfo link_info;
DBLINK *plink = (DBLINK *)pfield; DBLINK *plink = (DBLINK *)pfield;
DBENTRY infoentry;
unsigned opts = 0;
if(pdbentry->precnode && ellCount(&pdbentry->precnode->infoList)) { status = dbParseLink(pstring, pflddes->field_type, &link_info);
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);
if (status) break; if (status) break;
if (plink->type==CONSTANT && plink->value.constantStr==NULL) { if (plink->type==CONSTANT && plink->value.constantStr==NULL) {

View File

@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory. * Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7 * EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found * 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 */ /* dbStaticPvt.h */
/* /*
@ -59,13 +59,10 @@ typedef struct dbLinkInfo {
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec); long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
#define LINK_DEBUG_LSET 1
#define LINK_DEBUG_JPARSE 2
/* Parse link string. no record locks needed. /* Parse link string. no record locks needed.
* on success caller must free pinfo->target * 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 /* Check if link type allow the parsed link value pinfo
* to be assigned to the given link. * to be assigned to the given link.
* Record containing plink must be locked. * Record containing plink must be locked.

View File

@ -6,7 +6,11 @@
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* devSup.h Device Support */ /** @file devSup.h
*
* @brief Device support routines
*/
/* /*
* Author: Marty Kraimer * Author: Marty Kraimer
* Date: 6-1-90 * Date: 6-1-90
@ -21,6 +25,111 @@
/* structures defined elsewhere */ /* structures defined elsewhere */
struct dbCommon; struct dbCommon;
struct devSup; 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 #ifdef __cplusplus
extern "C" { extern "C" {
@ -29,6 +138,8 @@ extern "C" {
typedef long (*DEVSUPFUN)(); /* ptr to device support function*/ typedef long (*DEVSUPFUN)(); /* ptr to device support function*/
#endif #endif
#ifndef USE_TYPED_DSET
typedef struct dset { /* device support entry table */ typedef struct dset { /* device support entry table */
long number; /*number of support routines*/ long number; /*number of support routines*/
DEVSUPFUN report; /*print report*/ DEVSUPFUN report; /*print report*/
@ -38,11 +149,15 @@ typedef struct dset { /* device support entry table */
/*other functions are record dependent*/ /*other functions are record dependent*/
} dset; } dset;
typedef struct dsxt { /* device support extension table */ #else
long (*add_record)(struct dbCommon *precord); typedef typed_dset dset;
long (*del_record)(struct dbCommon *precord); #endif /* USE_TYPED_DSET */
/* Recordtypes are *not* allowed to extend this table */
} dsxt; /** 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 */ epicsShareExtern dsxt devSoft_DSXT; /* Allow anything table */

View File

@ -6,7 +6,10 @@
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* drvSup.h Driver Support */ /** @file drvSup.h
*
* @brief Driver support routines.
*/
/* /*
* Author: Marty Kraimer * Author: Marty Kraimer
@ -18,16 +21,38 @@
#include "errMdef.h" #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) ) #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_noDrvSup (M_drvSup| 1) /*SDR_DRVSUP: Driver support missing*/
#define S_drv_noDrvet (M_drvSup| 3) /*Missing driver support entry table*/ #define S_drv_noDrvet (M_drvSup| 3) /*Missing driver support entry table*/

File diff suppressed because it is too large Load Diff

View File

@ -34,10 +34,10 @@ be written to stdout unless the -o option is given.</p>
<dl> <dl>
<dt><tt>-V</tt></dt> <dt><tt>-V</tt></dt>
<dd>Verbose warnings; if this parameter is specified then any undefined <dd>Verbose warnings; if this parameter is specified then any undefined or
macro discovered in the template file which does not have an associated recursive macros discovered in the template will be considered an error and
default value is considered an error. An error message is generated, and will be marked in the output file. An error message will be shown, and when
when msi terminates it will do so with an exit status of 2.</dd> msi terminates it will do so with an exit status of 2.</dd>
<dt><tt>-g</tt></dt> <dt><tt>-g</tt></dt>
<dd>When this flag is given all macros defined in a substitution file will <dd>When this flag is given all macros defined in a substitution file will

View File

@ -26,3 +26,4 @@ dbCore_SRCS += miscIocRegister.c
dbCore_SRCS += dlload.c dbCore_SRCS += dlload.c
dbCore_SRCS += iocshRegisterCommon.c dbCore_SRCS += iocshRegisterCommon.c
miscIocRegister_CFLAGS_iOS = -DSYSTEM_UNAVAILABLE

View File

@ -12,6 +12,9 @@ variable(asCaDebug,int)
# CA server debug flag (very verbose) range[0,5] # CA server debug flag (very verbose) range[0,5]
variable(CASDEBUG,int) variable(CASDEBUG,int)
# Link parsing debug
variable(dbJLinkDebug,int)
# Static database access variables # Static database access variables
variable(dbRecordsOnceOnly,int) variable(dbRecordsOnceOnly,int)
variable(dbRecordsAbcSorted,int) variable(dbRecordsAbcSorted,int)
@ -19,8 +22,12 @@ variable(dbBptNotMonotonic,int)
variable(dbQuietMacroWarnings,int) variable(dbQuietMacroWarnings,int)
variable(dbConvertStrict,int) variable(dbConvertStrict,int)
# PUTF/RPRO tracing; set TPRO on records to trace
variable(dbAccessDebugPUTF,int)
# dbLoadTemplate settings # dbLoadTemplate settings
variable(dbTemplateMaxVars,int) variable(dbTemplateMaxVars,int)
# Default number of parallel callback threads # Default number of parallel callback threads
variable(callbackParallelThreadsDefault,int) variable(callbackParallelThreadsDefault,int)

View File

@ -66,10 +66,12 @@ void miscIocRegister(void)
/* system -- escape to system command interpreter. /* 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) * 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 systemArg0 = { "command string",iocshArgString};
static const iocshArg * const systemArgs[] = {&systemArg0}; static const iocshArg * const systemArgs[] = {&systemArg0};
static const iocshFuncDef systemFuncDef = {"system",1,systemArgs}; static const iocshFuncDef systemFuncDef = {"system",1,systemArgs};
@ -77,12 +79,15 @@ static void systemCallFunc(const iocshArgBuf *args)
{ {
system(args[0].sval); system(args[0].sval);
} }
#endif
static void iocshSystemCommand(void) static void iocshSystemCommand(void)
{ {
#ifndef SYSTEM_UNAVAILABLE
if (system(NULL)) if (system(NULL))
iocshRegister(&systemFuncDef, systemCallFunc); iocshRegister(&systemFuncDef, systemCallFunc);
else else
#endif
errlogPrintf ("Can't register 'system' command -- no command interpreter available.\n"); errlogPrintf ("Can't register 'system' command -- no command interpreter available.\n");
} }
epicsExportRegistrar(iocshSystemCommand); epicsExportRegistrar(iocshSystemCommand);

View File

@ -324,7 +324,7 @@ void rsrv_build_addr_lists(void)
#ifdef IP_MULTICAST_TTL #ifdef IP_MULTICAST_TTL
{ {
int ttl; osiSockOptMcastTTL_t ttl;
long val; long val;
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val)) if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
val =1; val =1;

View File

@ -23,6 +23,7 @@
#include "dbDefs.h" #include "dbDefs.h"
#include "dbAccess.h" #include "dbAccess.h"
#include "dbConstLink.h" #include "dbConstLink.h"
#include "dbEvent.h"
#include "recGbl.h" #include "recGbl.h"
#include "devSup.h" #include "devSup.h"
#include "cantProceed.h" #include "cantProceed.h"
@ -96,11 +97,15 @@ static long readLocked(struct link *pinp, void *dummy)
static long read_aai(aaiRecord *prec) static long read_aai(aaiRecord *prec)
{ {
epicsUInt32 nord = prec->nord;
struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp; struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp;
long status = dbLinkDoLocked(pinp, readLocked, NULL); long status = dbLinkDoLocked(pinp, readLocked, NULL);
if (status == S_db_noLSET) if (status == S_db_noLSET)
status = readLocked(pinp, NULL); status = readLocked(pinp, NULL);
if (!status && nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return status; return status;
} }

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 Lawrence Berkeley Laboratory,The Control Systems * Copyright (c) 2002 Lawrence Berkeley Laboratory,The Control Systems
* Group, Systems Engineering Department * Group, Systems Engineering Department
* EPICS BASE is distributed subject to a Software License Agreement found * 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 "alarm.h"
#include "dbDefs.h" #include "dbDefs.h"
#include "dbAccess.h" #include "dbAccess.h"
#include "dbEvent.h"
#include "recGbl.h" #include "recGbl.h"
#include "devSup.h" #include "devSup.h"
#include "subArrayRecord.h" #include "subArrayRecord.h"
@ -101,6 +102,7 @@ static long read_sa(subArrayRecord *prec)
{ {
long status; long status;
struct sart rt; struct sart rt;
epicsUInt32 nord = prec->nord;
rt.nRequest = prec->indx + prec->nelm; rt.nRequest = prec->indx + prec->nelm;
if (rt.nRequest > prec->malm) if (rt.nRequest > prec->malm)
@ -123,8 +125,12 @@ static long read_sa(subArrayRecord *prec)
status = readLocked(&prec->inp, &rt); status = readLocked(&prec->inp, &rt);
} }
if (!status && rt.nRequest > 0) if (!status && rt.nRequest > 0) {
subset(prec, rt.nRequest); subset(prec, rt.nRequest);
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
}
return status; return status;
} }

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as * Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory. * Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found * 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; long status;
struct wfrt rt; struct wfrt rt;
epicsUInt32 nord = prec->nord;
rt.nRequest = prec->nelm; rt.nRequest = prec->nelm;
rt.ptime = (dbLinkIsConstant(&prec->tsel) && rt.ptime = (dbLinkIsConstant(&prec->tsel) &&
@ -93,6 +94,8 @@ static long read_wf(waveformRecord *prec)
if (!status && rt.nRequest > 0) { if (!status && rt.nRequest > 0) {
prec->nord = rt.nRequest; prec->nord = rt.nRequest;
prec->udf = FALSE; prec->udf = FALSE;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
} }
return status; return status;

View File

@ -2,7 +2,7 @@
# Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne # Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory. # National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found # 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. # This is a Makefile fragment, see src/std/Makefile.
@ -13,6 +13,7 @@ DBD += links.dbd
dbRecStd_SRCS += lnkConst.c dbRecStd_SRCS += lnkConst.c
dbRecStd_SRCS += lnkCalc.c dbRecStd_SRCS += lnkCalc.c
dbRecStd_SRCS += lnkState.c
dbRecStd_SRCS += lnkDebug.c
HTMLS += links.html HTMLS += links.html

View File

@ -13,6 +13,12 @@ The following additional link types are available in this release:
=item * L<Calc|/"Calculation Link calc"> =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 =back
=head2 Using JSON Links =head2 Using JSON Links
@ -31,15 +37,16 @@ database file syntax.
=cut =cut
link(const, lnkConstIf) link(const, lnkConstIf)
=head3 Constant Link C<"const"> =head3 Constant Link C<"const">
Constant links provide one or more values at link initalization time, but do not Constant links are input links that provide literal values at link initalization
return any data when their C<getValue()> routine is called. Most record types time, but do not return any data when their C<getValue()> routine is called.
support the use of constant links by calling C<recGblInitConstantLink()> at Most record types support the use of constant links on their input links by
record initialization, which results in the constant value being loaded into the calling C<recGblInitConstantLink()> at record initialization, which results in
target field at that time. 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 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 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 =cut
link(calc, lnkCalcIf) link(calc, lnkCalcIf)
=head3 Calculation Link C<"calc"> =head3 Calculation Link C<"calc">
Calculation links can perform simple mathematical expressions on scalar A calculation link is an input link that can evaluate mathematical expressions
(double-precision floating-point) values obtained from other link types and on scalar (double-precision floating-point) values obtained from up to 12 child
return a single double-precision floating-point result. The expressions are input links, and returns a double-precision floating-point result. The
evaluated by the EPICS Calc engine, and up to 12 inputs can be provided. 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 =head4 Parameters
@ -88,6 +116,7 @@ The link address is a JSON map with the following keys:
=item expr =item expr
The primary expression to be evaluated, given as a string. The primary expression to be evaluated, given as a string.
This is optional for output links, required for input links.
=item major =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 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. 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 =item units
An optional string specifying the engineering units for the result of the 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}} {calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5], prec:3}}
=cut =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

View File

@ -6,13 +6,9 @@
\*************************************************************************/ \*************************************************************************/
/* lnkCalc.c */ /* lnkCalc.c */
/* Current usage /* Usage
* {calc:{expr:"A", args:[{...}, ...]}} * {calc:{expr:"A*B", args:[{...}, ...], units:"mm"}}
* First link in 'args' is 'A', second is 'B', and so forth. * 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> #include <string.h>
@ -26,6 +22,7 @@
#include "epicsAssert.h" #include "epicsAssert.h"
#include "epicsString.h" #include "epicsString.h"
#include "epicsTypes.h" #include "epicsTypes.h"
#include "epicsTime.h"
#include "dbAccessDefs.h" #include "dbAccessDefs.h"
#include "dbCommon.h" #include "dbCommon.h"
#include "dbConvertFast.h" #include "dbConvertFast.h"
@ -40,15 +37,14 @@
typedef long (*FASTCONVERT)(); typedef long (*FASTCONVERT)();
#define IFDEBUG(n) if(clink->jlink.debug)
typedef struct calc_link { typedef struct calc_link {
jlink jlink; /* embedded object */ jlink jlink; /* embedded object */
int nArgs; int nArgs;
short dbfType;
enum { enum {
ps_init, ps_init,
ps_expr, ps_major, ps_minor, ps_expr, ps_major, ps_minor,
ps_args, ps_args, ps_out,
ps_prec, ps_prec,
ps_units, ps_units,
ps_time, ps_time,
@ -66,7 +62,9 @@ typedef struct calc_link {
char *units; char *units;
short tinp; short tinp;
struct link inp[CALCPERFORM_NARGS]; struct link inp[CALCPERFORM_NARGS];
struct link out;
double arg[CALCPERFORM_NARGS]; double arg[CALCPERFORM_NARGS];
epicsTimeStamp time;
double val; double val;
} calc_link; } calc_link;
@ -77,19 +75,25 @@ static lset lnkCalc_lset;
static jlink* lnkCalc_alloc(short dbfType) static jlink* lnkCalc_alloc(short dbfType)
{ {
calc_link *clink = calloc(1, sizeof(struct calc_link)); calc_link *clink;
IFDEBUG(10) if (dbfType == DBF_FWDLINK) {
printf("lnkCalc_alloc()\n"); 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->nArgs = 0;
clink->dbfType = dbfType;
clink->pstate = ps_init; clink->pstate = ps_init;
clink->prec = 15; /* standard value for a double */ clink->prec = 15; /* standard value for a double */
clink->tinp = -1; clink->tinp = -1;
IFDEBUG(10)
printf("lnkCalc_alloc -> calc@%p\n", clink);
return &clink->jlink; return &clink->jlink;
} }
@ -98,12 +102,11 @@ static void lnkCalc_free(jlink *pjlink)
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i; int i;
IFDEBUG(10)
printf("lnkCalc_free(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) for (i = 0; i < clink->nArgs; i++)
dbJLinkFree(clink->inp[i].value.json.jlink); dbJLinkFree(clink->inp[i].value.json.jlink);
dbJLinkFree(clink->out.value.json.jlink);
free(clink->expr); free(clink->expr);
free(clink->major); free(clink->major);
free(clink->minor); 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); 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) { if (clink->pstate == ps_prec) {
clink->prec = num; clink->prec = num;
return jlif_continue; 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); 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) { if (clink->pstate != ps_args) {
return jlif_stop; return jlif_stop;
errlogPrintf("lnkCalc: Unexpected double %g\n", num); 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; char *inbuf, *postbuf;
short err; short err;
IFDEBUG(10)
printf("lnkCalc_string(calc@%p, \"%.*s\")\n", clink, (int) len, val);
if (clink->pstate == ps_units) { if (clink->pstate == ps_units) {
clink->units = epicsStrnDup(val, len); clink->units = epicsStrnDup(val, len);
return jlif_continue; 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) { if (clink->pstate == ps_time) {
char tinp; 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); errlogPrintf("lnkCalc: Bad 'time' parameter \"%.*s\"\n", (int) len, val);
return jlif_stop; 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); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_start_map(calc@%p)\n", clink);
if (clink->pstate == ps_args) 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) { if (clink->pstate != ps_init) {
errlogPrintf("lnkCalc: Unexpected map\n"); 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); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10) /* FIXME: These errors messages are wrong when a key is duplicated.
printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n", pjlink, (int) len, key); * 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) if (!strncmp(key, "expr", len) && !clink->post_expr)
clink->pstate = ps_expr; clink->pstate = ps_expr;
else if (!strncmp(key, "args", len) && !clink->nArgs) 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); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_end_map(calc@%p)\n", clink);
if (clink->pstate == ps_error) if (clink->pstate == ps_error)
return jlif_stop; return jlif_stop;
else if (!clink->post_expr) { else if (clink->dbfType == DBF_INLINK &&
errlogPrintf("lnkCalc: no expression ('expr' key)\n"); !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; return jlif_stop;
} }
@ -310,9 +318,6 @@ static jlif_result lnkCalc_start_array(jlink *pjlink)
{ {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_start_array(calc@%p)\n", clink);
if (clink->pstate != ps_args) { if (clink->pstate != ps_args) {
errlogPrintf("lnkCalc: Unexpected array\n"); errlogPrintf("lnkCalc: Unexpected array\n");
return jlif_stop; return jlif_stop;
@ -325,9 +330,6 @@ static jlif_result lnkCalc_end_array(jlink *pjlink)
{ {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_end_array(calc@%p)\n", clink);
if (clink->pstate == ps_error) if (clink->pstate == ps_error)
return jlif_stop; 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); calc_link *clink = CONTAINER(parent, struct calc_link, jlink);
struct link *plink; struct link *plink;
if (clink->nArgs == CALCPERFORM_NARGS) { if (clink->pstate == ps_args) {
dbJLinkFree(child); if (clink->nArgs == CALCPERFORM_NARGS) {
errlogPrintf("lnkCalc: Too many input args, limit is %d\n", errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
CALCPERFORM_NARGS); 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; clink->pstate = ps_error;
dbJLinkFree(child);
return; return;
} }
plink = &clink->inp[clink->nArgs++];
plink->type = JSON_LINK; plink->type = JSON_LINK;
plink->value.json.string = NULL; plink->value.json.string = NULL;
plink->value.json.jlink = child; 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) 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; 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); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i; int i;
IFDEBUG(10)
printf("lnkCalc_report(calc@%p)\n", clink);
printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "", printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "",
clink->expr, clink->prec, clink->val, clink->expr, clink->prec, clink->val,
clink->units ? clink->units : ""); 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, "", printf("%*s Minor expression: \"%s\"\n", indent, "",
clink->minor); clink->minor);
if (clink->tinp >= 0 && clink->tinp < clink->nArgs) if (clink->tinp >= 0) {
printf("%*s Timestamp input \"%c\"\n", indent, "", char timeStr[40];
clink->tinp + 'A'); 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++) { for (i = 0; i < clink->nArgs; i++) {
struct link *plink = &clink->inp[i]; struct link *plink = &clink->inp[i];
@ -403,17 +413,20 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
if (child) if (child)
dbJLinkReport(child, level - 1, indent + 4); 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); calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i; int i;
IFDEBUG(10)
printf("lnkCalc_map_children(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) { for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i]; struct link *child = &clink->inp[i];
long status = dbJLinkMapChildren(child, rtn, ctx); long status = dbJLinkMapChildren(child, rtn, ctx);
@ -421,6 +434,10 @@ long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
if (status) if (status)
return status; return status;
} }
if (clink->out.type == JSON_LINK) {
return dbJLinkMapChildren(&clink->out, rtn, ctx);
}
return 0; return 0;
} }
@ -432,9 +449,6 @@ static void lnkCalc_open(struct link *plink)
struct calc_link, jlink); struct calc_link, jlink);
int i; int i;
IFDEBUG(10)
printf("lnkCalc_open(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) { for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i]; struct link *child = &clink->inp[i];
@ -442,6 +456,10 @@ static void lnkCalc_open(struct link *plink)
dbJLinkInit(child); dbJLinkInit(child);
dbLoadLink(child, DBR_DOUBLE, &clink->arg[i]); 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) 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); struct calc_link, jlink);
int i; int i;
IFDEBUG(10)
printf("lnkCalc_remove(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) { for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i]; struct link *child = &clink->inp[i];
dbRemoveLink(locker, child); dbRemoveLink(locker, child);
} }
if (clink->out.type == JSON_LINK) {
dbRemoveLink(locker, &clink->out);
}
free(clink->expr); free(clink->expr);
free(clink->major); free(clink->major);
free(clink->minor); free(clink->minor);
@ -477,9 +496,6 @@ static int lnkCalc_isConn(const struct link *plink)
int connected = 1; int connected = 1;
int i; int i;
IFDEBUG(10)
printf("lnkCalc_isConn(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++) { for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i]; struct link *child = &clink->inp[i];
@ -488,37 +504,24 @@ static int lnkCalc_isConn(const struct link *plink)
connected = 0; connected = 0;
} }
if (clink->out.type == JSON_LINK) {
struct link *child = &clink->out;
if (dbLinkIsVolatile(child) &&
!dbIsLinkConnected(child))
connected = 0;
}
return connected; return connected;
} }
static int lnkCalc_getDBFtype(const struct link *plink) 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; return DBF_DOUBLE;
} }
static long lnkCalc_getElements(const struct link *plink, long *nelements) 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; *nelements = 1;
return 0; return 0;
} }
@ -551,23 +554,22 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
long status; long status;
FASTCONVERT conv = dbFastPutConvertRoutine[DBR_DOUBLE][dbrType]; 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 */ /* Any link errors will trigger a LINK/INVALID alarm in the child link */
for (i = 0; i < clink->nArgs; i++) { for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i]; struct link *child = &clink->inp[i];
long nReq = 1; long nReq = 1;
if (i == clink->tinp && if (i == clink->tinp) {
dbLinkIsConstant(&prec->tsel) && struct lcvt vt = {&clink->arg[i], &clink->time};
prec->tse == epicsTimeEventDeviceTime) {
struct lcvt vt = {&clink->arg[i], &prec->time};
status = dbLinkDoLocked(child, readLocked, &vt); status = dbLinkDoLocked(child, readLocked, &vt);
if (status == S_db_noLSET) if (status == S_db_noLSET)
status = readLocked(child, &vt); status = readLocked(child, &vt);
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime) {
prec->time = clink->time;
}
} }
else else
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq); 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; double alval = clink->val;
status = calcPerform(clink->arg, &alval, clink->post_minor); 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; 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) static long lnkCalc_getPrecision(const struct link *plink, short *precision)
{ {
calc_link *clink = CONTAINER(plink->value.json.jlink, calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink); struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getPrecision(calc@%p)\n", clink);
*precision = clink->prec; *precision = clink->prec;
return 0; 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, calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink); struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getUnits(calc@%p)\n", clink);
if (clink->units) { if (clink->units) {
strncpy(units, clink->units, --len); strncpy(units, clink->units, --len);
units[len] = '\0'; 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, calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink); struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_getAlarm(calc@%p)\n", clink);
if (status) if (status)
*status = clink->stat; *status = clink->stat;
if (severity) if (severity)
@ -659,6 +720,19 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
return 0; 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) static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
{ {
return rtn(plink, priv); return rtn(plink, priv);
@ -675,8 +749,8 @@ static lset lnkCalc_lset = {
lnkCalc_getValue, lnkCalc_getValue,
NULL, NULL, NULL, NULL, NULL, NULL,
lnkCalc_getPrecision, lnkCalc_getUnits, lnkCalc_getPrecision, lnkCalc_getUnits,
lnkCalc_getAlarm, NULL, lnkCalc_getAlarm, lnkCalc_getTimestamp,
NULL, NULL, lnkCalc_putValue, NULL,
NULL, doLocked NULL, doLocked
}; };
@ -686,6 +760,6 @@ static jlif lnkCalcIf = {
lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map, lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map,
lnkCalc_start_array, lnkCalc_end_array, lnkCalc_start_array, lnkCalc_end_array,
lnkCalc_end_child, lnkCalc_get_lset, lnkCalc_end_child, lnkCalc_get_lset,
lnkCalc_report, lnkCalc_map_children lnkCalc_report, lnkCalc_map_children, NULL
}; };
epicsExportAddress(jlif, lnkCalcIf); epicsExportAddress(jlif, lnkCalcIf);

View File

@ -2,7 +2,7 @@
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne * Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory. * National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found * 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 */ /* lnkConst.c */
@ -22,8 +22,6 @@
#include "epicsExport.h" #include "epicsExport.h"
#define IFDEBUG(n) if (clink->jlink.debug)
typedef long (*FASTCONVERT)(); typedef long (*FASTCONVERT)();
typedef struct const_link { typedef struct const_link {
@ -48,18 +46,23 @@ static lset lnkConst_lset;
static jlink* lnkConst_alloc(short dbfType) static jlink* lnkConst_alloc(short dbfType)
{ {
const_link *clink = calloc(1, sizeof(*clink)); const_link *clink;
IFDEBUG(10) if (dbfType != DBF_INLINK) {
printf("lnkConst_alloc()\n"); 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->type = s0;
clink->nElems = 0; clink->nElems = 0;
clink->value.pmem = NULL; clink->value.pmem = NULL;
IFDEBUG(10)
printf("lnkConst_alloc -> const@%p\n", clink);
return &clink->jlink; return &clink->jlink;
} }
@ -67,9 +70,6 @@ static void lnkConst_free(jlink *pjlink)
{ {
const_link *clink = CONTAINER(pjlink, const_link, jlink); const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_free(const@%p) type=%d\n", pjlink, clink->type);
switch (clink->type) { switch (clink->type) {
int i; int i;
case ac40: case ac40:
@ -95,16 +95,13 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
const_link *clink = CONTAINER(pjlink, const_link, jlink); const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1; int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_integer(const@%p, %lld)\n", pjlink, num);
switch (clink->type) { switch (clink->type) {
void *buf; void *buf;
case s0: case s0:
clink->type = si64; clink->type = si64;
clink->value.scalar_integer = num; clink->value.scalar_integer = num;
IFDEBUG(12) if (pjlink->debug)
printf(" si64 := %lld\n", num); printf(" si64 := %lld\n", num);
break; break;
@ -118,7 +115,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
clink->value.pmem = buf; clink->value.pmem = buf;
clink->value.pintegers[clink->nElems] = num; clink->value.pintegers[clink->nElems] = num;
IFDEBUG(12) if (pjlink->debug)
printf(" ai64 += %lld\n", num); printf(" ai64 += %lld\n", num);
break; break;
@ -129,7 +126,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
clink->value.pmem = buf; clink->value.pmem = buf;
clink->value.pdoubles[clink->nElems] = num; clink->value.pdoubles[clink->nElems] = num;
IFDEBUG(12) if (pjlink->debug)
printf(" af64 += %lld\n", num); printf(" af64 += %lld\n", num);
break; break;
@ -146,10 +143,6 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
static jlif_result lnkConst_boolean(jlink *pjlink, int val) 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); 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); const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1; int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_double(const@%p, %g)\n", pjlink, num);
switch (clink->type) { switch (clink->type) {
epicsFloat64 *f64buf; epicsFloat64 *f64buf;
int i; 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); const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1; int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
switch (clink->type) { switch (clink->type) {
char **vec, *str; char **vec, *str;
@ -262,9 +249,6 @@ static jlif_result lnkConst_start_array(jlink *pjlink)
{ {
const_link *clink = CONTAINER(pjlink, const_link, jlink); const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_start_array(const@%p)\n", pjlink);
if (clink->type != s0) { if (clink->type != s0) {
errlogPrintf("lnkConst: Embedded array value\n"); errlogPrintf("lnkConst: Embedded array value\n");
return jlif_stop; return jlif_stop;
@ -276,21 +260,11 @@ static jlif_result lnkConst_start_array(jlink *pjlink)
static jlif_result lnkConst_end_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; return jlif_continue;
} }
static struct lset* lnkConst_get_lset(const jlink *pjlink) 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; 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]; const char * const dtype = type_names[clink->type & 3];
IFDEBUG(10)
printf("lnkConst_report(const@%p)\n", clink);
if (clink->type > a0) { if (clink->type > a0) {
const char * const plural = clink->nElems > 1 ? "s" : ""; 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) 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); 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); const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
long status; long status;
IFDEBUG(10)
printf("lnkConst_loadScalar(const@%p, %d, %p)\n",
clink, dbrType, pbuffer);
switch (clink->type) { switch (clink->type) {
case si64: case si64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" si64 %lld\n", clink->value.scalar_integer); printf(" si64 %lld\n", clink->value.scalar_integer);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType] status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(&clink->value.scalar_integer, pbuffer, NULL); (&clink->value.scalar_integer, pbuffer, NULL);
break; break;
case sf64: case sf64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" sf64 %g\n", clink->value.scalar_double); printf(" sf64 %g\n", clink->value.scalar_double);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType] status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(&clink->value.scalar_double, pbuffer, NULL); (&clink->value.scalar_double, pbuffer, NULL);
break; break;
case sc40: case sc40:
IFDEBUG(12) if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string); printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType] status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL); (clink->value.scalar_string, pbuffer, NULL);
break; break;
case ai64: case ai64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]); printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType] status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(clink->value.pintegers, pbuffer, NULL); (clink->value.pintegers, pbuffer, NULL);
break; break;
case af64: case af64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]); printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType] status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(clink->value.pdoubles, pbuffer, NULL); (clink->value.pdoubles, pbuffer, NULL);
break; break;
case ac40: case ac40:
IFDEBUG(12) if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]); printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType] status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.pstrings[0], pbuffer, NULL); (clink->value.pstrings[0], pbuffer, NULL);
break; break;
default: default:
IFDEBUG(12) if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type); printf(" Bad type %d\n", clink->type);
status = S_db_badField; status = S_db_badField;
break; 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_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
const char *pstr; const char *pstr;
IFDEBUG(10)
printf("lnkConst_loadLS(const@%p, %p, %d, %d)\n",
clink, pbuffer, size, *plen);
if(!size) return 0; if(!size) return 0;
switch (clink->type) { switch (clink->type) {
case sc40: case sc40:
IFDEBUG(12) if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string); printf(" sc40 '%s'\n", clink->value.scalar_string);
pstr = clink->value.scalar_string; pstr = clink->value.scalar_string;
break; break;
case ac40: case ac40:
IFDEBUG(12) if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]); printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
pstr = clink->value.pstrings[0]; pstr = clink->value.pstrings[0];
break; break;
default: default:
IFDEBUG(12) if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type); printf(" Bad type %d\n", clink->type);
return S_db_badField; return S_db_badField;
} }
@ -499,10 +457,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
FASTCONVERT conv; FASTCONVERT conv;
long status; long status;
IFDEBUG(10)
printf("lnkConst_loadArray(const@%p, %d, %p, (%ld))\n",
clink, dbrType, pbuffer, *pnReq);
if (nElems > *pnReq) if (nElems > *pnReq)
nElems = *pnReq; nElems = *pnReq;
@ -510,28 +464,28 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
int i; int i;
case si64: case si64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" si64 %lld\n", clink->value.scalar_integer); printf(" si64 %lld\n", clink->value.scalar_integer);
status = dbFastPutConvertRoutine[DBF_INT64][dbrType] status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
(&clink->value.scalar_integer, pdest, NULL); (&clink->value.scalar_integer, pdest, NULL);
break; break;
case sf64: case sf64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" sf64 %g\n", clink->value.scalar_double); printf(" sf64 %g\n", clink->value.scalar_double);
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType] status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
(&clink->value.scalar_double, pdest, NULL); (&clink->value.scalar_double, pdest, NULL);
break; break;
case sc40: case sc40:
IFDEBUG(12) if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string); printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType] status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL); (clink->value.scalar_string, pbuffer, NULL);
break; break;
case ai64: case ai64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]); printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
conv = dbFastPutConvertRoutine[DBF_INT64][dbrType]; conv = dbFastPutConvertRoutine[DBF_INT64][dbrType];
for (i = 0; i < nElems; i++) { for (i = 0; i < nElems; i++) {
@ -542,7 +496,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break; break;
case af64: case af64:
IFDEBUG(12) if (clink->jlink.debug)
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]); printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]; conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType];
for (i = 0; i < nElems; i++) { for (i = 0; i < nElems; i++) {
@ -553,7 +507,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break; break;
case ac40: case ac40:
IFDEBUG(12) if (clink->jlink.debug)
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]); printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
conv = dbFastPutConvertRoutine[DBF_STRING][dbrType]; conv = dbFastPutConvertRoutine[DBF_STRING][dbrType];
for (i = 0; i < nElems; i++) { for (i = 0; i < nElems; i++) {
@ -564,7 +518,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
break; break;
default: default:
IFDEBUG(12) if (clink->jlink.debug)
printf(" Bad type %d\n", clink->type); printf(" Bad type %d\n", clink->type);
status = S_db_badField; 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) 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; *nelements = 0;
return 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, static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest) 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) if (pnRequest)
*pnRequest = 0; *pnRequest = 0;
return 0; return 0;
@ -626,7 +567,6 @@ static jlif lnkConstIf = {
NULL, NULL, NULL, NULL, NULL, NULL,
lnkConst_start_array, lnkConst_end_array, lnkConst_start_array, lnkConst_end_array,
NULL, lnkConst_get_lset, NULL, lnkConst_get_lset,
lnkConst_report, NULL lnkConst_report, NULL, NULL
}; };
epicsExportAddress(jlif, lnkConstIf); epicsExportAddress(jlif, lnkConstIf);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,230 @@
/*************************************************************************\
* Copyright (c) 2017 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.
\*************************************************************************/
/* lnkState.c */
/* Usage:
* {state:green}
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "alarm.h"
#include "dbDefs.h"
#include "errlog.h"
#include "epicsAssert.h"
#include "epicsString.h"
#include "epicsTypes.h"
#include "dbAccessDefs.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
#include "dbLink.h"
#include "dbJLink.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "dbState.h"
#include "recGbl.h"
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct state_link {
jlink jlink; /* embedded object */
char *name;
short val;
short invert;
dbStateId state;
} state_link;
static lset lnkState_lset;
/*************************** jlif Routines **************************/
static jlink* lnkState_alloc(short dbfType)
{
state_link *slink;
if (dbfType == DBF_FWDLINK) {
errlogPrintf("lnkState: DBF_FWDLINK not supported\n");
return NULL;
}
slink = calloc(1, sizeof(struct state_link));
if (!slink) {
errlogPrintf("lnkState: calloc() failed.\n");
return NULL;
}
slink->name = NULL;
slink->state = NULL;
slink->invert = 0;
slink->val = 0;
return &slink->jlink;
}
static void lnkState_free(jlink *pjlink)
{
state_link *slink = CONTAINER(pjlink, struct state_link, jlink);
free(slink->name);
free(slink);
}
static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len)
{
state_link *slink = CONTAINER(pjlink, struct state_link, jlink);
if (len > 1 && val[0] == '!') {
slink->invert = 1;
val++; len--;
}
slink->name = epicsStrnDup(val, len);
return jlif_continue;
}
static struct lset* lnkState_get_lset(const jlink *pjlink)
{
return &lnkState_lset;
}
static void lnkState_report(const jlink *pjlink, int level, int indent)
{
state_link *slink = CONTAINER(pjlink, struct state_link, jlink);
printf("%*s'state': \"%s\" = %s%s\n", indent, "",
slink->name, slink->invert ? "! " : "", slink->val ? "TRUE" : "FALSE");
}
/*************************** lset Routines **************************/
static void lnkState_open(struct link *plink)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
slink->state = dbStateCreate(slink->name);
}
static void lnkState_remove(struct dbLocker *locker, struct link *plink)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
free(slink->name);
free(slink);
plink->value.json.jlink = NULL;
}
static int lnkState_getDBFtype(const struct link *plink)
{
return DBF_SHORT;
}
static long lnkState_getElements(const struct link *plink, long *nelements)
{
*nelements = 1;
return 0;
}
static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
FASTCONVERT conv = dbFastPutConvertRoutine[DBR_SHORT][dbrType];
slink->val = slink->invert ^ dbStateGet(slink->state);
return conv(&slink->val, pbuffer, NULL);
}
static long lnkState_putValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
short val;
const char *pstr;
if (nRequest == 0)
return 0;
switch(dbrType) {
case DBR_CHAR:
case DBR_UCHAR:
val = !! *(const epicsInt8 *) pbuffer;
break;
case DBR_SHORT:
case DBR_USHORT:
val = !! *(const epicsInt16 *) pbuffer;
break;
case DBR_LONG:
case DBR_ULONG:
val = !! *(const epicsInt32 *) pbuffer;
break;
case DBR_INT64:
case DBR_UINT64:
val = !! *(const epicsInt64 *) pbuffer;
break;
case DBR_FLOAT:
val = !! *(const epicsFloat32 *) pbuffer;
break;
case DBR_DOUBLE:
val = !! *(const epicsFloat64 *) pbuffer;
break;
case DBR_STRING: /* Only "" and "0" are FALSE */
pstr = (const char *) pbuffer;
val = (pstr[0] != 0) && ((pstr[0] != '0') || (pstr[1] != 0));
break;
default:
return S_db_badDbrtype;
}
slink->val = val;
val ^= slink->invert;
(val ? dbStateSet : dbStateClear)(slink->state);
return 0;
}
/************************* Interface Tables *************************/
static lset lnkState_lset = {
0, 0, /* not constant, always connected */
lnkState_open, lnkState_remove,
NULL, NULL, NULL,
NULL, lnkState_getDBFtype, lnkState_getElements,
lnkState_getValue,
NULL, NULL, NULL,
NULL, NULL,
NULL, NULL,
lnkState_putValue, NULL,
NULL, NULL
};
static jlif lnkStateIf = {
"state", lnkState_alloc, lnkState_free,
NULL, NULL, NULL, NULL, lnkState_string,
NULL, NULL, NULL,
NULL, NULL,
NULL, lnkState_get_lset,
lnkState_report, NULL, NULL
};
epicsExportAddress(jlif, lnkStateIf);

View File

@ -2,7 +2,7 @@
* Copyright (c) 2002 Southeastern Universities Research Association, as * Copyright (c) 2002 Southeastern Universities Research Association, as
* Operator of Thomas Jefferson National Accelerator Facility. * Operator of Thomas Jefferson National Accelerator Facility.
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* recAai.c */ /* recAai.c */
@ -11,7 +11,7 @@
* Original Author: Dave Barker * Original Author: Dave Barker
* *
* C E B A F * C E B A F
* *
* Continuous Electron Beam Accelerator Facility * Continuous Electron Beam Accelerator Facility
* Newport News, Virginia, USA. * Newport News, Virginia, USA.
* *
@ -225,10 +225,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew) static long put_array_info(DBADDR *paddr, long nNew)
{ {
aaiRecord *prec = (aaiRecord *)paddr->precord; aaiRecord *prec = (aaiRecord *)paddr->precord;
epicsUInt32 nord = prec->nord;
prec->nord = nNew; prec->nord = nNew;
if (prec->nord > prec->nelm) if (prec->nord > prec->nelm)
prec->nord = prec->nelm; prec->nord = prec->nelm;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0; return 0;
} }
@ -241,7 +245,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) { switch (dbGetFieldIndex(paddr)) {
case indexof(VAL): case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM) if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break; break;
case indexof(HOPR): case indexof(HOPR):
case indexof(LOPR): case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE); strncpy(units,prec->egu,DB_UNITS_SIZE);
@ -336,33 +340,22 @@ static void monitor(aaiRecord *prec)
static long readValue(aaiRecord *prec) static long readValue(aaiRecord *prec)
{ {
struct aaidset *pdset = (struct aaidset *) prec->dset; struct aaidset *pdset = (struct aaidset *) prec->dset;
long status = 0; long status;
if (!prec->pact) { /* NB: Device support must post updates to NORD */
status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
if (status) return status;
}
switch (prec->simm) { if (prec->pact)
case menuYesNoNO: goto do_read;
status = pdset->read_aai(prec);
break;
case menuYesNoYES: { status = recGblGetSimm((dbCommon *)prec, &prec->sscn, &prec->oldsimm,
&prec->simm, &prec->siml);
if (status)
return status;
if (prec->simm == menuYesNoYES) {
recGblSetSevr(prec, SIMM_ALARM, prec->sims); recGblSetSevr(prec, SIMM_ALARM, prec->sims);
if (prec->pact || (prec->sdly < 0.)) {
/* Device suport is responsible for buffer
which might be read-only so we may not be
allowed to call dbGetLink on it.
Maybe also device support has an advanced
simulation mode.
Thus call device now.
Reading through SIOL is handled in Soft Channel Device Support if (prec->sdly >= 0) {
*/
status = pdset->read_aai(prec);
prec->pact = FALSE;
} else { /* !prec->pact && delay >= 0. */
CALLBACK *pvt = prec->simpvt; CALLBACK *pvt = prec->simpvt;
if (!pvt) { if (!pvt) {
pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */
@ -370,14 +363,14 @@ static long readValue(aaiRecord *prec)
} }
if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly);
prec->pact = TRUE; prec->pact = TRUE;
return 0;
} }
break;
} }
else if (prec->simm != menuYesNoNO) {
default:
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM); recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
status = -1; return -1;
} }
return status; do_read:
return pdset->read_aai(prec);
} }

View File

@ -2,7 +2,7 @@
* Copyright (c) 2002 Southeastern Universities Research Association, as * Copyright (c) 2002 Southeastern Universities Research Association, as
* Operator of Thomas Jefferson National Accelerator Facility. * Operator of Thomas Jefferson National Accelerator Facility.
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* recAao.c */ /* recAao.c */
@ -11,7 +11,7 @@
* Original Author: Dave Barker * Original Author: Dave Barker
* *
* C E B A F * C E B A F
* *
* Continuous Electron Beam Accelerator Facility * Continuous Electron Beam Accelerator Facility
* Newport News, Virginia, USA. * Newport News, Virginia, USA.
* *
@ -225,10 +225,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew) static long put_array_info(DBADDR *paddr, long nNew)
{ {
aaoRecord *prec = (aaoRecord *)paddr->precord; aaoRecord *prec = (aaoRecord *)paddr->precord;
epicsUInt32 nord = prec->nord;
prec->nord = nNew; prec->nord = nNew;
if (prec->nord > prec->nelm) if (prec->nord > prec->nelm)
prec->nord = prec->nelm; prec->nord = prec->nelm;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0; return 0;
} }
@ -241,7 +245,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) { switch (dbGetFieldIndex(paddr)) {
case indexof(VAL): case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM) if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break; break;
case indexof(HOPR): case indexof(HOPR):
case indexof(LOPR): case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE); strncpy(units,prec->egu,DB_UNITS_SIZE);

View File

@ -4,12 +4,12 @@
* Copyright (c) 2002 The Regents of the University of California, as * Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory. * Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* /*
* Original Author: Bob Dalesio * Original Author: Bob Dalesio
* Date: 7-14-89 * Date: 7-14-89
*/ */
#include <stddef.h> #include <stddef.h>
@ -439,12 +439,16 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew) static long put_array_info(DBADDR *paddr, long nNew)
{ {
compressRecord *prec = (compressRecord *) paddr->precord; compressRecord *prec = (compressRecord *) paddr->precord;
epicsUInt32 nuse = prec->nuse;
if (prec->balg == bufferingALG_FIFO) if (prec->balg == bufferingALG_FIFO)
prec->off = (prec->off + nNew) % prec->nsam; prec->off = (prec->off + nNew) % prec->nsam;
prec->nuse += nNew; prec->nuse += nNew;
if (prec->nuse > prec->nsam) if (prec->nuse > prec->nsam)
prec->nuse = prec->nsam; prec->nuse = prec->nsam;
if (nuse != prec->nuse)
db_post_events(prec, &prec->nuse, DBE_VALUE | DBE_LOG);
return 0; return 0;
} }

View File

@ -2,17 +2,17 @@
* Copyright (c) 2002 Lawrence Berkeley Laboratory,The Control Systems * Copyright (c) 2002 Lawrence Berkeley Laboratory,The Control Systems
* Group, Systems Engineering Department * Group, Systems Engineering Department
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* recSubArray.c - Record Support Routines for SubArray records /* recSubArray.c - Record Support Routines for SubArray records
* *
* *
* Author: Carl Lionberger * Author: Carl Lionberger
* Date: 090293 * Date: 090293
* *
* NOTES: * NOTES:
* Derived from waveform record. * Derived from waveform record.
* Modification Log: * Modification Log:
* ----------------- * -----------------
*/ */
@ -126,7 +126,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
} }
if (pdset->init_record) if (pdset->init_record)
return (*pdset->init_record)(prec); return pdset->init_record(prec);
return 0; return 0;
} }
@ -194,11 +194,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew) static long put_array_info(DBADDR *paddr, long nNew)
{ {
subArrayRecord *prec = (subArrayRecord *) paddr->precord; subArrayRecord *prec = (subArrayRecord *) paddr->precord;
epicsUInt32 nord = prec->nord;
if (nNew > prec->malm)
nNew = prec->malm;
prec->nord = nNew; prec->nord = nNew;
if (prec->nord > prec->malm)
prec->nord = prec->malm;
if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0; return 0;
} }
@ -211,7 +214,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) { switch (dbGetFieldIndex(paddr)) {
case indexof(VAL): case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM) if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break; break;
case indexof(HOPR): case indexof(HOPR):
case indexof(LOPR): case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE); strncpy(units,prec->egu,DB_UNITS_SIZE);
@ -321,4 +324,3 @@ static long readValue(subArrayRecord *prec)
return status; return status;
} }

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as * Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory. * Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* recWaveform.c - Record Support Routines for Waveform records */ /* recWaveform.c - Record Support Routines for Waveform records */
@ -205,12 +205,14 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
static long put_array_info(DBADDR *paddr, long nNew) static long put_array_info(DBADDR *paddr, long nNew)
{ {
waveformRecord *prec = (waveformRecord *) paddr->precord; waveformRecord *prec = (waveformRecord *) paddr->precord;
epicsUInt32 nord = prec->nord;
prec->nord = nNew; prec->nord = nNew;
if (prec->nord > prec->nelm) if (prec->nord > prec->nelm)
prec->nord = prec->nelm; prec->nord = prec->nelm;
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG); if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0; return 0;
} }
@ -223,7 +225,7 @@ static long get_units(DBADDR *paddr, char *units)
switch (dbGetFieldIndex(paddr)) { switch (dbGetFieldIndex(paddr)) {
case indexof(VAL): case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM) if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break; break;
case indexof(HOPR): case indexof(HOPR):
case indexof(LOPR): case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE); strncpy(units,prec->egu,DB_UNITS_SIZE);
@ -346,15 +348,18 @@ static long readValue(waveformRecord *prec)
case menuYesNoYES: { case menuYesNoYES: {
long nRequest = prec->nelm; long nRequest = prec->nelm;
epicsUInt32 nord = prec->nord;
recGblSetSevr(prec, SIMM_ALARM, prec->sims); recGblSetSevr(prec, SIMM_ALARM, prec->sims);
if (prec->pact || (prec->sdly < 0.)) { if (prec->pact || (prec->sdly < 0.)) {
status = dbGetLink(&prec->siol, prec->ftvl, prec->bptr, 0, &nRequest); status = dbGetLink(&prec->siol, prec->ftvl, prec->bptr, 0, &nRequest);
if (status == 0) prec->udf = FALSE; if (status == 0)
/* nord set only for db links: needed for old db_access */ prec->udf = FALSE;
if (!dbLinkIsConstant(&prec->siol)) { if (!dbLinkIsConstant(&prec->siol)) {
prec->nord = nRequest; prec->nord = nRequest;
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG); if (nord != prec->nord)
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
} }
prec->pact = FALSE; prec->pact = FALSE;
} else { /* !prec->pact && delay >= 0. */ } else { /* !prec->pact && delay >= 0. */

View File

@ -1,5 +1,4 @@
eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*- #!/usr/bin/env perl
if $running_under_some_shell;
#************************************************************************* #*************************************************************************
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne # Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory. # National Laboratory.

View File

@ -180,6 +180,8 @@ testHarness_SRCS += epicsRunDbTests.c
dbTestHarness_SRCS += $(testHarness_SRCS) dbTestHarness_SRCS += $(testHarness_SRCS)
dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
PROD_SRCS_RTEMS += rtemsTestData.c
PROD_vxWorks = dbTestHarness PROD_vxWorks = dbTestHarness
PROD_RTEMS = dbTestHarness PROD_RTEMS = dbTestHarness
@ -187,6 +189,10 @@ TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t) TESTSCRIPTS_HOST += $(TESTS:%=%.t)
ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
TESTPROD_RTEMS = $(TESTPROD_HOST)
TESTSCRIPTS_RTEMS += $(TESTS:%=%.t)
endif
include $(TOP)/configure/RULES include $(TOP)/configure/RULES
@ -197,3 +203,6 @@ dbStressLock$(DEP): $(COMMON_DIR)/xRecord.h
devx$(DEP): $(COMMON_DIR)/xRecord.h devx$(DEP): $(COMMON_DIR)/xRecord.h
scanIoTest$(DEP): $(COMMON_DIR)/xRecord.h scanIoTest$(DEP): $(COMMON_DIR)/xRecord.h
xRecord$(DEP): $(COMMON_DIR)/xRecord.h xRecord$(DEP): $(COMMON_DIR)/xRecord.h
rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl
$(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES)

View File

@ -14,3 +14,8 @@ record(x, "eINST_IO") {
field(DTYP, "Unit Test INST_IO") field(DTYP, "Unit Test INST_IO")
field(INP, "hello") field(INP, "hello")
} }
record(x, "eINST_IO2") {
field(DTYP, "Unit Test INST_IO")
field(INP, "RL @no")
}

View File

@ -60,7 +60,9 @@ static const struct testParseDataT {
TEST_PV_LINK(" world MSICP", "world", pvlOptMSI|pvlOptCP), TEST_PV_LINK(" world MSICP", "world", pvlOptMSI|pvlOptCP),
{"#C14 S145 @testing", {VME_IO, "testing", 0, "CS", {14, 145}}}, {"#C14 S145 @testing", {VME_IO, "testing", 0, "CS", {14, 145}}},
{"#C14 S145", {VME_IO, "", 0, "CS", {14, 145}}},
{"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}}, {"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}},
{"#B11 C12 N13 A14 F15", {CAMAC_IO, "", 0, "BCNAF", {11, 12, 13, 14, 15}}},
{" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}}, {" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}},
{" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}}, {" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}},
{" {\"x\":true} ", {JSON_LINK, "{\"x\":true}", 0, "", /*{}*/}}, {" {\"x\":true} ", {JSON_LINK, "{\"x\":true}", 0, "", /*{}*/}},
@ -87,11 +89,15 @@ static void testLinkParse(void)
for (;td->str; td++) { for (;td->str; td++) {
int i, N; int i, N;
testDiag("Parsing \"%s\"", td->str); testDiag("Parsing \"%s\"", td->str);
testOk(dbParseLink(td->str, DBF_INLINK, &info, 0) == 0, "Parser returned OK"); testOk(dbParseLink(td->str, DBF_INLINK, &info) == 0, "Parser returned OK");
if (!testOk(info.ltype == td->info.ltype, "Link type value")) if (!testOk(info.ltype == td->info.ltype, "Link type value"))
testDiag("Expected %d, got %d", td->info.ltype, info.ltype); testDiag("Expected %d, got %d", td->info.ltype, info.ltype);
if (td->info.target) if (td->info.target && info.target)
testStrcmp(0, info.target, td->info.target); testStrcmp(0, info.target, td->info.target);
else if(!!td->info.target ^ !!info.target)
testFail("info target NULL mis-match %s %s", info.target, td->info.target);
else
testPass("info target NULL as expected");
if (info.ltype == td->info.ltype) { if (info.ltype == td->info.ltype) {
switch (info.ltype) { switch (info.ltype) {
case PV_LINK: case PV_LINK:
@ -125,7 +131,6 @@ static const char *testParseFailData[] = {
"#A0 B @", "#A0 B @",
"#A0 B C @", "#A0 B C @",
"#R1 M2 D3 E4 @oops", /* RF_IO has no parm */ "#R1 M2 D3 E4 @oops", /* RF_IO has no parm */
"#C1 S2", /* VME_IO needs parm */
NULL NULL
}; };
@ -147,7 +152,7 @@ static void testLinkFailParse(void)
eltc(1); eltc(1);
for(;*td; td++) { for(;*td; td++) {
testOk(dbParseLink(*td, DBF_INLINK, &info, 0) == S_dbLib_badField, testOk(dbParseLink(*td, DBF_INLINK, &info) == S_dbLib_badField,
"dbParseLink correctly rejected \"%s\"", *td); "dbParseLink correctly rejected \"%s\"", *td);
} }
@ -480,6 +485,13 @@ static void testLinkInitFail(void)
testOk1(plink->type == INST_IO); testOk1(plink->type == INST_IO);
testOk1(plink->value.instio.string != NULL); testOk1(plink->value.instio.string != NULL);
testdbGetFieldEqual("eINST_IO2.INP", DBR_STRING, "@");
prec = (xRecord *) testdbRecordPtr("eINST_IO2");
plink = &prec->inp;
testOk1(plink->type == INST_IO);
testOk1(plink->value.instio.string != NULL);
testIocShutdownOk(); testIocShutdownOk();
testdbCleanup(); testdbCleanup();
@ -684,7 +696,7 @@ void testTSEL(void)
MAIN(dbPutLinkTest) MAIN(dbPutLinkTest)
{ {
testPlan(320); testPlan(337);
testLinkParse(); testLinkParse();
testLinkFailParse(); testLinkFailParse();
testCADBSet(); testCADBSet();

View File

@ -219,6 +219,11 @@ MAIN(dbStressTest)
testPlan(80+nworkers*3); testPlan(80+nworkers*3);
#if defined(__rtems__)
testSkip(80+nworkers*3, "Test assumes time sliced preempting scheduling");
return testDone();
#endif
priv = callocMustSucceed(nworkers, sizeof(*priv), "no memory"); priv = callocMustSucceed(nworkers, sizeof(*priv), "no memory");
testDiag("lock set stress test"); testDiag("lock set stress test");

View File

@ -246,7 +246,8 @@ static jlif jlifZ = {
NULL, /* end child */ NULL, /* end child */
&z_lset, &z_lset,
NULL, /* report */ NULL, /* report */
NULL /* map child */ NULL, /* map child */
NULL /* start child */
}; };
epicsExportAddress(jlif, jlifZ); epicsExportAddress(jlif, jlifZ);

View File

@ -2,7 +2,7 @@
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne * Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory. * National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found * 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.
\*************************************************************************/ \*************************************************************************/
/* xLink.c */ /* xLink.c */
@ -82,7 +82,6 @@ static jlif xlinkIf = {
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, xlink_get_lset, NULL, xlink_get_lset,
NULL, NULL NULL, NULL, NULL
}; };
epicsExportAddress(jlif, xlinkIf); epicsExportAddress(jlif, xlinkIf);

View File

@ -31,18 +31,18 @@ ok(msi('-S ../t5-substitute.txt ../t5-template.txt'), slurp('../t5-result.txt'))
# Substitution file, pattern format # Substitution file, pattern format
ok(msi('-S../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt')); ok(msi('-S../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt'));
# Output option -o # Output option -o and verbose option -V
my $out = 't7-output.txt'; my $out = 't7-output.txt';
my $count = 5; # Try up to 5 times... my $count = 5; # Try up to 5 times...
my $result; my $result;
do { do {
unlink $out; unlink $out;
msi("-I.. -o $out ../t1-template.txt"); msi("-I.. -V -o $out ../t1-template.txt");
$result = slurp($out); $result = slurp($out);
print "# msi output file empty, retrying\n" print "# msi output file empty, retrying\n"
if $result eq ''; if $result eq '';
} while ($result eq '') && (--$count > 0); } while ($result eq '') && (--$count > 0);
ok($result, slurp('../t1-result.txt')); ok($result, slurp('../t7-result.txt'));
# Dependency generation, include/substitute model # Dependency generation, include/substitute model
ok(msi('-I.. -D -o t8.txt ../t1-template.txt'), slurp('../t8-result.txt')); ok(msi('-I.. -D -o t8.txt ../t1-template.txt'), slurp('../t8-result.txt'));

View File

@ -1,6 +1,6 @@
This is t1-template.txt This is t1-template.txt
With $(a,undefined) & $(b,undefined): With $(a) & $(b):
This is t1-include.txt This is t1-include.txt
a = default value used when a is undefined a = default value used when a is undefined
b = default value used when b is undefined b = default value used when b is undefined

View File

@ -1,6 +1,6 @@
a = va1-a b = def-b c = def-c d = $(d,undefined) a = va1-a b = def-b c = def-c d = $(d)
a = va2-a b = va2-b c = def-c d = $(d,undefined) a = va2-a b = va2-b c = def-c d = $(d)
a = va3-a b = va3-b c = va3-c d = $(d,undefined) a = va3-a b = va3-b c = va3-c d = $(d)
a = va4-a b = va4-b c = def-c d = $(d,undefined) a = va4-a b = va4-b c = def-c d = $(d)
a = va5-a b = def-b c = def-c d = $(d,undefined) a = va5-a b = def-b c = def-c d = $(d)
a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) a = pt3-a b = pt3-b c = pt3-c d = $(d)

View File

@ -1,28 +1,28 @@
a = gb1-a b = gb1-b c = def-c d = $(d,undefined) a = gb1-a b = gb1-b c = def-c d = $(d)
a = va1-a b = gb1-b c = def-c d = $(d,undefined) a = va1-a b = gb1-b c = def-c d = $(d)
a = va2-a b = va2-b c = def-c d = $(d,undefined) a = va2-a b = va2-b c = def-c d = $(d)
a = va3-a b = va3-b c = va3-c d = $(d,undefined) a = va3-a b = va3-b c = va3-c d = $(d)
a = va4-a b = va4-b c = def-c d = $(d,undefined) a = va4-a b = va4-b c = def-c d = $(d)
a = va5-a b = gb1-b c = def-c d = $(d,undefined) a = va5-a b = gb1-b c = def-c d = $(d)
a = gb1-a b = gb1-b c = def-c d = $(d,undefined) a = gb1-a b = gb1-b c = def-c d = $(d)
a = gb2-a b = gb2-b c = def-c d = $(d,undefined) a = gb2-a b = gb2-b c = def-c d = $(d)
a = va1-a b = gb2-b c = def-c d = $(d,undefined) a = va1-a b = gb2-b c = def-c d = $(d)
a = va2-a b = va2-b c = def-c d = $(d,undefined) a = va2-a b = va2-b c = def-c d = $(d)
a = va3-a b = va3-b c = va3-c d = $(d,undefined) a = va3-a b = va3-b c = va3-c d = $(d)
a = va4-a b = va4-b c = def-c d = $(d,undefined) a = va4-a b = va4-b c = def-c d = $(d)
a = va5-a b = gb2-b c = def-c d = $(d,undefined) a = va5-a b = gb2-b c = def-c d = $(d)
a = gb2-a b = gb2-b c = def-c d = $(d,undefined) a = gb2-a b = gb2-b c = def-c d = $(d)
a = gb3-a b = gb3-b c = def-c d = $(d,undefined) a = gb3-a b = gb3-b c = def-c d = $(d)
a = pt1-a b = gb3-b c = def-c d = $(d,undefined) a = pt1-a b = gb3-b c = def-c d = $(d)
a = pt2-a b = pt2-b c = def-c d = $(d,undefined) a = pt2-a b = pt2-b c = def-c d = $(d)
a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) a = pt3-a b = pt3-b c = pt3-c d = $(d)
a = pt4-a b = pt4-b c = def-c d = $(d,undefined) a = pt4-a b = pt4-b c = def-c d = $(d)
a = pt5-a b = gb3-b c = def-c d = $(d,undefined) a = pt5-a b = gb3-b c = def-c d = $(d)
a = gb3-a b = gb3-b c = def-c d = $(d,undefined) a = gb3-a b = gb3-b c = def-c d = $(d)
a = gb4-a b = gb4-b c = def-c d = $(d,undefined) a = gb4-a b = gb4-b c = def-c d = $(d)
a = pt1-a b = gb4-b c = def-c d = $(d,undefined) a = pt1-a b = gb4-b c = def-c d = $(d)
a = pt2-a b = pt2-b c = def-c d = $(d,undefined) a = pt2-a b = pt2-b c = def-c d = $(d)
a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) a = pt3-a b = pt3-b c = pt3-c d = $(d)
a = pt4-a b = pt4-b c = def-c d = $(d,undefined) a = pt4-a b = pt4-b c = def-c d = $(d)
a = pt5-a b = gb4-b c = def-c d = $(d,undefined) a = pt5-a b = gb4-b c = def-c d = $(d)
a = gb4-a b = gb4-b c = def-c d = $(d,undefined) a = gb4-a b = gb4-b c = def-c d = $(d)

View File

@ -1,6 +1,6 @@
a = va1-a b = def-b c = def-c d = $(d,undefined) a = va1-a b = def-b c = def-c d = $(d)
a = va2-a b = va2-b c = def-c d = $(d,undefined) a = va2-a b = va2-b c = def-c d = $(d)
a = va3-a b = va3-b c = va3-c d = $(d,undefined) a = va3-a b = va3-b c = va3-c d = $(d)
a = va4-a b = va4-b c = va3-c d = $(d,undefined) a = va4-a b = va4-b c = va3-c d = $(d)
a = va5-a b = va4-b c = va3-c d = $(d,undefined) a = va5-a b = va4-b c = va3-c d = $(d)
a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) a = pt3-a b = pt3-b c = pt3-c d = $(d)

View File

@ -2,19 +2,19 @@
a = 111 a = 111
b = 222 b = 222
c = xx c = xx
d = $(d,undefined) d = $(d)
# comment line # comment line
a = aaa a = aaa
b = bbb b = bbb
c = ccc c = ccc
d = $(d,undefined) d = $(d)
# comment line # comment line
a = AA a = AA
b = BB b = BB
c = xx c = xx
d = $(d,undefined) d = $(d)
# comment line # comment line
a = aaa a = aaa
b = bbb b = bbb
c = yy c = yy
d = $(d,undefined) d = $(d)

View File

@ -2,19 +2,19 @@
a = 111 a = 111
b = 222 b = 222
c = xx c = xx
d = $(d,undefined) d = $(d)
# comment line # comment line
a = aaa a = aaa
b = bbb b = bbb
c = ccc c = ccc
d = $(d,undefined) d = $(d)
# comment line # comment line
a = AA a = AA
b = BB b = BB
c = xx c = xx
d = $(d,undefined) d = $(d)
# comment line # comment line
a = aaa a = aaa
b = bbb b = bbb
c = yy c = yy
d = $(d,undefined) d = $(d)

View File

@ -0,0 +1,21 @@
This is t1-template.txt
With $(a,undefined) & $(b,undefined):
This is t1-include.txt
a = default value used when a is undefined
b = default value used when b is undefined
End of t1-include.txt
On defining a=aaa & b=bbb:
This is t1-include.txt again
a = aaa
b = bbb
End of t1-include.txt
On setting a="aa":
This is t1-include.txt again
a = "aa"
b = bbb
End of t1-include.txt
End of t1-template.txt

View File

@ -63,6 +63,8 @@ testHarness_SRCS += epicsRunFilterTests.c
filterTestHarness_SRCS += $(testHarness_SRCS) filterTestHarness_SRCS += $(testHarness_SRCS)
filterTestHarness_SRCS_RTEMS += rtemsTestHarness.c filterTestHarness_SRCS_RTEMS += rtemsTestHarness.c
PROD_SRCS_RTEMS += rtemsTestData.c
PROD_vxWorks = filterTestHarness PROD_vxWorks = filterTestHarness
PROD_RTEMS = filterTestHarness PROD_RTEMS = filterTestHarness
@ -70,6 +72,10 @@ TESTSPEC_vxWorks = filterTestHarness.munch; epicsRunFilterTests
TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t) TESTSCRIPTS_HOST += $(TESTS:%=%.t)
ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
TESTPROD_RTEMS = $(TESTPROD_HOST)
TESTSCRIPTS_RTEMS += $(TESTS:%=%.t)
endif
include $(TOP)/configure/RULES include $(TOP)/configure/RULES
@ -79,3 +85,6 @@ dbndTest$(DEP): $(COMMON_DIR)/xRecord.h
syncTest$(DEP): $(COMMON_DIR)/xRecord.h syncTest$(DEP): $(COMMON_DIR)/xRecord.h
arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h
arrTest$(DEP): $(COMMON_DIR)/arrRecord.h arrTest$(DEP): $(COMMON_DIR)/arrRecord.h
rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl
$(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES)

View File

@ -0,0 +1,60 @@
#*************************************************************************
# 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.
#*************************************************************************
TOP=../../..
include $(TOP)/configure/CONFIG
TESTLIBRARY = Recs
Recs_SRCS += ioRecord.c
Recs_LIBS += dbCore ca Com
PROD_LIBS = Recs dbRecStd dbCore ca Com
DBDDEPENDS_FILES += linkTest.dbd$(DEP)
TARGETS += $(COMMON_DIR)/linkTest.dbd
linkTest_DBD += menuGlobal.dbd
linkTest_DBD += menuConvert.dbd
linkTest_DBD += menuScan.dbd
linkTest_DBD += links.dbd
linkTest_DBD += ioRecord.dbd
TESTFILES += $(COMMON_DIR)/linkTest.dbd
TESTFILES += ../ioRecord.db
testHarness_SRCS += linkTest_registerRecordDeviceDriver.cpp
TESTPROD_HOST += lnkStateTest
lnkStateTest_SRCS += lnkStateTest.c
lnkStateTest_SRCS += linkTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += lnkStateTest.c
TESTS += lnkStateTest
TESTPROD_HOST += lnkCalcTest
lnkCalcTest_SRCS += lnkCalcTest.c
lnkCalcTest_SRCS += linkTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += lnkCalcTest.c
TESTS += lnkCalcTest
# epicsRunLinkTests runs all the test programs in a known working order.
testHarness_SRCS += epicsRunLinkTests.c
linkTestHarness_SRCS += $(testHarness_SRCS)
linkTestHarness_SRCS_RTEMS += rtemsTestHarness.c
PROD_vxWorks = linkTestHarness
PROD_RTEMS = linkTestHarness
TESTSPEC_vxWorks = linkTestHarness.munch; epicsRunLinkTests
TESTSPEC_RTEMS = linkTestHarness.boot; epicsRunLinkTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
ioRecord$(DEP): $(COMMON_DIR)/ioRecord.h
lnkStateTest$(DEP): $(COMMON_DIR)/ioRecord.h
lnkCalcTest$(DEP): $(COMMON_DIR)/ioRecord.h

View File

@ -0,0 +1,29 @@
/*************************************************************************\
* 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.
\*************************************************************************/
/*
* Run filter tests as a batch.
*/
#include "epicsUnitTest.h"
#include "epicsExit.h"
#include "dbmf.h"
int lnkStateTest(void);
int lnkCalcTest(void);
void epicsRunLinkTests(void)
{
testHarness();
runTest(lnkStateTest);
runTest(lnkCalcTest);
dbmfFreeChunks();
epicsExit(0); /* Trigger test harness */
}

View File

@ -0,0 +1,22 @@
/*************************************************************************\
* 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.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
*/
#include <dbAccessDefs.h>
#include <recSup.h>
#define GEN_SIZE_OFFSET
#include "ioRecord.h"
#undef GEN_SIZE_OFFSET
#include <epicsExport.h>
static rset ioRSET;
epicsExportAddress(rset,ioRSET);

View File

@ -0,0 +1 @@
record(io, io) {}

View File

@ -0,0 +1,14 @@
# This is a soft record type with both input and output links
recordtype(io) {
include "dbCommon.dbd"
field(VAL, DBF_LONG) {
prompt("Value")
}
field(INPUT, DBF_INLINK) {
prompt("Input Link")
}
field(OUTPUT, DBF_OUTLINK) {
prompt("Output Link")
}
}

View File

@ -0,0 +1,164 @@
/*************************************************************************\
* Copyright (c) 2018 Andrew Johnson
* EPICS BASE is distributed subject to a Software License Agreement found
* in the file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include "dbAccess.h"
#include "alarm.h"
#include "dbUnitTest.h"
#include "errlog.h"
#include "epicsThread.h"
#include "dbLink.h"
#include "dbState.h"
#include "recGbl.h"
#include "testMain.h"
#include "ioRecord.h"
#define testPutLongStr(PV, VAL) \
testdbPutArrFieldOk(PV, DBF_CHAR, sizeof(VAL), VAL);
void linkTest_registerRecordDeviceDriver(struct dbBase *);
static void startTestIoc(const char *dbfile)
{
testdbPrepare();
testdbReadDatabase("linkTest.dbd", NULL, NULL);
linkTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase(dbfile, NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
}
static void testCalc()
{
ioRecord *pio;
DBLINK *pinp, *pout;
long status;
epicsFloat64 f64;
startTestIoc("ioRecord.db");
pio = (ioRecord *) testdbRecordPtr("io");
pinp = &pio->input;
pout = &pio->output;
testDiag("testing lnkCalc input");
{
dbStateId red;
testPutLongStr("io.INPUT", "{\"calc\":{"
"\"expr\":\"a\","
"\"args\":[{\"state\":\"red\"}]"
"}}");
if (testOk1(pinp->type == JSON_LINK))
testDiag("Link was set to '%s'", pinp->value.json.string);
red = dbStateFind("red");
testOk(!!red, "State red was created");
dbStateSet(red);
status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL);
testOk(!status, "dbGetLink succeeded (status = %ld)", status);
testOk(f64, "Got TRUE (%g)", f64);
dbStateClear(red);
status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL);
testOk(!status, "dbGetLink succeeded (status = %ld)", status);
testOk(!f64, "Got FALSE (%g)", f64);
}
{
dbStateId major = dbStateCreate("major");
dbStateId minor = dbStateCreate("minor");
epicsEnum16 stat, sevr;
testPutLongStr("io.INPUT", "{\"calc\":{"
"\"expr\":\"0\","
"\"major\":\"A\","
"\"minor\":\"B\","
"\"args\":[{\"state\":\"major\"},{\"state\":\"minor\"}]"
"}}");
if (testOk1(pinp->type == JSON_LINK))
testDiag("Link was set to '%s'", pinp->value.json.string);
dbStateSet(major);
dbStateSet(minor);
status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL);
testOk(!status, "dbGetLink succeeded (status = %ld)", status);
testOk(f64 == 0.0, "Got zero (%g)", f64);
testOk(recGblResetAlarms(pio) & DBE_ALARM, "Record alarm was raised");
status = dbGetAlarm(pinp, &stat, &sevr);
testOk(!status, "dbGetAlarm succeeded (status = %ld)", status);
testOk(stat == LINK_ALARM, "Alarm status = LINK (%d)", stat);
testOk(sevr == MAJOR_ALARM, "Alarm severity = MAJOR (%d)", sevr);
dbStateClear(major);
status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL);
testOk(!status, "dbGetLink succeeded (status = %ld)", status);
testOk(recGblResetAlarms(pio) & DBE_ALARM, "Record alarm was raised");
status = dbGetAlarm(pinp, &stat, &sevr);
testOk(!status, "dbGetAlarm succeeded (status = %ld)", status);
testOk(stat == LINK_ALARM, "Alarm status = LINK (%d)", stat);
testOk(sevr == MINOR_ALARM, "Alarm severity = MINOR (%d)", sevr);
}
testDiag("testing lnkCalc output");
{
dbStateId red = dbStateFind("red");
dbStateId out = dbStateCreate("out");
testPutLongStr("io.OUTPUT", "{\"calc\":{"
"\"expr\":\"!a\","
"\"out\":{\"state\":\"out\"},"
"\"args\":[{\"state\":\"red\"}],"
"\"units\":\"things\","
"\"prec\":3"
"}}");
if (testOk1(pout->type == JSON_LINK))
testDiag("Link was set to '%s'", pout->value.json.string);
dbStateSet(red);
f64 = 1.0;
status = dbPutLink(pout, DBF_DOUBLE, &f64, 1);
testOk(!status, "dbPutLink succeeded (status = %ld)", status);
testOk(!dbStateGet(out), "output was cleared");
dbStateClear(red);
status = dbPutLink(pout, DBF_DOUBLE, &f64, 1);
testOk(!status, "dbGetLink succeeded (status = %ld)", status);
testOk(dbStateGet(out), "output was set");
}
{
char units[20] = {0};
short prec = 0;
status = dbGetUnits(pout, units, sizeof(units));
testOk(!status, "dbGetUnits succeeded (status = %ld)", status);
testOk(!strcmp(units, "things"), "Units string correct (%s)", units);
status = dbGetPrecision(pout, &prec);
testOk(!status, "dbGetPrecision succeeded (status = %ld)", status);
testOk(prec == 3, "Precision correct (%d)", prec);
}
testIocShutdownOk();
testdbCleanup();
}
MAIN(lnkCalcTest)
{
testPlan(0);
testCalc();
return testDone();
}

View File

@ -0,0 +1,130 @@
/*************************************************************************\
* Copyright (c) 2018 Andrew Johnson
* EPICS BASE is distributed subject to a Software License Agreement found
* in the file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include "dbAccess.h"
#include "alarm.h"
#include "dbUnitTest.h"
#include "errlog.h"
#include "epicsThread.h"
#include "dbLink.h"
#include "dbState.h"
#include "ioRecord.h"
#include "testMain.h"
void linkTest_registerRecordDeviceDriver(struct dbBase *);
static void startTestIoc(const char *dbfile)
{
testdbPrepare();
testdbReadDatabase("linkTest.dbd", NULL, NULL);
linkTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase(dbfile, NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
}
static void testState()
{
dbStateId red;
ioRecord *pio;
DBLINK *pinp, *pout;
long status;
testDiag("testing lnkState");
startTestIoc("ioRecord.db");
pio = (ioRecord *) testdbRecordPtr("io");
pinp = &pio->input;
pout = &pio->output;
red = dbStateFind("red");
testOk(!red, "No state red exists");
testdbPutFieldOk("io.INPUT", DBF_STRING, "{\"state\":\"red\"}");
if (testOk1(pinp->type == JSON_LINK))
testDiag("Link was set to '%s'", pinp->value.json.string);
red = dbStateFind("red");
testOk(!!red, "state red exists");
{
epicsInt16 i16;
dbStateSet(red);
status = dbGetLink(pinp, DBF_SHORT, &i16, NULL, NULL);
testOk(!status, "dbGetLink succeeded (status = %ld)", status);
testOk(i16, "Got TRUE");
testdbPutFieldOk("io.INPUT", DBF_STRING, "{\"state\":\"!red\"}");
if (testOk1(pinp->type == JSON_LINK))
testDiag("Link was set to '%s'", pinp->value.json.string);
status = dbGetLink(pinp, DBF_SHORT, &i16, NULL, NULL);
testOk(!status, "dbGetLink succeeded (status = %ld)", status);
testOk(!i16, "Got FALSE");
testdbPutFieldOk("io.OUTPUT", DBF_STRING, "{\"state\":\"red\"}");
if (testOk1(pout->type == JSON_LINK))
testDiag("Link was set to '%s'", pout->value.json.string);
i16 = 0;
status = dbPutLink(pout, DBF_SHORT, &i16, 1);
testOk(!status, "dbPutLink %d succeeded (status = %ld)", i16, status);
testOk(!dbStateGet(red), "state was cleared");
i16 = 0x8000;
status = dbPutLink(pout, DBF_SHORT, &i16, 1);
testOk(!status, "dbPutLink 0x%hx succeeded (status = %ld)", i16, status);
testOk(dbStateGet(red), "state was set");
}
status = dbPutLink(pout, DBF_STRING, "", 1);
testOk(!status, "dbPutLink '' succeeded (status = %ld)", status);
testOk(!dbStateGet(red), "state was cleared");
status = dbPutLink(pout, DBF_STRING, "FALSE", 1); /* Not really... */
testOk(!status, "dbPutLink 'FALSE' succeeded (status = %ld)", status);
testOk(dbStateGet(red), "state was set");
status = dbPutLink(pout, DBF_STRING, "0", 1);
testOk(!status, "dbPutLink '0' succeeded (status = %ld)", status);
testOk(!dbStateGet(red), "state was cleared");
{
epicsFloat64 f64 = 0.1;
status = dbPutLink(pout, DBF_DOUBLE, &f64, 1);
testOk(!status, "dbPutLink %g succeeded (status = %ld)", f64, status);
testOk(dbStateGet(red), "state was set");
testdbPutFieldOk("io.OUTPUT", DBF_STRING, "{\"state\":\"!red\"}");
if (testOk1(pout->type == JSON_LINK))
testDiag("Link was set to '%s'", pout->value.json.string);
status = dbPutLink(pout, DBF_DOUBLE, &f64, 1);
testOk(!status, "dbPutLink %g succeeded (status = %ld)", f64, status);
testOk(!dbStateGet(red), "state was cleared");
}
testIocShutdownOk();
testdbCleanup();
}
MAIN(lnkStateTest)
{
testPlan(28);
testState();
return testDone();
}

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