diff --git a/.appveyor.yml b/.appveyor.yml index 2cdc51128..bba0292e8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -40,15 +40,16 @@ configuration: # Environment variables: compiler toolchain environment: matrix: - - TOOLCHAIN: 10.0 - - TOOLCHAIN: 11.0 - - TOOLCHAIN: 12.0 - - TOOLCHAIN: 14.0 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLCHAIN: 2017 - - TOOLCHAIN: cygwin - TOOLCHAIN: mingw APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TOOLCHAIN: 2019 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + TOOLCHAIN: 2017 + - TOOLCHAIN: 14.0 + - TOOLCHAIN: 12.0 + - TOOLCHAIN: 11.0 + - TOOLCHAIN: 10.0 # Platform: architecture platform: @@ -61,9 +62,19 @@ matrix: # VS Express installs don't have the 64 bit compiler - platform: x64 TOOLCHAIN: 10.0 - # Cygwin static-debug has compiler problems - - configuration: static-debug - TOOLCHAIN: cygwin + # Exclude to reduce total job runtime + # skip 64-bit for older and 32-bit for newer + - platform: x64 + TOOLCHAIN: 11.0 + - platform: x86 + TOOLCHAIN: mingw + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - platform: x86 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TOOLCHAIN: 2019 + - platform: x86 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + TOOLCHAIN: 2017 #---------------------------------# @@ -78,7 +89,25 @@ build_script: - cmd: .ci/appveyor-make.bat test_script: - - cmd: .ci/appveyor-make.bat runtests + - cmd: .ci/appveyor-make.bat tapfiles + - cmd: .ci/appveyor-make.bat test-results + +on_finish: + - ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + + +#---------------------------------# +# debugging # +#---------------------------------# + +## if you want to connect by remote desktop to a failed build, uncomment these lines +## note that you will need to connect within the usual build timeout limit (60 minutes) +## so you may want to adjust the build matrix above to just build the one of interest + +#on_failure: +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + #---------------------------------# # notifications # diff --git a/.ci/appveyor-make.bat b/.ci/appveyor-make.bat index 9cd8fe684..eb127c5ce 100644 --- a/.ci/appveyor-make.bat +++ b/.ci/appveyor-make.bat @@ -1,6 +1,6 @@ :: Universal build script for AppVeyor (https://ci.appveyor.com/) :: Environment: -:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/cygwin/mingw] +:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/2019/mingw] :: CONFIGURATION - determines EPICS build [dynamic/static] :: PLATFORM - architecture [x86/x64] :: @@ -8,39 +8,29 @@ Setlocal EnableDelayedExpansion +:: we do not currently have a combined static and debug EPICS_HOST_ARCH target +:: So a combined debug and static target will appear to be just static +:: but debug will have been specified in CONFIG_SITE by appveyor-prepare.bat set "ST=" -if /i "%CONFIGURATION%"=="static" set ST=-static +echo.%CONFIGURATION% | findstr /C:"debug">nul && ( + set "ST=-debug" +) +echo.%CONFIGURATION% | findstr /C:"static">nul && ( + set "ST=-static" +) -set OS=64BIT -if "%PLATFORM%"=="x86" set OS=32BIT +set MY_OS=64BIT +if "%PLATFORM%"=="x86" set MY_OS=32BIT -echo [INFO] Platform: %OS% +echo [INFO] Platform: %MY_OS% :: Use parallel make, except for 3.14 set "MAKEARGS=-j2 -Otarget" if "%APPVEYOR_REPO_BRANCH%"=="3.14" set MAKEARGS= -if "%TOOLCHAIN%"=="cygwin" ( - set "MAKE=make" - if "%OS%"=="64BIT" ( - set "EPICS_HOST_ARCH=cygwin-x86_64" - set "INCLUDE=C:\cygwin64\include;%INCLUDE%" - set "PATH=C:\cygwin64\bin;%PATH%" - echo [INFO] Cygwin Toolchain 64bit - ) else ( - set "EPICS_HOST_ARCH=cygwin-x86" - set "INCLUDE=C:\cygwin\include;%INCLUDE%" - set "PATH=C:\cygwin\bin;%PATH%" - echo [INFO] Cygwin Toolchain 32bit - ) - echo [INFO] Compiler Version - gcc -v - goto Finish -) - if "%TOOLCHAIN%"=="mingw" ( set "MAKE=mingw32-make" - if "%OS%"=="64BIT" ( + if "%MY_OS%"=="64BIT" ( set "EPICS_HOST_ARCH=windows-x64-mingw" set "INCLUDE=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\include;%INCLUDE%" set "PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%" @@ -56,6 +46,11 @@ if "%TOOLCHAIN%"=="mingw" ( goto Finish ) +if "%TOOLCHAIN%"=="2019" ( + echo [INFO] Setting strawberry perl path + set "PATH=c:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%" +) + set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio %TOOLCHAIN%" if not exist "%VSINSTALL%\" set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio\%TOOLCHAIN%\Community" if not exist "%VSINSTALL%\" goto MSMissing @@ -64,9 +59,9 @@ set "MAKE=C:\tools\make" echo [INFO] APPVEYOR_BUILD_WORKER_IMAGE=%APPVEYOR_BUILD_WORKER_IMAGE% -if "%OS%"=="64BIT" ( +if "%MY_OS%"=="64BIT" ( set EPICS_HOST_ARCH=windows-x64%ST% - :: VS 2017 + :: VS 2017/2019 if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" ( call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" where cl @@ -91,7 +86,7 @@ if "%OS%"=="64BIT" ( ) ) else ( set EPICS_HOST_ARCH=win32-x86%ST% - :: VS 2017 + :: VS 2017/2019 if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat" ( call "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat" where cl @@ -119,7 +114,7 @@ if "%OS%"=="64BIT" ( ) :MSMissing -echo [INFO] Installation for MSVC Toolchain %TOOLCHAIN% / %OS% seems to be missing +echo [INFO] Installation for MSVC Toolchain %TOOLCHAIN% / %MY_OS% seems to be missing exit 1 :MSFound diff --git a/.ci/appveyor-prepare.bat b/.ci/appveyor-prepare.bat index 9f105ee96..312223d16 100644 --- a/.ci/appveyor-prepare.bat +++ b/.ci/appveyor-prepare.bat @@ -1,63 +1,52 @@ :: Build script for AppVeyor (https://ci.appveyor.com/) :: Environment: -:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/cygwin/mingw] +:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/mingw] :: CONFIGURATION - determines EPICS build [dynamic/static, -debug] :: PLATFORM - "x86" -> use 32bit architecture :: :: Prepares an Appveyor build by excuting the following steps :: - Set up configure\CONFIG_SITE for static vs. dynamic build -:: - Install Cygwin / Mingw (TOOLCHAIN setting) in the in the appropriate flavor +:: - Install Mingw (TOOLCHAIN setting) in the in the appropriate flavor :: - Download and install Make-4.1 from EPICS download page Setlocal EnableDelayedExpansion -set OS=64BIT -if "%PLATFORM%"=="x86" set OS=32BIT +set MY_OS=64BIT +if "%PLATFORM%"=="x86" set MY_OS=32BIT -echo [INFO] Platform: %OS% +echo [INFO] Platform: %MY_OS% -if "%TOOLCHAIN%"=="cygwin" ( - echo.%CONFIGURATION% | findstr /C:"static">nul && ( - echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE - echo STATIC_BUILD=YES>> configure\CONFIG_SITE - echo [INFO] EPICS set up for static build - ) || ( - echo [INFO] EPICS set up for dynamic build - ) - echo.%CONFIGURATION% | findstr /C:"debug">nul && ( - echo HOST_OPT=NO>> configure\CONFIG_SITE - echo [INFO] EPICS set up for debug build - ) || ( - echo [INFO] EPICS set up for optimized build - ) - if "%OS%"=="64BIT" ( - echo [INFO] Installing Cygwin 64bit and dependencies - @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86_64.exe', 'C:\cygwin64\setup-x86_64.exe')" - C:\cygwin64\setup-x86_64.exe -q -P "libreadline-devel,libncursesw-devel" - ) else ( - echo [INFO] Installing Cygwin 32bit and dependencies - @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86.exe', 'C:\cygwin\setup-x86.exe')" - C:\cygwin\setup-x86.exe -q -P "libreadline-devel,libncursesw-devel" - ) +:: with MSVC either static or debug can be handled as part +:: of EPICS_HOST_ARCH but not both. So we set the appropriate +:: options in CONFIG_SITE. For mingw and cygwin they are missing +:: some static and debug targets so set things here too +echo.%CONFIGURATION% | findstr /C:"static">nul && ( + echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE + echo STATIC_BUILD=YES>> configure\CONFIG_SITE + echo [INFO] EPICS set up for static build +) || ( + echo [INFO] EPICS set up for dynamic build ) -if "%TOOLCHAIN%"=="mingw" ( - echo.%CONFIGURATION% | findstr /C:"static">nul && ( - echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE - echo STATIC_BUILD=YES>> configure\CONFIG_SITE - echo [INFO] EPICS set up for static build - ) || ( - echo [INFO] EPICS set up for dynamic build - ) - echo.%CONFIGURATION% | findstr /C:"debug">nul && ( - echo HOST_OPT=NO>> configure\CONFIG_SITE - echo [INFO] EPICS set up for debug build - ) || ( - echo [INFO] EPICS set up for optimized build - ) +echo.%CONFIGURATION% | findstr /C:"debug">nul && ( + echo HOST_OPT=NO>> configure\CONFIG_SITE + echo [INFO] EPICS set up for debug build +) || ( + echo [INFO] EPICS set up for optimized build ) echo [INFO] Installing Make 4.2.1 from ANL web site curl -fsS --retry 3 -o C:\tools\make-4.2.1.zip https://epics.anl.gov/download/tools/make-4.2.1-win64.zip cd \tools "C:\Program Files\7-Zip\7z" e make-4.2.1.zip + +set "PERLVER=5.30.0.1" +if "%TOOLCHAIN%"=="2019" ( + echo [INFO] Installing Strawberry Perl %PERLVER% + curl -fsS --retry 3 -o C:\tools\perl-%PERLVER%.zip http://strawberryperl.com/download/%PERLVER%/strawberry-perl-%PERLVER%-64bit.zip + cd \tools + "C:\Program Files\7-Zip\7z" x perl-%PERLVER%.zip -oC:\strawberry + cd \strawberry + :: we set PATH in appveyor-build.bat + call relocation.pl.bat +) diff --git a/.ci/travis-build.sh b/.ci/travis-build.sh index 39eb0ea5f..c71bdd90e 100755 --- a/.ci/travis-build.sh +++ b/.ci/travis-build.sh @@ -68,7 +68,7 @@ EOF type qemu-system-i386 || echo "Missing qemu" fi -make -j2 $EXTRA +make -j2 RTEMS_QEMU_FIXUPS=YES CMD_CFLAGS="${CMD_CFLAGS}" CMD_CXXFLAGS="${CMD_CXXFLAGS}" CMD_LDFLAGS="${CMD_LDFLAGS}" if [ "$TEST" != "NO" ] then diff --git a/.ci/travis-prepare.sh b/.ci/travis-prepare.sh new file mode 100755 index 000000000..393bd80b6 --- /dev/null +++ b/.ci/travis-prepare.sh @@ -0,0 +1,24 @@ +#!/bin/sh +set -e -x + +die() { + echo "$1" >&2 + exit 1 +} + +if [ -f /etc/hosts ] +then + # The travis-ci "bionic" image throws us a curveball in /etc/hosts + # by including two entries for localhost. The first for 127.0.1.1 + # which causes epicsSockResolveTest to fail. + # cat /etc/hosts + # ... + # 127.0.1.1 localhost localhost ip4-loopback + # 127.0.0.1 localhost nettuno travis vagrant travis-job-.... + + sudo sed -i -e '/^127\.0\.1\.1/ s|localhost\s*||g' /etc/hosts + + echo "==== /etc/hosts" + cat /etc/hosts + echo "====" +fi diff --git a/.travis.yml b/.travis.yml index d6130c753..1e7d45212 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,54 @@ -sudo: false -dist: trusty language: c -compiler: - - gcc + +matrix: + include: + - sudo: false + dist: bionic + compiler: gcc + env: CMPLR=gcc + - sudo: false + dist: xenial + compiler: gcc + env: CMPLR=gcc + - sudo: false + dist: bionic + compiler: gcc + env: CMPLR=gcc CMD_CXXFLAGS=-std=c++11 + - sudo: false + dist: trusty + compiler: gcc + env: CMPLR=gcc STATIC=YES CMD_CXXFLAGS=-std=c++11 + - sudo: false + dist: bionic + compiler: gcc + env: CMPLR=clang + - sudo: false + dist: xenial + compiler: gcc + env: CMPLR=clang + - sudo: false + dist: trusty + compiler: gcc + env: CMPLR=clang STATIC=YES + - sudo: false + dist: trusty + compiler: gcc + env: WINE=32 TEST=NO STATIC=YES + - sudo: false + dist: trusty + compiler: gcc + env: WINE=32 TEST=NO STATIC=NO + - sudo: false + dist: trusty + compiler: gcc + env: RTEMS=4.10 + - sudo: false + dist: trusty + compiler: gcc + env: RTEMS=4.9 + - os: osx + env: CMD_CFLAGS="-mmacosx-version-min=10.7" CMD_CXXFLAGS="-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++" CMD_LDXFLAGS="-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++" + addons: apt: packages: @@ -13,15 +59,5 @@ addons: - g++-mingw-w64-i686 - qemu-system-x86 script: + - .ci/travis-prepare.sh - .ci/travis-build.sh -env: - - CMPLR=gcc - - CMPLR=clang - - CMPLR=gcc STATIC=YES - - CMPLR=clang STATIC=YES - - CMPLR=gcc EXTRA=CMD_CXXFLAGS=-std=c++11 - - CMPLR=clang EXTRA=CMD_CXXFLAGS=-std=c++11 - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=YES - - RTEMS=4.9 TEST=YES diff --git a/configure/CONFIG b/configure/CONFIG index e40d3f5f7..153e69e8c 100644 --- a/configure/CONFIG +++ b/configure/CONFIG @@ -58,8 +58,12 @@ include $(CONFIG)/CONFIG_BASE_VERSION include $(CONFIG)/os/CONFIG.$(EPICS_HOST_ARCH).Common -include $(CONFIG)/os/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# Parse configure/RELEASE +# except when building Base itself, where this file is empty, +# and would error in src/tools/ anyway. +ifndef BASE_TOP RELEASE_TOPS := $(shell $(CONVERTRELEASE) -T $(TOP) releaseTops) - +endif ifdef T_A diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE index 963b83a32..8f9fadcdf 100644 --- a/configure/CONFIG_BASE +++ b/configure/CONFIG_BASE @@ -43,8 +43,11 @@ PODTOHTML = $(PERL) $(TOOLS)/podToHtml.pl CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl) FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl +PROVE = $(PERL) $(TOOLS)/epicsProve.pl GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG) +MAKERPATH = $(PYTHON) $(TOOLS)/makeRPath.py + #--------------------------------------------------------------- # tools for installing libraries and products INSTALL = $(PERL) $(TOOLS)/installEpics.pl $(QUIET_FLAG) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 53753d7e4..fbe1545a2 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -52,12 +52,12 @@ EPICS_MODIFICATION = 3 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included in the official EPICS version number if zero -EPICS_PATCH_LEVEL = 0 +EPICS_PATCH_LEVEL = 2 -# Between official releases, the EPICS_PATCH_LEVEL gets incremented -# and a -DEV suffix is added (similar to the Maven -SNAPSHOT versions) -EPICS_DEV_SNAPSHOT= -#EPICS_DEV_SNAPSHOT=-DEV +# Immediately after an official release the EPICS_PATCH_LEVEL is incremented +# and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions) +#EPICS_DEV_SNAPSHOT= +EPICS_DEV_SNAPSHOT=-DEV #EPICS_DEV_SNAPSHOT=-pre1 #EPICS_DEV_SNAPSHOT=-pre1-DEV #EPICS_DEV_SNAPSHOT=-pre2 diff --git a/modules/ca/configure/CONFIG_CA_MODULE b/configure/CONFIG_CA_MODULE similarity index 100% rename from modules/ca/configure/CONFIG_CA_MODULE rename to configure/CONFIG_CA_MODULE diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION new file mode 100644 index 000000000..c75b4e421 --- /dev/null +++ b/configure/CONFIG_CA_VERSION @@ -0,0 +1,12 @@ +# Version number for the Channel Access API and shared library + +EPICS_CA_MAJOR_VERSION = 4 +EPICS_CA_MINOR_VERSION = 13 +EPICS_CA_MAINTENANCE_VERSION = 6 + +# Development flag, set to zero for release versions + +EPICS_CA_DEVELOPMENT_FLAG = 1 + +# Immediately after a release the MAINTENANCE_VERSION +# will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON index d3a66968f..b79e15cf5 100644 --- a/configure/CONFIG_COMMON +++ b/configure/CONFIG_COMMON @@ -38,6 +38,8 @@ BUILD_ARCHS = $(EPICS_HOST_ARCH) $(CROSS1) $(CROSS2) # otherwise override this in os/CONFIG_SITE..Common PERL = perl -CSD +PYTHON = python + #------------------------------------------------------- # Check configure/RELEASE file for consistency CHECK_RELEASE_YES = checkRelease @@ -376,14 +378,14 @@ PATH_FILTER = $(1)$(warning PATH_FILTER is deprecated; used for $(1)) # each list starts with the destination directory name(s) # to make sure it's there -INSTALL_PROD= $(PRODNAME:%= $(INSTALL_BIN)/%) -INSTALL_LIBS= $(LIBNAME:%=$(INSTALL_LIB)/%) -INSTALL_MUNCHS= $(MUNCHNAME:%=$(INSTALL_BIN)/%) -INSTALL_SHRLIBS= $(SHRLIBNAME:%=$(INSTALL_SHRLIB)/%) -INSTALL_LOADABLE_SHRLIBS= $(LOADABLE_SHRLIBNAME:%=$(INSTALL_SHRLIB)/%) -INSTALL_DLLSTUB_LIBS=$(DLLSTUB_LIBNAME:%=$(INSTALL_LIB)/%) -INSTALL_TCLLIBS=$(TCLLIBNAME:%=$(INSTALL_TCLLIB)/%) -INSTALL_TCLINDEX=$(TCLINDEX:%=$(INSTALL_TCLLIB)/%) +INSTALL_PROD = $(PRODNAME:%= $(INSTALL_BIN)/%) +INSTALL_LIBS = $(LIBNAME:%=$(INSTALL_LIB)/%) +INSTALL_MUNCHS = $(MUNCHNAME:%=$(INSTALL_BIN)/%) +INSTALL_SHRLIBS = $(SHRLIBNAME:%=$(INSTALL_SHRLIB)/%) +INSTALL_LOADABLE_SHRLIBS = $(LOADABLE_SHRLIBNAME:%=$(INSTALL_SHRLIB)/%) +INSTALL_DLLSTUB_LIBS = $(DLLSTUB_LIBNAME:%=$(INSTALL_LIB)/%) +INSTALL_TCLLIBS = $(TCLLIBNAME:%=$(INSTALL_TCLLIB)/%) +INSTALL_TCLINDEX = $(TCLINDEX:%=$(INSTALL_TCLLIB)/%) INSTALL_SCRIPTS = $(SCRIPTS:%= $(INSTALL_BIN)/%) INSTALL_OBJS = $(OBJSNAME:%= $(INSTALL_BIN)/%) diff --git a/modules/database/configure/CONFIG_DATABASE_MODULE b/configure/CONFIG_DATABASE_MODULE similarity index 100% rename from modules/database/configure/CONFIG_DATABASE_MODULE rename to configure/CONFIG_DATABASE_MODULE diff --git a/configure/CONFIG_DATABASE_VERSION b/configure/CONFIG_DATABASE_VERSION new file mode 100644 index 000000000..21ac836b0 --- /dev/null +++ b/configure/CONFIG_DATABASE_VERSION @@ -0,0 +1,12 @@ +# Version number for the database APIs and shared library + +EPICS_DATABASE_MAJOR_VERSION = 3 +EPICS_DATABASE_MINOR_VERSION = 17 +EPICS_DATABASE_MAINTENANCE_VERSION = 6 + +# Development flag, set to zero for release versions + +EPICS_DATABASE_DEVELOPMENT_FLAG = 1 + +# Immediately after a release the MAINTENANCE_VERSION +# will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_ENV b/configure/CONFIG_ENV index 59e72d883..6d0d52a79 100644 --- a/configure/CONFIG_ENV +++ b/configure/CONFIG_ENV @@ -3,9 +3,8 @@ # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. #************************************************************************* # Author: Andrew Johnson # Date: 20 April 1995 @@ -54,8 +53,3 @@ EPICS_IOC_IGNORE_SERVERS="" # EPICS_IOC_LOG_PORT Log server port number etc. EPICS_IOC_LOG_PORT=7004 -# Other services: - -EPICS_CMD_PROTO_PORT= -EPICS_AR_PORT=7002 - diff --git a/modules/libcom/configure/CONFIG_LIBCOM_MODULE b/configure/CONFIG_LIBCOM_MODULE similarity index 61% rename from modules/libcom/configure/CONFIG_LIBCOM_MODULE rename to configure/CONFIG_LIBCOM_MODULE index 175606cdb..32bb937c2 100644 --- a/modules/libcom/configure/CONFIG_LIBCOM_MODULE +++ b/configure/CONFIG_LIBCOM_MODULE @@ -5,18 +5,10 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -# Set EPICS_LIBCOM if necessary -ifndef EPICS_LIBCOM - EPICS_LIBCOM = $(if $(BUILDING_LIBCOM),$(INSTALL_LOCATION),$(EPICS_BASE)) - - # Paths to tools built here - EPICS_LIBCOM_HOST_BIN ?= $(EPICS_LIBCOM)/bin/$(EPICS_HOST_ARCH) -endif - # Set location of locally generated tools -YACC = $(abspath $(EPICS_LIBCOM_HOST_BIN))/antelope$(HOSTEXE) -LEX = $(abspath $(EPICS_LIBCOM_HOST_BIN))/e_flex$(HOSTEXE) \ - -S$(EPICS_LIBCOM)/include/flex.skel.static +YACC = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/antelope$(HOSTEXE) +LEX = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/e_flex$(HOSTEXE) \ + -S$(EPICS_BASE)/include/flex.skel.static # Default stack size for osiThread OSITHREAD_USE_DEFAULT_STACK = NO diff --git a/configure/CONFIG_LIBCOM_VERSION b/configure/CONFIG_LIBCOM_VERSION new file mode 100644 index 000000000..3def716cb --- /dev/null +++ b/configure/CONFIG_LIBCOM_VERSION @@ -0,0 +1,12 @@ +# Version number for the libcom APIs and shared library + +EPICS_LIBCOM_MAJOR_VERSION = 3 +EPICS_LIBCOM_MINOR_VERSION = 17 +EPICS_LIBCOM_MAINTENANCE_VERSION = 7 + +# Development flag, set to zero for release versions + +EPICS_LIBCOM_DEVELOPMENT_FLAG = 1 + +# Immediately after a release the MAINTENANCE_VERSION +# will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index d91c3a963..535ef5707 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -171,10 +171,18 @@ endif GCC_PIPE = NO # Set RPATH when linking executables and libraries. -# Must be either YES or NO. If you set this to NO you must also provide a +# Must be either YES, NO, or ORIGIN. If you set this to NO you must also provide a # way for Base executables to find their shared libraries when they are # run at build-time, e.g. set the LD_LIBRARY_PATH environment variable. +# ORIGIN is a feature of the ELF executable format used by Linux, freebsd, and solaris. LINKER_USE_RPATH = YES +# Only used when LINKER_USE_RPATH=ORIGIN +# The build time root(s) of the relocatable tree (separate multiple w/ ':'). +# Linking to libraries under any root directory will be relative. +# Linking to libraries outside of this root will be absolute. +# All root directories are considered to be the same. +LINKER_ORIGIN_ROOT = $(INSTALL_LOCATION) + # Overrides for the settings above may appear in a CONFIG_SITE.local file -include $(CONFIG)/CONFIG_SITE.local diff --git a/configure/CONFIG_SITE_ENV b/configure/CONFIG_SITE_ENV index 5bf4960f7..bacbc14a5 100644 --- a/configure/CONFIG_SITE_ENV +++ b/configure/CONFIG_SITE_ENV @@ -24,40 +24,40 @@ # Site-specific environment settings -# Time service: -# EPICS_TIMEZONE -# Local timezone info for vxWorks and RTEMS. The format is -# :::: -# where is only used by strftime() for %Z conversions, -# and and are mmddhh - that is month,day,hour -# e.g. for ANL in 2018: EPICS_TIMEZONE=CUS::360:031102:110402 -# The future dates below assume the rules don't get changed; -# see http://www.timeanddate.com/time/dst/2018.html to check. -# -# DST for 2019 US: Mar 10 - Nov 03 -# EU: Mar 31 - Oct 27 -EPICS_TIMEZONE = CUS::360:031002:110302 -#EPICS_TIMEZONE = MET::-60:033102:102703 -# -# DST for 2020 US: Mar 08 - Nov 01 -# EU: Mar 29 - Oct 25 -#EPICS_TIMEZONE = CUS::360:030802:110102 -#EPICS_TIMEZONE = MET::-60:032902:102503 -# -# DST for 2021 US: Mar 14 - Nov 07 -# EU: Mar 28 - Oct 31 -#EPICS_TIMEZONE = CUS::360:031402:110702 -#EPICS_TIMEZONE = MET::-60:032802:103103 -# -# DST for 2022 US: Mar 13 - Nov 06 -# EU: Mar 27 - Oct 30 -#EPICS_TIMEZONE = CUS::360:031302:110602 -#EPICS_TIMEZONE = MET::-60:032702:103003 -# -# DST for 2023 US: Mar 13 - Nov 06 -# EU: Mar 27 - Oct 30 -#EPICS_TIMEZONE = CUS::360:031202:110502 -#EPICS_TIMEZONE = MET::-60:032602:102903 +## Time service: +# EPICS_TZ +# Local timezone rules for vxWorks and RTEMS. The value follows the Posix +# TZ environment variable's Mm.n.d/h format (see the IBM link below for +# details). If TZ hasn't already been set when the osdTime timeRegister() +# C++ static constructor runs, this parameter will be copied into the TZ +# environment variable. Once the OS clock has been synchronized to NTP the +# routine tz2timezone() will be run to convert TZ into the TIMEZONE +# variable format that VxWorks needs. +# https://developer.ibm.com/articles/au-aix-posix/ + +# Japan Standard Time, no DST: +#EPICS_TZ = "JST-9" + +# Central European (Summer) Time: +#EPICS_TZ = "CET-1CEST,M3.5.0/2,M10.5.0/3" + +# Greenwich Mean/British Summer Time: +#EPICS_TZ = "GMT0BST,M3.5.0/1,M10.5.0/2" + +# US Eastern Standard/Daylight Time: +#EPICS_TZ = "EST5EDT,M3.2.0/2,M11.1.0/2" + +# US Central Standard/Daylight Time: +EPICS_TZ = "CST6CDT,M3.2.0/2,M11.1.0/2" + +# US Mountain Standard/Daylight Time: +#EPICS_TZ = "MST7MDT,M3.2.0/2,M11.1.0/2" + +# US Pacific Standard/Daylight Time: +#EPICS_TZ = "PST8PDT,M3.2.0/2,M11.1.0/2" + +# US Hawaiian Standard Time, no DST: +#EPICS_TZ = "HST10" # EPICS_TS_NTP_INET # NTP time server ip address for VxWorks and RTEMS. diff --git a/configure/Makefile b/configure/Makefile index 377879766..f48278dd3 100644 --- a/configure/Makefile +++ b/configure/Makefile @@ -20,5 +20,14 @@ CONFIGS += $(subst ../,,$(wildcard ../os/CONFIG*)) CONFIGS += $(subst ../,,$(wildcard ../RELEASE*)) CONFIGS += $(subst ../,,$(wildcard ../RULES*)) +CFG += CONFIG_LIBCOM_MODULE +CFG += CONFIG_LIBCOM_VERSION + +CFG += CONFIG_CA_MODULE +CFG += CONFIG_CA_VERSION + +CFG += CONFIG_DATABASE_MODULE +CFG += CONFIG_DATABASE_VERSION + include $(TOP)/configure/RULES diff --git a/configure/RULES.Db b/configure/RULES.Db index 89f98b6a7..fae5014ab 100644 --- a/configure/RULES.Db +++ b/configure/RULES.Db @@ -161,13 +161,13 @@ actionArchTargets = $(foreach action, $(ACTIONS), \ $(foreach arch, $(BUILD_ARCHS), $(action)$(DIVIDER)$(arch))) cleanArchTargets = $(foreach arch, $(BUILD_ARCHS), clean$(DIVIDER)$(arch)) --include $(TOP)/configure/CONFIG_APP_INCLUDE +include $(CONFIG)/CONFIG_APP_INCLUDE all: install install: buildInstall -buildInstall : build +buildInstall: build rebuild: clean install @@ -196,21 +196,21 @@ endif #--------------------------------------------------------------- # build dependancies, clean rule -inc : $(COMMON_INC) $(INSTALL_INC) +inc: $(COMMON_INC) $(INSTALL_INC) -build : $(COMMON_DBDS) $(COMMON_DBS) $(COMMON_DBDCATS) \ +build: $(COMMON_DBDS) $(COMMON_DBS) $(COMMON_DBDCATS) \ $(INSTALL_DBDS) $(INSTALL_DBS) \ $(DBDDEPENDS_FILES) $(TARGETS) \ $(INSTALL_DB_INSTALLS) $(INSTALL_DBD_INSTALLS) clean: db_clean -db_clean : +db_clean: @$(RM) $(COMMONS) $(DBDDEPENDS_FILES) @$(RM) *_registerRecordDeviceDriver.cpp @$(RM) $(TARGETS) -.PHONY : db_clean +.PHONY: db_clean realclean: clean @@ -389,7 +389,7 @@ $(COMMON_DIR)/%.dbd: ../%Include.dbd # Make DBDCAT file x depend on x_DBD source files define DBDCAT_template -$$(COMMON_DIR)/$(1).dbd : ../Makefile $$(foreach file, $$($(1)_DBD),$$(DBDCAT_SOURCE) ) +$$(COMMON_DIR)/$(1).dbd: ../Makefile $$(foreach file, $$($(1)_DBD),$$(DBDCAT_SOURCE) ) endef $(foreach name,$(subst .dbd,,$(DBDCAT)), $(eval $(call DBDCAT_template,$(name)))) @@ -418,7 +418,7 @@ $(INSTALL_DBD)/%: ../% @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) define DBD_INSTALLS_template -$$(INSTALL_DBD)/$$(notdir $(1)) : $(1) +$$(INSTALL_DBD)/$$(notdir $(1)): $(1) $(ECHO) "Installing $$@" @$$(INSTALL) -d -m $$(INSTALL_PERMISSIONS) $$^ $$(INSTALL_DBD) endef @@ -460,7 +460,7 @@ $(COMMON_DIR)/%.html: ../%.pl #--------------------------------------------------------------- # DB files -$(COMMON_DIR)/%.db: $(COMMON_DIR)/%.edf +$(COMMON_DIR)/%.db: $(COMMON_DIR)/%.edf $(E2DB) $(E2DB_SYSFLAGS) $(E2DB_FLAGS) -n $*.VAR $< @$(REPLACEVAR) < $*.VAR > $@ @$(RM) $*.VAR @@ -514,7 +514,7 @@ $(INSTALL_DB)/%.db: $(COMMON_DIR)/%.db @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) define DB_INSTALLS_template -$$(INSTALL_DB)/$$(notdir $(1)) : $(1) +$$(INSTALL_DB)/$$(notdir $(1)): $(1) $(ECHO) "Installing $$@" @$$(INSTALL) -d -m $$(INSTALL_PERMISSIONS) $$^ $$(INSTALL_DB) endef @@ -539,4 +539,3 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file)))) $(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP) .PRECIOUS: %_registerRecordDeviceDriver.cpp - diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index d0ac1bf1f..843f59d8f 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -75,7 +75,7 @@ HTMLS_DIR ?= . # First target all: install -ifeq ($(EPICS_HOST_ARCH),$T_A) +ifeq ($(EPICS_HOST_ARCH),$(T_A)) host: install else # Do nothing @@ -164,14 +164,13 @@ build: inc build: $(OBJSNAME) $(LIBTARGETS) $(PRODTARGETS) $(TESTPRODTARGETS) \ $(TARGETS) $(TESTSCRIPTS) $(INSTALL_LIB_INSTALLS) -inc : $(COMMON_INC) $(INSTALL_INC) $(INSTALL_CONFIGS) +inc: $(COMMON_INC) $(INSTALL_INC) $(INSTALL_CONFIGS) -buildInstall : \ +buildInstall: \ $(INSTALL_SCRIPTS) $(INSTALL_PROD) $(INSTALL_MUNCHS) \ $(INSTALL_TCLLIBS) $(INSTALL_TCLINDEX) \ + $(INSTALL_HTMLS) $(INSTALL_DOCS) \ $(INSTALL_OBJS) \ - $(INSTALL_DOCS) \ - $(INSTALL_HTMLS) \ $(INSTALL_TEMPLATE) \ $(INSTALL_BIN_INSTALLS) @@ -191,9 +190,9 @@ ifdef RES @$(RM) *$(RES) endif -# Sort mkdir targets to remove duplicates & make parents first -$(DIRECTORY_TARGETS): - $(MKDIR) $(sort $@) +# Sort directories to remove duplicates & make parents first +$(sort $(DIRECTORY_TARGETS)): + $(MKDIR) $@ # Install LIB_INSTALLS libraries before linking executables $(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS) @@ -207,12 +206,19 @@ endif checkRelease: +$(CONVERTRELEASE) checkRelease warnRelease: - -$(CONVERTRELEASE) checkRelease + $(CONVERTRELEASE) checkRelease noCheckRelease: ifeq ($(EPICS_HOST_ARCH),$(T_A)) $(info Warning: RELEASE file consistency checks have been disabled) endif +# $(FINAL_DIR) signals eventual install locations to makeRPath script +$(TESTPRODNAME): FINAL_DIR=. +$(PRODNAME): FINAL_DIR=$(INSTALL_BIN) +$(TESTSHRLIBNAME): FINAL_DIR=. +$(SHRLIBNAME): FINAL_DIR=$(INSTALL_SHRLIB) +$(LOADABLE_SHRLIBNAME): FINAL_DIR=$(INSTALL_SHRLIB) + #--------------------------------------------------------------- # The order of the following rules is # VERY IMPORTANT !!!! @@ -224,7 +230,7 @@ $(TESTPRODNAME) $(PRODNAME): %$(EXE): $(DEBUGCMD) $(LINK.cpp) $(MT_EXE_COMMAND) -%_ctdt$(OBJ) : %_ctdt.c +%_ctdt$(OBJ): %_ctdt.c @$(RM) $@ $(COMPILE.ctdt) $< @@ -242,9 +248,9 @@ $(TESTPRODNAME) $(PRODNAME): %$(EXE): # Cancel GNUMake's built-in rules, which don't have our _INC # dependencies so could get used in some circumstances (gdd) -%.o : %.c -%.o : %.cc -%.o : %.cpp +%.o: %.c +%.o: %.cc +%.o: %.cpp # Include files are order-only prerequisites for compilation: %$(OBJ): %.c | $(COMMON_INC) $(INSTALL_INC) @@ -278,7 +284,7 @@ YACCOPT ?= $($*_YACCOPT) # must be a separate rule since when not using '-d' the # prefix for .h will be different then .c -%.h : %.c %.y +%.h: %.c %.y %.c: %.l @$(RM) $@ @@ -363,7 +369,7 @@ $(MODNAME): %$(MODEXT): %$(EXE) runtests: $(TESTSCRIPTS) ifdef RUNTESTS_ENABLED - -$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^ + $(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^ endif testspec: $(TESTSCRIPTS) @@ -377,7 +383,7 @@ testspec: $(TESTSCRIPTS) test-results: tapfiles ifneq ($(TAPFILES),) ifdef RUNTESTS_ENABLED - prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES) + $(PROVE) --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES) endif CURRENT_TAPFILES := $(wildcard $(TAPFILES)) @@ -398,7 +404,7 @@ junitfiles: $(JUNITFILES) # A .tap file is the output from running the associated test script %.tap: %.t ifdef RUNTESTS_ENABLED - -$(PERL) $< -tap > $@ + $(PERL) $< -tap > $@ endif %.xml: %.tap @@ -427,14 +433,14 @@ endif # Install rules for BIN_INSTALLS and LIB_INSTALLS define BIN_INSTALLS_template -$$(INSTALL_BIN)/$$(notdir $(1)) : $(1) +$$(INSTALL_BIN)/$$(notdir $(1)): $(1) $(ECHO) "Installing $$( level Makefile .e.g" @echo " xxxRecord.o" -.PHONY: cleandirs distclean uninstall help +.PHONY: distclean uninstall help .PHONY: realuninstall archuninstall uninstallDirs ifndef DISABLE_TOP_RULES diff --git a/configure/os/CONFIG.Common.linuxCommon b/configure/os/CONFIG.Common.linuxCommon index 965de09b8..24b1a0c33 100644 --- a/configure/os/CONFIG.Common.linuxCommon +++ b/configure/os/CONFIG.Common.linuxCommon @@ -23,15 +23,17 @@ STATIC_LDFLAGS_YES= -Wl,-Bstatic STATIC_LDFLAGS_NO= STATIC_LDLIBS_YES= -Wl,-Bdynamic -# Set runtime path for shared libraries if USE_RPATH=YES and STATIC_BUILD=NO -SHRLIBDIR_RPATH_LDFLAGS_YES_NO = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%) +# Set runtime path for shared libraries if LINKER_USE_RPATH=YES +SHRLIBDIR_RPATH_LDFLAGS_YES = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%) +SHRLIBDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(SHRLIB_DEPLIB_DIRS)) SHRLIBDIR_LDFLAGS += \ - $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD)) + $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) -# Set runtime path for products if USE_RPATH=YES and STATIC_BUILD=NO -PRODDIR_RPATH_LDFLAGS_YES_NO = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) +# Set runtime path for products if LINKER_USE_RPATH=YES +PRODDIR_RPATH_LDFLAGS_YES = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) +PRODDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(PROD_DEPLIB_DIRS)) PRODDIR_LDFLAGS += \ - $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD)) + $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) # Link libraries controlled by COMMANDLINE_LIBRARY # The newest Linux versions only need readline, older ones need both diff --git a/configure/os/CONFIG.Common.win32-x86-mingw b/configure/os/CONFIG.Common.win32-x86-mingw index 936b1d954..cb3f53978 100644 --- a/configure/os/CONFIG.Common.win32-x86-mingw +++ b/configure/os/CONFIG.Common.win32-x86-mingw @@ -30,7 +30,7 @@ ARCH_DEP_LDFLAGS += -m32 # Compiler does not define __unix __unix__ unix # Override for -DUNIX from CONFIG.Common.UnixCommon -OP_SYS_CPPFLAGS = -D_MINGW +OP_SYS_CPPFLAGS = -D_MINGW -Wno-format EXE = .exe RES = .coff diff --git a/configure/os/CONFIG.linux-x86.win32-x86-mingw b/configure/os/CONFIG.linux-x86.win32-x86-mingw index 150f13864..bd75f5ebd 100644 --- a/configure/os/CONFIG.linux-x86.win32-x86-mingw +++ b/configure/os/CONFIG.linux-x86.win32-x86-mingw @@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm +OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/configure/os/CONFIG.linux-x86.windows-x64-mingw b/configure/os/CONFIG.linux-x86.windows-x64-mingw index 3becd0045..78f1f31de 100644 --- a/configure/os/CONFIG.linux-x86.windows-x64-mingw +++ b/configure/os/CONFIG.linux-x86.windows-x64-mingw @@ -4,21 +4,5 @@ # Override these definitions in CONFIG_SITE.linux-x86.windows-x64-mingw #------------------------------------------------------- -# Include common gnu compiler definitions -include $(CONFIG)/CONFIG.gnuCommon - -# Add resource compiler -RCCMD = $(GNU_BIN)/$(CMPLR_PREFIX)windres$(CMPLR_SUFFIX) $(INCLUDES) $< $@ - -# Remove -fPIC flags, add out-implib -SHRLIB_CFLAGS = -SHRLIB_LDFLAGS = -shared \ - -Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX) -LOADABLE_SHRLIB_LDFLAGS = -shared \ - -Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX) - -# No need to explicitly link with gcc library -GNU_LDLIBS_YES = - -# Link with winsock2 -OP_SYS_LDLIBS = -lws2_32 +# Use the definitions from the win32-x86-mingw target +include $(CONFIG)/os/CONFIG.linux-x86.win32-x86-mingw diff --git a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw index 2a7827ccd..a08f19902 100644 --- a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw @@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm +OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 7d6c11b6b..62a3ee257 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -135,19 +135,22 @@ OBJ_CXXFLAG = -Fo STATIC_CXXFLAGS_YES= -MT$(VISC_CFLAGS_DEBUG) $(BUILD_DLL_CFLAGS) STATIC_CXXFLAGS_NO= -MD$(VISC_CFLAGS_DEBUG) $(BUILD_DLL_CFLAGS) -DEPICS_CALL_DLL -STATIC_LDLIBS_YES=ws2_32.lib advapi32.lib user32.lib kernel32.lib winmm.lib +STATIC_LDLIBS_YES=ws2_32.lib advapi32.lib user32.lib kernel32.lib winmm.lib dbghelp.lib STATIC_LDLIBS_NO= STATIC_LDFLAGS= RANLIB= # -# option needed for parallel builds with Visual Studio 2015 onward -# +# option needed for parallel builds with Visual Studio 2013 onward +# VS2012 and above have VisualStudioVersion, so just need to exclude 2012 (11.0) # -FS Force Synchronous PDB Writes +# ifneq ($(VisualStudioVersion),) +ifneq ($(VisualStudioVersion),11.0) OPT_CXXFLAGS_NO += -FS OPT_CFLAGS_NO += -FS endif +endif # diff --git a/configure/os/CONFIG_SITE.Common.linux-arm b/configure/os/CONFIG_SITE.Common.linux-arm index 556ac6f09..8f5fb8c82 100644 --- a/configure/os/CONFIG_SITE.Common.linux-arm +++ b/configure/os/CONFIG_SITE.Common.linux-arm @@ -1,39 +1,35 @@ # CONFIG_SITE.Common.linux-arm # -# Site Specific definitions for all linux-arm targets -#------------------------------------------------------- +# Site-specific settings for the linux-arm target -# NOTE for SHARED_LIBRARIES: In most cases if this is set to YES the +# NOTE: In most cases if SHARED_LIBRARIES is set to YES the # shared libraries will be found automatically. However if the .so # files are installed at a different path to their compile-time path # then in order to be found at runtime do one of these: # a) LD_LIBRARY_PATH must include the full absolute pathname to # $(INSTALL_LOCATION)/lib/$(EPICS_HOST_ARCH) when invoking base # executables. -# b) Add the runtime path to SHRLIB_DEPLIB_DIRS and PROD_DEPLIB_DIRS, which +# b) Add the runtime path to SHRLIB_DEPLIB_DIRS and PROD_DEPLIB_DIRS, which # will add the named directory to the list contained in the executables. # c) Add the runtime path to /etc/ld.so.conf and run ldconfig # to inform the system of the shared library location. -# Depending on your version of Linux you'll want one of the following -# lines to enable command-line editing and history in iocsh. If you're -# not sure which, start with the top one and work downwards until the -# build doesn't fail to link the readline library. If none of them work, -# comment them all out to build without readline support. -# No other libraries needed (recent Fedora, Ubuntu etc.): -#COMMANDLINE_LIBRARY = READLINE +# Use GNU Readline if the header file is installed +COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \ + $(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \ + READLINE, EPICS)) -# Needs -lncurses (RHEL 5 etc.): +# If libreadline needs additional libraries to be linked with it, try +# uncommenting each of the lines below in turn, starting with the top +# one and working downwards, until the build succeeds. Do a 'make rebuild' +# from the top of the Base tree after changing this setting. + +# Needs -lncurses: #COMMANDLINE_LIBRARY = READLINE_NCURSES -# Needs -lcurses (older versions) +# Needs -lcurses: #COMMANDLINE_LIBRARY = READLINE_CURSES - -# It makes sense to include debugging symbols even in optimized builds -# in case you want to attach gdb to the process or examine a core-dump. -# This does cost disk space, but not memory as debug symbols are not -# loaded into RAM when the binary is loaded. -OPT_CFLAGS_YES += -g -OPT_CXXFLAGS_YES += -g +# Readline is broken or you don't want use it: +#COMMANDLINE_LIBRARY = EPICS diff --git a/configure/os/CONFIG_SITE.Common.linux-cris b/configure/os/CONFIG_SITE.Common.linux-cris index b17cb0ee5..699f346ff 100644 --- a/configure/os/CONFIG_SITE.Common.linux-cris +++ b/configure/os/CONFIG_SITE.Common.linux-cris @@ -1,9 +1,8 @@ # CONFIG_SITE.Common.linux-cris # -# Site Specific definitions for linux-cris target -# Only the local epics system manager should modify this file +# Site-specific settings for the linux-cris target -# NOTE for SHARED_LIBRARIES: In most cases if this is set to YES the +# NOTE: In most cases if SHARED_LIBRARIES is set to YES the # shared libraries will be found automatically. However if the .so # files are installed at a different path to their compile-time path # then in order to be found at runtime do one of these: @@ -15,21 +14,21 @@ # c) Add the runtime path to /etc/ld.so.conf and run ldconfig # to inform the system of the shared library location. -# Depending on your version of Linux you may want one of the following -# lines to enable command-line editing and history in iocsh. If you're -# not sure which, start with the top one and work downwards until the -# build doesn't fail to link the readline library. If none of them work, -# comment them all out to build without readline support. -# No other libraries needed (recent Fedora, Ubuntu etc.): -#COMMANDLINE_LIBRARY = READLINE +# Use GNU Readline if the header file is installed +COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \ + $(GNU_DIR)/include/readline/readline.h), READLINE, EPICS)) -# Needs -lncurses (RHEL 5 etc.): +# If libreadline needs additional libraries to be linked with it, try +# uncommenting each of the lines below in turn, starting with the top +# one and working downwards, until the build succeeds. Do a 'make rebuild' +# from the top of the Base tree after changing this setting. + +# Needs -lncurses: #COMMANDLINE_LIBRARY = READLINE_NCURSES -# Needs -lcurses (older versions) +# Needs -lcurses: #COMMANDLINE_LIBRARY = READLINE_CURSES - -OP_SYS_CFLAGS += -g - +# Readline is broken or you don't want use it: +#COMMANDLINE_LIBRARY = EPICS diff --git a/configure/os/CONFIG_SITE.Common.linux-microblaze b/configure/os/CONFIG_SITE.Common.linux-microblaze index 43c543c2b..b66b4cced 100644 --- a/configure/os/CONFIG_SITE.Common.linux-microblaze +++ b/configure/os/CONFIG_SITE.Common.linux-microblaze @@ -1,7 +1,6 @@ # CONFIG_SITE.Common.linux-microblaze # -# Site specific definitions for linux-microblaze target builds. -#------------------------------------------------------- +# Site-specific settings for the linux-microblaze target # The gnu tools for cross compiling for MicroBlaze (little endian) # on Linux can be downloaded from the Xilinx git server: @@ -12,3 +11,21 @@ GNU_DIR = /usr/local/vw/microblaze-2.0/microblazeel-unknown-linux-gnu + +# Use GNU Readline if the header file is installed +COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \ + $(GNU_DIR)/include/readline/readline.h), READLINE, EPICS)) + +# If libreadline needs additional libraries to be linked with it, try +# uncommenting each of the lines below in turn, starting with the top +# one and working downwards, until the build succeeds. Do a 'make rebuild' +# from the top of the Base tree after changing this setting. + +# Needs -lncurses: +#COMMANDLINE_LIBRARY = READLINE_NCURSES + +# Needs -lcurses: +#COMMANDLINE_LIBRARY = READLINE_CURSES + +# Readline is broken or you don't want use it: +#COMMANDLINE_LIBRARY = EPICS diff --git a/configure/os/CONFIG_SITE.Common.linux-x86 b/configure/os/CONFIG_SITE.Common.linux-x86 index e4e7dd0fd..d243dae48 100644 --- a/configure/os/CONFIG_SITE.Common.linux-x86 +++ b/configure/os/CONFIG_SITE.Common.linux-x86 @@ -1,9 +1,8 @@ # CONFIG_SITE.Common.linux-x86 # -# Site Specific definitions for linux-x86 target -# Only the local epics system manager should modify this file +# Site-specific settings for the linux-x86 target -# NOTE for SHARED_LIBRARIES: In most cases if this is set to YES the +# NOTE: In most cases if SHARED_LIBRARIES is set to YES the # shared libraries will be found automatically. However if the .so # files are installed at a different path to their compile-time path # then in order to be found at runtime do one of these: @@ -15,14 +14,15 @@ # c) Add the runtime path to /etc/ld.so.conf and run ldconfig # to inform the system of the shared library location. -# Depending on your version of Linux you'll want one of the following -# lines to enable command-line editing and history in iocsh. If you're -# not sure which, start with the top one and work downwards until the -# build doesn't fail to link the readline library. If none of them work, -# comment them all out to build without readline support. -# No other libraries needed (recent Fedora, Ubuntu etc.): -COMMANDLINE_LIBRARY = READLINE +# Use GNU Readline if the header file is installed +COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \ + $(GNU_DIR)/include/readline/readline.h), READLINE, EPICS)) + +# If libreadline needs additional libraries to be linked with it, try +# uncommenting each of the lines below in turn, starting with the top +# one and working downwards, until the build succeeds. Do a 'make rebuild' +# from the top of the Base tree after changing this setting. # Needs -lncurses (RHEL 5 etc.): #COMMANDLINE_LIBRARY = READLINE_NCURSES @@ -30,6 +30,9 @@ COMMANDLINE_LIBRARY = READLINE # Needs -lcurses (older versions) #COMMANDLINE_LIBRARY = READLINE_CURSES +# Readline is broken or you don't want use it: +#COMMANDLINE_LIBRARY = EPICS + # Permit access to 64-bit file-systems OP_SYS_CFLAGS += -D_FILE_OFFSET_BITS=64 @@ -43,14 +46,6 @@ OP_SYS_CFLAGS += -D_FILE_OFFSET_BITS=64 #CCC = clang++ -# It makes sense to include debugging symbols even in optimized builds -# in case you want to attach gdb to the process or examine a core-dump. -# This does cost disk space, but not memory as debug symbols are not -# loaded into RAM when the binary is loaded. -OPT_CFLAGS_YES += -g -OPT_CXXFLAGS_YES += -g - - # Tune GNU compiler output for a specific 32-bit cpu-type # (e.g. generic, native, i386, i686, pentium2/3/4, prescott, k6, athlon etc.) GNU_TUNE_CFLAGS = -mtune=generic diff --git a/configure/os/CONFIG_SITE.Common.linux-x86_64 b/configure/os/CONFIG_SITE.Common.linux-x86_64 index 6f7a2dc7b..834da1e5a 100644 --- a/configure/os/CONFIG_SITE.Common.linux-x86_64 +++ b/configure/os/CONFIG_SITE.Common.linux-x86_64 @@ -1,9 +1,8 @@ # CONFIG_SITE.Common.linux-x86_64 # -# Site Specific definitions for linux-x86_64 target -# Only the local epics system manager should modify this file +# Site-specific settings for the linux-x86_64 target -# NOTE for SHARED_LIBRARIES: In most cases if this is set to YES the +# NOTE: In most cases if SHARED_LIBRARIES is set to YES the # shared libraries will be found automatically. However if the .so # files are installed at a different path to their compile-time path # then in order to be found at runtime do one of these: @@ -15,14 +14,15 @@ # c) Add the runtime path to /etc/ld.so.conf and run ldconfig # to inform the system of the shared library location. -# Depending on your version of Linux you'll want one of the following -# lines to enable command-line editing and history in iocsh. If you're -# not sure which, start with the top one and work downwards until the -# build doesn't fail to link the readline library. If none of them work, -# comment them all out to build without readline support. -# No other libraries needed (recent Fedora, Ubuntu etc.): -COMMANDLINE_LIBRARY = READLINE +# Use GNU Readline if the header file is installed +COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \ + $(GNU_DIR)/include/readline/readline.h), READLINE, EPICS)) + +# If libreadline needs additional libraries to be linked with it, try +# uncommenting each of the lines below in turn, starting with the top +# one and working downwards, until the build succeeds. Do a 'make rebuild' +# from the top of the Base tree after changing this setting. # Needs -lncurses (RHEL 5 etc.): #COMMANDLINE_LIBRARY = READLINE_NCURSES @@ -30,6 +30,9 @@ COMMANDLINE_LIBRARY = READLINE # Needs -lcurses (older versions) #COMMANDLINE_LIBRARY = READLINE_CURSES +# Readline is broken or you don't want use it: +#COMMANDLINE_LIBRARY = EPICS + # Uncomment the followings lines to build with CLANG instead of GCC. # @@ -39,14 +42,6 @@ COMMANDLINE_LIBRARY = READLINE #CCC = clang++ -# It makes sense to include debugging symbols even in optimized builds -# in case you want to attach gdb to the process or examine a core-dump. -# This does cost disk space, but not memory as debug symbols are not -# loaded into RAM when the binary is loaded. -OPT_CFLAGS_YES += -g -OPT_CXXFLAGS_YES += -g - - # Tune GNU compiler output for a specific 64-bit cpu-type # (e.g. generic, native, core2, nocona, k8, opteron, athlon64, barcelona etc.) GNU_TUNE_CFLAGS = -mtune=generic diff --git a/configure/os/CONFIG_SITE.Common.linux-xscale_be b/configure/os/CONFIG_SITE.Common.linux-xscale_be index 015229647..5fb5a4642 100644 --- a/configure/os/CONFIG_SITE.Common.linux-xscale_be +++ b/configure/os/CONFIG_SITE.Common.linux-xscale_be @@ -1,4 +1,23 @@ # CONFIG_SITE.Common.linux-xscale_be # -# Site specific definitions for all linux-xscale_be target builds. -#------------------------------------------------------- +# Site-specific settings for the linux-xscale_be target + + +# Use GNU Readline if the header file is installed +COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \ + $(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \ + READLINE, EPICS)) + +# If libreadline needs additional libraries to be linked with it, try +# uncommenting each of the lines below in turn, starting with the top +# one and working downwards, until the build succeeds. Do a 'make rebuild' +# from the top of the Base tree after changing this setting. + +# Needs -lncurses: +#COMMANDLINE_LIBRARY = READLINE_NCURSES + +# Needs -lcurses: +#COMMANDLINE_LIBRARY = READLINE_CURSES + +# Readline is broken or you don't want use it: +#COMMANDLINE_LIBRARY = EPICS diff --git a/configure/os/CONFIG_SITE.Common.linuxCommon b/configure/os/CONFIG_SITE.Common.linuxCommon index 907f4d796..015e6b0ba 100644 --- a/configure/os/CONFIG_SITE.Common.linuxCommon +++ b/configure/os/CONFIG_SITE.Common.linuxCommon @@ -1,2 +1,14 @@ +# CONFIG_SITE.Common.linuxCommon +# +# Site-specific settings for all linux targets + + +# It makes sense to include debugging symbols even in optimized builds +# in case you want to attach gdb to the process or examine a core-dump. +# This does cost disk space, but not memory as debug symbols are not +# loaded into RAM when the binary is loaded. +OPT_CFLAGS_YES += -g +OPT_CXXFLAGS_YES += -g + COMMANDLINE_LIBRARY = READLINE CODE_CPPFLAGS += -fno-strict-aliasing diff --git a/documentation/KnownProblems.html b/documentation/KnownProblems.html index 787d2db4b..5c29cc2a7 100644 --- a/documentation/KnownProblems.html +++ b/documentation/KnownProblems.html @@ -4,17 +4,17 @@ - Known Problems in EPICS 7.0.3 + Known Problems in EPICS 7.0.3.1 -

EPICS 7.0.3: Known Problems

+

EPICS 7.0.3.1: Known Problems

Any patch files linked below should be applied at the root of the -base-7.0.3 tree. Download them, then use the GNU Patch program as +base-7.0.3.1 tree. Download them, then use the GNU Patch program as follows:

-
% cd /path/to/base-7.0.3
+
% cd /path/to/base-7.0.3.1
 % patch -p1 < /path/to/file.patch

The following problems were known by the developers at the time of this @@ -28,10 +28,6 @@ release:

... --> -
  • IOCs running on some versions of Cygwin may display warnings at iocInit - about duplicate EPICS CA Address list entries. These warnings might be due - to a bug in Cygwin; they are benign and can be ignored.
  • - diff --git a/documentation/README.1st b/documentation/README.1st deleted file mode 100644 index 177205805..000000000 --- a/documentation/README.1st +++ /dev/null @@ -1,344 +0,0 @@ - Installation Instructions - - EPICS Base Release 7.0.3 - - -------------------------------------------------------------------------- - - Table of Contents - - * What is EPICS base? - * What is new in this release? - * Copyright - * Supported platforms - * Supported compilers - * Software requirements - * Host system storage requirements - * Documentation - * Directory Structure - * Build related components - * Building EPICS base (Unix and Win32) - * Example application and extension - * Multiple host platforms - - -------------------------------------------------------------------------- - - What is EPICS base? - - The Experimental Physics and Industrial Control Systems (EPICS) is an - extensible set of software components and tools with which application - developers can create a control system. This control system can be used - to control accelerators, detectors, telescopes, or other scientific - experimental equipment. EPICS base is the set of core software, i.e. the - components of EPICS without which EPICS would not function. EPICS base - allows an arbitrary number of target systems, IOCs (input/output - controllers), and host systems, OPIs (operator interfaces) of various - types. - - What is new in this release? - - Please check the RELEASE_NOTES file in the distribution for description - of changes and release migration details. - - Copyright - - Please review the LICENSE file included in the distribution for legal - terms of usage. - - Supported platforms - - The list of platforms supported by this version of EPICS base is given - in the configure/CONFIG_SITE file. If you are trying to build EPICS Base - on an unlisted host or for a different target machine you must have the - proper host/target cross compiler and header files, and you will have to - create and add the appropriate new configure files to the - base/configure/os/directory. You can start by copying existing - configuration files in the configure/os directory and then make changes - for your new platforms. - - Supported compilers - - This version of EPICS base has been built and tested using the host - vendor's C and C++ compilers, as well as the GNU gcc and g++ compilers. - The GNU cross-compilers work for all cross-compiled targets. You may - need the C and C++ compilers to be in your search path to do EPICS - builds; check the definitions of CC and CCC in - base/configure/os/CONFIG.. if you have problems. - - Software requirements - - GNU make - You must use the GNU version of make for EPICS builds, and we now - recommend version 4.1 or later (version 3.82 may work on Linux, but - doesn't on Windows). - - Perl - You must have Perl version 5.8.1 or later installed. The EPICS - configuration files do not specify the perl full pathname, so the perl - executable must be found through your normal search path. - - Unzip and tar (Winzip on WIN32 systems) - You must have tools available to unzip and untar the EPICS base - distribution file. - - Target systems - EPICS supports IOCs running on embedded platforms such as VxWorks and - RTEMS built using a cross-compiler, and also supports soft IOCs running - as processes on the host platform. - - vxWorks - You must have vxWorks 6 installed if any of your target systems are - vxWorks systems; the C++ compilers for vxWorks 5.x are now too old to - support. The vxWorks installation provides the cross-compiler and header - files needed to build for these targets. The absolute path to and the - version number of the vxWorks installation must be set in the - base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its - target-specific overrides. - - Consult the vxWorks 6.x EPICS web pages and the vxWorks documentation - for information about configuring your vxWorks operating system for use - with EPICS. - - RTEMS - For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or - 4.10. The newer 4.11 or 5.x releases are not supported yet. - - Command-line editing libraries - GNU readline or other OS-specific libraries can be used by the IOC shell - to provide command line editing and history recall. The default setting - is different for each OS. On Linux the default is to use READLINE since - most distributions include it. On MacOS the default is also READLINE - since Apple provides a compatible library, although it isn't GNU. On - RTEMS we support GNU readline and Tecla, although the default is to use - neither since these have to be added to the RTEMS installation - separately. On vxWorks we support the built-in ledLib library. - - Host system storage requirements - - The compressed tar file is approximately 1.6 MB in size. The - distribution source tree takes up approximately 12 MB. Each host target - will need around 40 MB for build files, and each cross-compiled target - around 20 MB. - - Documentation - - EPICS documentation is available through the EPICS website at Argonne. - - Release specific documentation can also be found in the - base/documentation directory of the distribution. - - Directory Structure - - Distribution directory structure: - - base Root directory of the base distribution - base/configure Operating system independent build config files - base/configure/os Operating system dependent build config files - base/documentation Distribution documentation - base/src Source code in various subdirectories - base/startup Scripts for setting up path and environment - - Install directories created by the build: - - bin Installed scripts and executables in subdirs - cfg Installed build configuration files - db Installed data bases - dbd Installed data base definitions - doc Installed documentation files - html Installed html documentation - include Installed header files - include/os Installed os specific header files in subdirs - include/compiler Installed compiler-specific header files - lib Installed libraries in arch subdirectories - lib/perl Installed perl modules - templates Installed templates - - Build related components - - base/documentation directory - contains setup, build, and install documents - - README.1st Instructions for setup and building epics base - README.html html version of README.1st - README.darwin.html Installation notes for Mac OS X (Darwin) - RELEASE_NOTES.html Notes on release changes - KnownProblems.html List of known problems and workarounds - - base/startup directory - contains scripts to set environment and path - - EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable - unix.csh C shell script to set path and env variables - unix.sh Bourne shell script to set path and env variables - win32.bat Bat file example to configure win32-x86 target - windows.bat Bat file example to configure windows-x64 target - - base/configure directory - contains build definitions and rules - - CONFIG Includes configure files and allows variable overrides - CONFIG.CrossCommon Cross build definitions - CONFIG.gnuCommon Gnu compiler build definitions for all archs - CONFIG_ADDONS Definitions for and DEFAULT options - CONFIG_APP_INCLUDE - CONFIG_BASE EPICS base tool and location definitions - CONFIG_BASE_VERSION Definitions for EPICS base version number - CONFIG_COMMON Definitions common to all builds - CONFIG_ENV Definitions of EPICS environment variables - CONFIG_FILE_TYPE - CONFIG_SITE Site specific make definitions - CONFIG_SITE_ENV Site defaults for EPICS environment variables - MAKEFILE Installs CONFIG* RULES* creates - RELEASE Location of external products - RULES Includes appropriate rules file - RULES.Db Rules for database and database definition files - RULES.ioc Rules for application iocBoot/ioc* directory - RULES_ARCHS Definitions and rules for building architectures - RULES_BUILD Build and install rules and definitions - RULES_DIRS Definitions and rules for building subdirectories - RULES_EXPAND - RULES_FILE_TYPE - RULES_TARGET - RULES_TOP Rules specific to a dir (uninstall and tar) - Sample.Makefile Sample makefile with comments - - base/configure/os directory - contains os-arch specific definitions - - CONFIG.. Specific host-target build definitions - CONFIG.Common. Specific target definitions for all hosts - CONFIG..Common Specific host definitions for all targets - CONFIG.UnixCommon.Common Definitions for Unix hosts and all targets - CONFIG.Common.UnixCommon Definitions for Unix targets and all hosts - CONFIG.Common.vxWorksCommon Specific host definitions for all vx targets - CONFIG_SITE.. Site specific host-target definitions - CONFIG_SITE.Common. Site specific target defs for all hosts - CONFIG_SITE..Common Site specific host defs for all targets - - Building EPICS base (Unix and Win32) - - Unpack file - - Unzip and untar the distribution file. Use WinZip on Windows systems. - - Set environment variables - - Files in the base/startup directory have been provided to help set - required path and other environment variables. - - EPICS_HOST_ARCH - Before you can build or use EPICS Base, the environment variable - EPICS_HOST_ARCH should be defined. A perl script EpicsHostArch.pl in - the base/startup directory has been provided to help set - EPICS_HOST_ARCH. You should have EPICS_HOST_ARCH set to your host - operating system followed by a dash and then your CPU architecture, - e.g. linux-x86_64. If you are not using the OS vendor's c/c++ compiler - for host builds, you will need another dash followed by the alternate - compiler name (e.g. "-gnu" for GNU c/c++ compilers on a solaris host - or "-mingw" for MinGW c/c++ compilers on a WIN32 host). See - configure/CONFIG_SITE for a list of supported EPICS_HOST_ARCH values. - - PERLLIB - On WIN32, some versions of Perl require that the environment variable - PERLLIB be set to . - - PATH - As already mentioned, you must have the perl executable and you may - need C and C++ compilers in your search path. For building base you - also must have echo in your search path. For Unix host builds you also - need ln, cpp, cp, rm, mv, and mkdir in your search path and /bin/chmod - must exist. On some Unix systems you may also need ar and ranlib in - your path, and the C compiler may require as and ld in your path. On - solaris systems you need uname in your path. - - LD_LIBRARY_PATH - EPICS shared libraries and executables normally contain the full path - to any libraries they require. However, if you move the EPICS files or - directories from their build-time location then in order for the - shared libraries to be found at runtime LD_LIBRARY_PATH must include - the full pathname to $(INSTALL_LOCATION)/lib/$(EPICS_HOST_ARCH) when - invoking executables, or some equivalent OS-specific mechanism (such - as /etc/ld.so.conf on Linux) must be used. Shared libraries are now - built by default on all Unix type hosts. - - Do site-specific build configuration - - Site configuration - To configure EPICS, you may want to modify the default definitions in - the following files: - - configure/CONFIG_SITE Build choices. Specify target archs. - configure/CONFIG_SITE_ENV Environment variable defaults - configure/RELEASE TORNADO2 full path location - - Host configuration - To configure each host system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - changed to CONFIG_SITE. - - configure/os/CONFIG.. Host build settings - configure/os/CONFIG..Common Host common build settings - - Target configuration - To configure each target system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - replaced by CONFIG_SITE. This step is necessary even if the host - system is the only target system. - - configure/os/CONFIG.Common. Target common settings - configure/os/CONFIG.. Host-target settings - - Build EPICS base - - After configuring the build you should be able to build EPICS base by - issuing the following commands in the distribution's root directory - (base): - - gnumake clean uninstall - gnumake - - The command "gnumake clean uninstall" will remove all files and - directories generated by a previous build. The command "gnumake" will - build and install everything for the configured host and targets. - - It is recommended that you do a "gnumake clean uninstall" at the root - directory of an EPICS directory structure before each complete rebuild - to ensure that all components will be rebuilt. - - Example application and extension - - A perl tool, makeBaseApp.pl is included in the distribution file. This - script will create a sample application that can be built and then - executed to try out this release of base. - - Instructions for building and executing the example IOC application can - be found in the section "Example Application" of Chapter 2, "Getting - Started", in the "IOC Application Developer's Guide" for this release. - The "Example IOC Application" section briefly explains how to create and - build an example application in a user created directory. It also - explains how to run the example application on a vxWorks ioc or as a - process on the host system. By running the example application as a - host-based IOC, you will be able to quickly implement a complete EPICS - system and be able to run channel access clients on the host system. - - A perl script, makeBaseExt.pl, is included in the distribution file. - This script will create a sample extension that can be built and - executed. The makeBaseApp.pl and makeBaseExt.pl scripts are installed - into the install location bin/ directory during the base - build. - - Multiple host platforms - - You can build using a single EPICS directory structure on multiple host - systems and for multiple cross target systems. The intermediate and - binary files generated by the build will be created in separate - subdirectories and installed into the appropriate separate host/target - install directories. EPICS executables and perl scripts are installed - into the $(INSTALL_LOCATION)/bin/ directories. Libraries are - installed into $(INSTALL_LOCATION)/lib/. The default definition - for $(INSTALL_LOCATION) is $(TOP) which is the root directory in the - distribution directory structure, base. Created object files are stored - in O. source subdirectories, This allows objects for multiple - cross target architectures to be maintained at the same time. To build - EPICS base for a specific host/target combination you must have the - proper host/target C/C++ cross compiler and target header files and the - base/configure/os directory must have the appropriate configure files. diff --git a/documentation/README.html b/documentation/README.html deleted file mode 100644 index 6e15470fd..000000000 --- a/documentation/README.html +++ /dev/null @@ -1,382 +0,0 @@ - - - - -README - EPICS Base Installation Instructions - - -
    -

    Installation Instructions

    -

    EPICS Base Release 7.0.3


    -
    -
    -

    Table of Contents

    - -
    - -

    What is EPICS base?

    -
    The Experimental Physics and Industrial Control Systems - (EPICS) is an extensible set of software components and tools with - which application developers can create a control system. This control - system can be used to control accelerators, detectors, telescopes, or - other scientific experimental equipment. EPICS base is the set of core - software, i.e. the components of EPICS without which EPICS would not - function. EPICS base allows an arbitrary number of target systems, IOCs - (input/output controllers), and host systems, OPIs (operator - interfaces) of various types.
    - -

    What is new in this release?

    -
    Please check the RELEASE_NOTES file in the distribution for - description of changes and release migration details.
    - -

    Copyright

    -
    Please review the LICENSE file included in the - distribution for legal terms of usage.
    - -

    Supported platforms

    - -
    The list of platforms supported by this version of EPICS base - is given in the configure/CONFIG_SITE file. If you are trying to build - EPICS Base on an unlisted host or for a different target machine you - must have the proper host/target cross compiler and header files, and - you will have to create and add the appropriate new configure files to - the base/configure/os/directory. You can start by copying existing - configuration files in the configure/os directory and then make changes - for your new platforms.
    - -

    Supported compilers

    - -
    This version of EPICS base has been built and tested using the host - vendor's C and C++ compilers, as well as the GNU gcc and g++ compilers. The GNU - cross-compilers work for all cross-compiled targets. You may need the C and C++ - compilers to be in your search path to do EPICS builds; check the definitions - of CC and CCC in base/configure/os/CONFIG.<host>.<host> if you have - problems.
    - -

    Software requirements

    - -
    GNU make
    - You must use the GNU version of make for EPICS builds, and we now recommend - version 4.1 or later (version 3.82 may work on Linux, but doesn't on Windows). - -

    Perl
    - You must have Perl version 5.8.1 or later installed. The EPICS configuration - files do not specify the perl full pathname, so the perl executable must - be found through your normal search path.

    - -

    Unzip and tar (Winzip on WIN32 systems)
    - You must have tools available to unzip and untar the EPICS base - distribution file.

    - -

    Target systems
    - EPICS supports IOCs running on embedded platforms such as VxWorks - and RTEMS built using a cross-compiler, and also supports soft IOCs running - as processes on the host platform.

    - -

    vxWorks
    - You must have vxWorks 6 installed if any of your target systems are vxWorks - systems; the C++ compilers for vxWorks 5.x are now too old to support. The - vxWorks installation provides the cross-compiler and header files needed to - build for these targets. The absolute path to and the version number of the - vxWorks installation must be set in the - base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its - target-specific overrides.

    - -

    Consult the vxWorks - 6.x EPICS web pages and the vxWorks documentation for information - about configuring your vxWorks operating system for use with EPICS.

    - -

    RTEMS
    - For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or 4.10. The - newer 4.11 or 5.x releases are not supported yet.

    - -

    Command-line editing libraries
    - - GNU readline or other OS-specific libraries can be used by the IOC shell to - provide command line editing and history recall. The default setting is - different for each OS. On Linux the default is to use READLINE since most - distributions include it. On MacOS the default is also READLINE since Apple - provides a compatible library, although it isn't GNU. On RTEMS we support GNU - readline and Tecla, although the default is to use neither since these have to - be added to the RTEMS installation separately. On vxWorks we support the - built-in ledLib library.

    - -
    - -

    Host system storage requirements

    - -
    The compressed tar file is approximately 1.6 MB in size. The - distribution source tree takes up approximately 12 MB. Each host target will - need around 40 MB for build files, and each cross-compiled target around 20 - MB.
    - -

    Documentation

    -
    EPICS documentation is available through the - EPICS website at Argonne. -

    Release specific documentation can also be found in the base/documentation - directory of the distribution.

    - -

    Directory Structure

    -

    Distribution directory structure:

    - -
    -        base                    Root directory of the base distribution
    -        base/configure          Operating system independent build config files
    -        base/configure/os       Operating system dependent build config files
    -        base/documentation      Distribution documentation
    -        base/src                Source code in various subdirectories
    -        base/startup            Scripts for setting up path and environment
    -
    - -

    Install directories created by the build:

    -
    -        bin                     Installed scripts and executables in subdirs
    -        cfg                     Installed build configuration files
    -        db                      Installed data bases
    -        dbd                     Installed data base definitions
    -        doc                     Installed documentation files
    -        html                    Installed html documentation
    -        include                 Installed header files
    -        include/os              Installed os specific header files in subdirs
    -        include/compiler        Installed compiler-specific header files
    -        lib                     Installed libraries in arch subdirectories
    -        lib/perl                Installed perl modules
    -        templates               Installed templates
    -
    -
    - -

    Build related components

    -
    - -

    base/documentation directory - contains setup, build, and install - documents

    -
    -        README.1st           Instructions for setup and building epics base
    -        README.html          html version of README.1st
    -        README.darwin.html   Installation notes for Mac OS X (Darwin)
    -        RELEASE_NOTES.html   Notes on release changes
    -        KnownProblems.html   List of known problems and workarounds
    -
    - -

    base/startup directory - contains scripts to set environment and path

    -
    -        EpicsHostArch       Shell script to set EPICS_HOST_ARCH env variable
    -        unix.csh            C shell script to set path and env variables
    -        unix.sh             Bourne shell script to set path and env variables
    -        win32.bat           Bat file example to configure win32-x86 target
    -        windows.bat         Bat file example to configure windows-x64 target
    -
    - -

    base/configure directory - contains build definitions and rules

    -
    -        CONFIG                Includes configure files and allows variable overrides
    -        CONFIG.CrossCommon    Cross build definitions
    -        CONFIG.gnuCommon      Gnu compiler build definitions for all archs
    -        CONFIG_ADDONS         Definitions for <osclass> and DEFAULT options
    -        CONFIG_APP_INCLUDE
    -        CONFIG_BASE           EPICS base tool and location definitions
    -        CONFIG_BASE_VERSION   Definitions for EPICS base version number
    -        CONFIG_COMMON         Definitions common to all builds
    -        CONFIG_ENV            Definitions of EPICS environment variables
    -        CONFIG_FILE_TYPE
    -        CONFIG_SITE           Site specific make definitions
    -        CONFIG_SITE_ENV       Site defaults for EPICS environment variables
    -        MAKEFILE              Installs CONFIG* RULES* creates
    -        RELEASE               Location of external products
    -        RULES                 Includes appropriate rules file
    -        RULES.Db              Rules for database and database definition files
    -        RULES.ioc             Rules for application iocBoot/ioc* directory
    -        RULES_ARCHS           Definitions and rules for building architectures
    -        RULES_BUILD           Build and install rules and definitions
    -        RULES_DIRS            Definitions and rules for building subdirectories
    -        RULES_EXPAND
    -        RULES_FILE_TYPE
    -        RULES_TARGET
    -        RULES_TOP             Rules specific to a <top> dir (uninstall and tar)
    -        Sample.Makefile       Sample makefile with comments
    -
    - -

    base/configure/os directory - contains os-arch specific definitions

    -
    -        CONFIG.<host>.<target>      Specific host-target build definitions
    -        CONFIG.Common.<target>      Specific target definitions for all hosts
    -        CONFIG.<host>.Common        Specific host definitions for all targets
    -        CONFIG.UnixCommon.Common    Definitions for Unix hosts and all targets
    -        CONFIG.Common.UnixCommon    Definitions for Unix targets and all hosts
    -        CONFIG.Common.vxWorksCommon Specific host definitions for all vx targets
    -        CONFIG_SITE.<host>.<target> Site specific host-target definitions
    -        CONFIG_SITE.Common.<target> Site specific target defs for all hosts
    -        CONFIG_SITE.<host>.Common   Site specific host defs for all targets
    -
    - -
    - -

    Building EPICS base (Unix and Win32)

    -
    - -

    Unpack file

    -
    -Unzip and untar the distribution file. Use WinZip on Windows - systems. -
    - -

    Set environment variables

    -
    -Files in the base/startup directory have been provided to - help set required path and other environment variables. - -

    EPICS_HOST_ARCH
    - Before you can build or use EPICS Base, the environment variable - EPICS_HOST_ARCH should be defined. A perl script EpicsHostArch.pl in the - base/startup directory has been provided to help set EPICS_HOST_ARCH. - You should have EPICS_HOST_ARCH set to your host operating system - followed by a dash and then your CPU architecture, e.g. linux-x86_64. - If you are not using the OS vendor's c/c++ compiler for host builds, - you will need another dash followed by the alternate compiler name - (e.g. "-gnu" for GNU c/c++ compilers on a solaris host or "-mingw" - for MinGW c/c++ compilers on a WIN32 host). See configure/CONFIG_SITE - for a list of supported EPICS_HOST_ARCH values.

    - -

    PERLLIB
    - On WIN32, some versions of Perl require that the environment - variable PERLLIB be set to <perl directory location>.

    - -

    PATH
    - As already mentioned, you must have the perl executable and you may - need C and C++ compilers in your search path. For building base you - also must have echo in your search path. For Unix host builds you also - need ln, cpp, cp, rm, mv, and mkdir in your search path and /bin/chmod - must exist. On some Unix systems you may also need ar and ranlib in - your path, and the C compiler may require as and ld in your path. On - solaris systems you need uname in your path.

    - -

    LD_LIBRARY_PATH
    - - EPICS shared libraries and executables normally contain the full path - to any libraries they require. - However, if you move the EPICS files or directories from their build-time - location then in order for the shared libraries to be found at runtime - LD_LIBRARY_PATH must include the full pathname to - $(INSTALL_LOCATION)/lib/$(EPICS_HOST_ARCH) when invoking executables, or - some equivalent OS-specific mechanism (such as /etc/ld.so.conf on Linux) - must be used. - Shared libraries are now built by default on all Unix type hosts.

    -
    - -

    Do site-specific build configuration

    -
    - -Site configuration
    - To configure EPICS, you may want to modify the default definitions - in the following files: -
    -        configure/CONFIG_SITE      Build choices. Specify target archs.
    -        configure/CONFIG_SITE_ENV  Environment variable defaults
    -        configure/RELEASE          TORNADO2 full path location
    -
    - - Host configuration
    - To configure each host system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - changed to CONFIG_SITE. - -
    -        configure/os/CONFIG.<host>.<host>      Host build settings
    -        configure/os/CONFIG.<host>.Common      Host common build settings
    -
    - -Target configuration
    - To configure each target system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - replaced by CONFIG_SITE. This step is necessary even if the host system - is the only target system. -
    -        configure/os/CONFIG.Common.<target>     Target common settings
    -        configure/os/CONFIG.<host>.<target>     Host-target settings
    -
    -
    - -

    Build EPICS base

    -
    After configuring the build you should be able to build - EPICS base by issuing the following commands in the distribution's root - directory (base): -
    -        gnumake clean uninstall
    -        gnumake
    -
    - - The command "gnumake clean uninstall" - will remove all files and directories generated by a previous build. - The command "gnumake" will build and install everything for the - configured host and targets. - -

    It is recommended that you do a "gnumake clean uninstall" at the - root directory of an EPICS directory structure before each complete - rebuild to ensure that all components will be rebuilt. -

    -
    - -

    Example application and extension

    -
    A perl tool, makeBaseApp.pl is included in the distribution - file. This script will create a sample application that can be built - and then executed to try out this release of base. - -

    - Instructions for building and executing the example IOC application - can be found in the section "Example Application" of Chapter 2, - "Getting Started", in the "IOC Application Developer's Guide" for this - release. The "Example IOC Application" section briefly explains how to - create and build an example application in a user created <top> - directory. It also explains how to run the example application on a - vxWorks ioc or as a process on the host system. - By running the example application as a host-based IOC, you will be - able to quickly implement a complete EPICS system and be able to run channel - access clients on the host system. - -

    - A perl script, - makeBaseExt.pl, is included in the distribution file. This script will - create a sample extension that can be built and executed. The - makeBaseApp.pl and makeBaseExt.pl scripts are installed into the - install location bin/<hostarch> directory during the base build. -

    - -

    Multiple host platforms

    -
    You can build using a single EPICS directory structure on - multiple host systems and for multiple cross target systems. The - intermediate and binary files generated by the build will be created in - separate subdirectories and installed into the appropriate separate - host/target install directories. EPICS executables and perl scripts are - installed into the $(INSTALL_LOCATION)/bin/<arch> directories. - Libraries are installed into $(INSTALL_LOCATION)/lib/<arch>. - The default definition for $(INSTALL_LOCATION) is $(TOP) - which is the root directory in the distribution directory structure, - base. Created object files are stored in O.<arch> source - subdirectories, This allows objects for multiple cross target - architectures to be maintained at the same time. To build EPICS base - for a specific host/target combination you must have the proper - host/target C/C++ cross compiler and target header files and the - base/configure/os directory must have the appropriate configure files. -
    - - diff --git a/documentation/README.md b/documentation/README.md new file mode 100644 index 000000000..78df41d55 --- /dev/null +++ b/documentation/README.md @@ -0,0 +1,372 @@ +# Installation Instructions + +## EPICS Base Release 7.0.3.1 + +----- + +### Table of Contents + + - [What is EPICS base?](#0_0_1) + - [What is new in this release?](#0_0_2) + - [Copyright](#0_0_3) + - [Supported platforms](#0_0_4) + - [Supported compilers](#0_0_5) + - [Software requirements](#0_0_6) + - [Host system storage requirements](#0_0_7) + - [Documentation](#0_0_8) + - [Directory Structure](#0_0_10) + - [Build related components](#0_0_11) + - [Building EPICS base (Unix and Win32)](#0_0_12) + - [Example application and extension](#0_0_13) + - [Multiple host platforms](#0_0_14) + +----- + +### What is EPICS base? + +The Experimental Physics and Industrial Control Systems (EPICS) is an +extensible set of software components and tools with which application +developers can create a control system. This control system can be +used to control accelerators, detectors, telescopes, or other +scientific experimental equipment. EPICS base is the set of core +software, i.e. the components of EPICS without which EPICS would not +function. EPICS base allows an arbitrary number of target systems, +IOCs (input/output controllers), and host systems, OPIs (operator +interfaces) of various types. + +### What is new in this release? + +Please check the `RELEASE_NOTES` file in the distribution for +description of changes and release migration details. + +### Copyright + +Please review the LICENSE file included in the distribution for legal +terms of usage. + +### Supported platforms + +The list of platforms supported by this version of EPICS base is given +in the `configure/CONFIG_SITE` file. If you are trying to build EPICS +Base on an unlisted host or for a different target machine you must +have the proper host/target cross compiler and header files, and you +will have to create and add the appropriate new configure files to the +base/configure/os/directory. You can start by copying existing +configuration files in the configure/os directory and then make +changes for your new platforms. + +### Supported compilers + +This version of EPICS base has been built and tested using the host +vendor's C and C++ compilers, as well as the GNU gcc and g++ +compilers. The GNU cross-compilers work for all cross-compiled +targets. You may need the C and C++ compilers to be in your search +path to do EPICS builds; check the definitions of CC and CCC in +`base/configure/os/CONFIG..` if you have problems. + +### Software requirements + +**GNU make** +You must use GNU make, gnumake, for any EPICS builds. Set your path so +that a gnumake version 3.81 or later is available. + +**Perl** +You must have Perl version 5.8.1 or later installed. The EPICS +configuration files do not specify the perl full pathname, so the perl +executable must be found through your normal search path. + +**Unzip and tar (Winzip on WIN32 systems)** +You must have tools available to unzip and untar the EPICS base +distribution file. + +**Target systems** +EPICS supports IOCs running on embedded platforms such as VxWorks and +RTEMS built using a cross-compiler, and also supports soft IOCs +running as processes on the host platform. + +**vxWorks** +You must have vxWorks 6.8 or later installed if any of your target +systems are vxWorks systems; the C++ compiler from older versions cannot +compile recently developed code. The vxWorks installation provides the +cross-compiler and header files needed to build for these targets. The +absolute path to and the version number of the vxWorks installation +must be set in the `base/configure/os/CONFIG_SITE.Common.vxWorksCommon` +file or in one of its target-specific overrides. + +Consult the [vxWorks 6.x](https://epics.anl.gov/base/vxWorks6.php) EPICS +web pages about and the vxWorks documentation for information about +configuring your vxWorks operating system for use with EPICS. + +**RTEMS** +For RTEMS targets, you need RTEMS core and toolset version 4.9.x or +4.10.x (4.11 or 5.x are not yet supported). + +**GNU readline or Tecla library** +GNU readline and Tecla libraries can be used by the IOC shell to +provide command line editing and command line history recall and edit. +GNU readline (or Tecla library) must be installed on your target +system when `COMMANDLINE_LIBRARY` is set to READLINE (or TECLA) for +that target. EPICS (EPICS shell) is the default specified in +`CONFIG_COMMON`. A READLINE override is defined for linux-x86 in the +EPICS distribution. Comment out `COMMANDLINE_LIBRARY=READLINE` in +`configure/os/CONFIG_SITE.Common.linux-x86` if readline is not +installed on linux-x86. Command-line editing and history will then be +those supplied by the os. On vxWorks the ledLib command-line input +library is used instead. + +### Host system storage requirements + +The compressed tar file is approximately 1.6 MB in size. The +distribution source tree takes up approximately 12 MB. Each host +target will need around 40 MB for build files, and each cross-compiled +target around 20 MB. + +### Documentation + +EPICS documentation is available through the [EPICS +website](https://epics.anl.gov/) at Argonne. + +Release specific documentation can also be found in the +base/documentation directory of the distribution. + +### Directory Structure + +#### Distribution directory structure: + +``` + base Root directory of the base distribution + base/configure Operating system independent build config files + base/configure/os Operating system dependent build config files + base/documentation Distribution documentation + base/src Source code in various subdirectories + base/startup Scripts for setting up path and environment +``` + +#### Install directories created by the build: + +``` + bin Installed scripts and executables in subdirs + cfg Installed build configuration files + db Installed data bases + dbd Installed data base definitions + doc Installed documentation files + html Installed html documentation + include Installed header files + include/os Installed os specific header files in subdirs + include/compiler Installed compiler-specific header files + lib Installed libraries in arch subdirectories + lib/perl Installed perl modules + templates Installed templates +``` + +### Build related components + +#### base/documentation directory - contains setup, build, and install documents + +``` + README.md Instructions for setup and building epics base + README.darwin.html Installation notes for Mac OS X (Darwin) + RELEASE_NOTES.html Notes on release changes + KnownProblems.html List of known problems and workarounds +``` + +#### base/startup directory - contains scripts to set environment and path + +``` + EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable + unix.csh C shell script to set path and env variables + unix.sh Bourne shell script to set path and env variables + win32.bat Bat file example to configure win32-x86 target + windows.bat Bat file example to configure windows-x64 target +``` + +#### base/configure directory - contains build definitions and rules + +``` + CONFIG Includes configure files and allows variable overrides + CONFIG.CrossCommon Cross build definitions + CONFIG.gnuCommon Gnu compiler build definitions for all archs + CONFIG_ADDONS Definitions for and DEFAULT options + CONFIG_APP_INCLUDE + CONFIG_BASE EPICS base tool and location definitions + CONFIG_BASE_VERSION Definitions for EPICS base version number + CONFIG_COMMON Definitions common to all builds + CONFIG_ENV Definitions of EPICS environment variables + CONFIG_FILE_TYPE + CONFIG_SITE Site specific make definitions + CONFIG_SITE_ENV Site defaults for EPICS environment variables + MAKEFILE Installs CONFIG* RULES* creates + RELEASE Location of external products + RULES Includes appropriate rules file + RULES.Db Rules for database and database definition files + RULES.ioc Rules for application iocBoot/ioc* directory + RULES_ARCHS Definitions and rules for building architectures + RULES_BUILD Build and install rules and definitions + RULES_DIRS Definitions and rules for building subdirectories + RULES_EXPAND + RULES_FILE_TYPE + RULES_TARGET + RULES_TOP Rules specific to a dir (uninstall and tar) + Sample.Makefile Sample makefile with comments +``` + +#### base/configure/os directory - contains os-arch specific definitions + +``` + CONFIG.. Specific host-target build definitions + CONFIG.Common. Specific target definitions for all hosts + CONFIG..Common Specific host definitions for all targets + CONFIG.UnixCommon.Common Definitions for Unix hosts and all targets + CONFIG.Common.UnixCommon Definitions for Unix targets and all hosts + CONFIG.Common.vxWorksCommon Specific host definitions for all vx targets + CONFIG_SITE.. Site specific host-target definitions + CONFIG_SITE.Common. Site specific target defs for all hosts + CONFIG_SITE..Common Site specific host defs for all targets +``` + +### Building EPICS base (Unix and Win32) + +#### Unpack file + +Unzip and untar the distribution file. Use WinZip on Windows +systems. + +#### Set environment variables + +Files in the base/startup directory have been provided to help set +required path and other environment variables. + +* `EPICS_HOST_ARCH` +Before you can build or use EPICS R3.15, the environment variable +`EPICS_HOST_ARCH` must be defined. A perl script EpicsHostArch.pl in +the base/startup directory has been provided to help set +`EPICS_HOST_ARCH.` You should have `EPICS_HOST_ARCH` set to your +host operating system followed by a dash and then your host +architecture, e.g. solaris-sparc. If you are not using the OS +vendor's c/c++ compiler for host builds, you will need another dash +followed by the alternate compiler name (e.g. "-gnu" for GNU c/c++ +compilers on a solaris host or "-mingw" for MinGW c/c++ compilers on +a WIN32 host). See `configure/CONFIG_SITE` for a list of supported +`EPICS_HOST_ARCH` values. + +* `PERLLIB` +On WIN32, some versions of Perl require that the environment +variable PERLLIB be set to <perl directory location>. + +* `PATH` +As already mentioned, you must have the perl executable and you may +need C and C++ compilers in your search path. For building base you +also must have echo in your search path. For Unix host builds you +also need ln, cpp, cp, rm, mv, and mkdir in your search path and +/bin/chmod must exist. On some Unix systems you may also need ar and +ranlib in your path, and the C compiler may require as and ld in +your path. On solaris systems you need uname in your path. + +* `LD_LIBRARY_PATH` +R3.15 shared libraries and executables normally contain the full +path to any libraries they require. However, if you move the EPICS +files or directories from their build-time location then in order +for the shared libraries to be found at runtime `LD_LIBRARY_PATH` +must include the full pathname to +`$(INSTALL_LOCATION)/lib/$(EPICS_HOST_ARCH)` when invoking +executables, or some equivalent OS-specific mechanism (such as +/etc/ld.so.conf on Linux) must be used. Shared libraries are now +built by default on all Unix type hosts. + +#### Do site-specific build configuration + +**Site configuration** +To configure EPICS, you may want to modify the default definitions +in the following files: + +``` + configure/CONFIG_SITE Build choices. Specify target archs. + configure/CONFIG_SITE_ENV Environment variable defaults + configure/RELEASE TORNADO2 full path location +``` + +**Host configuration** +To configure each host system, you may override the default +definitions by adding a new file in the configure/os directory with +override definitions. The new file should have the same name as the +distribution file to be overridden except with CONFIG in the name +changed to `CONFIG_SITE`. + +``` + configure/os/CONFIG.. Host build settings + configure/os/CONFIG..Common Host common build settings +``` + +**Target configuration** +To configure each target system, you may override the default +definitions by adding a new file in the configure/os directory with +override definitions. The new file should have the same name as the +distribution file to be overridden except with CONFIG in the name +replaced by `CONFIG_SITE`. This step is necessary even if the host +system is the only target system. + +``` + configure/os/CONFIG.Common. Target common settings + configure/os/CONFIG.. Host-target settings +``` + +#### Build EPICS base + +After configuring the build you should be able to build EPICS base +by issuing the following commands in the distribution's root +directory (base): + +``` + gnumake clean uninstall + gnumake +``` + +The command "gnumake clean uninstall" will remove all files and +directories generated by a previous build. The command "gnumake" +will build and install everything for the configured host and +targets. + +It is recommended that you do a "gnumake clean uninstall" at the +root directory of an EPICS directory structure before each complete +rebuild to ensure that all components will be rebuilt. + +### Example application and extension + +A perl tool, makeBaseApp.pl is included in the distribution file. This +script will create a sample application that can be built and then +executed to try out this release of base. + +Instructions for building and executing the 3.15 example application +can be found in the section "Example Application" of Chapter 2, +"Getting Started", in the "IOC Application Developer's Guide" for this +release. The "Example IOC Application" section briefly explains how to +create and build an example application in a user created <top> +directory. It also explains how to run the example application on a +vxWorks ioc or as a process on the host system. By running the example +application as a host-based IOC, you will be able to quickly implement +a complete EPICS system and be able to run channel access clients on +the host system. + +A perl script, makeBaseExt.pl, is included in the distribution file. +This script will create a sample extension that can be built and +executed. The makeBaseApp.pl and makeBaseExt.pl scripts are installed +into the install location `bin/` directory during the base +build. + +### Multiple host platforms + +You can build using a single EPICS directory structure on multiple +host systems and for multiple cross target systems. The intermediate +and binary files generated by the build will be created in separate +subdirectories and installed into the appropriate separate host/target +install directories. EPICS executables and perl scripts are installed +into the `$(INSTALL_LOCATION)/bin/` directories. Libraries are +installed into $`(INSTALL_LOCATION)/lib/`. The default +definition for `$(INSTALL_LOCATION)` is `$(TOP)` which is the root +directory in the distribution directory structure, base. Created +object files are stored in `O.` source subdirectories, This +allows objects for multiple cross target architectures to be +maintained at the same time. To build EPICS base for a specific +host/target combination you must have the proper host/target C/C++ +cross compiler and target header files and the base/configure/os +directory must have the appropriate configure files. diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html deleted file mode 100644 index 103e5a957..000000000 --- a/documentation/RELEASE_NOTES.html +++ /dev/null @@ -1,1695 +0,0 @@ - - - - - EPICS 7.0 Release Notes - - - - -

    These release notes describe changes that have been made since the previous -release of this series of EPICS Base. Note that changes which were merged up -from commits to new releases in an older Base series are not described at the -top of this file but have entries that appear lower down, under the series to -which they were originally committed. Thus it is important to read more than -just the first section to understand everything that has changed in each -release.

    - -

    The external PVA submodules each have their own separate set of release notes -which should also be read to understand what has changed since an earlier -release.

    - -

    EPICS Release 7.0.3

    - - - -

    epicsTimeGetCurrent() optimization

    - -

    Add a fast path to epicsTimeGetCurrent() and related calls -in the common case where only the default OS current time provider is -registered. This path does not take the global mutex guarding -the time providers list, potentially reducing lock contention.

    - -

    dbEvent tweak Queue size

    - -

    The size of the queue used by dbEvent to push monitor updates -has been slightly increased based on DBR_TIME_DOUBLE to better fill -an ethernet frame. This may result in slightly fewer, but larger -frames being sent.

    - -

    mbbo/mbbiDirect number of bits as precision

    - -

    Report NOBT as "precision" through the dbAccess API. -This is not accessible through CA, but is planned to be used through -QSRV.

    - -

    EPICS Release 7.0.2.2

    - -

    Build System changes

    - -
      - -
    • The GNUmake build targets cvsclean and depclean are now -available from any directory; previously they were only available from -application top directories.
    • - -
    • The approach that EPICS Base uses for building submodules inside the parent -module looks useful for support modules too. The rules for building submodules -have been modified and extracted into a new RULES_MODULES file, so a -support module will be able to use them too without having to copy them into its -own modules/Makefile. There are some specific requirements that support -modules and their submodules must follow, which are described as comments in the -new base/configure/RULES_MODULES file itself.
    • - -
    - -

    EPICS_BASE_VERSION Update Policy change

    - -

    In the past, a build of EPICS using sources checked out from the repository -branch between official releases would have shown the version number of the -previous release, followed by a -DEV suffix, for example -7.0.2.1-DEV.

    - -

    The policy that controls when the number gets updated has been changed, and -now immediately after a release has been tagged the version number will be -updated to the next patch release version, plus the -DEV suffix as -before. Thus following 7.0.2.2 the version number will show as -7.0.2.3-DEV. This does not require the next official release to be -numbered 7.0.2.3 though, it could become 7.0.3 or even -7.1.0 if the changes incorporated into it are more substantial than bug -fixes.

    - -

    Drop CLOCK_MONOTONIC_RAW from posix/osdMonotonic.c

    - -

    Turns out this is ~10x slower to query than CLOCK_MONOTONIC.

    - - -

    EPICS Release 7.0.2.1

    - -

    Linking shared libraries on macOS

    - -

    The linker flag -flat_namespace has been restored for creating -shared libraries, although not for loadable libraries (bundles). This was -required for building using the latest versions of Apple XCode.

    - -

    Fix DB_LINK loop breaking

    - -

    A regression was introduced in 7.0.2 which caused record chains with loops to -be incorrectly broken. Processing should be skipped when a DB_LINK with Process -Passive (PP) closes a loop to a synchronous record.

    - -

    Instead in 7.0.2 the targeted record would be processed if processing began -with a remote action (or some other caller of dbPutField()). This would -result in the loop running a second time. The loop would be broken on the second -iteration.

    - -

    See lp: -#1809570

    - -

    Old dbStaticLib APIs removed

    - -

    Support for some obsolete dbStaticLib Database Configuration Tool (DCT) APIs -was removed some time ago, but vestiges of them still remained. The following -routines and macros and have now finally been removed:

    - -
      -
    • int dbGetFieldType(DBENTRY *pdbentry)
    • -
    • int dbGetLinkType(DBENTRY *pdbentry)
    • -
    • DCT_STRING
    • -
    • DCT_INTEGER
    • -
    • DCT_REAL
    • -
    • DCT_MENU
    • -
    • DCT_MENUFORM
    • -
    • DCT_INLINK
    • -
    • DCT_OUTLINK
    • -
    • DCT_FWDLINK
    • -
    • DCT_NOACCESS
    • -
    • DCT_LINK_CONSTANT
    • -
    • DCT_LINK_FORM
    • -
    • DCT_LINK_PV
    • -
    - -

    Fix for dbhcr before iocInit

    - -

    The dbhcr command used to work before iocInit as well as -afterwards. It displays all records that have hardware addresses (VME_IO, -CAMAC_IO, GPIB_IO, INST_IO etc.) but stopped working if run before iocInit due -to the rewrite of the link address parser code in dbStaticLib. This release -fixes that issue, although in some cases the output may be slightly different -than it used to be.

    - - -

    EPICS Release 7.0.2

    - -

    Launchpad Bugs

    - -

    The list of tracked bugs fixed in this release can be found on the -Launchpad Milestone -page for EPICS Base 7.0.2.

    - - -

    Git Branches Recombined

    - -

    The four separate Git branches core/master, libcom/master, -ca/master and database/master have been recombined into one -branch called 7.0. Keeping these as 4 separate branches in the same -repository made it impossible to create merge requests that contained changes in -more than one of these modules. The layout of the source files has not changed -at all however, so the source code for libcom, ca and the database are still -found separately under the module subdirectory.

    - - -

    EPICS Release 7.0.1.1

    - -

    Changed SIML failure behavior

    - -

    A failure when fetching the simulation mode through SIML will not -put the record into INVALID alarm state anymore. Instead, as long as the -record's current alarm severity (SEVR)is NO_ALARM, its alarm status -(STAT) will be set to LINK_ALARM without increasing the severity. This -allows clients to get some notification of a failing or bad SIML link -without otherwise affecting record processing.

    - - -

    dbVerify() has been restored to dbStaticLib

    - -

    This routine was removed in Base-3.16.1 but has been reimplemented in this -release by special request. Note that the error message strings that it returns -when verification fails have changed, but are still designed for display to the -user.

    - - -

    Simulation mode improvements

    - -

    Records that support simulation mode have two new fields, SSCN -(Simulation Scan Mode) and SDLY (Simulation Delay). SSCN is a -menu field that provides an alternate value for the SCAN field to be -used while the record is in simulation mode. This is especially useful for I/O -scanned records, for which simulation mode was not working at all. Setting -SDLY to a positive value makes the record process asynchronously in -simulation mode, with the second stage processing happening after the specified -time (in seconds).

    - - -

    Extend the dbServer API with init/run/pause/stop methods

    - -

    This change permits IOCs to be built that omit the CA server (RSRV) by -removing its registrar entry which is now provided in the new rsrv.dbd -file. Other server layers can be built into the IOC (alongside RSRV or in place -of it) by registering them in a similar manner. The dbServer API is documented -with Doxygen comments in the header file.

    - -

    Specific IOC server layers can be disabled at runtime by adding their name to -the environment variable EPICS_IOC_IGNORE_SERVERS (separated by spaces if more -than one should be ignored).

    - - -

    Grand source-code reorganization

    - -

    EPICS 7.0.1 contains the IOC Database, RSRV server and the Channel Access -client code from EPICS Base 3.16.1 along with all the original record types and -soft device support, but GDD and the Portable Channel Access Server have been -unbundled and are now available separately. In their place we have brought in -the more recently written EPICS V4 C++ libraries (collectively referred to as -the PVA modules). The directory tree for EPICS is somewhat larger as a result, -and the original structure of the Base directories has been split into 4 -separate Git repositories. External modules should build against this new -structure with little or no changes needed, except that some allowance may be -needed for the merging of the V4 modules.

    - -

    There should be rather more description and documantation of these changes -than is currently available, but as developers we generally much prefer to write -code than documentation. Send questions to the tech-talk mailing list and we'll -be happy to try and answer them!

    - - -

    Changes between 3.16.1 and 3.16.2

    - -

    The list of tracked bugs fixed in this release can be found on the -Launchpad Milestone -page for EPICS Base 3.16.2.

    - -

    Status reporting for the callback and scanOnce task queues

    - -

    Two new iocsh commands and some associated underlying APIs have been added to -show the state of the queues that feed the three callback tasks and the scanOnce -task, including a high-water mark which can optionally be reset. The new iocsh -commands are callbackQueueShow and scanOnceQueueShow; both -take an optional integer argument which must be non-zero to reset the -high-water mark.

    - -

    Support for event codes greater than or equal to NUM_TIME_EVENTS

    - -

    Event numbers greater than or equal to NUM_TIME_EVENTS are now allowed if -supported by the registered event time provider, which must provide its own -advancing timestamp validation for such events.

    - -

    Time events numbered 0 through (NUM_TIME_EVENTS-1) are still validated by -code in epicsGeneralTime.c that checks for advancing timestamps and enforces -that restriction.

    - -

    Type-safe Device and Driver Support Tables

    - -

    Type-safe versions of the device and driver support structures dset -and drvet 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.

    - -

    The old structure definitions will be replaced by the new ones if the macros -USE_TYPED_DSET and/or USE_TYPED_DRVET are defined when the -appropriate header is included. The best place to define these is in the -Makefile, as with the USE_TYPED_RSET 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 -this commit to the ipac module to see a module conversion.

    - -

    A helper function DBLINK* dbGetDevLink(dbCommon *prec) has also been -added to devSup.h which fetches a pointer to the INP or OUT field of the -record.

    - -

    RTEMS build configuration update, running tests under QEMU

    - -

    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 (qemu-system-i386). It is also now -possible to create sub-architectures of RTEMS targets, whereas previously the -EPICS target architecture name had to be RTEMS-$(RTEMS_BSP).

    - -

    The new target RTEMS-pc386-qemu builds binaries that can be run in -the qemu-system-i386 PC System emulator. This target is a derivative of -the original RTEMS-pc386 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 -make runtests) will also run the tests for RTEMS using QEMU.

    - -

    To allow the new 3-component RTEMS target name, the EPICS build system for -RTEMS was modified to allow a configure/os/CONFIG.Common.<arch> -file to set the RTEMS_BSP variable to inform the build what RTEMS BSP -to use. Previously this was inferred from the value of the T_A 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 RTEMS_BSP if it hasn't been set when -needed.

    - -

    Link type enhancements

    - -

    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 -jlink::debug 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.

    - -

    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.

    - -

    A new start_child() method was added to the end of the jlif -interface table.

    - -

    The lset 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.

    - -

    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 -parse_start_map() method. The jlif_key_result enum now -contains 3 values jlif_key_child_inlink, -jlif_key_child_outlink and jlif_key_child_fwdlink -instead of the single jlif_key_child_link that was previously used -for this.

    - -

    GNUmake targets for debugging

    - -

    Some additional build rules have been added to help debug configuration -problems with the build system. Run make show-makefiles to get a sorted -list of all the files that the build system includes when building in the -current directory.

    - -

    A new pattern rule for PRINT.% 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 -O.arch build directory). For example make PRINT.T_A -will display the build target architecture name from inside a -O.arch directory but the variable will be empty from an -application top or src directory. make PRINT.EPICS_BASE will show the -path to Base from any EPICS application directory though.

    - -

    Propagate PUTF across Asynchronous record processing

    - -

    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.

    - -

    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 dbAccessDebugPUTF is set in addition to TPRO.

    - -

    Finding info fields

    - -

    A new iocsh command dbli lists the info fields defined in the -database, and can take a glob pattern to limit output to specific info names. -The newly added dbStaticLib function dbNextMatchingInfo() iterates -through the info fields defined in the current record, and is used to implement -the new command.

    - -

    Output from dbpr command enhanced

    - -

    The "DataBase Print Record" command dbpr now generates slightly -better output, with more field types having their own display methods. This -release also includes additional protection against buffer overflows while -printing long links in dbpr, and corrects the output of long strings -from the dbgf command.

    - -

    Record types mbbiDirect and mbboDirect upgraded to 32 bit

    - -

    The VAL fields and related fields of these records are now DBF_LONG. -(Not DBF_ULONG in order to prevent Channel Access from promoting them -to DBF_DOUBLE.) Additional bit fields B10...B1F have -been added.

    - -

    Device support that accesses VAL or the bit fields directly (most -don't) and aims for compatibility with old and new versions of these records -should use at least 32 bit integer types to avoid bit loss. The number of bit -fields can be calculated using 8 * sizeof(prec->val) -which is correct in both versions.

    - -

    Restore use of ledlib for VxWorks command editing

    - -

    The epicsReadline refactoring work described below unfortunately disabled the -VxWorks implementation of the osdReadline.c API that uses ledlib for command -editing and history. This functionality has now been restored, see Launchpad -bug #1741578.

    - -

    Constant link types

    - -

    Constant links can now hold 64-bit integer values, either as scalars or -arrays. Only base 10 is supported by the JSON parser though, the JSON standard -doesn't allow for hexadecimal numbers.

    - -

    Upgraded the YAJL JSON Library

    - -

    The third-party YAJL library that has been included in libCom for several -years has been upgraded to version 2.1.0 and several bugs fixed. This has an -updated API, requiring any code that uses it to parse its own JSON files to be -modified to match. The changes are mainly that it uses size_t instead -unsigned int for string lengths, but it also uses long long -instead of long for JSON integer values, which was the main motivation -for the upgrade.

    - -

    The self-tests that YAJL comes with have been imported and are now run as an -EPICS Unit Test program, and the JSON syntax accepted by the parser was extended -to permit trailing commas in both arrays and maps. The difference between the -old and new YAJL APIs can be detected at compile time by looking for the macro -EPICS_YAJL_VERSION which is defined in the yajl_common.h header file -along with a brief description of the API changes.

    - -

    Timestamp support for the calc link type

    - -

    A new optional parameter can be given when specifying a calc JSON link. The -time parameter is a string containing a single letter A..L -that selects one of the input links to be used for the timestamp of calculation -if requested. The timestamp will be fetched atomically with the value from the -chosen input link (providing that input link type supports the readLocked() -method).

    - -

    Silence errors from puts to constant link types

    - -

    A soft channel output record with the OUT link unset uses the CONSTANT link -type. The new link type code was causing some soft channel device supports to -return an error status from the write method of that link type, which would -cause a ca_put() operation to such a record to generate an exception. This has -been silenced by giving the constant link types a dummy putValue method. A new -test program has been added to prevent regressions of this behaviour.

    - -

    RSRV expanding large buffer causes crash

    - -

    In the 3.16.1 release a crash can occur in the IOC's RSRV server when a large -array is made even larger; the previous array buffer was not being released -correctly. See Launchpad -bug -#1706703.

    - - -

    Changes made between 3.16.0.1 and 3.16.1

    - -

    IOC Database Support for 64-bit integers

    - -

    The IOC now supports the 64-bit integer field types DBF_INT64 and -DBF_UINT64, and there are new record types int64in and -int64out derived from the longin and longout types -respectively that use the DBF_INT64 data type for their VAL and related -fields. The usual range of Soft Channel device support are included for these -new record types.

    - -

    All internal IOC APIs such as dbAccess can handle the new field types and -their associated request values DBR_INT64 and DBR_UINT64, -which are implemented using the epicsInt64 and epicsUInt64 -typedef's from the epicsTypes.h header.

    - -

    The waveform record type has been updated to support these new field types. -All waveform device support layers must be updated to recognize the new -type enumeration values, which had to be inserted before the -FLOAT value in the enum dbfType and in menuFtype. C -or C++ code can detect at compile-time whether this version of base provides -64-bit support by checking for the presence of the DBR_INT64 macro as -follows (Note that DBF_INT64 is an enum tag and not a -preprocessor macro):

    - -
    -#ifdef DBR_INT64
    -    /* Code where Base has INT64 support */
    -#else
    -    /* Code for older versions */
    -#endif
    -
    - -

    If the code uses the old db_access.h types (probably because it's calling -Channel Access APIs) then it will have to test against the EPICS version number -instead, like this:

    - -
    -#include <epicsVersion.h>
    -
    -#ifndef VERSION_INT
    -#  define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
    -#endif
    -#ifndef EPICS_VERSION_INT
    -#  define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
    -#endif
    -
    -#if EPICS_VERSION_INT >= VERSION_INT(3,16,1,0)
    -    /* Code where Base has INT64 support */
    -#else
    -    /* Code for older versions */
    -#endif
    -
    - -

    Channel Access does not (and probably never will) directly support 64-bit -integer types, so the new field types are presented to the CA server as -DBF_DOUBLE values. This means that field values larger than 2^52 -(0x10_0000_0000_0000 = 4503599627370496) cannot be transported over Channel -Access without their least significant bits being truncated. The EPICS V4 -pvAccess network protocol can transport 64-bit data types however, and -a future release of the pvaSrv module will connect this ability to the fields of -the IOC.

    - -

    Additional 64-bit support will be provided in later release. For instance the -JSON parser for the new Link Support feature only handles integers up to -32 bits wide, so constant array initializer values cannot hold larger -values in this release.

    - - -

    Add EPICS_CA_MCAST_TTL

    - -

    A new environment parameter EPICS_CA_MCAST_TTL is used to set the Time To -Live (TTL) value of any IP multi-cast CA search or beacon packets sent.

    - - -

    EPICS_CA_MAX_ARRAY_BYTES is optional

    - -

    A new environment parameter EPICS_CA_AUTO_ARRAY_BYTES is now used by libca -and RSRV (CA clients and the IOC CA server). The default is equivalent to -setting EPICS_CA_AUTO_ARRAY_BYTES=YES which removes the need to set -EPICS_CA_MAX_ARRAY_BYTES and always attempts to allocate sufficiently large -network buffers to transfer large arrays properly over the network. In this case -the value of the EPICS_CA_MAX_ARRAY_BYTES parameter is ignored.

    - -

    Explicitly setting EPICS_CA_AUTO_ARRAY_BYTES=NO will continue to honor the -buffer setting in EPICS_CA_AUTO_ARRAY_BYTES as in previous releases.

    - -

    The default setting for EPICS_CA_AUTO_ARRAY_BYTES can be changed by -adding the line

    - -
    -EPICS_CA_AUTO_ARRAY_BYTES=NO
    -
    - -

    to the configure/CONFIG_SITE_ENV file before building Base. Sites that wish -to override this only for specific IOC architectures can create new files for -each architecture named configure/os/CONFIG_SITE_ENV.<target-arch> with -the above setting in before building Base. The configuration can also be -explicitly changed by setting the environment variable in the IOC's startup -script, anywhere above the iocInit line.

    - -

    The PCAS server (used by the PV Gateway and other CA servers) now always -behaves as if EPICS_CA_AUTO_ARRAY_BYTES is set to YES (it ignores the -configuration parameter and environment variable).

    - - -

    Channel Access "modernization"

    - -

    Drop support for CA clients advertising protocol versions less than 4.

    - -

    This effects clients from Base older than 3.12.0-beta1. -Newer clients will continue to be able to connect to older servers. -Older clients will be ignored by newer servers.

    - -

    This allows removal of UDP echo and similar protocol features which -are not compatible with secure protocol design practice.

    - - -

    Lookup-tables using the subArrray record

    - -

    The subArray record can now be used as a lookup-table from a constant array -specified in its INP field. For example:

    - -
    -record(subArray, "powers-of-2") {
    -  field(FTVL, "LONG")
    -  field(MALM, 12)
    -  field(INP, [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048])
    -  field(INDX, 0)
    -  field(NELM, 1)
    -}
    -
    - -

    The INDX field selects which power of 2 to set the VAL field to. In previous -releases the INP field would have to have been pointed to a separate waveform -record that was initialized with the array values somehow at initialization -time.

    - -

    Synchronized Timestamps with TSEL=-2

    - -

    Most Soft Channel input device support routines have supported fetching the -timestamp through the INP link along with the input data. However before now -there was no guarantee that the timestamp provided by a CA link came from the -same update as the data, since the two were read from the CA input buffer at -separate times without maintaining a lock on that buffer in between. This -shortcoming could be fixed as a result of the new link support code, which -allows code using a link to pass a subroutine to the link type which will be run -with the link locked. The subroutine may make multiple requests for metadata -from the link, but must not block.

    - - -

    Extensible Link Types

    - -
    - -

    A major new feature introduced with this release of EPICS Base is an -Extensible Link Type mechanism, also known as Link Support or JSON Link Types. -This addition permits new kinds of link I/O to be added to an IOC in a similar -manner to the other extension points already supported (e.g. record, device and -driver support).

    - -

    A new link type must implement two related APIs, one for parsing the JSON -string which provides the link address and the other which implements the link -operations that get called at run-time to perform I/O. The link type is built -into the IOC by providing a new link entry in a DBD file.

    - - -

    New Link Types Added

    - -

    This release contains two new JSON link types, const and -calc:

    - -
      - -
    • The const link type is almost equivalent to the old CONSTANT link -type with the updates described below to accept arrays and strings, except that -there is no need to wrap a scalar string constant inside array brackets since a -constant string will never be confused with a PV name.
    • - -
    • The calc link type allows CALC expressions to be used to combine -values from other JSON links to produce its value. Until additional JSON link -types are created though, the calc link type has little practical -utility as it can currently only fetch inputs from other calc links or -from const links.
    • - -
    - -
    -  field(INP, {calc:{expr:"A+B+1",
    -                    args:[5,         # A
    -                          {const:6}] # B
    -             }})
    -
    - -

    The new link types are documented in a -separate -document -.

    - - -

    Device Support Addressing using JSON_LINK

    - -

    The API to allow device support to use JSON addresses is currently -incomplete; developers are advised not to try creating device support that -specifies a JSON_LINK address type.

    - - -

    Support Routine Modifications for Extensible Link Types

    - -

    For link fields in external record types and soft device support to be able -to use the new link types properly, various changes are required to utilize the -new Link Support API as defined in the dbLink.h header file and outlined below. -The existing built-in Database and Channel Access link types have been altered -to implement the link APIs, so will work properly after these conversions:

    - -
      - -
    • Make all calls to recGblInitConstantLink() unconditional on the -link type, i.e. change this code: - -
      -    if (prec->siml.type == CONSTANT) {
      -        recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
      -    }
      -
      - -into this: - -
      -    recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
      -
      - -Note that recGblInitConstantLink() still returns TRUE if the field was -successfully initialized from the link (implying the link is constant).
      -This change will work properly with all Base releases currently in use.
    • - -
    • Code that needs to identify a constant link should be modified to use the -new routine dbLinkIsConstant() instead, which returns TRUE for constant -or undefined links, FALSE for links whose dbGetLink() routine may -return different values on different calls. For example this: - -
      -    if (prec->dol.type != CONSTANT)
      -
      - -should become this: - -
      -    if (!dbLinkIsConstant(&prec->dol))
      -
      - -When the converted software is also required to build against older versions of -Base, this macro definition may be useful: - -
      -#define dbLinkIsConstant(lnk) ((lnk)->type == CONSTANT)
      -
      -
    • - -
    • Any code that calls dbCa routines directly, or that explicitly checks if a -link has been resolved as a CA link using code such as - -
      -    if (prec->inp.type == CA_LINK)
      -
      - -will still compile and run, but will only work properly with the old CA link -type. To operate with the new extensible link types such code must be modified -to use the new generic routines defined in dbLink.h and should never attempt to -examine or modify data inside the link. After conversion the above line would -probably become: - -
      -    if (dbLinkIsVolatile(&prec->inp))
      -
      - -A volatile link is one like a Channel Access link which may disconnect and -reconnect without notice at runtime. Database links and constant links are not -volatile; unless their link address is changed they will always remain in the -same state they started in. For compatibility when building against older -versions of Base, this macro definition may be useful: - -
      -#define dbLinkIsVolatile(lnk) ((lnk)->type == CA_LINK)
      -
      -
    • - -
    • The current connection state of a volatile link can be found using the -routine dbIsLinkConnected() which will only return TRUE for a volatile -link that is currently connected. Code using the older dbCa API returning this -information used to look like this: - -
      -    stat = dbCaIsLinkConnected(plink);
      -
      - -which should become: -
      -    stat = dbIsLinkConnected(plink);
      -
      - -Similar changes should be made for calls to the other dbCa routines.
    • - - -
    • A full example can be found by looking at the changes to the calcout record -type, which has been modified in this release to use the new dbLink generic -API.
    • - -
    - -
    - - -

    Constant Link Values

    - -

    Previously a constant link (i.e. a link that did not point to another PV, -either locally or over Channel Access) was only able to provide a single numeric -value to a record initialization; any string given in a link field that was not -recognized as a number was treated as a PV name. In this release, constant links -can be expressed using JSON array syntax and may provide array initialization of -values containing integers, doubles or strings. An array containing a single -string value can also be used to initialize scalar strings, so the stringin, -stringout, lsi (long string input), lso (long string output), printf, waveform, -subArray and aai (analog array input) record types and/or their soft device -supports have been modified to support this.

    - -

    Some examples of constant array and string initialized records are:

    - -
    -  record(stringin, "const:string") {
    -    field(INP, ["Not-a-PV-name"])
    -  }
    -  record(waveform, "const:longs") {
    -    field(FTVL, LONG)
    -    field(NELM, 10)
    -    field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    -  }
    -  record(aai, "const:doubles") {
    -    field(FTVL, DOUBLE)
    -    field(NELM, 10)
    -    field(INP, [0, 1, 1.6e-19, 2.718, 3.141593])
    -  }
    -  record(aSub, "select") {
    -    field(FTA, STRING)
    -    field(NOA, 4)
    -    field(INPA, ["Zero", "One", "Two", "Three"])
    -    field(FTB, SHORT)
    -    field(NOB, 1)
    -    field(FTVA, STRING)
    -    field(NOVA, 1)
    -    field(SNAM, "select_asub")
    -  }
    -
    - -

    Reminder: Link initialization with constant values normally only occurs at -record initialization time. The calcout and printf record types are the only -exceptions in the Base record types to this rule, so it is generally not useful -to change a const link value after iocInit.

    - - -

    Database Parsing of "Relaxed JSON" Values

    - -

    A database file can now provide a "relaxed JSON" value for a database field -value or an info tag. Only a few field types can currently accept such values, -but the capability is now available for use in other places in the future. When -writing to a JSON-capable field at run-time however, only strictly compliant -JSON may be used (the dbStaticLib parser rewrites relaxed JSON values into -strict JSON before passing them to the datase for interpretation, where the -strict rules must be followed).

    - -

    "Relaxed JSON" was developed to maximize compatibility with the previous -database parser rules and reduce the number of double-quotes that would be -needed for strict JSON syntax. The parser does accept strict JSON too though, -which should be used when machine-generating database files. The differences -are:

    - -
      - -
    • Strings containing only the characters a-z A-Z 0-9 _ - + . -do not have to be enclosed in double-quote characters.
    • - -
    • The above rule applies to map keys as well as to regular string values.
    • - -
    • The JSON keywords null, true and false (all -lower-case) will be recognized as keywords, so they must be quoted to use any of -these single words as a string.
    • - -
    • Comments may be used, introduced as usual by the # -character and extending to the end of the line.
    • - -
    - -

    A JSON field or info value is only enclosed in quotes when the value being -provided is a single string, and even here the quotes can be omitted in some -cases as described above. The following shows both correct and incorrect -excerpts from a database file:

    - -
    -    record(ai, math:pi) {
    -        field(INP, {const: 3.14159265358979})   # Correct
    -        field(SIOL, "{const: 3.142857}")        # Wrong
    -
    -        info(autosave, {            # White-space and comments are allowed
    -            fields:[DESC, SIMM],
    -            pass0:[VAL]
    -        })                          # Correct
    -    }
    -
    - -

    Note that the record, field and info-tag names do not accept JSON -values, so they follows the older bareword rules for quoting where the colon -: and several additional characters are legal in a bareword -string. Only the value (after the comma) is parsed as JSON. The autosave module -has not been modified to accept JSON syntax, the above is only an example of -how JSON might be used.

    - -

    Echoless comments in iocsh

    - -

    The way comments are parsed by the iocsh interpreter has changed. The -interpreter can be selectively disabled from echoing comments coming from -a script by starting those lines with '#-' rather than just '#'.

    - - -

    Typed record support methods

    - -

    The table of record support functions (rset methods for short) no longer -has entries of type RECSUPFUN (which says: any number and type of -arguments). Instead, rset methods are now typed by default. The -RECSUPFUN typedef has been deprecated and casts to it as well as -using the untyped struct rset will create compilation warnings.

    - -

    Existing code (e.g. external record supports) will generate such -warnings when compiled against this version of Base, but it will work -without changes.

    - -

    For a conversion period, the new typed rset definitions are activated -by defining USE_TYPED_RSET, preferably by setting -USR_CPPFLAGS += -DUSE_TYPED_RSET inside a Makefile. -After activating the new typed rset in this way and making the following -changes, the result should still compile and work properly against older -versions of Base.

    - -

    The first parameter of init_record and process has been -changed to struct dbCommon *. Record types that use -void* here should be changed to use struct dbCommon*, and -cast the argument to their own xxxRecord *.

    - -

    When compiled against this release, compiler warnings about incompatible -types for the method pointers should be taken seriously. When compiled -against older versions of base, such warnings are unavoidable.

    - -

    Record types written in C++ need to take more drastic measures because of -the stricter type checking in C++. To remain compatible with older versions -of base you will need to use something like:

    - -
    -#include "epicsVersion.h"
    -#ifdef VERSION_INT
    -#  if EPICS_VERSION_INT < VERSION_INT(3,16,0,2)
    -#    define RECSUPFUN_CAST (RECSUPFUN)
    -#  else
    -#    define RECSUPFUN_CAST
    -#  endif
    -#else
    -#  define RECSUPFUN_CAST (RECSUPFUN)
    -#endif
    -
    - -

    and then replace (RECSUPFUN) with RECSUPFUN_CAST -when initializing the rset. -Further changes might also be needed, e.g. to adapt const-ness of -method parameters.

    - -
    - -

    Changes made between 3.15.3 and 3.16.0.1

    - -

    Build support for CapFast and dbst removed

    - -

    The build rules associated with the CapFast-related tools sch2edif -and e2db and the database optimization tool dbst have -been removed, along with the DB_OPT build configuration variable.

    - -

    compressRecord buffering order

    - -

    The compressRecord has a new field BALG which can select between -FIFO (append) and LIFO (prepend) ordering for insertion of new elements. FIFO -ordering is the default, matching the behviour of previous versions.

    - -

    Valgrind Instrumentation

    - -

    Valgrind is a software debugging suite provided by many Linux distributions. -The header valgrind/valgrind.h is now included in, and installed by, Base. -When included by a C or C++ source file this header defines some macros which -expand to provide hints to the Valgrind runtime. -These have no effect on normal operation of the software, but when run using the -valgrind tool they can help to find memory leaks and buffer overflows. -Suitable hints have been added to several free-lists within libCom, including -freeListLib, allowing valgrind to provide more accurate information about the -source of potential leaks.

    - -

    valgrind.h automatically disables itself when the build target is not -supported by the valgrind tool. -It can also explicitly be disabled by defining the macro NVALGRIND. -See src/libCom/Makefile for a commented-out example.

    - -

    As a matter of policy valgrind.h will never be included by any header file -installed by Base, so its use will remain purely an implementation -detail hidden from application software. -Support modules which choose to use valgrind.h are advised to do -likewise.

    - -

    Database Multi-locking

    - -

    The IOC record locking code has been re-written with an expanded API; global -locks are no longer required by the IOC database implementation.

    - -

    The new API functions center around dbScanLockMany(), which behaves like -dbScanLock() applied to an arbitrary group of records. dbLockerAlloc() is used -to prepare a list or record pointers, then dbScanLockMany() is called. When it -returns, all of the records listed may be accessed (in any order) until -dbScanUnlockMany() is called.

    - -

    The Application Developer's Guide has been updated to describe the API and -implementation is more detail.

    - -

    Previously a global mutex 'lockSetModifyLock' was locked and unlocked during -dbScanLock(), acting as a sequencing point for otherwise unrelated calls. The -new dbLock.c implementation does not include any global mutex in dbScanLock() or -dbScanLockMany(). Locking/unlocking of unrelated lock sets is now completely -concurrent.

    - -

    Generate Version Header

    - -

    A Perl script and Makefile rules have been added to allow modules to generate -a C header file with a macro defined with an automatically updated identifier. -This is a VCS revision ID (Darcs, Git, Mercurial, Subversion, and Bazaar are -supported) or the date/time of the build if no VCS system is in use.

    - -

    The makeBaseApp example template has been updated with a new device support -which makes this identifier visible via a lsi (long string input) record.

    - -

    epicsTime API return status

    - -

    The epicsTime routines that used to return epicsTimeERROR now return a -specific S_time_ status value, allowing the caller to discover the reason for -any failure. The identifier epicsTimeERROR is no longer defined, so any -references to it in source code will no longer compile. The identifier -epicsTimeOK still exists and has the value 0 as before, so most code that uses -these APIs can be changed in a way that is backwards-compatible with the -previous return status.

    - -

    Time providers that have to return a status value and still need to be built -with earlier versions of Base can define the necessary status symbols like -this:

    - -
    -#include "epicsTime.h"
    -
    -#ifndef M_time
    -/* S_time_... status values were not provided before Base 3.16 */
    -#define S_time_unsynchronized epicsTimeERROR
    -#define S_time_...whatever... epicsTimeERROR
    -#endif
    -
    - -

    Refactoring of epicsReadline

    - -

    The epicsReadline code has been reorganized to allow the commandline history -editor to be disabled at runtime. The EPICS_COMMANDLINE_LIBRARY build setting -still selects the preferred editor, but the new IOCSH_HISTEDIT_DISABLE -environment variable can be set at runtime to disable history editing and make -the IOC or other program use the basic editor instead. This is useful when -starting and controlling an IOC from another program through its stdin and -stdout streams since history editors often insert invisible escape codes into -the stdout stream, making it hard to parse.

    - -

    Callback subsystem API

    - -

    Added a new macro callbackGetPriority(prio, callback) to the -callback.h header and removed the need for dbScan.c to reach into the internals -of its CALLBACK objects.

    - -

    Changes from the 3.15 branch since 3.15.6

    - - - -

    Cleaning up with Multiple CA contexts in a Process

    - -

    Bruno Martins reported a problem with the CA client library at shutdown in a -process that uses multiple CA client contexts. The first context that triggers -the CA client exit handler prevents any others from being able to clean up -because it resets the ID of an internal epicsThreadPrivate variable which is -shared by all clients. This action has been removed from the client library, -which makes cleanup of clients like this possible.

    - -

    Perl CA bindings fixed for macOS Mojave

    - -

    Apple removed some Perl header files from macOS Mojave that were available -in their SDK, requiring a change to the include paths used when compiling the -CA bindings. The new version should build on new and older macOS versions, and -these changes may also help other targets that have an incomplete installation -of Perl (the build will continue after printing a warning that the Perl CA -bindings could not be built).

    - -

    Routine epicsTempName() removed from libCom

    - -

    This routine was a simple wrapper around the C89 function tmpnam() -which is now seen as unsafe and causes warning messages to be generated by -most modern compilers. The two internal uses of this function have been -modified to call epicsTempFile() instead. We were unable to find any -published code that used this function, so it was removed immediately instead -of being deprecated.

    - -

    DBD Parsing of Record Types

    - -

    The Perl DBD file parser has been made slightly more liberal; the order in -which DBD files must be parsed is now more flexible, so that a record type -definition can now be parsed after a device support that referred to that -record type. A warning message will be displayed when the device support is -seen, but the subsequent loading of the record type will be accepted without -triggering an error. See -Launchpad bug -#1801145.

    - -

    menuScan and several record types documented with POD

    - -

    The EPICS Wiki pages describing a number of standard record types has been -converted into the Perl POD documentation format and added to the DBD files, -so at build-time an HTML version of these documents is generated and installed -into the htmls directory. Thanks to Tony Pietryla.

    - -

    CA client tools learned -V option

    - -

    This displays the version numbers of EPICS Base and the CA protocol.

    - - -

    Changes made between 3.15.5 and 3.15.6

    - -

    Unsetting environment variables

    - -

    The new command epicsEnvUnset varname can be used to -unset an environment variable.

    - -

    Warning indicators in msi (and macLib) output

    - -

    The libCom macro expansion library has been modified so that when the -SUPPRESS_WARNINGS flag is set it will no longer include any ,undefined -or ,recursive 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 msi -tool was used to generate other kinds of files they caused problems. If the -msi -V flag is used the markers will still be present in the output -whenever the appropriate condition is seen.

    - -

    Improvements to msi

    - -

    In addition to fixing its response to discovering parsing errors in its -substitution input file (reported as Launchpad -bug #1503661) -so it now deletes the incomplete output file, the msi program has been cleaned -up a little bit internally.

    - -

    All array records now post monitors on their array-length fields

    - -

    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 -Launchpad bug #1730727.

    - -

    HOWTO: Converting Wiki Record Reference to POD

    - -

    Some documentation has been added to the dbdToHtml.pl script -explaining how Perl POD (Plain Old Documentation) markup can be added to -.dbd files to generate HTML documentation for the record types. To see -these instructions, run perl bin/<host>/dbdToHtml.pl -H -or perldoc bin/<host>/dbdToHtml.pl.

    - -

    Fix problem with numeric soft events

    - -

    Changing from numeric to named soft events introduced an incompatibility -when a numeric event 1-255 is converted from a DOUBLE, e.g. from a calc record. -The post_event() API is not marked deprecated any more. - -

    Also scanpel has been modified to accept a glob pattern for -event name filtering and to show events with no connected records as well.

    - -

    Add osiSockOptMcastLoop_t and osiSockTest

    - -

    Added a new OS-independent typedef for multicast socket options, and a test -file to check their correct operation.

    - -

    Support for CONFIG_SITE.local in Base

    - -

    This feature is mostly meant for use by developers; configuration -settings that would normally appear in Base/configure/CONFIG_SITE can now -be put in a locally created base/configure/CONFIG_SITE.local file instead -of having go modify or replace the original. A new .gitignore pattern -tells git to ignore all configure/*.local files.

    - - -

    Changes from the 3.14 branch between 3.15.5 and 3.15.6

    - -

    Fix broken EPICS_IOC_LOG_FILE_LIMIT=0 setting

    - -

    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.

    - -

    Fixes lp:1786858 -and part of lp:1786966. -

    - -

    Cleanup of startup directory

    - -

    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:

    - -
      - -
    • The Perl EpicsHostArch.pl script has been rewritten, and support -for a few previously missing host architectures has been added to it.
    • - -
    • The EpicsHostArch.pl script has also been moved into the standard -src/tools directory, from where it will be installed into -lib/perl. In this new location it is no longer executable, so it must -be run by the perl executable.
    • - -
    • The build system has been adjusted to look for EpicsHostArch.pl in -both places if the EPICS_HOST_ARCH environment variable has not been -set at build-time.
    • - -
    • Sites that used the original Perl script to set EPICS_HOST_ARCH as -part of their standard environment will need to adjust their scripts when they -upgrade to this release.
    • - -
    • The EpicsHostArch shell script has been replaced with a wrapper -routine that calls the Perl EpicsHostArch.pl script. Sites that rely on -this script to set EPICS_HOST_ARCH should consider switching to the -Perl script instead.
    • - -
    • The Site.cshrc and Site.profile files have been renamed to -unix.csh and unix.sh, respectively.
    • - -
    • The existing win32.bat file has been cleaned up and a new -windows.bat 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.
    • - -
    - -

    Recent Apple XCode Build Issues

    - -

    The latest version of XCode will not compile calls to system() or -clock_settime() 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.

    - -

    Prevent illegal alarm severities

    - -

    A check has been added to recGblResetAlarms() 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.

    - -

    Fixes for Launchpad bugs

    - -

    The following launchpad bugs have fixes included:

    - - - -

    Updated VxWorks Timezone settings

    - -

    Removed the settings for 2017; fixed the hour of the change for MET.

    - -

    Fixed camonitor server side relative timestamps bug

    - -

    Initialize the first time-stamp from the first monitor, not the client-side -current time in this configuration.

    - -

    Build changes for MSVC

    - -

    Windows builds using Visual Studio 2015 and later now use the -FS -compiler option to allow parallel builds to work properly.

    - -

    We now give the -FC option to tell the compiler to print absolute -paths for source files in diagnostic messages.

    - -

    Extend maximum Posix epicsEventWaitWithTimeout() delay

    - -

    The Posix implementation of epicsEventWaitWithTimeout() was limiting the -timeout delay to at most 60 minutes (3600.0 seconds). This has been changed to -10 years; significantly longer maximum delays cause problems on systems where -time_t is still a signed 32-bit integer so cannot represent absolute -time-stamps after 2038-01-19. Our assumption is that such 32-bit systems will -have been retired before the year 2028, but some additional tests have been -added to the epicsTimeTest program to detect and fail if this assumption is -violated.

    - -

    New test-related make targets

    - -

    This release adds several new make targets intended for use by developers -and Continuous Integration systems which simplify the task of running the -built-in self-test programs and viewing the results. Since these targets are -intended for limited use they can have requirements for the build host which -go beyond the standard minimum set needed to build and run Base.

    - -
    - -

    test-results — Summarize test results

    - -

    The new make target test-results will run the self-tests if -necessary to generate a TAP file for each test, then summarizes the TAP output -files in each test directory in turn, displaying the details of any failures. -This step uses the program prove which comes with Perl, but also needs -cat to be provided in the default search path so will not work on most -Windows systems.

    - -

    junitfiles — Convert test results to JUnit XML Format

    - -

    The new make target junitfiles will run the self-tests if necessary -and then convert the TAP output files into the more commonly-supported JUnit -XML format. The program that performs this conversion needs the Perl module -XML::Generator to have been installed.

    - -

    clean-tests — Delete test result files

    - -

    The new make target clean-tests removes any test result files from -previous test runs. It cleans both TAP and JUnit XML files.

    - -
    - -

    Fix DNS related crash on exit

    - -

    The attempt to fix DNS related delays for short lived CLI programs (eg. caget) -in lp:1527636 introduced a bug which cased these short lived clients to crash on exit. -This bug should now be fixed.

    - -

    Server bind issue on Windows

    - -

    When a National Instruments network variables CA server is already running on -a Windows system and an IOC or PCAS server is started, the IOC's attempt to -bind a TCP socket to the CA server port number fails, but Windows returns a -different error status value than the IOC is expecting in that circumstance -(because the National Instruments code requests exclusive use of that port, -unlike the EPICS code) so the IOC fails to start properly. The relevent EPICS -bind() checks have now been updated so the IOC will request that a dynamic port -number be allocated for this TCP socket instead when this happens.

    - -

    Checking Periodic Scan Rates

    - -

    Code has been added to the IOC startup to better protect it against bad -periodic scan rates, including against locales where . is not -accepted as a decimal separator character. If the scan period in a menuScan -choice string cannot be parsed, the associated periodic scan thread will no -longer be started by the IOC and a warning message will be displayed at iocInit -time. The scanppl command will also flag the faulty menuScan value.

    - - -

    Changes made between 3.15.4 and 3.15.5

    - -

    dbStatic Library Speedup and Cleanup

    - -

    Loading of database files has been optimized to avoid overproportionally -long loading times for large databases. As a part of this, the alphabetical -ordering of records instances (within a record type) has been dropped. In the -unexpected case that applications were relying on the alphabetic order, setting -dbRecordsAbcSorted = 1 before loading the databases will retain the -old behavior.

    - -

    The routine dbRenameRecord() has been removed, as it was intended -to be used by database configuration tools linked against a host side version -of the dbStatic library that is not being built anymore.

    - -

    Launchpad Bug-fixes

    - -

    In addition to the more detailed change descriptions below, the following -Launchpad bugs have also been fixed in this release:

    - -
      -
    • - #1440186 Crash due to a too small buffer being provided in - dbContextReadNotifyCache
    • -
    • - #1479316 Some data races found using Helgrind
    • -
    • - #1495833 biRecord prompt groups are nonsensical
    • -
    • - #1606848 WSAIoctl SIO_GET_INTERFACE_LIST failed in Windows
    • -
    - -

    Whole-Program Optimization for MS Visual Studio Targets

    - -

    When using the Microsoft compilers a new build system variable is provided -that controls whether whole program optimization is used or not. For static -builds using Visual Studio 2010 this optimization must be disabled. This is -controlled in the files configure/os/CONFIG_SITE.Common.windows-x64-static and -configure/os/CONFIG_SITE.Common.win32-x86-static by setting the variable -OPT_WHOLE_PROGRAM = NO to override the default value -YES that would otherwise be used.

    - -

    Note that enabling this optimization slows down the build process. It is not -possible to selectively disable this optimization, when building a particular -module say; Microsoft's linker will restart itself automatically with the --LTCG flag set and display a warning if it is asked to link any object -files that were compiled with the -GL flag.

    - -

    Add dynamic (variable length) array support to PCAS

    - -

    Dynamic array sizing support was added to the IOC server (RSRV) in the -Base-3.14.12 release, but has not until now been supported in the Portable -Channel Access Server (PCAS). Channel Access server applications using the -PCAS may not need to be modified at all; if they already push monitors with -different gdd array lengths, those variable sizes will be forwarded to any CA -clients who have requested variable length updates. The example CAS server -application has been modified to demonstrate this feature.

    - -

    In implementing the above, the gdd method gdd::put(const gdd *) now -copies the full-sized array from the source gdd if the destination gdd is of -type array, has no allocated memory and a boundary size of 0.

    - -

    Additional epicsTime conversion

    - -

    The EPICS timestamp library (epicsTime) inside libCom's OSI layer has -been extended by routines that convert from struct tm to the EPICS -internal epicsTime type, assuming UTC - i.e. without going through -the timezone mechanism. This solves issues with converting from the structured -type to the EPICS timestamp at driver level from multiple threads at a high -repetition rate, where the timezone mechanism was blocking on file access.

    - -

    MinGW Cross-builds from Linux

    - -

    The build configuration files that allow cross-building of the 32-bit -win32-x86-mingw cross-target have been adjusted to default to building shared -libraries (DLLs) as this is now supported by recent MinGW compilers. The 64-bit -windows-x64-mingw cross-target was already being built that way by default. The -configuration options to tell the minGW cross-compiler to link programs with -static versions of the compiler support libraries have now been moved into the -CONFIG_SITE.linux-x86.target files.

    - -

    General Time updates

    - -

    The iocInit code now performs a sanity check of the current time -returned by the generalTime subsystem and will print a warning if the wall-clock -time returned has not been initialized yet. This is just a warning message; when -a time provider does synchonize the IOC will subsequently pick up and use the -correct time. This check code also primes the registered event system provider -if there is one so the epicsTimeGetEventInt() routine will work on IOCs -that ask for event time within an interrupt service routine.

    - -

    The osiClockTime provider's synchronization thread (which is only used on -some embedded targets) will now poll the other time providers at 1Hz until the -first time it manages to get a successful timestamp, after which it will poll -for updates every 60 seconds as before.

    - -

    The routine generalTimeGetExceptPriority() was designed for use by -backup (lower priority) time providers like the osiClockTime provider which do -not have their own absolute time reference and rely on other providers for an -absolute time source. This routine no longer implements the ratchet mechanism -that prevented the time it returned from going backwards. If the backup clock's -tick-timer runs fast the synchronization of the backup time provider would never -allow it to be corrected backwards when the ratchet was in place. The regular -epicsTimeGetCurrent() API still uses the ratchet mechanism, so this -change will not cause the IOC to see time going backwards.

    - -

    Microsoft Visual Studio builds

    - -

    The build configuration files for builds using the Microsoft compilers have -been updated, although there should be no noticable difference at most sites. -One extra compiler warning is now being suppressed for C++ code, C4344: -behavior change: use of explicit template arguments results in ... which is -gratuitous and was appearing frequently in builds of the EPICS V4 modules.

    - -

    Cross-builds of the windows-x64 target from a win32-x86 host have been -removed as they don't actually work within the context of a single make -run. Significant changes to the build configuration files would be necessary for -these kinds of cross-builds to work properly, which could be done if someone -needs them (email Andrew Johnson before working on this, and see - -this stack-overflow answer for a starting point).

    - -

    Bazaar keywords such as 'Revision-Id' removed

    - -

    In preparation for moving to git in place of the Bazaar revision control -system we have removed all the keywords from the Base source code.

    - -

    Linux systemd service file for CA Repeater

    - -

    Building this version of Base on a Linux system creates a systemd service -file suitable for starting the Channel Access Repeater under systemd. The file -will be installed into the target bin directory, from where it can be copied -into the appropriate systemd location and modified as necessary. Installation -instructions are included as comments in the file.

    - - -

    Changes made between 3.15.3 and 3.15.4

    - -

    New string input device support "getenv"

    - -

    A new "getenv" device support for both the stringin and lsi (long string -input) record types can be used to read the value of an environment variable -from the IOC at runtime. See base/db/softIocExit.db for sample usage.

    - -

    Build rules and DELAY_INSTALL_LIBS

    - -

    A new order-only prerequisite build rule has been added to ensure that -library files (and DLL stubs on Windows) get installed before linking any -executables, which resolves parallel build problems on high-powered CPUs. There -are some (rare) cases though where a Makefile has to build an executable and run -it to be able to compile code for a library built by the same Makefile. With -this new build rule GNUmake will complain about a circular dependency and the -build will probably fail in those cases. To avoid this problem the failing -Makefile should set DELAY_INSTALL_LIBS = YES before including the -$(TOP)/configure/RULES file, disabling the new build rule.

    - -

    IOC environment variables and build parameters

    - -

    The IOC now sets a number of environment variables at startup that provide -the version of EPICS Base it was built against (EPICS_VERSION_...) and its build -architecture (ARCH). In some cases this allows a single iocBoot/ioc directory to -be used to run the same IOC on several different architectures without any -changes.

    - -

    There are also 3 new environment parameters (EPICS_BUILD_...) available that -C/C++ code can use to find out the target architecture, OS class and compiler -class it was built with. These may be useful when writing interfaces to other -languages.

    - -

    New implementation of promptgroup/gui_group field property

    - -

    The mechanism behind the "promptgroup()" field property inside a record type -definition has been changed. Instead of using a fixed set of choices, -the static database access library now collects the used gui group names -while parsing DBD information. Group names should start with a two-digit number -plus space-dash-space to allow proper sorting of groups.

    - -

    The include file guigroup.h that defined the fixed set of choices -has been deprecated. Instead, use the conversion functions between index number -and group string that have been added to dbStaticLib.

    - -

    When a DBD file containing record-type descriptions is expanded, any -old-style GUI_xxx group names will be replaced by a new-style -string for use by the IOC. This permits an older record type to be used with -the 3.15.4 release, although eventually record types should be converted by -hand with better group names used.

    - -

    CA server configuration changes

    - -

    RSRV now honors EPICS_CAS_INTF_ADDR_LIST and binds only to the provided list -of network interfaces. Name searches (UDP and TCP) on other network interfaces -are ignored. For example on a computer with interfaces 10.5.1.1/24, 10.5.2.1/24, -and 10.5.3.1/24, setting "EPICS_CAS_INTF_ADDR_LIST='10.5.1.1 10.5.2.1'" will -accept traffic on the .1.1 and .2.1, but ignore from .3.1

    - -

    RSRV now honors EPICS_CAS_IGNORE_ADDR_LIST and ignores UDP messages received -from addresses in this list.

    - -

    Previously, CA servers (RSRV and PCAS) would build the beacon address list -using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set. This is no -longer done. Sites depending on this should set both envronment variables to the -same value.

    - -

    IPv4 multicast for name search and beacons

    - -

    libca, RSRV, and PCAS may now use IPv4 multicasting for UDP traffic (name -search and beacons). This is disabled by default. To enable multicast address(s) -must be listed in EPICS_CA_ADDR_LIST for clients and EPICS_CAS_INTF_ADDR_LIST -for servers (IOCs should set both). For example: -"EPICS_CAS_INTF_ADDR_LIST='224.0.2.9' EPICS_CA_ADDR_LIST=224.0.2.9".

    - -

    Please note that no IPv4 multicast address is officially assigned for Channel -Access by IANA. The example 224.0.2.9 is taken from the AD-HOC Block I range.

    - -

    Moved mlockall() into its own epicsThread routine

    - -

    Since EPICS Base 3.15.0.2 on Posix OSs the initialization of the epicsThread -subsystem has called mlockall() when the OS supports it and thread -priority scheduling is enabled. Doing so has caused problems in third-party -applications that call the CA client library, so the functionality has been -moved to a separate routine epicsThreadRealtimeLock() which will be -called by the IOC at iocInit (unless disabled by setting the global variable -dbThreadRealtimeLock to zero).

    - -

    Added dbQuietMacroWarnings control

    - -

    When loading database files, macros get expanded even on comment lines. If a -comment contains an undefined macro, the load still continues but an error -message gets printed. For this release the error message has been changed to a -warning, but even this warning can be made less verbose by setting this new -variable to a non-zero value before loading the file, like this:

    - -
    -var dbQuietMacroWarnings 1      iocsh
    -dbQuietMacroWarnings=1          VxWorks
    -
    - -

    This was Launchpad bug -541119.

    - - -

    Changes from the 3.14 branch between 3.15.3 and 3.15.4

    - -

    NTP Time Provider adjusts to OS tick rate changes

    - -

    Dirk Zimoch provided code that allows the NTP Time provider (used on VxWorks -and RTEMS only) to adapt to changes in the OS clock tick rate after the provider -has been initialized. Note that changing the tick rate after iocInit() is not -advisable, and that other software might still misbehave if initialized before -an OS tick rate change. This change was back-ported from the 3.15 branch.

    - -

    Making IOC ca_get operations atomic

    - -

    When a CA client gets data from an IOC record using a compound data type such -as DBR_TIME_DOUBLE the value field is fetched from the database in a -separate call than the other metadata, without keeping the record locked. This -allows some other thread such as a periodic scan thread a chance to interrupt -the get operation and process the record in between. CA monitors have always -been atomic as long as the value data isn't a string or an array, but this race -condition in the CA get path has now been fixed so the record will stay locked -between the two fetch operations.

    - -

    This fixes -Launchpad bug #1581212, thanks to Till Strauman and Dehong Zhang.

    - -

    New CONFIG_SITE variable for running self-tests

    - -

    The 'make runtests' and 'make tapfiles' build targets normally only run the -self-tests for the main EPICS_HOST_ARCH architecture. If the host is -able to execute self-test programs for other target architectures that are being -built by the host, such as when building a -debug version of the host -architecture for example, the names of those other architectures can be added to -the new CROSS_COMPILER_RUNTEST_ARCHS variable in either the -configure/CONFIG_SITE file or in an appropriate -configure/os/CONFIG_SITE.<host>.Common file to have the test -programs for those targets be run as well.

    - -

    Additional RELEASE file checks

    - -

    An additional check has been added at build-time for the contents of the -configure/RELEASE file(s), which will mostly only affect users of the Debian -EPICS packages published by NSLS-2. Support modules may share an install path, -but all such modules must be listed adjacent to each other in any RELEASE files -that point to them. For example the following will fail the new checks:

    - -
    -AUTOSAVE = /usr/lib/epics
    -ASYN = /home/mdavidsaver/asyn
    -EPICS_BASE = /usr/lib/epics
    -
    - -

    giving the compile-time error

    - -
    -This application's RELEASE file(s) define
    -	EPICS_BASE = /usr/lib/epics
    -after but not adjacent to
    -	AUTOSAVE = /usr/lib/epics
    -Module definitions that share paths must be grouped together.
    -Either remove a definition, or move it to a line immediately
    -above or below the other(s).
    -Any non-module definitions belong in configure/CONFIG_SITE.
    -
    - - -

    In many cases such as the one above the order of the AUTOSAVE and -ASYN lines can be swapped to let the checks pass, but if the -AUTOSAVE module depended on ASYN and hence had to appear -before it in the list this error indicates that AUTOSAVE should also be -built in its own private area; a shared copy would likely be incompatible with -the version of ASYN built in the home directory.

    - -

    String field buffer overflows

    - -

    Two buffer overflow bugs that can crash the IOC have been fixed, caused by -initializing a string field with a value larger than the field size -(Launchpad bug -#1563191).

    - -

    Fixed stack corruption bug in epicsThread C++ API

    - -

    The C++ interface to the epicsThread API could corrupt the stack on thread -exit in some rare circumstances, usually at program exit. This bug has been -fixed (Launchpad bug -#1558206).

    - -

    RTEMS NTP Support Issue

    - -

    On RTEMS the NTP Time Provider could in some circumstances get out of sync -with the server because the osdNTPGet() code wasn't clearing its input socket -before sending out a new request. This -(Launchpad bug 1549908) -has now been fixed.

    - -

    CALC engine bitwise operator fixes

    - -

    The bitwise operators in the CALC engine have been modified to work properly -with values that have bit 31 (0x80000000) set. This modification involved -back-porting some earlier changes from the 3.15 branch, and fixes -Launchpad bug -#1514520.

    - -

    Fix ipAddrToAsciiAsync(): Don't try to join the daemon thread

    - -

    On process exit, don't try to stop the worker thread that makes DNS lookups -asynchronous. Previously this would wait for any lookups still in progress, -delaying the exit unnecessarily. This was most obvious with catools (eg. -cainfo). -lp:1527636

    - -

    Fix epicsTime_localtime() on Windows

    - -

    Simpler versions of the epicsTime_gmtime() and epicsTime_localtime() -routines have been included in the Windows implementations, and a new test -program added. The original versions do not report DST status properly. Fixes -Launchpad bug 1528284.

    - - - - diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md new file mode 100644 index 000000000..2adeacf24 --- /dev/null +++ b/documentation/RELEASE_NOTES.md @@ -0,0 +1,1857 @@ +# EPICS 7.0 Release Notes + +These release notes describe changes that have been made since the previous +release of this series of EPICS Base. **Note that changes which were merged up +from commits to new releases in an older Base series are not described at the +top of this file but have entries that appear lower down, under the series to +which they were originally committed.** Thus it is important to read more than +just the first section to understand everything that has changed in each +release. + +The external PVA submodules each have their own separate set of release notes +which should also be read to understand what has changed since an earlier +release. + +## EPICS Release 7.0.3.1 + +**IMPORTANT NOTE:** *Some record types in this release will not be compatible +with device support binaries compiled against earlier versions of those record +types, because importing the record documentation from the EPICS Wiki +[as described below](#imported-record-reference-documentation-from-wiki) +also modified the order of some of the fields in the record definitions.* +As long as all support modules and IOCs are rebuilt from source after updating +them to use this release of EPICS Base, these changes should not have any +affect. + + +### logClient reliability + +On supported targets (Linux, Mac, Windows) logClient will attempt to avoid dropping +undelivered log messages when the connection to the log server is closed/reset. + +### Timers and delays use monotonic clock + +Many internal timers and delay calculations use a monotonic clock +epicsTimeGetMonotonic() instead of the realtime epicsTimeGetCurrent(). This is +intended to make IOCs less susceptible to jumps in system time. + +### Iocsh `on error ...` + +A new statement is added to enable IOC shell commands to signal error +conditions, and for scripts to respond. This first is through the new function + +```C + int iocshSetError(int err); +``` + +A script may be prefixed with eg. "on error break" to stop at the failed +command. + +```sh + on error continue | break | wait [value] | halt +``` + +A suggested form for IOC shell commands is: + +```C + static void doSomethingCallFunc(const iocshArgBuf *args) + { + iocshSetError(doSomething(...)); /* return 0 == success */ + } +``` + +### Relocatable Builds + +Allows built trees to be copied or moved without invalidating RPATH entires. + +The `LINKER_USE_RPATH` Makefile variable (see `configure/CONFIG_SITE`) may be +set to `YES`, `NO`, and a new third option `ORIGIN`. This is limited to +targets using the ELF executable format (eg. Linux). + +When `LINKER_USE_RPATH=ORIGIN`, the variable `LINKER_ORIGIN_ROOT` is set to +one of the parents of the build directory. Any libraries being linked +to which are found under this root will have a relative RPATH entry. +Other libraries continue to result in absolute RPATH entries. + +An effect of this might change a support library from being linked with +`-Wl,-rpath /build/epics-base/lib/linux-x86` +to being linked with +`-Wl,-rpath \$ORIGIN/../../../epics-base/lib/linux-x86` +if the support module directory is `/build/mymodule` +and `LINKER_ORIGIN_ROOT=/build`. + +The API functions `epicsGetExecDir()` and `epicsGetExecName()` are also +added to `osiFileName.h` to provide runtime access to the directory or +filename of the executable with which the process was started. + +### Decouple LINKER_USE_RPATH and STATIC_BUILD + +Previously, setting `STATIC_BUILD=NO` implied `LINKER_USE_RPATH=NO`. +This is no longer the case. Setting `LINKER_USE_RPATH=YES` will +always emit RPATH entries. This was found to be helpful when linking +against some 3rd party libraries which are only available as shared objects. + +### Channel Access Security: Check Hostname Against DNS + +Host names given in a `HAG` entry of an IOC's Access Security Configuration +File (ACF) have to date been compared against the hostname provided by the CA +client at connection time, which may or may not be the actual name of that +client. This allows rogue clients to pretend to be a different host, and the +IOC would believe them. + +An option is now available to cause an IOC to ask its operating system to look +up the IP address of any hostnames listed in its ACF (which will normally be +done using the DNS or the `/etc/hosts` file). The IOC will then compare the +resulting IP address against the client's actual IP address when checking +access permissions at connection time. This name resolution is performed at +ACF file load time, which has a few consequences: + + 1. If the DNS is slow when the names are resolved this will delay the process +of loading the ACF file. + + 2. If a host name cannot be resolved the IOC will proceed, but this host name +will never be matched. + + 3. Any changes in the hostname to IP address mapping will not be picked up by +the IOC unless and until the ACF file gets reloaded. + +Optionally, IP addresses may be added instead of, or in addition to, host +names in the ACF file. + +This feature can be enabled before `iocInit` with + +``` + var("asCheckClientIP",1) +``` + +or with the VxWorks target shell use + +```C + asCheckClientIP = 1 +``` + +### New and modified epicsThread APIs + +#### `epicsThreadCreateOpt()` + +A new routine `epicsThreadCreateOpt()` is an alternative to +`epicsThreadCreate()` which takes some arguments via a structure (`struct +epicsThreadOpts`) to allow for future extensions. + +```C + typedef struct epicsThreadOpts { + unsigned int priority; + unsigned int stackSize; + unsigned int joinable; + } epicsThreadOpts; + #define EPICS_THREAD_OPTS_INIT { \ + epicsThreadPriorityLow, epicsThreadStackMedium, 0} + epicsThreadId epicsThreadCreateOpt(const char * name, + EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts); +``` + +The final `opts` parameter may be `NULL` to use the default values of thread +priority (low) and stack size (medium). Callers wishing to provide alternative +settings for these thread options or to create a joinable thread (see below) +should create and pass in an `epicsThreadOpts` structure as shown below. +Always initialize one of these structures using the `EPICS_THREAD_OPTS_INIT` +macro to ensure that any additional fields that get added in the future are +set to their default values. + +```C + void startitup(void) { + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + epicsThreadId tid; + + opts.priority = epicsThreadPriorityMedium; + tid = epicsThreadCreateOpt("my thread", &threadMain, NULL, &opts); + } +``` + +C or C++ Code that also needs to build on earlier versions of Base can use +`#ifdef EPICS_THREAD_OPTS_INIT` to determine whether the +`epicsThreadCreateOpt()` API is available on this Base version. + +#### Thread stack sizes + +The `stackSize` member of the `epicsThreadOpts` structure and the equivalent +parameters to the `epicsThreadCreate()` and `epicsThreadMustCreate()` routines +can now be passed either one of the `epicsThreadStackSizeClass` enum values or +a value returned from the `epicsThreadGetStackSize()` routine. + +#### `epicsThreadMustJoin()` + +If the new `joinable` flag of an `epicsThreadOpts` structure is non-zero (the +default value is zero), the new API routine `epicsThreadMustJoin()` *must* be +called with the thread's `epicsThreadId` when/after the thread exits, to free +up thread resources. This function will block until the thread's main function +has returned, allowing the parent to wait for its child thread. The child's +`epicsThreadId` will no longer be valid and should not be used after the +`epicsThreadMustJoin()` routine returns. + +A thread that was originally created with its joinable flag set may itself +call `epicsThreadMustJoin()`, passing in its own epicsThreadId. This marks the +thread as no longer being joinable, so it will then free the thread resources +itself when its main function returns. The `epicsThreadId` of a thread that is +not joinable gets invalidated as soon as its main function returns. + +### Non-VME RTEMS targets now define pdevLibVME + +Previously IOC executables that made calls to devLib routines would fail to +link when built for some non-VME based RTEMS targets, which would have to be +explicitly filtered out by sites that build Base for those targets. [This +fix](https://bugs.launchpad.net/epics-base/+bug/1841692) makes that no longer +necessary, all RTEMS targets should now link although the IOC won't be able to +be used with the VME I/O on those systems (that we don't have VMEbus I/O +support for in libCom). + +## EPICS Release 7.0.3 + +### `epicsTimeGetCurrent()` optimization + +Add a fast path to epicsTimeGetCurrent() and related calls in the common case +where only the default OS current time provider is registered. This path does +not take the global mutex guarding the time providers list, potentially +reducing lock contention. + +### dbEvent tweak Queue size + +The size of the queue used by dbEvent to push monitor updates has been +slightly increased based on `DBR_TIME_DOUBLE` to better fill an ethernet frame. +This may result in slightly fewer, but larger frames being sent. + +### mbbo/mbbiDirect number of bits as precision + +Report NOBT as "precision" through the dbAccess API. This is not accessible +through CA, but is planned to be used through QSRV. + +## EPICS Release 7.0.2.2 + +### Build System changes + + * The GNUmake build targets `cvsclean` and `depclean` are now available from +any directory; previously they were only available from application top +directories. + + * The approach that EPICS Base uses for building submodules inside the parent +module looks useful for support modules too. The rules for building submodules +have been modified and extracted into a new `RULES_MODULES` file, so a support +module will be able to use them too without having to copy them into its own +`modules/Makefile`. There are some specific requirements that support modules +and their submodules must follow, which are described as comments in the new +`base/configure/RULES_MODULES` file itself. + +### `EPICS_BASE_VERSION` Update Policy change + +In the past, a build of EPICS using sources checked out from the repository +branch between official releases would have shown the version number of the +previous release, followed by a -DEV suffix, for example 7.0.2.1-DEV. + +The policy that controls when the number gets updated has been changed, and +now immediately after a release has been tagged the version number will be +updated to the next patch release version, plus the -DEV suffix as before. +Thus following 7.0.2.2 the version number will show as 7.0.2.3-DEV. This does +not require the next official release to be numbered 7.0.2.3 though, it could +become 7.0.3 or even 7.1.0 if the changes incorporated into it are more +substantial than bug fixes. + +### Drop `CLOCK_MONOTONIC_RAW` from posix/osdMonotonic.c + +Turns out this is ~10x slower to query than `CLOCK_MONOTONIC`. + +## EPICS Release 7.0.2.1 + +### Linking shared libraries on macOS + +The linker flag `-flat_namespace` has been restored for creating shared +libraries, although not for loadable libraries (bundles). This was required +for building using the latest versions of Apple XCode. + +### Fix `DB_LINK` loop breaking + +A regression was introduced in 7.0.2 which caused record chains with loops to +be incorrectly broken. Processing should be skipped when a `DB_LINK` with +Process Passive (PP) closes a loop to a synchronous record. + +Instead in 7.0.2 the targeted record would be processed if processing began +with a remote action (or some other caller of `dbPutField()`). This would +result in the loop running a second time. The loop would be broken on the +second iteration. + +[See lp: #1809570](https://bugs.launchpad.net/epics-base/+bug/1809570) + +### Old dbStaticLib APIs removed + +Support for some obsolete dbStaticLib Database Configuration Tool (DCT) APIs +was removed some time ago, but vestiges of them still remained. The following +routines and macros and have now finally been removed: + + * `int dbGetFieldType(DBENTRY *pdbentry)` + * `int dbGetLinkType(DBENTRY *pdbentry)` + * `DCT_STRING` + * `DCT_INTEGER` + * `DCT_REAL` + * `DCT_MENU` + * `DCT_MENUFORM` + * `DCT_INLINK` + * `DCT_OUTLINK` + * `DCT_FWDLINK` + * `DCT_NOACCESS` + * `DCT_LINK_CONSTANT` + * `DCT_LINK_FORM` + * `DCT_LINK_PV` + +### Fix for `dbhcr` before `iocInit` + +The `dbhcr` command used to work before `iocInit` as well as afterwards. It +displays all records that have hardware addresses (`VME_IO`, `CAMAC_IO`, +`GPIB_IO`, `INST_IO` etc.) but stopped working if run before iocInit due to the +rewrite of the link address parser code in dbStaticLib. This release fixes that +issue, although in some cases the output may be slightly different than it used +to be. + +## EPICS Release 7.0.2 + +### Launchpad Bugs + +The list of tracked bugs fixed in this release can be found on the +[Launchpad Milestone page for EPICS Base 7.0.2](https://launchpad.net/epics-base/+milestone/7.0.2). + +### Git Branches Recombined + +The four separate Git branches `core/master`, `libcom/master`, `ca/master` and +`database/master` have been recombined into one branch called `7.0`. Keeping +these as 4 separate branches in the same repository made it impossible to +create merge requests that contained changes in more than one of these +modules. The layout of the source files has not changed at all however, so the +source code for libcom, ca and the database are still found separately under +the module subdirectory. + +## EPICS Release 7.0.1.1 + +### Changed SIML failure behavior + +A failure when fetching the simulation mode through `SIML` will not put the +record into INVALID alarm state anymore. Instead, as long as the record's +current alarm severity (`SEVR`)is `NO_ALARM`, its alarm status (`STAT`) will be +set to `LINK_ALARM` without increasing the severity. This allows clients to get +some notification of a failing or bad `SIML` link without otherwise affecting +record processing. + +### `dbVerify()` has been restored to dbStaticLib + +This routine was removed in Base-3.16.1 but has been reimplemented in this +release by special request. Note that the error message strings that it +returns when verification fails have changed, but are still designed for +display to the user. + +### Simulation mode improvements + +Records that support simulation mode have two new fields, `SSCN` (Simulation +Scan Mode) and `SDLY` (Simulation Delay). `SSCN` is a menu field that provides +an alternate value for the `SCAN` field to be used while the record is in +simulation mode. This is especially useful for I/O scanned records, for which +simulation mode was not working at all. Setting `SDLY` to a positive value +makes the record process asynchronously in simulation mode, with the second +stage processing happening after the specified time (in seconds). + +### Extend the dbServer API with init/run/pause/stop methods + +This change permits IOCs to be built that omit the CA server (RSRV) by +removing its registrar entry which is now provided in the new `rsrv.dbd` file. +Other server layers can be built into the IOC (alongside RSRV or in place of +it) by registering them in a similar manner. The dbServer API is documented +with Doxygen comments in the header file. + +Specific IOC server layers can be disabled at runtime by adding their name to +the environment variable `EPICS_IOC_IGNORE_SERVERS` (separated by spaces if more +than one should be ignored). + +### Grand source-code reorganization + +EPICS 7.0.1 contains the IOC Database, RSRV server and the Channel Access +client code from EPICS Base 3.16.1 along with all the original record types +and soft device support, but GDD and the Portable Channel Access Server have +been unbundled and are now available separately. In their place we have +brought in the more recently written EPICS V4 C++ libraries (collectively +referred to as the PVA modules). The directory tree for EPICS is somewhat +larger as a result, and the original structure of the Base directories has +been split into 4 separate Git repositories. External modules should build +against this new structure with little or no changes needed, except that some +allowance may be needed for the merging of the V4 modules. + +There should be rather more description and documantation of these changes +than is currently available, but as developers we generally much prefer to +write code than documentation. Send questions to the tech-talk mailing list +and we'll be happy to try and answer them! + +## Changes between 3.16.1 and 3.16.2 + +The list of tracked bugs fixed in this release can be found on the +[Launchpad Milestone page for EPICS Base 3.16.2](https://launchpad.net/epics-base/+milestone/3.16.2). + +### Status reporting for the callback and scanOnce task queues + +Two new iocsh commands and some associated underlying APIs have been added to +show the state of the queues that feed the three callback tasks and the +scanOnce task, including a high-water mark which can optionally be reset. The +new iocsh commands are `callbackQueueShow` and `scanOnceQueueShow`; both take +an optional integer argument which must be non-zero to reset the high-water +mark. + +### Support for event codes greater than or equal to `NUM_TIME_EVENTS` + +Event numbers greater than or equal to `NUM_TIME_EVENTS` are now allowed if +supported by the registered event time provider, which must provide its own +advancing timestamp validation for such events. + +Time events numbered 0 through `(NUM_TIME_EVENTS-1)` are still validated by code +in epicsGeneralTime.c that checks for advancing timestamps and enforces that +restriction. + +### Type-safe Device and Driver Support Tables + +Type-safe versions of the device and driver support structures `dset` and +`drvet` 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. + +The old structure definitions will be replaced by the new ones if the macros +`USE_TYPED_DSET` and/or `USE_TYPED_DRVET` are defined when the appropriate +header is included. The best place to define these is in the Makefile, as with +the `USE_TYPED_RSET` 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 +[this commit](https://github.com/epics-modules/ipac/commit/a7e0ff4089b9aa39108bc8569e95ba7fcf07cee9) +to the ipac module to see a module conversion. + +A helper function `DBLINK* dbGetDevLink(dbCommon *prec)` has also been added +to devSup.h which fetches a pointer to the INP or OUT field of the record. + +### RTEMS build configuration update, running tests under QEMU + +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 (`qemu-system-i386`). It is also now +possible to create sub-architectures of RTEMS targets, whereas previously the +EPICS target architecture name had to be `RTEMS-$(RTEMS_BSP)`. + +The new target `RTEMS-pc386-qemu` builds binaries that can be run in the +`qemu-system-i386` PC System emulator. This target is a derivative of the +original `RTEMS-pc386` 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 `make +runtests`) will also run the tests for RTEMS using QEMU. + +To allow the new 3-component RTEMS target name, the EPICS build system for +RTEMS was modified to allow a `configure/os/CONFIG.Common.` file to set +the `RTEMS_BSP` variable to inform the build what RTEMS BSP to use. Previously +this was inferred from the value of the `T_A` 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 `RTEMS_BSP` if it hasn't been set when needed. + +### Link type enhancements + +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 +`jlink::debug` 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. + +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. + +A new `start_child()` method was added to the end of the jlif interface table. + +The `lset` 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. + +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 +`parse_start_map()` method. The `jlif_key_result` enum now contains 3 values +`jlif_key_child_inlink`, `jlif_key_child_outlink` and `jlif_key_child_fwdlink` +instead of the single `jlif_key_child_link` that was previously used for this. + +### GNUmake targets for debugging + +Some additional build rules have been added to help debug configuration +problems with the build system. Run `make show-makefiles` to get a sorted list +of all the files that the build system includes when building in the current +directory. + +A new pattern rule for `PRINT.%` 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 `O.` build +directory). For example `make PRINT.T_A` will display the build target +architecture name from inside a `O.` directory but the variable will be +empty from an application top or src directory. `make PRINT.EPICS_BASE` will +show the path to Base from any EPICS application directory though. + +### Propagate PUTF across Asynchronous record processing + +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. + +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 `dbAccessDebugPUTF` is set in addition to TPRO. + +### Finding info fields + +A new iocsh command `dbli` lists the info fields defined in the database, and +can take a glob pattern to limit output to specific info names. The newly +added dbStaticLib function `dbNextMatchingInfo()` iterates through the info +fields defined in the current record, and is used to implement the new +command. + +### Output from `dbpr` command enhanced + +The "DataBase Print Record" command `dbpr` now generates slightly better +output, with more field types having their own display methods. This release +also includes additional protection against buffer overflows while printing +long links in `dbpr`, and corrects the output of long strings from the `dbgf` +command. + +### Record types mbbiDirect and mbboDirect upgraded to 32 bit + +The VAL fields and related fields of these records are now `DBF_LONG`. (Not +`DBF_ULONG` in order to prevent Channel Access from promoting them to +`DBF_DOUBLE`.) Additional bit fields `B10`...`B1F` have been added. + +Device support that accesses `VAL` or the bit fields directly (most don't) and +aims for compatibility with old and new versions of these records should use +at least 32 bit integer types to avoid bit loss. The number of bit fields can +be calculated using `8 * sizeof(prec->val)` which is correct in both versions. + +### Restore use of ledlib for VxWorks command editing + +The epicsReadline refactoring work described below unfortunately disabled the +VxWorks implementation of the osdReadline.c API that uses ledlib for command +editing and history. This functionality has now been restored, see Launchpad +[bug #1741578](https://bugs.launchpad.net/bugs/1741578). + +### Constant link types + +Constant links can now hold 64-bit integer values, either as scalars or +arrays. Only base 10 is supported by the JSON parser though, the JSON standard +doesn't allow for hexadecimal numbers. + +### Upgraded the YAJL JSON Library + +The third-party YAJL library that has been included in libCom for several +years has been upgraded to version 2.1.0 and several bugs fixed. This has an +updated API, requiring any code that uses it to parse its own JSON files to be +modified to match. The changes are mainly that it uses `size_t` instead +`unsigned int` for string lengths, but it also uses `long long` instead of +`long` for JSON integer values, which was the main motivation for the upgrade. + +The self-tests that YAJL comes with have been imported and are now run as an +EPICS Unit Test program, and the JSON syntax accepted by the parser was +extended to permit trailing commas in both arrays and maps. The difference +between the old and new YAJL APIs can be detected at compile time by looking +for the macro `EPICS_YAJL_VERSION` which is defined in the `yajl_common.h` +header file along with a brief description of the API changes. + +### Timestamp support for the calc link type + +A new optional parameter can be given when specifying a calc JSON link. The +`time` parameter is a string containing a single letter `A..L` that selects +one of the input links to be used for the timestamp of calculation if +requested. The timestamp will be fetched atomically with the value from the +chosen input link (providing that input link type supports the readLocked() +method). + +### Silence errors from puts to constant link types + +A soft channel output record with the OUT link unset uses the CONSTANT link +type. The new link type code was causing some soft channel device supports to +return an error status from the write method of that link type, which would +cause a `ca_put()` operation to such a record to generate an exception. This has +been silenced by giving the constant link types a dummy putValue method. A new +test program has been added to prevent regressions of this behaviour. + +### RSRV expanding large buffer causes crash + +In the 3.16.1 release a crash can occur in the IOC's RSRV server when a large +array is made even larger; the previous array buffer was not being released +correctly. See Launchpad +[bug #1706703](https://bugs.launchpad.net/epics-base/+bug/1706703). + +## Changes made between 3.16.0.1 and 3.16.1 + +### IOC Database Support for 64-bit integers + +The IOC now supports the 64-bit integer field types `DBF_INT64` and +`DBF_UINT64`, and there are new record types `int64in` and `int64out` derived +from the `longin` and `longout` types respectively that use the `DBF_INT64` +data type for their VAL and related fields. The usual range of Soft Channel +device support are included for these new record types. + +All internal IOC APIs such as dbAccess can handle the new field types and +their associated request values `DBR_INT64` and `DBR_UINT64`, which are +implemented using the `epicsInt64` and `epicsUInt64` typedef's from the +`epicsTypes.h` header. + +The waveform record type has been updated to support these new field types. +**All waveform device support layers must be updated to recognize the new type +enumeration values**, which had to be inserted before the `FLOAT` value in the +enum `dbfType` and in `menuFtype`. C or C++ code can detect at compile-time +whether this version of base provides 64-bit support by checking for the +presence of the `DBR_INT64` macro as follows (Note that `DBF_INT64` is an +enum tag and not a preprocessor macro): + +``` + #ifdef DBR_INT64 + /* Code where Base has INT64 support */ + #else + /* Code for older versions */ + #endif +``` + +If the code uses the old `db_access.h` types (probably because it's calling +Channel Access APIs) then it will have to test against the EPICS version +number instead, like this: + +``` + #include + + #ifndef VERSION_INT + # define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P)) + #endif + #ifndef EPICS_VERSION_INT + # define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL) + #endif + + #if EPICS_VERSION_INT >= VERSION_INT(3,16,1,0) + /* Code where Base has INT64 support */ + #else + /* Code for older versions */ + #endif +``` + +Channel Access does not (and probably never will) directly support 64-bit +integer types, so the new field types are presented to the CA server as +`DBF_DOUBLE` values. This means that field values larger than 2^52 +(0x10_0000_0000_0000 = 4503599627370496) cannot be transported over Channel +Access without their least significant bits being truncated. The EPICS V4 +pvAccess network protocol _can_ transport 64-bit data types however, and a +future release of the pvaSrv module will connect this ability to the fields of +the IOC. + +Additional 64-bit support will be provided in later release. For instance the +JSON parser for the new Link Support feature only handles integers up to 32 +bits wide, so constant array initializer values cannot hold larger values in +this release. + +### Add `EPICS_CA_MCAST_TTL` + +A new environment parameter `EPICS_CA_MCAST_TTL` is used to set the Time To Live +(TTL) value of any IP multi-cast CA search or beacon packets sent. + +### `EPICS_CA_MAX_ARRAY_BYTES` is optional + +A new environment parameter `EPICS_CA_AUTO_ARRAY_BYTES` is now used by libca and +RSRV (CA clients and the IOC CA server). The default is equivalent to setting +`EPICS_CA_AUTO_ARRAY_BYTES=YES` which removes the need to set +`EPICS_CA_MAX_ARRAY_BYTES` and always attempts to allocate sufficiently large +network buffers to transfer large arrays properly over the network. In this case +the value of the `EPICS_CA_MAX_ARRAY_BYTES` parameter is ignored. + +Explicitly setting `EPICS_CA_AUTO_ARRAY_BYTES=NO` will continue to honor the +buffer setting in `EPICS_CA_AUTO_ARRAY_BYTES` as in previous releases. + +The default setting for `EPICS_CA_AUTO_ARRAY_BYTES` can be changed by adding the +line + +```makefile + EPICS_CA_AUTO_ARRAY_BYTES=NO +``` + +to the `configure/CONFIG_SITE_ENV` file before building Base. Sites that wish to +override this only for specific IOC architectures can create new files for each +architecture named `configure/os/CONFIG_SITE_ENV.` with the above +setting in before building Base. The configuration can also be explicitly +changed by setting the environment variable in the IOC's startup script, +anywhere above the `iocInit` line. + +The PCAS server (used by the PV Gateway and other CA servers) now always behaves +as if `EPICS_CA_AUTO_ARRAY_BYTES` is set to `YES` (it ignores the configuration +parameter and environment variable). + +### Channel Access "modernization" + +Drop support for CA clients advertising protocol versions less than 4. + +This effects clients from Base older than 3.12.0-beta1. Newer clients will +continue to be able to connect to older servers. Older clients will be ignored +by newer servers. + +This allows removal of UDP echo and similar protocol features which are not +compatible with secure protocol design practice. + +### Lookup-tables using the subArrray record + +The subArray record can now be used as a lookup-table from a constant array +specified in its INP field. For example: + +``` + record(subArray, "powers-of-2") { + field(FTVL, "LONG") + field(MALM, 12) + field(INP, [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]) + field(INDX, 0) + field(NELM, 1) + } +``` + +The INDX field selects which power of 2 to set the VAL field to. In previous +releases the INP field would have to have been pointed to a separate waveform +record that was initialized with the array values somehow at initialization +time. + +### Synchronized Timestamps with TSEL=-2 + +Most Soft Channel input device support routines have supported fetching the +timestamp through the INP link along with the input data. However before now +there was no guarantee that the timestamp provided by a CA link came from the +same update as the data, since the two were read from the CA input buffer at +separate times without maintaining a lock on that buffer in between. This +shortcoming could be fixed as a result of the new link support code, which +allows code using a link to pass a subroutine to the link type which will be +run with the link locked. The subroutine may make multiple requests for +metadata from the link, but must not block. + +### Extensible Link Types + +A major new feature introduced with this release of EPICS Base is an +Extensible Link Type mechanism, also known as Link Support or JSON Link Types. +This addition permits new kinds of link I/O to be added to an IOC in a similar +manner to the other extension points already supported (e.g. record, device +and driver support). + +A new link type must implement two related APIs, one for parsing the JSON +string which provides the link address and the other which implements the link +operations that get called at run-time to perform I/O. The link type is built +into the IOC by providing a new `link` entry in a DBD file. + +#### New Link Types Added + +This release contains two new JSON link types, `const` and `calc`: + + * The `const` link type is almost equivalent to the old CONSTANT link type +with the updates described below to accept arrays and strings, except that +there is no need to wrap a scalar string constant inside array brackets since +a constant string will never be confused with a PV name. + + * The `calc` link type allows CALC expressions to be used to combine +values from other JSON links to produce its value. Until additional JSON link +types are created though, the `calc` link type has little practical utility as +it can currently only fetch inputs from other `calc` links or from `const` +links. + +``` + field(INP, {calc:{expr:"A+B+1", + args:[5, # A + {const:6}] # B + } + } + ) +``` + +The new link types are documented in a separate document that gets generated at build time and installed as `html/links.html`. + +#### Device Support Addressing using `JSON_LINK` + +The API to allow device support to use JSON addresses is currently +incomplete; developers are advised not to try creating device support that +specifies a `JSON_LINK` address type. + +#### Support Routine Modifications for Extensible Link Types + +For link fields in external record types and soft device support to be able +to use the new link types properly, various changes are required to utilize +the new Link Support API as defined in the dbLink.h header file and outlined +below. The existing built-in Database and Channel Access link types have been +altered to implement the link APIs, so will work properly after these +conversions: + + * Make all calls to `recGblInitConstantLink()` unconditional on the link +type, i.e. change this code: + +```C + if (prec->siml.type == CONSTANT) { + recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm); + } +``` + + into this: + +```C + recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm); +``` + + Note that `recGblInitConstantLink()` still returns TRUE if the field was + successfully initialized from the link (implying the link is constant). + This change will work properly with all Base releases currently in use. + + * Code that needs to identify a constant link should be modified to use +the new routine `dbLinkIsConstant()` instead, which returns TRUE for constant +or undefined links, FALSE for links whose `dbGetLink()` routine may return +different values on different calls. For example this: + +```C + if (prec->dol.type != CONSTANT) +``` + + should become this: + +```C + if (!dbLinkIsConstant(&prec->dol)) +``` + + When the converted software is also required to build against older versions + of Base, this macro definition may be useful: + +```C + #define dbLinkIsConstant(lnk) ((lnk)->type == CONSTANT) +``` + + * Any code that calls dbCa routines directly, or that explicitly checks if +a link has been resolved as a CA link using code such as + +```C + if (prec->inp.type == CA_LINK) +``` + + will still compile and run, but will only work properly with the old CA link + type. To operate with the new extensible link types such code must be + modified to use the new generic routines defined in dbLink.h and should + never attempt to examine or modify data inside the link. After conversion + the above line would probably become: + +```C + if (dbLinkIsVolatile(&prec->inp)) +``` + + A volatile link is one like a Channel Access link which may disconnect and + reconnect without notice at runtime. Database links and constant links are + not volatile; unless their link address is changed they will always remain + in the same state they started in. For compatibility when building against + older versions of Base, this macro definition may be useful: + +```C + #define dbLinkIsVolatile(lnk) ((lnk)->type == CA_LINK) +``` + + * The current connection state of a volatile link can be found using the +routine `dbIsLinkConnected()` which will only return TRUE for a volatile link +that is currently connected. Code using the older dbCa API returning this +information used to look like this: + +```C + stat = dbCaIsLinkConnected(plink); +``` + + which should become: + +```C + stat = dbIsLinkConnected(plink); +``` + + Similar changes should be made for calls to the other dbCa routines. + + * A full example can be found by looking at the changes to the calcout +record type, which has been modified in this release to use the new dbLink +generic API. + +### Constant Link Values + +Previously a constant link (i.e. a link that did not point to another PV, +either locally or over Channel Access) was only able to provide a single +numeric value to a record initialization; any string given in a link field +that was not recognized as a number was treated as a PV name. In this release, +constant links can be expressed using JSON array syntax and may provide array +initialization of values containing integers, doubles or strings. An array +containing a single string value can also be used to initialize scalar +strings, so the stringin, stringout, lsi (long string input), lso (long string +output), printf, waveform, subArray and aai (analog array input) record types +and/or their soft device supports have been modified to support this. + +Some examples of constant array and string initialized records are: + +``` + record(stringin, "const:string") { + field(INP, ["Not-a-PV-name"]) + } + record(waveform, "const:longs") { + field(FTVL, LONG) + field(NELM, 10) + field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + } + record(aai, "const:doubles") { + field(FTVL, DOUBLE) + field(NELM, 10) + field(INP, [0, 1, 1.6e-19, 2.718, 3.141593]) + } + record(aSub, "select") { + field(FTA, STRING) + field(NOA, 4) + field(INPA, ["Zero", "One", "Two", "Three"]) + field(FTB, SHORT) + field(NOB, 1) + field(FTVA, STRING) + field(NOVA, 1) + field(SNAM, "select_asub") + } +``` + +Reminder: Link initialization with constant values normally only occurs at +record initialization time. The calcout and printf record types are the only +exceptions in the Base record types to this rule, so it is generally not +useful to change a const link value after iocInit. + +### Database Parsing of "Relaxed JSON" Values + +A database file can now provide a "relaxed JSON" value for a database field +value or an info tag. Only a few field types can currently accept such values, +but the capability is now available for use in other places in the future. +When writing to a JSON-capable field at run-time however, only strictly +compliant JSON may be used (the dbStaticLib parser rewrites relaxed JSON +values into strict JSON before passing them to the datase for interpretation, +where the strict rules must be followed). + +"Relaxed JSON" was developed to maximize compatibility with the previous +database parser rules and reduce the number of double-quotes that would be +needed for strict JSON syntax. The parser does accept strict JSON too though, +which should be used when machine-generating database files. The differences +are: + + * Strings containing only the characters `a-z A-Z 0-9 _ - + .` do not have to +be enclosed in double-quote characters. + + * The above rule applies to map keys as well as to regular string values. + + * The JSON keywords `null`, `true` and `false` (all lower-case) will be +recognized as keywords, so they must be quoted to use any of these single words +as a string. + + * Comments may be used, introduced as usual by the `#` character and extending +to the end of the line. + +A JSON field or info value is only enclosed in quotes when the value being +provided is a single string, and even here the quotes can be omitted in some +cases as described above. The following shows both correct and incorrect +excerpts from a database file: + +``` + record(ai, math:pi) { + field(INP, {const: 3.14159265358979}) # Correct + field(SIOL, "{const: 3.142857}") # Wrong + + info(autosave, { # White-space and comments are allowed + fields:[DESC, SIMM], + pass0:[VAL] + }) # Correct + } +``` + +Note that the record, field and info-tag names do *not* accept JSON values, so +they follows the older bareword rules for quoting where the colon `:` and +several additional characters are legal in a bareword string. Only the value +(after the comma) is parsed as JSON. The autosave module has not been modified +to accept JSON syntax, the above is only an example of how JSON might be used. + +### Echoless comments in iocsh + +The way comments are parsed by the iocsh interpreter has changed. The +interpreter can be selectively disabled from echoing comments coming from a +script by starting those lines with `#-` rather than just `#`. + +### Typed record support methods + +The table of record support functions (rset methods for short) no longer has +entries of type `RECSUPFUN` (which says: any number and type of arguments). +Instead, rset methods are now typed by default. The `RECSUPFUN` typedef has +been deprecated and casts to it as well as using the untyped `struct rset` +will create compilation warnings. + +Existing code (e.g. external record supports) will generate such warnings when +compiled against this version of Base, but it will work without changes. + +For a conversion period, the new typed rset definitions are activated by +defining `USE_TYPED_RSET`, preferably by setting `USR_CPPFLAGS += +-DUSE_TYPED_RSET` inside a Makefile. After activating the new typed rset in +this way and making the following changes, the result should still compile and +work properly against older versions of Base. + +The first parameter of `init_record` and `process` has been changed to `struct +dbCommon *`. Record types that use `void*` here should be changed to use +`struct dbCommon*`, and cast the argument to their own `xxxRecord *`. + +When compiled against this release, compiler warnings about incompatible types +for the method pointers should be taken seriously. When compiled against older +versions of base, such warnings are unavoidable. + +Record types written in C++ need to take more drastic measures because of the +stricter type checking in C++. To remain compatible with older versions of +base you will need to use something like: + +``` + #include "epicsVersion.h" + #ifdef VERSION_INT + # if EPICS_VERSION_INT < VERSION_INT(3,16,0,2) + # define RECSUPFUN_CAST (RECSUPFUN) + # else + # define RECSUPFUN_CAST + # endif + #else + # define RECSUPFUN_CAST (RECSUPFUN) + #endif +``` + +and then replace `(RECSUPFUN)` with `RECSUPFUN_CAST` when initializing the +rset. Further changes might also be needed, e.g. to adapt `const`-ness of +method parameters. + + +## Changes made between 3.15.3 and 3.16.0.1 + +### Build support for CapFast and dbst removed + +The build rules associated with the CapFast-related tools `sch2edif` and +`e2db` and the database optimization tool `dbst` have been removed, along with +the `DB_OPT` build configuration variable. + +### compressRecord buffering order + +The compressRecord has a new field `BALG` which can select between FIFO +(append) and LIFO (prepend) ordering for insertion of new elements. FIFO +ordering is the default, matching the behviour of previous versions. + +### Valgrind Instrumentation + +Valgrind is a software debugging suite provided by many Linux distributions. +The header valgrind/valgrind.h is now included in, and installed by, Base. +When included by a C or C++ source file this header defines some macros which +expand to provide hints to the Valgrind runtime. These have no effect on +normal operation of the software, but when run using the valgrind tool they +can help to find memory leaks and buffer overflows. Suitable hints have been +added to several free-lists within libCom, including freeListLib, allowing +valgrind to provide more accurate information about the source of potential +leaks. + +valgrind.h automatically disables itself when the build target is not +supported by the valgrind tool. It can also explicitly be disabled by defining +the macro `NVALGRIND`. See `src/libCom/Makefile` for a commented-out example. + +As a matter of policy valgrind.h will never be included by any header file +installed by Base, so its use will remain purely an implementation detail +hidden from application software. Support modules which choose to use +valgrind.h are advised to do likewise. + +### Database Multi-locking + +The IOC record locking code has been re-written with an expanded API; global +locks are no longer required by the IOC database implementation. + +The new API functions center around `dbScanLockMany()`, which behaves like +`dbScanLock()` applied to an arbitrary group of records. `dbLockerAlloc()` is +used to prepare a list or record pointers, then `dbScanLockMany()` is called. +When it returns, all of the records listed may be accessed (in any order) until +`dbScanUnlockMany()` is called. + +The Application Developer's Guide has been updated to describe the API and +implementation is more detail. + +Previously a global mutex `lockSetModifyLock` was locked and unlocked during +`dbScanLock()`, acting as a sequencing point for otherwise unrelated calls. The +new dbLock.c implementation does not include any global mutex in `dbScanLock()` +or `dbScanLockMany()`. Locking and unlocking of unrelated lock sets is now +completely concurrent. + +### Generate Version Header + +A Perl script and Makefile rules have been added to allow modules to generate +a C header file with a macro defined with an automatically updated identifier. +This is a VCS revision ID (Darcs, Git, Mercurial, Subversion, and Bazaar are +supported) or the date/time of the build if no VCS system is in use. + +The makeBaseApp example template has been updated with a new device support +which makes this identifier visible via a lsi (long string input) record. + +### epicsTime API return status + +The epicsTime routines that used to return epicsTimeERROR now return a +specific `S_time_` status value, allowing the caller to discover the reason for +any failure. The identifier `epicsTimeERROR` is no longer defined, so any +references to it in source code will no longer compile. The identifier +epicsTimeOK still exists and has the value 0 as before, so most code that uses +these APIs can be changed in a way that is backwards-compatible with the +previous return status. + +Time providers that have to return a status value and still need to be built +with earlier versions of Base can define the necessary status symbols like +this: + +``` + #include "epicsTime.h" + + #ifndef M_time + /* S_time_... status values were not provided before Base 3.16 */ + #define S_time_unsynchronized epicsTimeERROR + #define S_time_...whatever... epicsTimeERROR + #endif +``` + +### Refactoring of epicsReadline + +The epicsReadline code has been reorganized to allow the commandline history +editor to be disabled at runtime. The `EPICS_COMMANDLINE_LIBRARY` build setting +still selects the preferred editor, but the new `IOCSH_HISTEDIT_DISABLE` +environment variable can be set at runtime to disable history editing and make +the IOC or other program use the basic editor instead. This is useful when +starting and controlling an IOC from another program through its stdin and +stdout streams since history editors often insert invisible escape codes into +the stdout stream, making it hard to parse. + +### Callback subsystem API + +Added a new macro `callbackGetPriority(prio, callback)` to the callback.h +header and removed the need for dbScan.c to reach into the internals of its +`CALLBACK` objects. + +## Changes from the 3.15 branch since 3.15.7 + +> None. + +## Changes made between 3.15.6 and 3.15.7 + +### GNU Readline detection on Linux + +Most Linux architectures should now configure themselves automatically to use +the GNU Readline library if its main header file can be found in the expected +place, and not try to use Readline if the header file isn't present. For older +Linux architectures where libncurses or libcurses must also be linked with, the +manual configuration of the `COMMANDLINE_LIBRARY` variable in the appropriate +`configure/os/CONFIG_SITE.Common.` file will still be necessary. + +### Replace `EPICS_TIMEZONE` with `EPICS_TZ` + +The `EPICS_TIMEZONE` environment parameter provided time-zone information for +the IOC's locale in the old ANSI format expected by VxWorks for its `TIMEZONE` +environment variable, and can also used by RTEMS to set its `TZ` environment +variable. However the `TIMEZONE` value has to be updated every year since it +contains the exact dates of the daylight-savings time changes. The Posix TZ +format that RTEMS uses contains rules that for calculating those dates, thus its +value would only need updating if the rules (or the locale) are changed. + +This release contains changes that replace the `EPICS_TIMEZONE` environment +parameter with one called `EPICS_TZ` and a routine for VxWorks that calculates +the `TIMEZONE` environment variable from the current `TZ` value. This routine +will be run once at start-up, when the EPICS clock has synchronized to its NTP +server. The calculations it contains were worked out and donated to EPICS by +Larry Hoff in 2009; it is unforunate that it has taken 10 years for them to be +integrated into Base. + +The default value for the `EPICS_TZ` environment parameter is set in the Base +`configure/CONFIG_SITE_ENV` file, which contains example settings for most EPICS +sites that use VxWorks, and a link to a page describing the Posix TZ format for +any locations that I missed. + +If a VxWorks IOC runs continuously without being rebooted from December 31st to +the start of daylight savings time the following year, its `TIMEZONE` value will +be wrong as it was calculated for the previous year. This only affects times +that are converted to a string on the IOC however and is easily fixed; just run +the command `tz2timezone()` on the VxWorks shell and the calculation will be +redone for the current year. IOCs that get rebooted at least once before the +start of summer time will not need this to be done. + +### Added new decimation channel filter + +A new server-side filter has been added to the IOC for reducing the number +and frequency of monitor updates from a channel by a client-specified factor. +The filter's behaviour is quite simplistic, it passes the first monitor event it +sees to the client and then drops the next N-1 events before passing another +event. For example to sample a 60Hz channel at 1Hz, a 10Hz channel every 6 +seconds, or a 1Hz channel once every minute: + +``` + Hal$ camonitor 'test:channel.{"dec":{"n":60}}' + ... +``` + +More information is included in the filters documentation, which can be found +in the `html/filters.html` document that is generated during the build. + +### Imported Record Reference Documentation from Wiki + +The remaining record types that had 3.14 reference documentation in the EPICS +Wiki have had that documentation converted and imported into their DBD files. +The preferred form for future updates to the record type descriptions is now an +emailed patch file, a Pull Request through GitHub, or a Merge Request through +Launchpad. Note that in some cases the behavior of a record type in a 7.0.x +release may differ from that of the same record type in a 3.15 release, although +this would be unusual, so it may be important to indicate the branch that your +changes apply to. + +**NOTE:** *These documentation changes have modified the order of the fields in +some record definitions. As a result this release is not compatible with record +or device support binaries that were compiled against earlier releases.* + +### `make test-results` for Windows + +The make target `test-results` should now work properly on Windows. Some Perl +installations used versions of `prove.bat` that would only display the results of +up to 3 tests or didn't return an error status in the event of tests failing. The +build system now calls its own perl script to summarize the results instead of +passing a list of TAP filenames to `prove`. + +### Add option to avoid CALLBACK conflict + +If a macro `EPICS_NO_CALLBACK` is defined, then callback.h will no longer +(re)define CALLBACK. The name `CALLBACK` is used by the WIN32 API, and +redefinition in callback.h cause errors if some windows headers are later +included. + +Code which defines `EPICS_NO_CALLBACK`, but still wishes to use callbacks, +should use the alternate name `epicsCallback` introduced in 3.15.6, 3.16.2, and +7.0.2. It is also possible, though not encouraged, to use `struct callbackPvt` +which has been present since the callback API was introduced. + +### Cleaning up with Multiple CA contexts in a Process + +Bruno Martins reported a problem with the CA client library at shutdown in a +process that uses multiple CA client contexts. The first context that triggers +the CA client exit handler prevents any others from being able to clean up +because it resets the ID of an internal epicsThreadPrivate variable which is +shared by all clients. This action has been removed from the client library, +which makes cleanup of clients like this possible. + +### Perl CA bindings fixed for macOS Mojave + +Apple removed some Perl header files from macOS Mojave that were available +in their SDK, requiring a change to the include paths used when compiling the +CA bindings. The new version should build on new and older macOS versions, and +these changes may also help other targets that have an incomplete installation +of Perl (the build will continue after printing a warning that the Perl CA +bindings could not be built). + +### Routine `epicsTempName()` removed from libCom + +This routine was a simple wrapper around the C89 function `tmpnam()` +which is now seen as unsafe and causes warning messages to be generated by +most modern compilers. The two internal uses of this function have been +modified to call `epicsTempFile()` instead. We were unable to find any +published code that used this function, so it was removed immediately instead +of being deprecated. + +### DBD Parsing of Record Types + +The Perl DBD file parser has been made slightly more liberal; the order in +which DBD files must be parsed is now more flexible, so that a record type +definition can now be parsed after a device support that referred to that +record type. A warning message will be displayed when the device support is +seen, but the subsequent loading of the record type will be accepted without +triggering an error. See +[Launchpad bug 1801145](https://bugs.launchpad.net/epics-base/+bug/1801145). + +### menuScan and several record types documented with POD + +The EPICS Wiki pages describing a number of standard record types has been +converted into the Perl POD documentation format and added to the DBD files, +so at build-time an HTML version of these documents is generated and installed +into the htmls directory. Thanks to Tony Pietryla. + +### CA client tools learned `-V` option + +This displays the version numbers of EPICS Base and the CA protocol. + +## Changes made between 3.15.5 and 3.15.6 + +### Unsetting environment variables + +The new command `epicsEnvUnset varname` can be used to +unset an environment variable. + +### Warning indicators in msi (and macLib) output + +The libCom macro expansion library has been modified so that when the +`SUPPRESS_WARNINGS` flag is set it will no longer include any `,undefined` +or `,recursive` 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 `msi` +tool was used to generate other kinds of files they caused problems. If the +`msi -V` flag is used the markers will still be present in the output +whenever the appropriate condition is seen. + +### Improvements to msi + +In addition to fixing its response to discovering parsing errors in its +substitution input file (reported as Launchpad +[bug 1503661](https://bugs.launchpad.net/epics-base/+bug/1503661)) +so it now deletes the incomplete output file, the msi program has been cleaned +up a little bit internally. + +### All array records now post monitors on their array-length fields + +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 +[Launchpad bug 1730727](https://bugs.launchpad.net/epics-base/+bug/1730727). + +### HOWTO: Converting Wiki Record Reference to POD + +Some documentation has been added to the `dbdToHtml.pl` script +explaining how Perl POD (Plain Old Documentation) markup can be added to +`.dbd` files to generate HTML documentation for the record types. To see +these instructions, run `perl bin//dbdToHtml.pl -H` +or `perldoc bin//dbdToHtml.pl`. + +### Fix problem with numeric soft events + +Changing from numeric to named soft events introduced an incompatibility +when a numeric event 1-255 is converted from a DOUBLE, e.g. from a calc record. +The `post_event()` API is not marked deprecated any more. + +Also `scanpel` has been modified to accept a glob pattern for +event name filtering and to show events with no connected records as well. + +### Add `osiSockOptMcastLoop_t` and osiSockTest + +Added a new OS-independent typedef for multicast socket options, and a test +file to check their correct operation. + +### Support for `CONFIG_SITE.local` in Base + +This feature is mostly meant for use by developers; configuration +settings that would normally appear in `base/configure/CONFIG_SITE` can now +be put in a locally created `base/configure/CONFIG_SITE.local` file instead +of having go modify or replace the original. A new `.gitignore` pattern +tells git to ignore all `configure/*.local` files. + +### Fix broken `EPICS_IOC_LOG_FILE_LIMIT=0` setting + +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. + +Fixes [lp:1786858](https://bugs.launchpad.net/bugs/1786858) +and part of [lp:1786966](https://bugs.launchpad.net/bugs/1786966). + +### Cleanup of startup directory + +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: + + - The Perl `EpicsHostArch.pl` script has been rewritten, and support + for a few previously missing host architectures has been added to it. + - The `EpicsHostArch.pl` script has also been moved into the standard + `src/tools` directory, from where it will be installed into + `lib/perl`. In this new location it is no longer executable, so it must + be run by the `perl` executable. + - The build system has been adjusted to look for `EpicsHostArch.pl` in + both places if the `EPICS_HOST_ARCH` environment variable has not been + set at build-time. + - Sites that used the original Perl script to set `EPICS_HOST_ARCH` as part of + their standard environment will need to adjust their scripts when they + upgrade to this release. + - The `EpicsHostArch` shell script has been replaced with a wrapper + routine that calls the Perl `EpicsHostArch.pl` script. Sites that rely on + this script to set `EPICS_HOST_ARCH` should consider switching to the + Perl script instead. + - The `Site.cshrc` and `Site.profile` files have been renamed to + `unix.csh` and `unix.sh`, respectively. + - The existing `win32.bat` file has been cleaned up and a new + `windows.bat` 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. + +### Recent Apple XCode Build Issues + +The latest version of XCode will not compile calls to `system()` or +`clock_settime()` 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. + +### Prevent illegal alarm severities + +A check has been added to `recGblResetAlarms()` 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`. + +### Fixes for Launchpad bugs + +The following launchpad bugs have fixes included: + + - [lp: 1786320](https://bugs.launchpad.net/epics-base/+bug/1786320), dbCa + subscribes twice to ENUM + - [lp: 541221](https://bugs.launchpad.net/epics-base/+bug/541221), + `assert (pca->pgetNative)` failed in ../dbCa.c + - [lp: 1747091](https://bugs.launchpad.net/epics-base/+bug/1747091), + epicsTimeGetEvent() / generalTime bug + - [lp: 1743076](https://bugs.launchpad.net/epics-base/+bug/1743076), Segfault + in `ca_attach_context()` during exits + - [lp: 1751380](https://bugs.launchpad.net/epics-base/+bug/1751380), Deadlock + in `ca_clear_subscription()` + - [lp: 1597809](https://bugs.launchpad.net/epics-base/+bug/1597809), Setting + NAME field in DB file may break IOC + - [lp: 1770292](https://bugs.launchpad.net/epics-base/+bug/1770292), + `get_alarm_double()` inconsistent across record types + - [lp: 1771298](https://bugs.launchpad.net/epics-base/+bug/1771298), + Conversion of NaN to integer relies on undefined behavior + +### Updated VxWorks Timezone settings + +Removed the settings for 2017; fixed the hour of the change for MET. + +### Fixed camonitor server side relative timestamps bug + +Initialize the first time-stamp from the first monitor, not the client-side +current time in this configuration. + +### Build changes for MSVC + +Windows builds using Visual Studio 2015 and later now use the `-FS` +compiler option to allow parallel builds to work properly. + +We now give the `-FC` option to tell the compiler to print absolute +paths for source files in diagnostic messages. + +### Extend maximum Posix epicsEventWaitWithTimeout() delay + +The Posix implementation of epicsEventWaitWithTimeout() was limiting the +timeout delay to at most 60 minutes (3600.0 seconds). This has been changed to +10 years; significantly longer maximum delays cause problems on systems where +`time_t` is still a signed 32-bit integer so cannot represent absolute +time-stamps after 2038-01-19. Our assumption is that such 32-bit systems will +have been retired before the year 2028, but some additional tests have been +added to the epicsTimeTest program to detect and fail if this assumption is +violated. + +### New test-related make targets + +This release adds several new make targets intended for use by developers +and Continuous Integration systems which simplify the task of running the +built-in self-test programs and viewing the results. Since these targets are +intended for limited use they can have requirements for the build host which +go beyond the standard minimum set needed to build and run Base. + +#### `test-results` - Summarize test results + +The new make target `test-results` will run the self-tests if +necessary to generate a TAP file for each test, then summarizes the TAP output +files in each test directory in turn, displaying the details of any failures. +This step uses the program `prove` which comes with Perl, but also needs +`cat` to be provided in the default search path so will not work on most +Windows systems. + +#### `junitfiles` - Convert test results to JUnit XML Format + +The new make target `junitfiles` will run the self-tests if necessary +and then convert the TAP output files into the more commonly-supported JUnit +XML format. The program that performs this conversion needs the Perl module +`XML::Generator` to have been installed. + +#### `clean-tests` - Delete test result files + +The new make target `clean-tests` removes any test result files from +previous test runs. It cleans both TAP and JUnit XML files. + +### Fix DNS related crash on exit + +The attempt to fix DNS related delays for short lived CLI programs (eg. caget) +in [lp:1527636](https://bugs.launchpad.net/epics-base/+bug/1527636) introduced a +bug which cased these short lived clients to crash on exit. This bug should now +be fixed. + +### Server bind issue on Windows + +When a National Instruments network variables CA server is already running on +a Windows system and an IOC or PCAS server is started, the IOC's attempt to +bind a TCP socket to the CA server port number fails, but Windows returns a +different error status value than the IOC is expecting in that circumstance +(because the National Instruments code requests exclusive use of that port, +unlike the EPICS code) so the IOC fails to start properly. The relevent EPICS +bind() checks have now been updated so the IOC will request that a dynamic port +number be allocated for this TCP socket instead when this happens. + +### Checking Periodic Scan Rates + +Code has been added to the IOC startup to better protect it against bad +periodic scan rates, including against locales where `.` is not +accepted as a decimal separator character. If the scan period in a menuScan +choice string cannot be parsed, the associated periodic scan thread will no +longer be started by the IOC and a warning message will be displayed at iocInit +time. The `scanppl` command will also flag the faulty menuScan value. + +## Changes made between 3.15.4 and 3.15.5 + +### dbStatic Library Speedup and Cleanup + +Loading of database files has been optimized to avoid over-proportionally +long loading times for large databases. As a part of this, the alphabetical +ordering of records instances (within a record type) has been dropped. In the +unexpected case that applications were relying on the alphabetic order, setting +`dbRecordsAbcSorted = 1` before loading the databases will retain the +old behavior. + +The routine `dbRenameRecord()` has been removed, as it was intended +to be used by database configuration tools linked against a host side version +of the dbStatic library that is not being built anymore. + +### Launchpad Bug-fixes + +In addition to the more detailed change descriptions below, the following +Launchpad bugs have also been fixed in this release: + + - [lp:1440186](https://bugs.launchpad.net/epics-base/+bug/1440186) Crash due + to a too small buffer being provided in `dbContextReadNotifyCache()` + - [lp:1479316](https://bugs.launchpad.net/epics-base/+bug/1479316) Some data + races found using Helgrind + - [lp:1495833](https://bugs.launchpad.net/epics-base/+bug/1495833) biRecord + prompt groups are nonsensical + - [lp:1606848](https://bugs.launchpad.net/epics-base/+bug/1606848) WSAIoctl + `SIO_GET_INTERFACE_LIST` failed in Windows + +### Whole-Program Optimization for MS Visual Studio Targets + +When using the Microsoft compilers a new build system variable is provided that +controls whether whole program optimization is used or not. For static builds +using Visual Studio 2010 this optimization must be disabled. This is controlled +in the files `configure/os/CONFIG_SITE.Common.windows-x64-static` and +`configure/os/CONFIG_SITE.Common.win32-x86-static` by setting the variable +`OPT_WHOLE_PROGRAM=NO` to override the default value `YES` that would otherwise +be used. + +Note that enabling this optimization slows down the build process. It is not +possible to selectively disable this optimization, when building a particular +module say; Microsoft's linker will restart itself automatically with the +`-LTCG` flag set and display a warning if it is asked to link any object +files that were compiled with the `-GL` flag. + +### Add dynamic (variable length) array support to PCAS + +Dynamic array sizing support was added to the IOC server (RSRV) in the +Base-3.14.12 release, but has not until now been supported in the Portable +Channel Access Server (PCAS). Channel Access server applications using the +PCAS may not need to be modified at all; if they already push monitors with +different gdd array lengths, those variable sizes will be forwarded to any CA +clients who have requested variable length updates. The example CAS server +application has been modified to demonstrate this feature. + +In implementing the above, the gdd method `gdd::put(const gdd *)` now +copies the full-sized array from the source gdd if the destination gdd is of +type array, has no allocated memory and a boundary size of 0. + +### Additional epicsTime conversion + +The EPICS timestamp library (epicsTime) inside libCom's OSI layer has +been extended by routines that convert from `struct tm` to the EPICS +internal `epicsTime` type, assuming UTC - i.e. without going through +the timezone mechanism. This solves issues with converting from the structured +type to the EPICS timestamp at driver level from multiple threads at a high +repetition rate, where the timezone mechanism was blocking on file access. + +### MinGW Cross-builds from Linux + +The build configuration files that allow cross-building of the 32-bit +win32-x86-mingw cross-target have been adjusted to default to building shared +libraries (DLLs) as this is now supported by recent MinGW compilers. The 64-bit +windows-x64-mingw cross-target was already being built that way by default. The +configuration options to tell the minGW cross-compiler to link programs with +static versions of the compiler support libraries have now been moved into the +`CONFIG_SITE.linux-x86.` files. + +### General Time updates + +The `iocInit` code now performs a sanity check of the current time +returned by the generalTime subsystem and will print a warning if the wall-clock +time returned has not been initialized yet. This is just a warning message; when +a time provider does synchonize the IOC will subsequently pick up and use the +correct time. This check code also primes the registered event system provider +if there is one so the `epicsTimeGetEventInt()` routine will work on IOCs +that ask for event time within an interrupt service routine. + +The osiClockTime provider's synchronization thread (which is only used on +some embedded targets) will now poll the other time providers at 1Hz until the +first time it manages to get a successful timestamp, after which it will poll +for updates every 60 seconds as before. + +The routine `generalTimeGetExceptPriority()` was designed for use by +backup (lower priority) time providers like the osiClockTime provider which do +not have their own absolute time reference and rely on other providers for an +absolute time source. This routine no longer implements the ratchet mechanism +that prevented the time it returned from going backwards. If the backup clock's +tick-timer runs fast the synchronization of the backup time provider would never +allow it to be corrected backwards when the ratchet was in place. The regular +`epicsTimeGetCurrent()` API still uses the ratchet mechanism, so this +change will not cause the IOC to see time going backwards. + +### Microsoft Visual Studio builds + +The build configuration files for builds using the Microsoft compilers have been +updated, although there should be no noticable difference at most sites. One +extra compiler warning is now being suppressed for C++ code, `C4344: behavior +change: use of explicit template arguments results in ...` which is gratuitous +and was appearing frequently in builds of the EPICS V4 modules. + +Cross-builds of the windows-x64 target from a win32-x86 host have been +removed as they don't actually work within the context of a single `make` +run. Significant changes to the build configuration files would be necessary for +these kinds of cross-builds to work properly, which could be done if someone +needs them (email Andrew Johnson before working on this, and see +[this stack-overflow answer](http://stackoverflow.com/questions/5807647/how-do-you-compile-32-bit-and-64-bit-applications-at-the-same-time-in-visual-stu) for a starting point). + +### Bazaar keywords such as 'Revision-Id' removed + +In preparation for moving to git in place of the Bazaar revision control +system we have removed all the keywords from the Base source code. + +### Linux systemd service file for CA Repeater + +Building this version of Base on a Linux system creates a systemd service +file suitable for starting the Channel Access Repeater under systemd. The file +will be installed into the target bin directory, from where it can be copied +into the appropriate systemd location and modified as necessary. Installation +instructions are included as comments in the file. + +## Changes made between 3.15.3 and 3.15.4 + +### New string input device support "getenv" + +A new "getenv" device support for both the stringin and lsi (long string +input) record types can be used to read the value of an environment variable +from the IOC at runtime. See base/db/softIocExit.db for sample usage. + +### Build rules and `DELAY_INSTALL_LIBS` + +A new order-only prerequisite build rule has been added to ensure that +library files (and DLL stubs on Windows) get installed before linking any +executables, which resolves parallel build problems on high-powered CPUs. There +are some (rare) cases though where a Makefile has to build an executable and run +it to be able to compile code for a library built by the same Makefile. With +this new build rule GNUmake will complain about a circular dependency and the +build will probably fail in those cases. To avoid this problem the failing +Makefile should set `DELAY_INSTALL_LIBS = YES` before including the +`$(TOP)/configure/RULES` file, disabling the new build rule. + +### IOC environment variables and build parameters + +The IOC now sets a number of environment variables at startup that provide the +version of EPICS Base it was built against (`EPICS_VERSION_...`) and its build +architecture (ARCH). In some cases this allows a single iocBoot/ioc directory to +be used to run the same IOC on several different architectures without any +changes. + +There are also 3 new environment parameters (`EPICS_BUILD_...`) available that +C/C++ code can use to find out the target architecture, OS class and compiler +class it was built with. These may be useful when writing interfaces to other +languages. + +### New implementation of `promptgroup`/`gui_group` field property + +The mechanism behind the `promptgroup()` field property inside a record type +definition has been changed. Instead of using a fixed set of choices, +the static database access library now collects the used gui group names +while parsing DBD information. Group names should start with a two-digit number +plus space-dash-space to allow proper sorting of groups. + +The include file `guigroup.h` that defined the fixed set of choices +has been deprecated. Instead, use the conversion functions between index number +and group string that have been added to dbStaticLib. + +When a DBD file containing record-type descriptions is expanded, any +old-style `GUI_xxx` group names will be replaced by a new-style +string for use by the IOC. This permits an older record type to be used with +the 3.15.4 release, although eventually record types should be converted by +hand with better group names used. + +### CA server configuration changes + +RSRV now honors `EPICS_CAS_INTF_ADDR_LIST` and binds only to the provided list +of network interfaces. Name searches (UDP and TCP) on other network interfaces +are ignored. For example on a computer with interfaces 10.5.1.1/24, 10.5.2.1/24, +and 10.5.3.1/24, setting `EPICS_CAS_INTF_ADDR_LIST='10.5.1.1 10.5.2.1'` will +accept traffic on the .1.1 and .2.1, but ignore from .3.1 + +RSRV now honors `EPICS_CAS_IGNORE_ADDR_LIST` and ignores UDP messages received +from addresses in this list. + +Previously, CA servers (RSRV and PCAS) would build the beacon address list using +`EPICS_CA_ADDR_LIST` if `EPICS_CAS_BEACON_ADDR_LIST` was no set. This is no +longer done. Sites depending on this should set both environment variables to +the same value. + +### IPv4 multicast for name search and beacons + +libca, RSRV, and PCAS may now use IPv4 multicasting for UDP traffic (name search +and beacons). This is disabled by default. To enable multicast address(s) must +be listed in `EPICS_CA_ADDR_LIST` for clients and `EPICS_CAS_INTF_ADDR_LIST` for +servers (IOCs should set both). For example: + + EPICS_CAS_INTF_ADDR_LIST='224.0.2.9' EPICS_CA_ADDR_LIST=224.0.2.9 + +Please note that no IPv4 multicast address is officially assigned for Channel +Access by IANA. The example 224.0.2.9 is taken from the AD-HOC Block I range. + +### Moved `mlockall()` into its own epicsThread routine + +Since EPICS Base 3.15.0.2 on Posix OSs the initialization of the epicsThread +subsystem has called `mlockall()` when the OS supports it and thread +priority scheduling is enabled. Doing so has caused problems in third-party +applications that call the CA client library, so the functionality has been +moved to a separate routine `epicsThreadRealtimeLock()` which will be +called by the IOC at iocInit (unless disabled by setting the global variable +`dbThreadRealtimeLock` to zero). + +### Added dbQuietMacroWarnings control + +When loading database files, macros get expanded even on comment lines. If a +comment contains an undefined macro, the load still continues but an error +message gets printed. For this release the error message has been changed to a +warning, but even this warning can be made less verbose by setting this new +variable to a non-zero value before loading the file, like this: + +``` + var dbQuietMacroWarnings 1 iocsh + dbQuietMacroWarnings=1 VxWorks +``` + +This was [Launchpad bug +541119](https://bugs.launchpad.net/bugs/541119). + +## Changes from the 3.14 branch between 3.15.3 and 3.15.4 + +### NTP Time Provider adjusts to OS tick rate changes + +Dirk Zimoch provided code that allows the NTP Time provider (used on VxWorks +and RTEMS only) to adapt to changes in the OS clock tick rate after the provider +has been initialized. Note that changing the tick rate after iocInit() is not +advisable, and that other software might still misbehave if initialized before +an OS tick rate change. This change was back-ported from the 3.15 branch. + +### Making IOC `ca_get` operations atomic + +When a CA client gets data from an IOC record using a compound data type such +as `DBR_TIME_DOUBLE` the value field is fetched from the database in a +separate call than the other metadata, without keeping the record locked. This +allows some other thread such as a periodic scan thread a chance to interrupt +the get operation and process the record in between. CA monitors have always +been atomic as long as the value data isn't a string or an array, but this race +condition in the CA get path has now been fixed so the record will stay locked +between the two fetch operations. + +This fixes +[Launchpad bug 1581212](https://bugs.launchpad.net/epics-base/+bug/1581212), +thanks to Till Strauman and Dehong Zhang. + +### New `CONFIG_SITE` variable for running self-tests + +The 'make runtests' and 'make tapfiles' build targets normally only run the +self-tests for the main `EPICS_HOST_ARCH` architecture. If the host is +able to execute self-test programs for other target architectures that are being +built by the host, such as when building a `-debug` version of the host +architecture for example, the names of those other architectures can be added to +the new `CROSS_COMPILER_RUNTEST_ARCHS` variable in either the +`configure/CONFIG_SITE` file or in an appropriate +`configure/os/CONFIG_SITE..Common` file to have the test +programs for those targets be run as well. + +### Additional RELEASE file checks + +An additional check has been added at build-time for the contents of the +`configure/RELEASE` file(s), which will mostly only affect users of the Debian +EPICS packages published by NSLS-2. Support modules may share an install path, +but all such modules must be listed adjacent to each other in any `RELEASE` +files that point to them. For example the following will fail the new checks: + +``` + AUTOSAVE = /usr/lib/epics + ASYN = /home/mdavidsaver/asyn + EPICS_BASE = /usr/lib/epics +``` + +giving the compile-time error + +``` + This application's RELEASE file(s) define + EPICS_BASE = /usr/lib/epics + after but not adjacent to + AUTOSAVE = /usr/lib/epics + Module definitions that share paths must be grouped together. + Either remove a definition, or move it to a line immediately + above or below the other(s). + Any non-module definitions belong in configure/CONFIG_SITE. +``` + +In many cases such as the one above the order of the `AUTOSAVE` and +`ASYN` lines can be swapped to let the checks pass, but if the +`AUTOSAVE` module depended on `ASYN` and hence had to appear +before it in the list this error indicates that `AUTOSAVE` should also be +built in its own private area; a shared copy would likely be incompatible with +the version of `ASYN` built in the home directory. + +### String field buffer overflows + +Two buffer overflow bugs that can crash the IOC have been fixed, caused by +initializing a string field with a value larger than the field size +([Launchpad bug 1563191](https://bugs.launchpad.net/bugs/1563191)). + +### Fixed stack corruption bug in epicsThread C++ API + +The C++ interface to the epicsThread API could corrupt the stack on thread +exit in some rare circumstances, usually at program exit. This bug has been +fixed ([Launchpad bug 1558206](https://bugs.launchpad.net/bugs/1558206)). + +### RTEMS NTP Support Issue + +On RTEMS the NTP Time Provider could in some circumstances get out of sync +with the server because the `osdNTPGet()` code wasn't clearing its input socket +before sending out a new request. This +([Launchpad bug 1549908](https://bugs.launchpad.net/bugs/1549908)) +has now been fixed. + +### CALC engine bitwise operator fixes + +The bitwise operators in the CALC engine have been modified to work properly +with values that have bit 31 (0x80000000) set. This modification involved +back-porting some earlier changes from the 3.15 branch, and fixes +[Launchpad bug 1514520](https://code.launchpad.net/bugs/1514520). + +### Fix `ipAddrToAsciiAsync()`: Don't try to join the daemon thread + +On process exit, don't try to stop the worker thread that makes DNS lookups +asynchronous. Previously this would wait for any lookups still in progress, +delaying the exit unnecessarily. This was most obvious with catools (eg. +cainfo). +[lp:1527636](https://bugs.launchpad.net/bugs/1527636) + +### Fix `epicsTime_localtime()` on Windows + +Simpler versions of the `epicsTime_gmtime()` and `epicsTime_localtime()` +routines have been included in the Windows implementations, and a new test +program added. The original versions do not report DST status properly. Fixes +[Launchpad bug 1528284](https://bugs.launchpad.net/bugs/1528284). + diff --git a/documentation/RecordReference.md b/documentation/RecordReference.md new file mode 100644 index 000000000..587ec6148 --- /dev/null +++ b/documentation/RecordReference.md @@ -0,0 +1,50 @@ +# Record Reference Documentation + +The following documentation for the record types and menus include with Base was converted from the old EPICS Wiki pages and updated. This list does not include all of the available record types as some have not been documented yet. + +## Record Types + +* [Analog Input Record (ai)](aiRecord.html) +* [Analog Output Record (ao)](aoRecord.html) +* [Array Subroutine Record (aSub)](aSubRecord.html) +* [Binary Input Record (bi)](biRecord.html) +* [Binary Output Record (bo)](boRecord.html) +* [Calculation Output Record (calcout)](calcoutRecord.html) +* [Calculation Record (calc)](calcRecord.html) +* [Compression Record (compress)](compressRecord.html) +* [Data Fanout Record (dfanout)](dfanoutRecord.html) +* [Event Record (event)](eventRecord.html) +* [Fanout Record (fanout)](fanoutRecord.html) +* [64bit Integer Input Record (int64in)](int64inRecord.html) +* [64bit Integer Output Record (int64out)](int64outRecord.html) +* [Long Input Record (longin)](longinRecord.html) +* [Long Output Record (longout)](longoutRecord.html) +* [Multi-Bit Binary Input Direct Record (mbbiDirect)](mbbiDirectRecord.html) +* [Multi-Bit Binary Input Record (mbbi)](mbbiRecord.html) +* [Multi-Bit Binary Output Direct Record (mbboDirect)](mbboDirectRecord.html) +* [Multi-Bit Binary Output Record (mbbo)](mbboRecord.html) +* [Permissive Record (permissive)](permissiveRecord.html) +* [Select Record (sel)](selRecord.html) +* [Sequence Record (seq)](seqRecord.html) +* [State Record (state)](stateRecord.html) +* [String Input Record (stringin)](stringinRecord.html) +* [String Output Record (stringout)](stringoutRecord.html) +* [Sub-Array Record (subArray)](subArrayRecord.html) +* [Subroutine Record (sub)](subRecord.html) +* [Waveform Record (waveform)](waveformRecord.html) + +## Menu Definitions + +* [Alarm Severity Menu](menuAlarmSevr.html) +* [Alarm Status Menu](menuAlarmStat.html) +* [Analog Conversions Menu](menuConvert.html) +* [Field Type Menu](menuFtype.html) +* [Invalid Value Output Action Menu](menuIvoa.html) +* [Output Mode Select Menu](menuOmsl.html) +* [Scan Menu](menuScan.html) +* [Simulation Mode Menu](menuSimm.html) +* [Yes/No Menu](menuYesNo.html) + +## Corrections and Updates + +Corrections to these documents can be submitted as patch files to the EPICS core developers, or as merge requests or pull requests to the 7.0 branch of epics-base. The document sources can be found in the `modules/database/src/std/rec` and `modules/database/src/ioc/db` directories in files with extension `.dbd.pod`. The documentation format is an extended version of Perl POD, run `perldoc pod` for details. diff --git a/documentation/ReleaseChecklist.html b/documentation/ReleaseChecklist.html index 81784e8cc..0a80c7cba 100644 --- a/documentation/ReleaseChecklist.html +++ b/documentation/ReleaseChecklist.html @@ -147,17 +147,17 @@ starting at Release Approval.

    Tag the module in Git, using these tag conventions:
    • - R7.0.3-pren + R7.0.3.2-pren — pre-release tag
    • - R7.0.3-rcn + R7.0.3.2-rcn — release candidate tag
    cd base-7.0
    - git tag -m 'ANJ: Tagged for 7.0.3-rc1' R7.0.3-rc1 + git tag -m 'ANJ: Tagged for 7.0.3.2-rc1' R7.0.3.2-rc1
    Note that submodules must not be tagged with the version used for the top-level, they each have their own separate version numbers @@ -171,11 +171,11 @@ starting at Release Approval.

    files and directories that are only used for continuous integration:
    cd base-7.0
    - ./.tools/make-tar.sh R7.0.3-rc1 base-7.0.3-rc1.tar.gz base-7.0.3-rc1/ + ./.tools/make-tar.sh R7.0.3.2-rc1 base-7.0.3.2-rc1.tar.gz base-7.0.3.2-rc1/
    Create a GPG signature file of the tarfile as follows:
    - gpg --armor --sign --detach-sig base-7.0.3-rc1.tar.gz + gpg --armor --sign --detach-sig base-7.0.3.2-rc1.tar.gz
    @@ -277,25 +277,77 @@ starting at Release Approval.

    Release Manager -

    For each external submodule, check if the module's release version - number (and SHRLIB_VERSION setting) has been updated if appropriate, - and that its Release Notes have been updated to cover any changes. - Commit any fixes and tag the module if that hasn't already been - done.

    -

    Update all external submodules on the Base-7.0 branch and - commit.

    +

    For each external submodule in turn (assuming it has not been tagged + yet):

    +
      +
    1. Check that the module's Release Notes have been updated to cover + all changes; add items as necessary, and set the module version + number and release date if appropriate. Convert to HTML and view in + a browser to check the formatting: +
      + cd base-7.0/modules/<module>/documentation
      + pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md +
      + Commit changes (don't push yet).
    2. + +
    3. Edit the module's release version file + configure/CONFIG_module_VERSION and its top-level + Doxyfile; set the DEVELOPMENT_FLAG value to 0 and + remove -dev from the PROJECT_NUMBER string. + Commit changes (don't push).
    4. + +
    5. Tag the module: +
      + git tag -m 'ANJ: Tag for EPICS 7.0.3.2' <module-version> +
      +
    6. + +
    7. Update the git submodule on the Base-7.0 branch to the + newly-tagged version, but don't commit yet: +
      + cd base-7.0/modules
      + git add <module>
      + git submodule status --cached +
      +
    8. + +
    9. Edit the module's release version file + configure/CONFIG_module_VERSION and its top-level + Doxyfile; increment the MAINTENANCE_VERSION, set + the DEVELOPMENT_FLAG value to 1, and update the + PROJECT_NUMBER string, appending -dev to the new + module version number. Commit changes.
    10. + +
    11. Push commits and the new tag to the submodule's GitHub repository: +
      + cd base-7.0/modules/<module>
      + git push --follow-tags upstream master +
      +
    12. + +
    +

    Commit all the submodule updates to the 7.0 branch.

    + Release Manager - Edit and commit changes to the EPICS Base version number file and - the embedded module version files: + + Edit the main EPICS Base version file and the built-in module version + files:
      -
    • configure/CONFIG_BASE_VERSION
    • -
    • modules/libcom/configure/CONFIG_LIBCOM_VERSION
    • -
    • modules/ca/configure/CONFIG_CA_VERSION
    • -
    • modules/database/configure/CONFIG_DATABASE_VERSION
    • -
    +
  • configure/CONFIG_BASE_VERSION
  • +
  • configure/CONFIG_LIBCOM_VERSION
  • +
  • configure/CONFIG_CA_VERSION
  • +
  • configure/CONFIG_DATABASE_VERSION
  • + +

    Version numbers should be set according to the level of changes made + since the last release. Note that the MAINTENANCE_VERSION or + PATCH_LEVEL value should have been incremented after the + previous release tag was applied. Set all DEVELOPMENT_FLAG + values to 0 and EPICS_DEV_SNAPSHOT to the empty string.

    +

    Commit these changes (don't push).

    + @@ -303,9 +355,29 @@ starting at Release Approval.

    Tag the epics-base module in Git:
    cd base-7.0
    - git tag -m 'ANJ: Tagged for 7.0.3' R7.0.3 + git tag -m 'ANJ: Tagged for 7.0.3.2' R7.0.3.2
    - Don't push the new tag to the Launchpad repository yet. +

    Don't push these commits or the new tag to the Launchpad repository + yet.

    + + + + + Release Manager + Edit the main EPICS Base version file and the built-in module version + files: +
      +
    • configure/CONFIG_BASE_VERSION
    • +
    • configure/CONFIG_LIBCOM_VERSION
    • +
    • configure/CONFIG_CA_VERSION
    • +
    • configure/CONFIG_DATABASE_VERSION
    • +
    +

    Version numbers should be set for the next expected patch/maintenance + release by incrementing the MAINTENANCE_VERSION or PATCH_LEVEL value + in each file. Set all DEVELOPMENT_FLAG values to 1 and + EPICS_DEV_SNAPSHOT to "-DEV".

    +

    Commit these changes (don't push).

    + @@ -315,11 +387,12 @@ starting at Release Approval.

    files and directories that are only used for continuous integration:
    cd base-7.0
    - ./.tools/make-tar.sh R7.0.3 base-7.0.3.tar.gz base-7.0.3/ + ./.tools/make-tar.sh R7.0.3.2 ../base-7.0.3.2.tar.gz base-7.0.3.2/
    Create a GPG signature file of the tarfile as follows:
    - gpg --armor --sign --detach-sig base-7.0.3.tar.gz + cd ..
    + gpg --armor --sign --detach-sig base-7.0.3.2.tar.gz
    @@ -327,29 +400,13 @@ starting at Release Approval.

    Release Manager Test the tar file by extracting its contents and building it on at - least one supported platform. When this succeeds the new git tag can be - pushed to the Launchpad repository: + least one supported platform. When this succeeds the commits and new git + tag can be pushed to the Launchpad repository:
    git push --follow-tags upstream 7.0
    - - - Release Manager - Edit and commit changes to the EPICS Base version number file and - the embedded module version files: -
      -
    • configure/CONFIG_BASE_VERSION
    • -
    • modules/libcom/configure/CONFIG_LIBCOM_VERSION
    • -
    • modules/ca/configure/CONFIG_CA_VERSION
    • -
    • modules/database/configure/CONFIG_DATABASE_VERSION
    • -
    - Version numbers should be set to the next expected patch release, - with a "-DEV" tag added (where applicable). - - - Publish to epics.anl.gov @@ -398,7 +455,11 @@ starting at Release Approval.

    Website Manager Upload the tar file and its .asc signature file to the - epics-controls web-server [ToDo: ssh-key, location] + epics-controls web-server. +
    + scp base-7.0.3.2.tar.gz base-7.0.3.2.tar.gz.asc epics-controls:download/base
    +
    + @@ -406,7 +467,10 @@ starting at Release Approval.

    Follow instructions on Add a page for a new release to create a new release webpage (not - required for a patch release though, just edit the existing page). + required for a patch release, just edit the existing page). Update the + TablePress "Point Releases" table and add the new download, and adjust + the XYZ Html Snippet for the series download. + diff --git a/modules/Makefile b/modules/Makefile index 9a189daf6..11a1671fb 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -7,15 +7,15 @@ TOP = .. include $(TOP)/configure/CONFIG include CONFIG_SITE.local -# Submodules for bundle build -SUBMODULES += libcom +DIRS += libcom -SUBMODULES += ca +DIRS += ca ca_DEPEND_DIRS = libcom -SUBMODULES += database +DIRS += database database_DEPEND_DIRS = ca +# Submodules for bundle build SUBMODULES += pvData pvData_DEPEND_DIRS = libcom diff --git a/modules/ca/.ci/travis-build.sh b/modules/ca/.ci/travis-build.sh deleted file mode 100755 index 622979b9d..000000000 --- a/modules/ca/.ci/travis-build.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -x - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 $EXTRA - -if [ "$TEST" != "NO" ] -then - make -j2 tapfiles - make -s test-results -fi diff --git a/modules/ca/.ci/travis-prepare.sh b/modules/ca/.ci/travis-prepare.sh deleted file mode 100755 index 85dc8d7ce..000000000 --- a/modules/ca/.ci/travis-prepare.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/sh -set -e -x - -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/RELEASE.local -EPICS_BASE=$HOME/.source/epics-base -EOF - -install -d "$HOME/.source" -cd "$HOME/.source" - -add_base_module() { - MODULE=$1 - BRANCH=$2 - ( cd epics-base/modules && \ - git clone --quiet --depth 5 --branch "$MODULE"/"$BRANCH" https://github.com/${REPOBASE:-epics-base}/epics-base.git "$MODULE" && \ - cd "$MODULE" && git log -n1 ) -} - -git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base -( cd epics-base && git log -n1 ) -add_base_module libcom "${BRLIBCOM:-master}" - -EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch` - -# requires wine and g++-mingw-w64-i686 -if [ "$WINE" = "32" ] -then - echo "Cross mingw32" - sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw - cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw -CMPLR_PREFIX=i686-w64-mingw32- -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw -EOF -fi - -if [ "$STATIC" = "YES" ] -then - echo "Build static libraries/executables" - cat << EOF >> epics-base/configure/CONFIG_SITE -SHARED_LIBRARIES=NO -STATIC_BUILD=YES -EOF -fi - -case "$CMPLR" in -clang) - echo "Host compiler is clang" - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH -GNU = NO -CMPLR_CLASS = clang -CC = clang -CCC = clang++ -EOF - - # hack - sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon - - clang --version - ;; -*) - echo "Host compiler is default" - gcc --version - ;; -esac - -cat <> epics-base/configure/CONFIG_SITE -USR_CPPFLAGS += $USR_CPPFLAGS -USR_CFLAGS += $USR_CFLAGS -USR_CXXFLAGS += $USR_CXXFLAGS -EOF - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - echo "Cross RTEMS${RTEMS} for pc386" - install -d /home/travis/.cache - curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \ - | tar -C /home/travis/.cache -xj - - sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS -RTEMS_VERSION=$RTEMS -RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 -EOF - - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 -C epics-base $EXTRA diff --git a/modules/ca/.travis.yml b/modules/ca/.travis.yml deleted file mode 100644 index 5a99b886a..000000000 --- a/modules/ca/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: false -dist: trusty -language: c -compiler: - - gcc -addons: - apt: - packages: - - libreadline6-dev - - libncurses5-dev - - perl - - clang - - g++-mingw-w64-i686 -install: - - ./.ci/travis-prepare.sh -script: - - ./.ci/travis-build.sh -env: - - BRCORE=master BRLIBCOM=master TEST=NO - - CMPLR=clang TEST=NO - - USR_CXXFLAGS=-std=c++11 TEST=NO - - CMPLR=clang USR_CXXFLAGS=-std=c++11 TEST=NO - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO diff --git a/modules/ca/Makefile b/modules/ca/Makefile index 13feff6c2..eeb147b07 100644 --- a/modules/ca/Makefile +++ b/modules/ca/Makefile @@ -7,11 +7,9 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = . +TOP = ../.. include $(TOP)/configure/CONFIG -DIRS += configure src - -src_DEPEND_DIRS = configure +DIRS += src include $(TOP)/configure/RULES_TOP diff --git a/modules/ca/configure/CONFIG b/modules/ca/configure/CONFIG deleted file mode 100644 index 331fd7024..000000000 --- a/modules/ca/configure/CONFIG +++ /dev/null @@ -1,28 +0,0 @@ -# CONFIG - Load build configuration data -# -# Do not make changes to this file! - -# Allow user to override where the build rules come from -RULES = $(EPICS_BASE) - -# RELEASE files point to other application tops -include $(TOP)/configure/RELEASE --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common -ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) -endif - -CONFIG = $(RULES)/configure -include $(CONFIG)/CONFIG - -# Override the Base definition: -INSTALL_LOCATION = $(TOP) - -# CONFIG_SITE files contain other build configuration settings -include $(TOP)/configure/CONFIG_SITE --include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common -ifdef T_A - -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) - -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif diff --git a/modules/ca/configure/CONFIG_CA_VERSION b/modules/ca/configure/CONFIG_CA_VERSION deleted file mode 100644 index 8a6649666..000000000 --- a/modules/ca/configure/CONFIG_CA_VERSION +++ /dev/null @@ -1,4 +0,0 @@ -EPICS_CA_MAJOR_VERSION = 4 -EPICS_CA_MINOR_VERSION = 13 -EPICS_CA_MAINTENANCE_VERSION = 4 -EPICS_CA_DEVELOPMENT_FLAG = 0 diff --git a/modules/ca/configure/CONFIG_SITE b/modules/ca/configure/CONFIG_SITE deleted file mode 100644 index d78c7f514..000000000 --- a/modules/ca/configure/CONFIG_SITE +++ /dev/null @@ -1,42 +0,0 @@ -# CONFIG_SITE - -# Make any application-specific changes to the EPICS build -# configuration variables in this file. -# -# Host/target specific settings can be specified in files named -# CONFIG_SITE.$(EPICS_HOST_ARCH).Common -# CONFIG_SITE.Common.$(T_A) -# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - -# CHECK_RELEASE controls the consistency checking of the support -# applications pointed to by the RELEASE* files. -# Normally CHECK_RELEASE should be set to YES. -# Set CHECK_RELEASE to NO to disable checking completely. -# Set CHECK_RELEASE to WARN to perform consistency checking but -# continue building even if conflicts are found. -CHECK_RELEASE = YES - -# Set this when you only want to compile this application -# for a subset of the cross-compiled target architectures -# that Base is built for. -#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 - -# To install files into a location other than $(TOP) define -# INSTALL_LOCATION here. -#INSTALL_LOCATION= - -# Set this when the IOC and build host use different paths -# to the install location. This may be needed to boot from -# a Microsoft FTP server say, or on some NFS configurations. -#IOCS_APPL_TOP = - -# For application debugging purposes, override the HOST_OPT and/ -# or CROSS_OPT settings from base/configure/CONFIG_SITE -#HOST_OPT = NO -#CROSS_OPT = NO - -# These allow developers to override the CONFIG_SITE variable -# settings without having to modify the configure/CONFIG_SITE -# file itself. --include $(TOP)/../CONFIG_SITE.local --include $(TOP)/configure/CONFIG_SITE.local diff --git a/modules/ca/configure/Makefile b/modules/ca/configure/Makefile deleted file mode 100644 index e2f373893..000000000 --- a/modules/ca/configure/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -#************************************************************************* -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -TOP = .. - -include $(TOP)/configure/CONFIG - -TARGETS = $(CONFIG_TARGETS) -CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) - -CFG += CONFIG_CA_MODULE -CFG += CONFIG_CA_VERSION - -include $(TOP)/configure/RULES diff --git a/modules/ca/configure/RELEASE b/modules/ca/configure/RELEASE deleted file mode 100644 index a2d9f554a..000000000 --- a/modules/ca/configure/RELEASE +++ /dev/null @@ -1,39 +0,0 @@ -# RELEASE - Location of external support modules -# -# IF YOU CHANGE ANY PATHS in this file or make API changes to -# any modules it refers to, you should do a "make rebuild" in -# this application's top level directory. -# -# The EPICS build process does not check dependencies against -# any files from outside the application, so it is safest to -# rebuild it completely if any modules it depends on change. -# -# Host- or target-specific settings can be given in files named -# RELEASE.$(EPICS_HOST_ARCH).Common -# RELEASE.Common.$(T_A) -# RELEASE.$(EPICS_HOST_ARCH).$(T_A) -# -# This file is parsed by both GNUmake and an EPICS Perl script, -# so it may ONLY contain definititions of paths to other support -# modules, variable definitions that are used in module paths, -# and include statements that pull in other RELEASE files. -# Variables may be used before their values have been set. -# Build variables that are NOT used in paths should be set in -# the CONFIG_SITE file. - -# Variables and paths to dependent modules: -#MODULES = /path/to/modules -#MYMODULE = $(MODULES)/my-module - -# If building the EPICS modules individually, set these: -#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0 -#EPICS_BASE = $(MODULES)/core-7.0.1 - -# Set RULES here if you want to use build rules from elsewhere: -#RULES = $(MODULES)/build-rules - -# These lines allow developers to override these RELEASE settings -# without having to modify this file directly. --include $(TOP)/../RELEASE.local --include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local --include $(TOP)/configure/RELEASE.local diff --git a/modules/ca/configure/RULES b/modules/ca/configure/RULES deleted file mode 100644 index 6d56e14e8..000000000 --- a/modules/ca/configure/RULES +++ /dev/null @@ -1,6 +0,0 @@ -# RULES - -include $(CONFIG)/RULES - -# Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile diff --git a/modules/ca/configure/RULES_DIRS b/modules/ca/configure/RULES_DIRS deleted file mode 100644 index 3ba269dcc..000000000 --- a/modules/ca/configure/RULES_DIRS +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_DIRS -include $(CONFIG)/RULES_DIRS diff --git a/modules/ca/configure/RULES_TOP b/modules/ca/configure/RULES_TOP deleted file mode 100644 index 2b8cbc6da..000000000 --- a/modules/ca/configure/RULES_TOP +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_TOP -include $(CONFIG)/RULES_TOP diff --git a/modules/ca/src/Makefile b/modules/ca/src/Makefile index 650b3550f..335cec67e 100644 --- a/modules/ca/src/Makefile +++ b/modules/ca/src/Makefile @@ -7,7 +7,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG # Channel Access Client diff --git a/modules/ca/src/client/CASG.cpp b/modules/ca/src/client/CASG.cpp index b2dbaac4d..4ffb414c7 100644 --- a/modules/ca/src/client/CASG.cpp +++ b/modules/ca/src/client/CASG.cpp @@ -83,7 +83,7 @@ int CASG::block ( return ECA_TIMEOUT; } - cur_time = epicsTime::getCurrent (); + cur_time = epicsTime::getMonotonic (); this->client.flush ( guard ); @@ -121,7 +121,7 @@ int CASG::block ( /* * force a time update */ - cur_time = epicsTime::getCurrent (); + cur_time = epicsTime::getMonotonic (); delay = cur_time - beg_time; } diff --git a/modules/ca/src/client/Makefile b/modules/ca/src/client/Makefile index d707d5395..b59eee465 100644 --- a/modules/ca/src/client/Makefile +++ b/modules/ca/src/client/Makefile @@ -6,8 +6,8 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* - -TOP = ../.. +CURDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +TOP = ../../../.. include $(TOP)/configure/CONFIG @@ -110,7 +110,7 @@ EXPAND += S99caRepeater@ EXPAND += caRepeater.service@ EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN)) -SRC_DIRS += $(TOP)/src/client/test +SRC_DIRS += $(CURDIR)/test PROD_HOST += ca_test ca_test_SRCS = ca_test_main.c ca_test.c ca_test_LIBS = ca Com diff --git a/modules/ca/src/client/caRepeater.cpp b/modules/ca/src/client/caRepeater.cpp index 9879af2b4..03cb8957d 100644 --- a/modules/ca/src/client/caRepeater.cpp +++ b/modules/ca/src/client/caRepeater.cpp @@ -32,10 +32,12 @@ #define epicsAssertAuthor "Jeff Hill johill@lanl.gov" #include "epicsAssert.h" +#include "osiUnistd.h" #include "udpiiu.h" int main() { + chdir ( "/" ); ca_repeater (); return ( 0 ); } diff --git a/modules/ca/src/client/ca_client_context.cpp b/modules/ca/src/client/ca_client_context.cpp index edd88cd09..3fd0512d6 100644 --- a/modules/ca/src/client/ca_client_context.cpp +++ b/modules/ca/src/client/ca_client_context.cpp @@ -475,7 +475,7 @@ int ca_client_context::pendIO ( const double & timeout ) } int status = ECA_NORMAL; - epicsTime beg_time = epicsTime::getCurrent (); + epicsTime beg_time = epicsTime::getMonotonic (); double remaining = timeout; epicsGuard < epicsMutex > guard ( this->mutex ); @@ -493,7 +493,7 @@ int ca_client_context::pendIO ( const double & timeout ) this->blockForEventAndEnableCallbacks ( this->ioDone, remaining ); } - double delay = epicsTime::getCurrent () - beg_time; + double delay = epicsTime::getMonotonic () - beg_time; if ( delay < timeout ) { remaining = timeout - delay; } @@ -522,7 +522,7 @@ int ca_client_context::pendEvent ( const double & timeout ) return ECA_EVDISALLOW; } - epicsTime current = epicsTime::getCurrent (); + epicsTime current = epicsTime::getMonotonic (); { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -563,7 +563,7 @@ int ca_client_context::pendEvent ( const double & timeout ) this->noWakeupSincePend = true; } - double elapsed = epicsTime::getCurrent() - current; + double elapsed = epicsTime::getMonotonic() - current; double delay; if ( timeout > elapsed ) { diff --git a/modules/ca/src/client/cac.cpp b/modules/ca/src/client/cac.cpp index 5748353bd..476d1c380 100644 --- a/modules/ca/src/client/cac.cpp +++ b/modules/ca/src/client/cac.cpp @@ -53,7 +53,7 @@ static const char pVersionCAC[] = "@(#) " EPICS_VERSION_STRING - ", CA Client Library " __DATE__; + ", CA Client Library"; // TCP response dispatch table const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = @@ -130,7 +130,7 @@ cac::cac ( epicsMutex & callbackControlIn, cacContextNotify & notifyIn ) : _refLocalHostName ( localHostNameCache.getReference () ), - programBeginTime ( epicsTime::getCurrent() ), + programBeginTime ( epicsTime::getMonotonic() ), connTMO ( CA_CONN_VERIFY_PERIOD ), mutex ( mutualExclusionIn ), cbMutex ( callbackControlIn ), diff --git a/modules/ca/src/client/casw.cpp b/modules/ca/src/client/casw.cpp index f69632c13..bdb08e04d 100644 --- a/modules/ca/src/client/casw.cpp +++ b/modules/ca/src/client/casw.cpp @@ -59,7 +59,7 @@ int main ( int argc, char ** argv ) epicsMutex mutex; epicsGuard < epicsMutex > guard ( mutex ); bheFreeStoreMgr bheFreeList; - epicsTime programBeginTime = epicsTime::getCurrent (); + epicsTime programBeginTime = epicsTime::getMonotonic (); bool validCommandLine = false; unsigned interest = 0u; SOCKET sock; @@ -244,7 +244,7 @@ int main ( int argc, char ** argv ) ca_uint32_t beaconNumber = ntohl ( pCurMsg->m_cid ); unsigned protocolRevision = ntohs ( pCurMsg->m_dataType ); - epicsTime currentTime = epicsTime::getCurrent(); + epicsTime currentTime = epicsTime::getMonotonic(); /* * look for it in the hash table diff --git a/modules/ca/src/client/searchTimer.cpp b/modules/ca/src/client/searchTimer.cpp index e55e49eab..bb9b9a91c 100644 --- a/modules/ca/src/client/searchTimer.cpp +++ b/modules/ca/src/client/searchTimer.cpp @@ -43,7 +43,7 @@ searchTimer::searchTimer ( const unsigned indexIn, epicsMutex & mutexIn, bool boostPossibleIn ) : - timeAtLastSend ( epicsTime::getCurrent () ), + timeAtLastSend ( epicsTime::getMonotonic () ), timer ( queueIn.createTimer () ), iiu ( iiuIn ), mutex ( mutexIn ), diff --git a/modules/ca/src/client/tcpiiu.cpp b/modules/ca/src/client/tcpiiu.cpp index 045f8d57e..9d174ab84 100644 --- a/modules/ca/src/client/tcpiiu.cpp +++ b/modules/ca/src/client/tcpiiu.cpp @@ -476,7 +476,7 @@ void tcpRecvThread::run () statusWireIO stat; pComBuf->fillFromWire ( this->iiu, stat ); - epicsTime currentTime = epicsTime::getCurrent (); + epicsTime currentTime = epicsTime::getMonotonic (); { epicsGuard < epicsMutex > guard ( this->iiu.mutex ); @@ -1669,7 +1669,7 @@ bool tcpiiu::sendThreadFlush ( epicsGuard < epicsMutex > & guard ) if ( this->sendQue.occupiedBytes() > 0 ) { while ( comBuf * pBuf = this->sendQue.popNextComBufToSend () ) { - epicsTime current = epicsTime::getCurrent (); + epicsTime current = epicsTime::getMonotonic (); unsigned bytesToBeSent = pBuf->occupiedBytes (); bool success = false; diff --git a/modules/ca/src/client/udpiiu.cpp b/modules/ca/src/client/udpiiu.cpp index 1bcb03716..fe15f1b69 100644 --- a/modules/ca/src/client/udpiiu.cpp +++ b/modules/ca/src/client/udpiiu.cpp @@ -435,7 +435,7 @@ void udpRecvThread::run () } else if ( status > 0 ) { this->iiu.postMsg ( src, this->iiu.recvBuf, - (arrayElementCount) status, epicsTime::getCurrent() ); + (arrayElementCount) status, epicsTime::getMonotonic() ); } } while ( ! this->iiu.shutdownCmd ); @@ -1162,7 +1162,7 @@ void udpiiu :: show ( unsigned level ) const } } if ( level > 2u ) { - ::printf ("\tsocket identifier %d\n", this->sock ); + ::printf ("\tsocket identifier %d\n", int(this->sock) ); ::printf ("\tbytes in xmit buffer %u\n", this->nBytesInXmitBuf ); ::printf ("\tshut down command bool %u\n", this->shutdownCmd ); ::printf ( "\trecv thread exit signal:\n" ); @@ -1195,10 +1195,7 @@ bool udpiiu::wakeupMsg () // send a wakeup msg so the UDP recv thread will exit int status = sendto ( this->sock, reinterpret_cast < char * > ( &msg ), sizeof (msg), 0, &addr.sa, sizeof ( addr.sa ) ); - if ( status == sizeof (msg) ) { - return true; - } - return false; + return status == sizeof (msg); } void udpiiu::beaconAnomalyNotify ( diff --git a/modules/ca/src/perl/Makefile b/modules/ca/src/perl/Makefile index 7890f34e4..65619e93e 100644 --- a/modules/ca/src/perl/Makefile +++ b/modules/ca/src/perl/Makefile @@ -5,7 +5,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../.. +TOP = ../../../.. include $(TOP)/configure/CONFIG ifdef T_A @@ -55,8 +55,6 @@ ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32 PERL_MODULES += CA.pm PERL_MODULES += $(PERL_ARCHPATH)/$(LOADABLE_SHRLIB_PREFIX)Cap5$(LOADABLE_SHRLIB_SUFFIX) - PERL_SCRIPTS += caModuleDirs.pm - HTMLS_DIR = . HTMLS = CA.html endif diff --git a/modules/ca/src/perl/capr.pl b/modules/ca/src/perl/capr.pl index e551afcef..21e56ecd9 100644 --- a/modules/ca/src/perl/capr.pl +++ b/modules/ca/src/perl/capr.pl @@ -10,9 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use caModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use Getopt::Std; use EPICS::Path; diff --git a/modules/ca/src/template/Makefile b/modules/ca/src/template/Makefile index 913d92bf4..8683dfd3c 100644 --- a/modules/ca/src/template/Makefile +++ b/modules/ca/src/template/Makefile @@ -1,4 +1,4 @@ -TOP=../.. +TOP=../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/ca/src/tools/Makefile b/modules/ca/src/tools/Makefile index 7ebcc021b..c56e21eca 100644 --- a/modules/ca/src/tools/Makefile +++ b/modules/ca/src/tools/Makefile @@ -9,7 +9,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../.. +TOP = ../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/.ci/travis-build.sh b/modules/database/.ci/travis-build.sh deleted file mode 100755 index 622979b9d..000000000 --- a/modules/database/.ci/travis-build.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -x - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 $EXTRA - -if [ "$TEST" != "NO" ] -then - make -j2 tapfiles - make -s test-results -fi diff --git a/modules/database/.ci/travis-prepare.sh b/modules/database/.ci/travis-prepare.sh deleted file mode 100755 index ce2c18b5d..000000000 --- a/modules/database/.ci/travis-prepare.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/sh -set -e -x - -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/RELEASE.local -EPICS_BASE=$HOME/.source/epics-base -EOF - -install -d "$HOME/.source" -cd "$HOME/.source" - -add_base_module() { - MODULE=$1 - BRANCH=$2 - ( cd epics-base/modules && \ - git clone --quiet --depth 5 --branch "$MODULE"/"$BRANCH" https://github.com/${REPOBASE:-epics-base}/epics-base.git "$MODULE" && \ - cd "$MODULE" && git log -n1 ) -} - -git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base -( cd epics-base && git log -n1 ) -add_base_module libcom "${BRLIBCOM:-master}" -add_base_module ca "${BRCA:-master}" - -EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch` - -# requires wine and g++-mingw-w64-i686 -if [ "$WINE" = "32" ] -then - echo "Cross mingw32" - sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw - cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw -CMPLR_PREFIX=i686-w64-mingw32- -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw -EOF -fi - -if [ "$STATIC" = "YES" ] -then - echo "Build static libraries/executables" - cat << EOF >> epics-base/configure/CONFIG_SITE -SHARED_LIBRARIES=NO -STATIC_BUILD=YES -EOF -fi - -case "$CMPLR" in -clang) - echo "Host compiler is clang" - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH -GNU = NO -CMPLR_CLASS = clang -CC = clang -CCC = clang++ -EOF - - # hack - sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon - - clang --version - ;; -*) - echo "Host compiler is default" - gcc --version - ;; -esac - -cat <> epics-base/configure/CONFIG_SITE -USR_CPPFLAGS += $USR_CPPFLAGS -USR_CFLAGS += $USR_CFLAGS -USR_CXXFLAGS += $USR_CXXFLAGS -EOF - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - echo "Cross RTEMS${RTEMS} for pc386" - install -d /home/travis/.cache - curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \ - | tar -C /home/travis/.cache -xj - - sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS -RTEMS_VERSION=$RTEMS -RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 -EOF - - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 -C epics-base $EXTRA diff --git a/modules/database/.travis.yml b/modules/database/.travis.yml deleted file mode 100644 index 127ae7bc9..000000000 --- a/modules/database/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: false -dist: trusty -language: c -compiler: - - gcc -addons: - apt: - packages: - - libreadline6-dev - - libncurses5-dev - - perl - - clang - - g++-mingw-w64-i686 -install: - - ./.ci/travis-prepare.sh -script: - - ./.ci/travis-build.sh -env: - - BRCORE=master BRLIBCOM=master BRCA=master - - CMPLR=clang - - USR_CXXFLAGS=-std=c++11 - - CMPLR=clang USR_CXXFLAGS=-std=c++11 - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO diff --git a/modules/database/Makefile b/modules/database/Makefile index 9998e6cf5..9bb746e82 100644 --- a/modules/database/Makefile +++ b/modules/database/Makefile @@ -7,11 +7,10 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = . +TOP = ../.. include $(TOP)/configure/CONFIG -DIRS += configure src -src_DEPEND_DIRS = configure +DIRS += src DIRS += test test_DEPEND_DIRS = src diff --git a/modules/database/configure/CONFIG b/modules/database/configure/CONFIG deleted file mode 100644 index c471407c4..000000000 --- a/modules/database/configure/CONFIG +++ /dev/null @@ -1,36 +0,0 @@ -# CONFIG - Load build configuration data -# -# Do not make changes to this file! - -# Allow user to override where the build rules come from -RULES = $(EPICS_BASE) - -# RELEASE files point to other application tops -include $(TOP)/configure/RELEASE --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common -ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) -endif - -BUILDING_DATABASE = DEFINED - -CONFIG = $(RULES)/configure -include $(CONFIG)/CONFIG - -# Override the Base definition: -INSTALL_LOCATION = $(TOP) - -# Use new RSET definition -BASE_CPPFLAGS += -DUSE_TYPED_RSET - -# Shared library ABI version. -SHRLIB_VERSION = $(EPICS_DATABASE_MAJOR_VERSION).$(EPICS_DATABASE_MINOR_VERSION).$(EPICS_DATABASE_MAINTENANCE_VERSION) - -# CONFIG_SITE files contain other build configuration settings -include $(TOP)/configure/CONFIG_SITE --include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common -ifdef T_A - -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) - -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif diff --git a/modules/database/configure/CONFIG_DATABASE_VERSION b/modules/database/configure/CONFIG_DATABASE_VERSION deleted file mode 100644 index ad8d54ab5..000000000 --- a/modules/database/configure/CONFIG_DATABASE_VERSION +++ /dev/null @@ -1,4 +0,0 @@ -EPICS_DATABASE_MAJOR_VERSION = 3 -EPICS_DATABASE_MINOR_VERSION = 17 -EPICS_DATABASE_MAINTENANCE_VERSION = 4 -EPICS_DATABASE_DEVELOPMENT_FLAG = 0 diff --git a/modules/database/configure/CONFIG_SITE b/modules/database/configure/CONFIG_SITE deleted file mode 100644 index d78c7f514..000000000 --- a/modules/database/configure/CONFIG_SITE +++ /dev/null @@ -1,42 +0,0 @@ -# CONFIG_SITE - -# Make any application-specific changes to the EPICS build -# configuration variables in this file. -# -# Host/target specific settings can be specified in files named -# CONFIG_SITE.$(EPICS_HOST_ARCH).Common -# CONFIG_SITE.Common.$(T_A) -# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - -# CHECK_RELEASE controls the consistency checking of the support -# applications pointed to by the RELEASE* files. -# Normally CHECK_RELEASE should be set to YES. -# Set CHECK_RELEASE to NO to disable checking completely. -# Set CHECK_RELEASE to WARN to perform consistency checking but -# continue building even if conflicts are found. -CHECK_RELEASE = YES - -# Set this when you only want to compile this application -# for a subset of the cross-compiled target architectures -# that Base is built for. -#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 - -# To install files into a location other than $(TOP) define -# INSTALL_LOCATION here. -#INSTALL_LOCATION= - -# Set this when the IOC and build host use different paths -# to the install location. This may be needed to boot from -# a Microsoft FTP server say, or on some NFS configurations. -#IOCS_APPL_TOP = - -# For application debugging purposes, override the HOST_OPT and/ -# or CROSS_OPT settings from base/configure/CONFIG_SITE -#HOST_OPT = NO -#CROSS_OPT = NO - -# These allow developers to override the CONFIG_SITE variable -# settings without having to modify the configure/CONFIG_SITE -# file itself. --include $(TOP)/../CONFIG_SITE.local --include $(TOP)/configure/CONFIG_SITE.local diff --git a/modules/database/configure/Makefile b/modules/database/configure/Makefile deleted file mode 100644 index dd292091c..000000000 --- a/modules/database/configure/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -#************************************************************************* -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -TOP = .. - -include $(TOP)/configure/CONFIG - -TARGETS = $(CONFIG_TARGETS) -CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) - -CFG += CONFIG_DATABASE_MODULE -CFG += CONFIG_DATABASE_VERSION - -include $(TOP)/configure/RULES diff --git a/modules/database/configure/RELEASE b/modules/database/configure/RELEASE deleted file mode 100644 index 9b685a13e..000000000 --- a/modules/database/configure/RELEASE +++ /dev/null @@ -1,40 +0,0 @@ -# RELEASE - Location of external support modules -# -# IF YOU CHANGE ANY PATHS in this file or make API changes to -# any modules it refers to, you should do a "make rebuild" in -# this application's top level directory. -# -# The EPICS build process does not check dependencies against -# any files from outside the application, so it is safest to -# rebuild it completely if any modules it depends on change. -# -# Host- or target-specific settings can be given in files named -# RELEASE.$(EPICS_HOST_ARCH).Common -# RELEASE.Common.$(T_A) -# RELEASE.$(EPICS_HOST_ARCH).$(T_A) -# -# This file is parsed by both GNUmake and an EPICS Perl script, -# so it may ONLY contain definititions of paths to other support -# modules, variable definitions that are used in module paths, -# and include statements that pull in other RELEASE files. -# Variables may be used before their values have been set. -# Build variables that are NOT used in paths should be set in -# the CONFIG_SITE file. - -# Variables and paths to dependent modules: -#MODULES = /path/to/modules -#MYMODULE = $(MODULES)/my-module - -# If building the EPICS modules individually, set these: -#EPICS_CA = $(MODULES)/ca-4.13.1 -#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0 -#EPICS_BASE = $(MODULES)/core-7.0.1 - -# Set RULES here if you want to use build rules from elsewhere: -#RULES = $(MODULES)/build-rules - -# These lines allow developers to override these RELEASE settings -# without having to modify this file directly. --include $(TOP)/../RELEASE.local --include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local --include $(TOP)/configure/RELEASE.local diff --git a/modules/database/configure/RULES b/modules/database/configure/RULES deleted file mode 100644 index 6d56e14e8..000000000 --- a/modules/database/configure/RULES +++ /dev/null @@ -1,6 +0,0 @@ -# RULES - -include $(CONFIG)/RULES - -# Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile diff --git a/modules/database/configure/RULES.ioc b/modules/database/configure/RULES.ioc deleted file mode 100644 index 901987c6c..000000000 --- a/modules/database/configure/RULES.ioc +++ /dev/null @@ -1,2 +0,0 @@ -#RULES.ioc -include $(CONFIG)/RULES.ioc diff --git a/modules/database/configure/RULES_DIRS b/modules/database/configure/RULES_DIRS deleted file mode 100644 index 3ba269dcc..000000000 --- a/modules/database/configure/RULES_DIRS +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_DIRS -include $(CONFIG)/RULES_DIRS diff --git a/modules/database/configure/RULES_TOP b/modules/database/configure/RULES_TOP deleted file mode 100644 index 2b8cbc6da..000000000 --- a/modules/database/configure/RULES_TOP +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_TOP -include $(CONFIG)/RULES_TOP diff --git a/modules/database/src/Makefile b/modules/database/src/Makefile index dfd1d3be9..0cc46fa40 100644 --- a/modules/database/src/Makefile +++ b/modules/database/src/Makefile @@ -7,7 +7,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG # PDB Tools diff --git a/modules/database/src/ioc/Makefile b/modules/database/src/ioc/Makefile index 325872826..70b1b5558 100644 --- a/modules/database/src/ioc/Makefile +++ b/modules/database/src/ioc/Makefile @@ -6,12 +6,14 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* -TOP=../.. +IOCDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +TOP = ../../../.. include $(TOP)/configure/CONFIG -SRC = $(TOP)/src -IOCDIR = $(SRC)/ioc +USR_CPPFLAGS += -DUSE_TYPED_RSET + +SHRLIB_VERSION = 3.17.0 LIBRARY_IOC += dbCore dbCore_LIBS += ca Com @@ -34,6 +36,9 @@ include $(IOCDIR)/misc/Makefile include $(IOCDIR)/registry/Makefile include $(IOCDIR)/rsrv/Makefile +GENVERSION = epicsVCS.h +GENVERSIONMACRO = EPICS_VCS_VERSION + EXPANDVARS += EPICS_DATABASE_MAJOR_VERSION EXPANDVARS += EPICS_DATABASE_MINOR_VERSION EXPANDVARS += EPICS_DATABASE_MAINTENANCE_VERSION @@ -53,3 +58,5 @@ include $(IOCDIR)/dbtemplate/RULES ../O.Common/databaseVersionNum.h: ../databaseVersionNum.h@ $(MKDIR) $(COMMON_DIR) $(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@ + +epicsRelease$(DEP): $(COMMON_DIR)/$(GENVERSION) diff --git a/modules/database/src/ioc/as/asCa.c b/modules/database/src/ioc/as/asCa.c index d0180448b..21bb47f5f 100644 --- a/modules/database/src/ioc/as/asCa.c +++ b/modules/database/src/ioc/as/asCa.c @@ -229,20 +229,23 @@ static void asCaTask(void) void asCaStart(void) { + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + + opts.stackSize = epicsThreadGetStackSize(epicsThreadStackBig); + opts.priority = epicsThreadPriorityScanLow - 3; + opts.joinable = 1; + if(asCaDebug) printf("asCaStart called\n"); if(firstTime) { - firstTime = FALSE; + firstTime = FALSE; asCaTaskLock=epicsMutexMustCreate(); asCaTaskWait=epicsEventMustCreate(epicsEventEmpty); asCaTaskAddChannels=epicsEventMustCreate(epicsEventEmpty); asCaTaskClearChannels=epicsEventMustCreate(epicsEventEmpty); - threadid = epicsThreadCreate("asCaTask", - (epicsThreadPriorityScanLow - 3), - epicsThreadGetStackSize(epicsThreadStackBig), - (EPICSTHREADFUNC)asCaTask,0); - if(threadid==0) { - errMessage(0,"asCaStart: taskSpawn Failure\n"); - } + threadid = epicsThreadCreateOpt("asCaTask", (EPICSTHREADFUNC)asCaTask, 0, &opts); + if(threadid==0) { + errMessage(0,"asCaStart: taskSpawn Failure\n"); + } } epicsMutexMustLock(asCaTaskLock); epicsEventSignal(asCaTaskAddChannels); @@ -260,6 +263,8 @@ void asCaStop(void) epicsEventMustWait(asCaTaskWait); if(asCaDebug) printf("asCaStop done\n"); epicsMutexUnlock(asCaTaskLock); + epicsThreadMustJoin(threadid); + threadid = 0; } int ascar(int level) { return ascarFP(stdout,level);} diff --git a/modules/database/src/ioc/as/asCa.h b/modules/database/src/ioc/as/asCa.h index 360296fe2..a99cb544a 100644 --- a/modules/database/src/ioc/as/asCa.h +++ b/modules/database/src/ioc/as/asCa.h @@ -11,6 +11,8 @@ #ifndef INCasCah #define INCasCah +#include + #include "shareLib.h" #ifdef __cplusplus diff --git a/modules/database/src/ioc/as/asDbLib.h b/modules/database/src/ioc/as/asDbLib.h index 65c4c6f59..235bbbd4b 100644 --- a/modules/database/src/ioc/as/asDbLib.h +++ b/modules/database/src/ioc/as/asDbLib.h @@ -12,11 +12,13 @@ #ifndef INCdbAsLibh #define INCdbAsLibh +#include + #include "callback.h" #include "shareLib.h" typedef struct { - CALLBACK callback; + epicsCallback callback; long status; } ASDBCALLBACK; diff --git a/modules/database/src/ioc/as/asIocRegister.c b/modules/database/src/ioc/as/asIocRegister.c index 16cba90c6..d5926a551 100644 --- a/modules/database/src/ioc/as/asIocRegister.c +++ b/modules/database/src/ioc/as/asIocRegister.c @@ -39,7 +39,7 @@ static void asSetSubstitutionsCallFunc(const iocshArgBuf *args) static const iocshFuncDef asInitFuncDef = {"asInit",0}; static void asInitCallFunc(const iocshArgBuf *args) { - asInit(); + iocshSetError(asInit()); } /* asdbdump */ diff --git a/modules/database/src/ioc/db/callback.c b/modules/database/src/ioc/db/callback.c index e1f1d45a2..bbd798ed4 100644 --- a/modules/database/src/ioc/db/callback.c +++ b/modules/database/src/ioc/db/callback.c @@ -216,7 +216,7 @@ static void callbackTask(void *arg) epicsEventMustWait(mySet->semWakeUp); while ((ptr = epicsRingPointerPop(mySet->queue))) { - CALLBACK *pcallback = (CALLBACK *)ptr; + epicsCallback *pcallback = (epicsCallback *)ptr; if(!epicsRingPointerIsEmpty(mySet->queue)) epicsEventMustTrigger(mySet->semWakeUp); mySet->queueOverflow = FALSE; @@ -317,7 +317,7 @@ void callbackInit(void) } /* This routine can be called from interrupt context */ -int callbackRequest(CALLBACK *pcallback) +int callbackRequest(epicsCallback *pcallback) { int priority; int pushOK; @@ -347,7 +347,7 @@ int callbackRequest(CALLBACK *pcallback) return 0; } -static void ProcessCallback(CALLBACK *pcallback) +static void ProcessCallback(epicsCallback *pcallback) { dbCommon *pRec; @@ -358,14 +358,14 @@ static void ProcessCallback(CALLBACK *pcallback) dbScanUnlock(pRec); } -void callbackSetProcess(CALLBACK *pcallback, int Priority, void *pRec) +void callbackSetProcess(epicsCallback *pcallback, int Priority, void *pRec) { callbackSetCallback(ProcessCallback, pcallback); callbackSetPriority(Priority, pcallback); callbackSetUser(pRec, pcallback); } -int callbackRequestProcessCallback(CALLBACK *pcallback, +int callbackRequestProcessCallback(epicsCallback *pcallback, int Priority, void *pRec) { callbackSetProcess(pcallback, Priority, pRec); @@ -374,11 +374,11 @@ int callbackRequestProcessCallback(CALLBACK *pcallback, static void notify(void *pPrivate) { - CALLBACK *pcallback = (CALLBACK *)pPrivate; + epicsCallback *pcallback = (epicsCallback *)pPrivate; callbackRequest(pcallback); } -void callbackRequestDelayed(CALLBACK *pcallback, double seconds) +void callbackRequestDelayed(epicsCallback *pcallback, double seconds) { epicsTimerId timer = (epicsTimerId)pcallback->timer; @@ -389,7 +389,7 @@ void callbackRequestDelayed(CALLBACK *pcallback, double seconds) epicsTimerStartDelay(timer, seconds); } -void callbackCancelDelayed(CALLBACK *pcallback) +void callbackCancelDelayed(epicsCallback *pcallback) { epicsTimerId timer = (epicsTimerId)pcallback->timer; @@ -398,7 +398,7 @@ void callbackCancelDelayed(CALLBACK *pcallback) } } -void callbackRequestProcessCallbackDelayed(CALLBACK *pcallback, +void callbackRequestProcessCallbackDelayed(epicsCallback *pcallback, int Priority, void *pRec, double seconds) { callbackSetProcess(pcallback, Priority, pRec); diff --git a/modules/database/src/ioc/db/callback.h b/modules/database/src/ioc/db/callback.h index 720cf337d..a77a888f9 100644 --- a/modules/database/src/ioc/db/callback.h +++ b/modules/database/src/ioc/db/callback.h @@ -26,7 +26,7 @@ extern "C" { /* * WINDOWS also has a "CALLBACK" type def */ -#ifdef _WIN32 +#if defined(_WIN32) && !defined(EPICS_NO_CALLBACK) # ifdef CALLBACK # undef CALLBACK # endif /*CALLBACK*/ @@ -44,7 +44,9 @@ typedef struct callbackPvt { void *timer; /*for use by callback itself*/ }epicsCallback; +#if !defined(EPICS_NO_CALLBACK) typedef epicsCallback CALLBACK; +#endif typedef void (*CALLBACKFUNC)(struct callbackPvt*); @@ -69,16 +71,16 @@ typedef struct callbackQueueStats { epicsShareFunc void callbackInit(void); epicsShareFunc void callbackStop(void); epicsShareFunc void callbackCleanup(void); -epicsShareFunc int callbackRequest(CALLBACK *pCallback); +epicsShareFunc int callbackRequest(epicsCallback *pCallback); epicsShareFunc void callbackSetProcess( - CALLBACK *pcallback, int Priority, void *pRec); + epicsCallback *pcallback, int Priority, void *pRec); epicsShareFunc int callbackRequestProcessCallback( - CALLBACK *pCallback,int Priority, void *pRec); + epicsCallback *pCallback,int Priority, void *pRec); epicsShareFunc void callbackRequestDelayed( - CALLBACK *pCallback,double seconds); -epicsShareFunc void callbackCancelDelayed(CALLBACK *pcallback); + epicsCallback *pCallback,double seconds); +epicsShareFunc void callbackCancelDelayed(epicsCallback *pcallback); epicsShareFunc void callbackRequestProcessCallbackDelayed( - CALLBACK *pCallback, int Priority, void *pRec, double seconds); + epicsCallback *pCallback, int Priority, void *pRec, double seconds); epicsShareFunc int callbackSetQueueSize(int size); epicsShareFunc int callbackQueueStatus(const int reset, callbackQueueStats *result); epicsShareFunc void callbackQueueShow(const int reset); diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index be81d22ed..19f60381d 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -1010,7 +1010,7 @@ devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp) { return (devSup *)ellNth(&prdes->devList, dtyp+1); } -devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset) { +devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) { devSup *pdevSup = (devSup *)ellFirst(&prdes->devList); while (pdevSup) { if (pdset == pdevSup->pdset) return pdevSup; @@ -1032,7 +1032,7 @@ static long dbPutFieldLink(DBADDR *paddr, struct link *plink = (struct link *)paddr->pfield; const char *pstring = (const char *)pbuffer; struct dsxt *old_dsxt = NULL; - struct dset *new_dset = NULL; + dset *new_dset = NULL; struct dsxt *new_dsxt = NULL; devSup *new_devsup = NULL; long status; diff --git a/modules/database/src/ioc/db/dbAccessDefs.h b/modules/database/src/ioc/db/dbAccessDefs.h index 52ac4016d..805dfd41f 100644 --- a/modules/database/src/ioc/db/dbAccessDefs.h +++ b/modules/database/src/ioc/db/dbAccessDefs.h @@ -18,15 +18,16 @@ #include "epicsTypes.h" #include "epicsTime.h" -#include "dbBase.h" -#include "dbAddr.h" -#include "recSup.h" #ifdef INCLdb_accessh_epicsExportSharedSymbols # define epicsExportSharedSymbols # include "shareLib.h" #endif +#include "dbBase.h" +#include "dbAddr.h" +#include "recSup.h" + #ifdef __cplusplus extern "C" { #endif @@ -239,7 +240,7 @@ epicsShareFunc void dbInitEntryFromRecord(struct dbCommon *prec, struct dbEntry *pdbentry); epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp); -epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset); +epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset); epicsShareFunc long dbGetField( struct dbAddr *,short dbrType,void *pbuffer,long *options, long *nRequest,void *pfl); diff --git a/modules/database/src/ioc/db/dbCa.c b/modules/database/src/ioc/db/dbCa.c index 843fbfc0c..45e178cae 100644 --- a/modules/database/src/ioc/db/dbCa.c +++ b/modules/database/src/ioc/db/dbCa.c @@ -68,6 +68,7 @@ static volatile enum dbCaCtl_t { ctlInit, ctlRun, ctlPause, ctlExit } dbCaCtl; static epicsEventId startStopEvent; +static epicsThreadId dbCaWorker; struct ca_client_context * dbCaClientContext; @@ -258,10 +259,18 @@ void dbCaShutdown(void) dbCaCtl = ctlExit; epicsEventSignal(workListEvent); epicsEventMustWait(startStopEvent); + if(dbCaWorker) + epicsThreadMustJoin(dbCaWorker); } static void dbCaLinkInitImpl(int isolate) { + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + + opts.stackSize = epicsThreadGetStackSize(epicsThreadStackBig); + opts.priority = epicsThreadPriorityMedium; + opts.joinable = 1; + dbServiceIsolate = isolate; dbServiceIOInit(); @@ -274,9 +283,8 @@ static void dbCaLinkInitImpl(int isolate) startStopEvent = epicsEventMustCreate(epicsEventEmpty); dbCaCtl = ctlPause; - epicsThreadCreate("dbCaLink", epicsThreadPriorityMedium, - epicsThreadGetStackSize(epicsThreadStackBig), - dbCaTask, NULL); + dbCaWorker = epicsThreadCreateOpt("dbCaLink", dbCaTask, NULL, &opts); + /* wait for worker to startup and initialize dbCaClientContext */ epicsEventMustWait(startStopEvent); } diff --git a/modules/database/src/ioc/db/dbCommon.dbd b/modules/database/src/ioc/db/dbCommon.dbd index 1b093e6a8..aa6a63345 100644 --- a/modules/database/src/ioc/db/dbCommon.dbd +++ b/modules/database/src/ioc/db/dbCommon.dbd @@ -199,11 +199,12 @@ interest(4) extra("struct typed_rset *rset") } + %#include "devSup.h" field(DSET,DBF_NOACCESS) { prompt("DSET address") special(SPC_NOMOD) interest(4) - extra("struct dset *dset") + extra("unambiguous_dset *dset") } field(DPVT,DBF_NOACCESS) { prompt("Device Private") diff --git a/modules/database/src/ioc/db/dbContext.cpp b/modules/database/src/ioc/db/dbContext.cpp index 832820206..36cc66538 100644 --- a/modules/database/src/ioc/db/dbContext.cpp +++ b/modules/database/src/ioc/db/dbContext.cpp @@ -384,7 +384,7 @@ void dbContext::show ( this->mutex.show ( level - 2u ); } if ( this->pNetContext.get() ) { - this->pNetContext.get()->show ( guard, level ); + this->pNetContext->show ( guard, level ); } } @@ -393,7 +393,7 @@ void dbContext::flush ( { guard.assertIdenticalMutex ( this->mutex ); if ( this->pNetContext.get() ) { - this->pNetContext.get()->flush ( guard ); + this->pNetContext->flush ( guard ); } } @@ -402,7 +402,7 @@ unsigned dbContext::circuitCount ( { guard.assertIdenticalMutex ( this->mutex ); if ( this->pNetContext.get() ) { - return this->pNetContext.get()->circuitCount ( guard ); + return this->pNetContext->circuitCount ( guard ); } else { return 0u; @@ -416,7 +416,7 @@ void dbContext::selfTest ( this->ioTable.verify (); if ( this->pNetContext.get() ) { - this->pNetContext.get()->selfTest ( guard ); + this->pNetContext->selfTest ( guard ); } } @@ -425,7 +425,7 @@ unsigned dbContext::beaconAnomaliesSinceProgramStart ( { guard.assertIdenticalMutex ( this->mutex ); if ( this->pNetContext.get() ) { - return this->pNetContext.get()->beaconAnomaliesSinceProgramStart ( guard ); + return this->pNetContext->beaconAnomaliesSinceProgramStart ( guard ); } else { return 0u; diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index 77b12de8d..0d96e12e5 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -84,7 +84,6 @@ struct event_user { epicsMutexId lock; epicsEventId ppendsem; /* Wait while empty */ epicsEventId pflush_sem; /* wait for flush */ - epicsEventId pexitsem; /* wait for event task to join */ EXTRALABORFUNC *extralabor_sub;/* off load to event task */ void *extralabor_arg;/* parameter to above */ @@ -123,8 +122,6 @@ static char *EVENT_PEND_NAME = "eventTask"; static struct evSubscrip canceledEvent; -static epicsMutexId stopSync; - static unsigned short ringSpace ( const struct event_que *pevq ) { if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) { @@ -266,10 +263,6 @@ dbEventCtx db_init_events (void) { struct event_user * evUser; - if (!stopSync) { - stopSync = epicsMutexMustCreate(); - } - if (!dbevEventUserFreeList) { freeListInitPvt(&dbevEventUserFreeList, sizeof(struct event_user),8); @@ -293,9 +286,6 @@ dbEventCtx db_init_events (void) return NULL; } - /* Flag will be cleared when event task starts */ - evUser->pendexit = TRUE; - evUser->firstque.evUser = evUser; evUser->firstque.writelock = epicsMutexCreate(); if (!evUser->firstque.writelock) @@ -310,9 +300,6 @@ dbEventCtx db_init_events (void) evUser->lock = epicsMutexCreate(); if (!evUser->lock) goto fail; - evUser->pexitsem = epicsEventCreate(epicsEventEmpty); - if (!evUser->pexitsem) - goto fail; evUser->flowCtrlMode = FALSE; evUser->extraLaborBusy = FALSE; @@ -327,8 +314,6 @@ fail: epicsEventDestroy (evUser->ppendsem); if(evUser->pflush_sem) epicsEventDestroy (evUser->pflush_sem); - if(evUser->pexitsem) - epicsEventDestroy (evUser->pexitsem); freeListFree(dbevEventUserFreeList,evUser); return NULL; } @@ -349,7 +334,6 @@ epicsShareFunc void db_cleanup_events(void) dbevFieldLogFreeList = NULL; } - /* intentionally leak stopSync to avoid possible shutdown races */ /* * DB_CLOSE_EVENTS() * @@ -371,30 +355,15 @@ void db_close_events (dbEventCtx ctx) * hazardous to the system's health. */ epicsMutexMustLock ( evUser->lock ); - if(!evUser->pendexit) { /* event task running */ - evUser->pendexit = TRUE; - epicsMutexUnlock ( evUser->lock ); - - /* notify the waiting task */ - epicsEventSignal(evUser->ppendsem); - /* wait for task to exit */ - epicsEventMustWait(evUser->pexitsem); - - epicsMutexMustLock ( evUser->lock ); - } - + evUser->pendexit = TRUE; epicsMutexUnlock ( evUser->lock ); - epicsMutexMustLock (stopSync); + /* notify the waiting task */ + epicsEventSignal(evUser->ppendsem); - epicsEventDestroy(evUser->pexitsem); - epicsEventDestroy(evUser->ppendsem); - epicsEventDestroy(evUser->pflush_sem); - epicsMutexDestroy(evUser->lock); - - epicsMutexUnlock (stopSync); - - freeListFree(dbevEventUserFreeList, evUser); + if(evUser->taskid) + epicsThreadMustJoin(evUser->taskid); + /* evUser has been deleted by the worker */ } /* @@ -1074,17 +1043,14 @@ static void event_task (void *pParm) } } + epicsEventDestroy(evUser->ppendsem); + epicsEventDestroy(evUser->pflush_sem); + epicsMutexDestroy(evUser->lock); + + freeListFree(dbevEventUserFreeList, evUser); + taskwdRemove(epicsThreadGetIdSelf()); - /* use stopSync to ensure pexitsem is not destroy'd - * until epicsEventSignal() has returned. - */ - epicsMutexMustLock (stopSync); - - epicsEventSignal(evUser->pexitsem); - - epicsMutexUnlock(stopSync); - return; } @@ -1096,6 +1062,11 @@ int db_start_events ( void *init_func_arg, unsigned osiPriority ) { struct event_user * const evUser = (struct event_user *) ctx; + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + + opts.stackSize = epicsThreadGetStackSize(epicsThreadStackMedium); + opts.priority = osiPriority; + opts.joinable = 1; epicsMutexMustLock ( evUser->lock ); @@ -1113,15 +1084,12 @@ int db_start_events ( if (!taskname) { taskname = EVENT_PEND_NAME; } - evUser->taskid = epicsThreadCreate ( - taskname, osiPriority, - epicsThreadGetStackSize(epicsThreadStackMedium), - event_task, (void *)evUser); + evUser->taskid = epicsThreadCreateOpt ( + taskname, event_task, (void *)evUser, &opts); if (!evUser->taskid) { epicsMutexUnlock ( evUser->lock ); return DB_EVENT_ERROR; } - evUser->pendexit = FALSE; epicsMutexUnlock ( evUser->lock ); return DB_EVENT_OK; } @@ -1186,3 +1154,8 @@ void db_delete_field_log (db_field_log *pfl) freeListFree(dbevFieldLogFreeList, pfl); } } + +int db_available_logs(void) +{ + return (int) freeListItemsAvail(dbevFieldLogFreeList); +} diff --git a/modules/database/src/ioc/db/dbEvent.h b/modules/database/src/ioc/db/dbEvent.h index 8ee109373..374e84996 100644 --- a/modules/database/src/ioc/db/dbEvent.h +++ b/modules/database/src/ioc/db/dbEvent.h @@ -82,6 +82,7 @@ epicsShareFunc void db_event_disable (dbEventSubscription es); epicsShareFunc struct db_field_log* db_create_event_log (struct evSubscrip *pevent); epicsShareFunc struct db_field_log* db_create_read_log (struct dbChannel *chan); epicsShareFunc void db_delete_field_log (struct db_field_log *pfl); +epicsShareFunc int db_available_logs(void); #define DB_EVENT_OK 0 #define DB_EVENT_ERROR (-1) @@ -91,4 +92,3 @@ epicsShareFunc void db_delete_field_log (struct db_field_log *pfl); #endif #endif /*INCLdbEventh*/ - diff --git a/modules/database/src/ioc/db/dbIocRegister.c b/modules/database/src/ioc/db/dbIocRegister.c index c40af92c1..afb31151d 100644 --- a/modules/database/src/ioc/db/dbIocRegister.c +++ b/modules/database/src/ioc/db/dbIocRegister.c @@ -39,7 +39,7 @@ static const iocshFuncDef dbLoadDatabaseFuncDef = {"dbLoadDatabase",3,dbLoadDatabaseArgs}; static void dbLoadDatabaseCallFunc(const iocshArgBuf *args) { - dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval); + iocshSetError(dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval)); } /* dbLoadRecords */ @@ -49,7 +49,7 @@ static const iocshArg * const dbLoadRecordsArgs[2] = {&dbLoadRecordsArg0,&dbLoad static const iocshFuncDef dbLoadRecordsFuncDef = {"dbLoadRecords",2,dbLoadRecordsArgs}; static void dbLoadRecordsCallFunc(const iocshArgBuf *args) { - dbLoadRecords(args[0].sval,args[1].sval); + iocshSetError(dbLoadRecords(args[0].sval,args[1].sval)); } /* dbb */ diff --git a/modules/database/src/ioc/db/dbNotify.c b/modules/database/src/ioc/db/dbNotify.c index 794672a55..e25ce4aa0 100644 --- a/modules/database/src/ioc/db/dbNotify.c +++ b/modules/database/src/ioc/db/dbNotify.c @@ -69,7 +69,7 @@ typedef struct notifyPvt { ELLNODE node; /*For free list*/ long magic; short state; - CALLBACK callback; + epicsCallback callback; ELLLIST waitList; /*list of records for current processNotify*/ short cancelWait; short userCallbackWait; @@ -86,7 +86,7 @@ typedef struct notifyGlobal { static notifyGlobal *pnotifyGlobal = 0; -static void notifyCallback(CALLBACK *pcallback); +static void notifyCallback(epicsCallback *pcallback); #define ellSafeAdd(list,listnode) \ { \ @@ -270,7 +270,7 @@ static void processNotifyCommon(processNotify *ppn, dbCommon *precord, int first callDone(precord, ppn); } -static void notifyCallback(CALLBACK *pcallback) +static void notifyCallback(epicsCallback *pcallback) { processNotify *ppn = NULL; dbCommon *precord; diff --git a/modules/database/src/ioc/db/dbNotify.h b/modules/database/src/ioc/db/dbNotify.h index 4b7c3e4dd..5641cff0f 100644 --- a/modules/database/src/ioc/db/dbNotify.h +++ b/modules/database/src/ioc/db/dbNotify.h @@ -13,8 +13,6 @@ #include "shareLib.h" #include "ellLib.h" -#include "epicsEvent.h" -#include "callback.h" #ifdef __cplusplus extern "C" { diff --git a/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp b/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp index 1a796cdbd..2215f8468 100644 --- a/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp +++ b/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp @@ -144,12 +144,12 @@ void dbPutNotifyBlocker::initiatePutNotify ( break; } if ( beginTimeInit ) { - if ( epicsTime::getCurrent () - begin > 30.0 ) { + if ( epicsTime::getMonotonic () - begin > 30.0 ) { throw cacChannel::requestTimedOut (); } } else { - begin = epicsTime::getCurrent (); + begin = epicsTime::getMonotonic (); beginTimeInit = true; } { diff --git a/modules/database/src/ioc/db/dbScan.c b/modules/database/src/ioc/db/dbScan.c index 9224ed504..f319a2452 100644 --- a/modules/database/src/ioc/db/dbScan.c +++ b/modules/database/src/ioc/db/dbScan.c @@ -109,7 +109,7 @@ static char *priorityName[NUM_CALLBACK_PRIORITIES] = { /* EVENT */ typedef struct event_list { - CALLBACK callback[NUM_CALLBACK_PRIORITIES]; + epicsCallback callback[NUM_CALLBACK_PRIORITIES]; scan_list scan_list[NUM_CALLBACK_PRIORITIES]; struct event_list *next; char eventname[1]; /* actually arbitrary size */ @@ -120,7 +120,7 @@ static epicsMutexId event_lock; /* IO_EVENT*/ typedef struct io_scan_list { - CALLBACK callback; + epicsCallback callback; scan_list scan_list; } io_scan_list; @@ -141,9 +141,9 @@ static void periodicTask(void *arg); static void initPeriodic(void); static void deletePeriodic(void); static void spawnPeriodic(int ind); -static void eventCallback(CALLBACK *pcallback); +static void eventCallback(epicsCallback *pcallback); static void ioscanInit(void); -static void ioscanCallback(CALLBACK *pcallback); +static void ioscanCallback(epicsCallback *pcallback); static void ioscanDestroy(void); static void printList(scan_list *psl, char *message); static void scanList(scan_list *psl); @@ -448,7 +448,7 @@ int scanpiol(void) /* print pioscan_list */ return 0; } -static void eventCallback(CALLBACK *pcallback) +static void eventCallback(epicsCallback *pcallback) { scan_list *psl; @@ -787,7 +787,7 @@ static void periodicTask(void *arg) taskwdInsert(0, NULL, NULL); epicsEventSignal(startStopEvent); - epicsTimeGetCurrent(&next); + epicsTimeGetMonotonic(&next); reported = next; while (ppsl->scanCtl != ctlExit) { @@ -798,7 +798,7 @@ static void periodicTask(void *arg) scanList(&ppsl->scan_list); epicsTimeAddSeconds(&next, ppsl->period); - epicsTimeGetCurrent(&now); + epicsTimeGetMonotonic(&now); delay = epicsTimeDiffInSeconds(&next, &now); if (delay <= 0.0) { if (overtime == 0.0) { @@ -944,7 +944,7 @@ static void spawnPeriodic(int ind) epicsEventWait(startStopEvent); } -static void ioscanCallback(CALLBACK *pcallback) +static void ioscanCallback(epicsCallback *pcallback) { ioscan_head *piosh; int prio; diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index 0daafc436..11939545b 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -56,7 +56,7 @@ typedef struct msgBuff TAB_BUFFER; # define MIN(x,y) (((x) < (y)) ? (x) : (y)) #endif #ifndef MAX -# define MAX(x,y) (((x) < (y)) ? (x) : (y)) +# define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif /* Local Routines */ @@ -712,7 +712,7 @@ long dbior(const char *pdrvName,int interest_level) for (pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) { - struct dset *pdset = pdevSup->pdset; + dset *pdset = pdevSup->pdset; const char *pname = pdevSup->name; if (!pdset || !pname) diff --git a/modules/database/src/ioc/db/db_test.c b/modules/database/src/ioc/db/db_test.c index 3d536f080..544cfdde2 100644 --- a/modules/database/src/ioc/db/db_test.c +++ b/modules/database/src/ioc/db/db_test.c @@ -21,6 +21,7 @@ #include "epicsStdlib.h" #include "epicsString.h" #include "errlog.h" +#include "epicsEvent.h" #define epicsExportSharedSymbols #include "db_access_routines.h" diff --git a/modules/database/src/ioc/db/menuAlarmStat.dbd b/modules/database/src/ioc/db/menuAlarmStat.dbd.pod similarity index 84% rename from modules/database/src/ioc/db/menuAlarmStat.dbd rename to modules/database/src/ioc/db/menuAlarmStat.dbd.pod index e8d7f1ced..78debf8c5 100644 --- a/modules/database/src/ioc/db/menuAlarmStat.dbd +++ b/modules/database/src/ioc/db/menuAlarmStat.dbd.pod @@ -7,6 +7,17 @@ # and higher are distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuAlarmStat + +This menu defines the possible alarm statuses that EPICS records can exhibit +which is used for C and C fields of all record types. +See L for more information. + +=menu menuAlarmStat + +=cut + menu(menuAlarmStat) { choice(menuAlarmStatNO_ALARM,"NO_ALARM") choice(menuAlarmStatREAD,"READ") diff --git a/modules/database/src/ioc/db/menuFtype.dbd b/modules/database/src/ioc/db/menuFtype.dbd.pod similarity index 88% rename from modules/database/src/ioc/db/menuFtype.dbd rename to modules/database/src/ioc/db/menuFtype.dbd.pod index af6a8803d..9df014d22 100644 --- a/modules/database/src/ioc/db/menuFtype.dbd +++ b/modules/database/src/ioc/db/menuFtype.dbd.pod @@ -6,6 +6,15 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuFtype + +This menu is used for the C and similar fields of many record types. + +=menu menuFtype + +=cut + menu(menuFtype) { choice(menuFtypeSTRING,"STRING") choice(menuFtypeCHAR,"CHAR") diff --git a/modules/database/src/ioc/db/menuIvoa.dbd b/modules/database/src/ioc/db/menuIvoa.dbd.pod similarity index 63% rename from modules/database/src/ioc/db/menuIvoa.dbd rename to modules/database/src/ioc/db/menuIvoa.dbd.pod index b1b3ce51f..8ea2c7a7d 100644 --- a/modules/database/src/ioc/db/menuIvoa.dbd +++ b/modules/database/src/ioc/db/menuIvoa.dbd.pod @@ -3,10 +3,19 @@ # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuIvoa + +This menu specifies the possibile actions to take when the INVALID alarm is +triggered. See individual record types for more information. + +=menu menuIvoa + +=cut + menu(menuIvoa) { choice(menuIvoaContinue_normally,"Continue normally") choice(menuIvoaDon_t_drive_outputs,"Don't drive outputs") diff --git a/modules/database/src/ioc/db/menuOmsl.dbd b/modules/database/src/ioc/db/menuOmsl.dbd deleted file mode 100644 index 3022437dc..000000000 --- a/modules/database/src/ioc/db/menuOmsl.dbd +++ /dev/null @@ -1,13 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -menu(menuOmsl) { - choice(menuOmslsupervisory,"supervisory") - choice(menuOmslclosed_loop,"closed_loop") -} diff --git a/modules/database/src/std/rec/stateRecord.dbd b/modules/database/src/ioc/db/menuOmsl.dbd.pod similarity index 50% rename from modules/database/src/std/rec/stateRecord.dbd rename to modules/database/src/ioc/db/menuOmsl.dbd.pod index 6e43ddbba..833f44354 100644 --- a/modules/database/src/std/rec/stateRecord.dbd +++ b/modules/database/src/ioc/db/menuOmsl.dbd.pod @@ -6,19 +6,20 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* -recordtype(state) { - include "dbCommon.dbd" - field(VAL,DBF_STRING) { - prompt("Value") - promptgroup("40 - Input") - asl(ASL0) - pp(TRUE) - size(20) - } - field(OVAL,DBF_STRING) { - prompt("Prev Value") - special(SPC_NOMOD) - interest(3) - size(20) - } + +=head1 Menu menuOmsl + +This menu is used for the C field of many output record types. It controls +whether the record will fetch an input value from its C input link when +processed, which is useful when it is part of a closed loop control algorithm. +The C state means the input link will not be used, C +enables the input link. + +=menu menuOmsl + +=cut + +menu(menuOmsl) { + choice(menuOmslsupervisory,"supervisory") + choice(menuOmslclosed_loop,"closed_loop") } diff --git a/modules/database/src/ioc/db/menuYesNo.dbd b/modules/database/src/ioc/db/menuYesNo.dbd deleted file mode 100644 index 2d09dd65a..000000000 --- a/modules/database/src/ioc/db/menuYesNo.dbd +++ /dev/null @@ -1,13 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -menu(menuYesNo) { - choice(menuYesNoNO,"NO") - choice(menuYesNoYES,"YES") -} diff --git a/modules/database/src/ioc/db/menuYesNo.dbd.pod b/modules/database/src/ioc/db/menuYesNo.dbd.pod new file mode 100644 index 000000000..d4237e7b8 --- /dev/null +++ b/modules/database/src/ioc/db/menuYesNo.dbd.pod @@ -0,0 +1,29 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=head1 Menu menuYesNo + +This menu is used by many record types to specify simple C or C +options for record-specific purposes. + +Note that no other values for a field that uses menuYesNo are possible, e.g. +C or C would not be accepted as choices for the field. +Also, the choices C, C, and C are not valid choices since they +don't match the case of C or C. +The integer values C<0> and C<1> may often be used instead however, they are +used as an index into the choices so C<0> becomes C and C<1> becomes . + +=menu menuYesNo + +=cut + +menu(menuYesNo) { + choice(menuYesNoNO,"NO") + choice(menuYesNoYES,"YES") +} diff --git a/modules/database/src/ioc/dbStatic/dbBase.h b/modules/database/src/ioc/dbStatic/dbBase.h index df3be4352..9e61211c6 100644 --- a/modules/database/src/ioc/dbStatic/dbBase.h +++ b/modules/database/src/ioc/dbStatic/dbBase.h @@ -19,6 +19,7 @@ #include "ellLib.h" #include "dbDefs.h" #include "recSup.h" +#include "devSup.h" typedef struct dbMenu { ELLNODE node; @@ -40,7 +41,7 @@ typedef struct devSup { char *choice; int link_type; /*Following only available on run time system*/ - struct dset *pdset; + dset *pdset; struct dsxt *pdsxt; /* Extended device support */ }devSup; diff --git a/modules/database/src/ioc/dbStatic/devSup.h b/modules/database/src/ioc/dbStatic/devSup.h index 73dba198c..dc55a35dd 100644 --- a/modules/database/src/ioc/dbStatic/devSup.h +++ b/modules/database/src/ioc/dbStatic/devSup.h @@ -153,6 +153,9 @@ typedef struct dset { /* device support entry table */ typedef typed_dset dset; #endif /* USE_TYPED_DSET */ +/* exists only to disambiguate dset dbCommon::dset */ +typedef dset unambiguous_dset; + /** Fetch INP or OUT link (or NULL if record type has neither). * * Recommended for use in device support init_record() diff --git a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h index a6ca60617..d08357b6e 100644 --- a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h +++ b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h @@ -12,7 +12,16 @@ #define INCdbLoadTemplateh #include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + epicsShareFunc int dbLoadTemplate( const char *sub_file, const char *cmd_collect); +#ifdef __cplusplus +} +#endif + #endif /*INCdbLoadTemplateh*/ diff --git a/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c b/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c index 201a32398..879f67e19 100644 --- a/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c +++ b/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c @@ -22,7 +22,7 @@ static const iocshFuncDef dbLoadTemplateFuncDef = {"dbLoadTemplate", 2, dbLoadTemplateArgs}; static void dbLoadTemplateCallFunc(const iocshArgBuf *args) { - dbLoadTemplate(args[0].sval, args[1].sval); + iocshSetError(dbLoadTemplate(args[0].sval, args[1].sval)); } diff --git a/modules/database/src/ioc/misc/dbCore.dbd b/modules/database/src/ioc/misc/dbCore.dbd index 51f9c9640..adde24e4f 100644 --- a/modules/database/src/ioc/misc/dbCore.dbd +++ b/modules/database/src/ioc/misc/dbCore.dbd @@ -33,3 +33,6 @@ variable(callbackParallelThreadsDefault,int) # Real-time operation variable(dbThreadRealtimeLock,int) + +# show logClient network activity +variable(logClientDebug,int) diff --git a/modules/database/src/ioc/misc/epicsRelease.c b/modules/database/src/ioc/misc/epicsRelease.c index 5eb55960c..90056d99f 100644 --- a/modules/database/src/ioc/misc/epicsRelease.c +++ b/modules/database/src/ioc/misc/epicsRelease.c @@ -16,12 +16,13 @@ #define epicsExportSharedSymbols #include "epicsRelease.h" +#include "epicsVCS.h" epicsShareFunc int coreRelease(void) { printf ( "############################################################################\n" ); printf ( "## %s\n", epicsReleaseVersion ); - printf ( "## %s\n", "EPICS Base built " __DATE__ ); + printf ( "## %s\n", "Rev. " EPICS_VCS_VERSION ); printf ( "############################################################################\n" ); return 0; } diff --git a/modules/database/src/ioc/misc/iocInit.c b/modules/database/src/ioc/misc/iocInit.c index 05bf7880e..b8aa438a2 100644 --- a/modules/database/src/ioc/misc/iocInit.c +++ b/modules/database/src/ioc/misc/iocInit.c @@ -433,7 +433,7 @@ static void initDevSup(void) for (pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) { - struct dset *pdset = registryDeviceSupportFind(pdevSup->name); + dset *pdset = registryDeviceSupportFind(pdevSup->name); if (!pdset) { errlogPrintf("device support %s not found\n",pdevSup->name); @@ -456,7 +456,7 @@ static void finishDevSup(void) for (pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) { - struct dset *pdset = pdevSup->pdset; + dset *pdset = pdevSup->pdset; if (pdset && pdset->init) pdset->init(1); diff --git a/modules/database/src/ioc/misc/miscIocRegister.c b/modules/database/src/ioc/misc/miscIocRegister.c index 6c08ef0c9..4dffdfca0 100644 --- a/modules/database/src/ioc/misc/miscIocRegister.c +++ b/modules/database/src/ioc/misc/miscIocRegister.c @@ -22,28 +22,28 @@ static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL}; static void iocInitCallFunc(const iocshArgBuf *args) { - iocInit(); + iocshSetError(iocInit()); } /* iocBuild */ static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL}; static void iocBuildCallFunc(const iocshArgBuf *args) { - iocBuild(); + iocshSetError(iocBuild()); } /* iocRun */ static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL}; static void iocRunCallFunc(const iocshArgBuf *args) { - iocRun(); + iocshSetError(iocRun()); } /* iocPause */ static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL}; static void iocPauseCallFunc(const iocshArgBuf *args) { - iocPause(); + iocshSetError(iocPause()); } /* coreRelease */ @@ -77,7 +77,7 @@ static const iocshArg * const systemArgs[] = {&systemArg0}; static const iocshFuncDef systemFuncDef = {"system",1,systemArgs}; static void systemCallFunc(const iocshArgBuf *args) { - system(args[0].sval); + iocshSetError(system(args[0].sval)); } #endif diff --git a/modules/database/src/ioc/registry/registryCommon.c b/modules/database/src/ioc/registry/registryCommon.c index 56664c5bb..dbd10d8f9 100644 --- a/modules/database/src/ioc/registry/registryCommon.c +++ b/modules/database/src/ioc/registry/registryCommon.c @@ -46,6 +46,7 @@ void registerRecordTypes(DBBASE *pbase, int nRecordTypes, } else { sizeOffset(dbEntry.precordType); } + dbFinishEntry(&dbEntry); } } diff --git a/modules/database/src/ioc/registry/registryDeviceSupport.c b/modules/database/src/ioc/registry/registryDeviceSupport.c index 4310c923d..ab3584ecd 100644 --- a/modules/database/src/ioc/registry/registryDeviceSupport.c +++ b/modules/database/src/ioc/registry/registryDeviceSupport.c @@ -18,12 +18,12 @@ static void *registryID = "device support"; epicsShareFunc int registryDeviceSupportAdd( - const char *name, const struct dset *pdset) + const char *name, const dset *pdset) { return registryAdd(registryID, name, (void *)pdset); } -epicsShareFunc struct dset * registryDeviceSupportFind( +epicsShareFunc dset * registryDeviceSupportFind( const char *name) { return registryFind(registryID, name); diff --git a/modules/database/src/ioc/registry/registryDeviceSupport.h b/modules/database/src/ioc/registry/registryDeviceSupport.h index 52a269863..78cdea6f0 100644 --- a/modules/database/src/ioc/registry/registryDeviceSupport.h +++ b/modules/database/src/ioc/registry/registryDeviceSupport.h @@ -18,8 +18,8 @@ extern "C" { #endif epicsShareFunc int registryDeviceSupportAdd( - const char *name, const struct dset *pdset); -epicsShareFunc struct dset * registryDeviceSupportFind( + const char *name, const dset *pdset); +epicsShareFunc dset * registryDeviceSupportFind( const char *name); #ifdef __cplusplus diff --git a/modules/database/src/ioc/rsrv/camessage.c b/modules/database/src/ioc/rsrv/camessage.c index 72a4b17a1..f54bb4888 100644 --- a/modules/database/src/ioc/rsrv/camessage.c +++ b/modules/database/src/ioc/rsrv/camessage.c @@ -861,6 +861,14 @@ static int host_name_action ( caHdrLargeArray *mp, void *pPayload, return RSRV_ERROR; } + /* after all validation */ + if(asCheckClientIP) { + + DLOG (2, ( "CAS: host_name_action for \"%s\" ignores client provided host name\n", + client->pHostName ) ); + return RSRV_OK; + } + /* * user name will not change if there isnt enough memory */ diff --git a/modules/database/src/ioc/rsrv/caserverio.c b/modules/database/src/ioc/rsrv/caserverio.c index 20a1c1c5b..afce46e25 100644 --- a/modules/database/src/ioc/rsrv/caserverio.c +++ b/modules/database/src/ioc/rsrv/caserverio.c @@ -56,7 +56,7 @@ void cas_send_bs_msg ( struct client *pclient, int lock_needed ) if ( pclient->disconnect ) { if ( CASDEBUG > 2 ) { errlogPrintf ( "CAS: msg Discard for sock %d addr %x\n", - pclient->sock, (unsigned) pclient->addr.sin_addr.s_addr ); + (int)pclient->sock, (unsigned) pclient->addr.sin_addr.s_addr ); } pclient->send.stk = 0u; if(lock_needed) diff --git a/modules/database/src/ioc/rsrv/caservertask.c b/modules/database/src/ioc/rsrv/caservertask.c index f377d837f..629b7b0b5 100644 --- a/modules/database/src/ioc/rsrv/caservertask.c +++ b/modules/database/src/ioc/rsrv/caservertask.c @@ -335,7 +335,7 @@ void rsrv_build_addr_lists(void) char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - errlogPrintf("rsrv: failed to set mcast ttl %d\n", ttl); + errlogPrintf("rsrv: failed to set mcast ttl %d\n", (int)ttl); } } #endif @@ -1343,10 +1343,13 @@ void casExpandBuffer ( struct message_buffer *buf, ca_uint32_t size, int sendbuf // round up to multiple of 4K size = ((size-1)|0xfff)+1; - if (buf->type==mbtLargeTCP) + if (buf->type==mbtLargeTCP) { newbuf = realloc (buf->buf, size); - else + if(newbuf) + buf->buf = newbuf; + } else { newbuf = malloc (size); + } newtype = mbtLargeTCP; newsize = size; @@ -1421,6 +1424,20 @@ struct client *create_tcp_client (SOCKET sock , const osiSockAddr *peerAddr) } client->addr = peerAddr->ia; + if(asCheckClientIP) { + epicsUInt32 ip = ntohl(client->addr.sin_addr.s_addr); + client->pHostName = malloc(24); + if(!client->pHostName) { + destroy_client ( client ); + return NULL; + } + epicsSnprintf(client->pHostName, 24, + "%u.%u.%u.%u", + (ip>>24)&0xff, + (ip>>16)&0xff, + (ip>>8)&0xff, + (ip>>0)&0xff); + } /* * see TCP(4P) this seems to make unsolicited single events much diff --git a/modules/database/src/ioc/rsrv/server.h b/modules/database/src/ioc/rsrv/server.h index 4d502f77f..6392c692b 100644 --- a/modules/database/src/ioc/rsrv/server.h +++ b/modules/database/src/ioc/rsrv/server.h @@ -86,7 +86,7 @@ typedef struct client { ELLLIST chanList; ELLLIST chanPendingUpdateARList; ELLLIST putNotifyQue; - struct sockaddr_in addr; + struct sockaddr_in addr; /* peer address, TCP only */ epicsTimeStamp time_at_last_send; epicsTimeStamp time_at_last_recv; void *evuser; diff --git a/modules/database/src/std/Makefile b/modules/database/src/std/Makefile index 20a8658cb..d8eb39bdb 100644 --- a/modules/database/src/std/Makefile +++ b/modules/database/src/std/Makefile @@ -6,11 +6,14 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* +STDDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +TOP = ../../../.. -TOP = ../.. include $(TOP)/configure/CONFIG -STDDIR=$(TOP)/src/std +USR_CPPFLAGS += -DUSE_TYPED_RSET + +SHRLIB_VERSION = 3.17.0 LIBRARY_IOC += dbRecStd dbRecStd_LIBS = dbCore ca Com diff --git a/modules/database/src/std/dev/asSubRecordFunctions.c b/modules/database/src/std/dev/asSubRecordFunctions.c index 76943e94b..5bbd95886 100644 --- a/modules/database/src/std/dev/asSubRecordFunctions.c +++ b/modules/database/src/std/dev/asSubRecordFunctions.c @@ -34,7 +34,7 @@ /* The following is provided for access security*/ /*It allows a CA client to force access security initialization*/ -static void myCallback(CALLBACK *pcallback) +static void myCallback(epicsCallback *pcallback) { ASDBCALLBACK *pasdbcallback = (ASDBCALLBACK *)pcallback; subRecord *precord; diff --git a/modules/database/src/std/dev/devAiSoftCallback.c b/modules/database/src/std/dev/devAiSoftCallback.c index cf38c8713..8bf6385e1 100644 --- a/modules/database/src/std/dev/devAiSoftCallback.c +++ b/modules/database/src/std/dev/devAiSoftCallback.c @@ -36,7 +36,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; int smooth; diff --git a/modules/database/src/std/dev/devBiSoftCallback.c b/modules/database/src/std/dev/devBiSoftCallback.c index 314460049..607b1af33 100644 --- a/modules/database/src/std/dev/devBiSoftCallback.c +++ b/modules/database/src/std/dev/devBiSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/modules/database/src/std/dev/devLiSoftCallback.c b/modules/database/src/std/dev/devLiSoftCallback.c index caab523e5..d833939ee 100644 --- a/modules/database/src/std/dev/devLiSoftCallback.c +++ b/modules/database/src/std/dev/devLiSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/modules/database/src/std/dev/devMbbiDirectSoftCallback.c b/modules/database/src/std/dev/devMbbiDirectSoftCallback.c index d785f7386..e40a6b006 100644 --- a/modules/database/src/std/dev/devMbbiDirectSoftCallback.c +++ b/modules/database/src/std/dev/devMbbiDirectSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/modules/database/src/std/dev/devMbbiSoftCallback.c b/modules/database/src/std/dev/devMbbiSoftCallback.c index 3796bcee6..fee81b5d9 100644 --- a/modules/database/src/std/dev/devMbbiSoftCallback.c +++ b/modules/database/src/std/dev/devMbbiSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/modules/database/src/std/dev/devSiSoftCallback.c b/modules/database/src/std/dev/devSiSoftCallback.c index 8f679889e..fd0e3761b 100644 --- a/modules/database/src/std/dev/devSiSoftCallback.c +++ b/modules/database/src/std/dev/devSiSoftCallback.c @@ -37,7 +37,7 @@ typedef struct devPvt { DBADDR dbaddr; processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/modules/database/src/std/filters/Makefile b/modules/database/src/std/filters/Makefile index 6b4dc7917..ee6a0ae68 100644 --- a/modules/database/src/std/filters/Makefile +++ b/modules/database/src/std/filters/Makefile @@ -15,6 +15,7 @@ dbRecStd_SRCS += ts.c dbRecStd_SRCS += dbnd.c dbRecStd_SRCS += arr.c dbRecStd_SRCS += sync.c +dbRecStd_SRCS += decimate.c HTMLS += filters.html diff --git a/modules/database/src/std/filters/decimate.c b/modules/database/src/std/filters/decimate.c new file mode 100644 index 000000000..502422f55 --- /dev/null +++ b/modules/database/src/std/filters/decimate.c @@ -0,0 +1,117 @@ +/*************************************************************************\ +* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2010 Brookhaven National Laboratory. +* Copyright (c) 2010 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Authors: Ralph Lange , + * Andrew Johnson + */ + +#include + +#include "freeList.h" +#include "db_field_log.h" +#include "chfPlugin.h" +#include "epicsExport.h" + +typedef struct myStruct { + epicsInt32 n, i; +} myStruct; + +static void *myStructFreeList; + +static const +chfPluginArgDef opts[] = { + chfInt32(myStruct, n, "n", 1, 0), + chfPluginArgEnd +}; + +static void * allocPvt(void) +{ + myStruct *my = (myStruct*) freeListCalloc(myStructFreeList); + return (void *) my; +} + +static void freePvt(void *pvt) +{ + freeListFree(myStructFreeList, pvt); +} + +static int parse_ok(void *pvt) +{ + myStruct *my = (myStruct*) pvt; + + if (my->n < 1) + return -1; + + return 0; +} + +static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { + db_field_log *passfl = NULL; + myStruct *my = (myStruct*) pvt; + epicsInt32 i = my->i; + + if (pfl->ctx == dbfl_context_read) + return pfl; + + if (i++ == 0) + passfl = pfl; + else + db_delete_field_log(pfl); + + if (i >= my->n) + i = 0; + + my->i = i; + return passfl; +} + +static void channelRegisterPre(dbChannel *chan, void *pvt, + chPostEventFunc **cb_out, void **arg_out, db_field_log *probe) +{ + *cb_out = filter; + *arg_out = pvt; +} + +static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent) +{ + myStruct *my = (myStruct*) pvt; + printf("%*sDecimate (dec): n=%d, i=%d\n", indent, "", + my->n, my->i); +} + +static chfPluginIf pif = { + allocPvt, + freePvt, + + NULL, /* parse_error, */ + parse_ok, + + NULL, /* channel_open, */ + channelRegisterPre, + NULL, /* channelRegisterPost, */ + channel_report, + NULL /* channel_close */ +}; + +static void decInitialize(void) +{ + static int firstTime = 1; + + if (!firstTime) return; + firstTime = 0; + + if (!myStructFreeList) + freeListInitPvt(&myStructFreeList, sizeof(myStruct), 64); + + chfPluginRegister("dec", &pif, opts); +} + +epicsExportRegistrar(decInitialize); diff --git a/modules/database/src/std/filters/filters.dbd.pod b/modules/database/src/std/filters/filters.dbd.pod index d7ab785f5..27e356f83 100644 --- a/modules/database/src/std/filters/filters.dbd.pod +++ b/modules/database/src/std/filters/filters.dbd.pod @@ -14,6 +14,8 @@ The following filters are available in this release: =item * L +=item * L + =back =head2 Using Filters @@ -245,3 +247,41 @@ periods only when "blue" is true by using ... =cut + +registrar(decInitialize) + +=head3 Decimation Filter C<"dec"> + +This filter is used to reduce the number or rate of monitor updates from a +channel by an integer factor C that is provided as a filter argument, +discarding the other updates. A true decimation following the original meaning +of the word would be achieved by giving C as 10, to only allow every tenth +update through. + +=head4 Parameters + +=over + +=item Number C<"n"> + +The decimation factor, a positive integer. Giving n=1 is equivalent to a no-op +that allows all updates to be passed to the client. + +=back + +This filter is intentionally very simplistic. It passes on the first monitor +event that it sees after the channel connects, then discards the next N-1 events +before sending the next event. If several clients connect to a channel using the +same filter settings they may see completely different data streams since each +client gets its own instance of the filter whose event counter starts when that +client connects. + +=head4 Example + +To sample a 60Hz channel at 1Hz, a 10Hz channel every 6 seconds or a 1Hz channel +once every minute: + + Hal$ camonitor 'test:channel' 'test:channel.{"dec":{"n":60}}' + ... + +=cut diff --git a/modules/database/src/std/filters/sync.c b/modules/database/src/std/filters/sync.c index d137dd7a9..a7f7b6bd1 100644 --- a/modules/database/src/std/filters/sync.c +++ b/modules/database/src/std/filters/sync.c @@ -110,7 +110,9 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { passfl = pfl; pfl = NULL; } - break; + else + db_delete_field_log(pfl); + goto save_state; case syncModeLast: if (!actstate && my->laststate) { passfl = my->lastfl; @@ -122,28 +124,34 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { passfl = pfl; pfl = NULL; } - break; + else + db_delete_field_log(pfl); + goto save_state; case syncModeWhile: - if (actstate) { + if (actstate) passfl = pfl; - } + else + db_delete_field_log(pfl); goto no_shift; case syncModeUnless: - if (!actstate) { + if (!actstate) passfl = pfl; - } + else + db_delete_field_log(pfl); goto no_shift; } if (my->lastfl) db_delete_field_log(my->lastfl); my->lastfl = pfl; - my->laststate = actstate; /* since no copy is made we can't keep a reference to the returned fl */ assert(my->lastfl != passfl); - no_shift: +save_state: + my->laststate = actstate; + +no_shift: return passfl; } diff --git a/modules/database/src/std/rec/Makefile b/modules/database/src/std/rec/Makefile index b2c0512ed..87021987e 100644 --- a/modules/database/src/std/rec/Makefile +++ b/modules/database/src/std/rec/Makefile @@ -55,3 +55,7 @@ stdRecords_DBD = $(patsubst %,%.dbd,$(stdRecords)) dbRecStd_SRCS += $(patsubst %,%.c,$(stdRecords)) HTMLS += $(patsubst %.dbd.pod,%.html,$(notdir $(wildcard ../rec/*Record.dbd.pod))) + +vpath %.png $(SRC_DIRS) +HTMLS += image/compress-1.png +HTMLS += image/compress-2.png diff --git a/modules/database/src/std/rec/aaiRecord.c b/modules/database/src/std/rec/aaiRecord.c index 7805c9fba..51af45f61 100644 --- a/modules/database/src/std/rec/aaiRecord.c +++ b/modules/database/src/std/rec/aaiRecord.c @@ -356,10 +356,10 @@ static long readValue(aaiRecord *prec) recGblSetSevr(prec, SIMM_ALARM, prec->sims); if (prec->sdly >= 0) { - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { /* very lazy allocation of callback structure */ - pvt = calloc(1, sizeof(CALLBACK)); + pvt = calloc(1, sizeof(epicsCallback)); prec->simpvt = pvt; } if (pvt) diff --git a/modules/database/src/std/rec/aaiRecord.dbd b/modules/database/src/std/rec/aaiRecord.dbd index 15db6d360..b4675b302 100644 --- a/modules/database/src/std/rec/aaiRecord.dbd +++ b/modules/database/src/std/rec/aaiRecord.dbd @@ -122,7 +122,7 @@ recordtype(aai) { prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } field(MPST,DBF_MENU) { prompt("Post Value Monitors") diff --git a/modules/database/src/std/rec/aaoRecord.c b/modules/database/src/std/rec/aaoRecord.c index b71750052..ccf05179f 100644 --- a/modules/database/src/std/rec/aaoRecord.c +++ b/modules/database/src/std/rec/aaoRecord.c @@ -367,9 +367,9 @@ static long writeValue(aaoRecord *prec) status = pdset->write_aao(prec); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/aaoRecord.dbd b/modules/database/src/std/rec/aaoRecord.dbd index a1731a3cb..20e957ff4 100644 --- a/modules/database/src/std/rec/aaoRecord.dbd +++ b/modules/database/src/std/rec/aaoRecord.dbd @@ -122,7 +122,7 @@ recordtype(aao) { prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } field(MPST,DBF_MENU) { prompt("Post Value Monitors") diff --git a/modules/database/src/std/rec/aiRecord.c b/modules/database/src/std/rec/aiRecord.c index 500193360..0e3593282 100644 --- a/modules/database/src/std/rec/aiRecord.c +++ b/modules/database/src/std/rec/aiRecord.c @@ -508,9 +508,9 @@ static long readValue(aiRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/aiRecord.dbd.pod b/modules/database/src/std/rec/aiRecord.dbd.pod index 69ca65f3f..3b53b7a24 100644 --- a/modules/database/src/std/rec/aiRecord.dbd.pod +++ b/modules/database/src/std/rec/aiRecord.dbd.pod @@ -4,7 +4,7 @@ # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# in file LICENSE that is included with this distribution. #************************************************************************* =title Analog Input Record (ai) @@ -214,7 +214,7 @@ monitoring functionality. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_DOUBLE) { prompt("Current EGU Value") promptgroup("40 - Input") @@ -516,7 +516,7 @@ simulation mode. prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } } @@ -547,7 +547,7 @@ The individual routines are described below. =head3 Device Support Routines -=head4 long report(int level) + long report(int level) This optional routine is called by the IOC command C and is passed the report level that was requested by the user. @@ -557,7 +557,7 @@ information at higher levels, or to select different types of information with different levels. Level zero should print no more than a small summary. -=head4 long init(int after) + long init(int after) This optional routine is called twice at IOC initialization time. The first call happens before any of the C calls are made, with @@ -565,7 +565,7 @@ the integer parameter C set to 0. The second call happens after all of the C calls have been made, with C set to 1. -=head4 long init_record(aiRecord *prec) + long init_record(aiRecord *prec) This optional routine is called by the record initialization code for each ai record instance that has its DTYP field set to use this device support. @@ -582,7 +582,7 @@ C, but it is not necessary to check that condition first. This same calculation takes place in the C routine, so the implementation can usually just call that routine to perform the task. -=head4 long get_ioint_info(int cmd, aiRecord *prec, IOSCANPVT *piosl) + long get_ioint_info(int cmd, aiRecord *prec, IOSCANPVT *piosl) This optional routine is called whenever the record's SCAN field is being changed to or from the value C to find out which I/O Interrupt Scan @@ -611,7 +611,7 @@ thread. The C routine is safe to call from an interrupt service routine on embedded architectures (vxWorks and RTEMS). -=head4 long read_ai(aiRecord *prec) + long read_ai(aiRecord *prec) This essential routine is called when the record wants a new value from the addressed device. @@ -622,7 +622,7 @@ It is responsible for performing (or at least initiating) a read operation, and ... return value ... -=head4 long special_linconv(aiRecord *prec, int after) + long special_linconv(aiRecord *prec, int after) This optional routine should be provided if the record type's unit conversion features are used by the device support's C routine returning a diff --git a/modules/database/src/std/rec/aoRecord.c b/modules/database/src/std/rec/aoRecord.c index c5a84f615..6fa65859b 100644 --- a/modules/database/src/std/rec/aoRecord.c +++ b/modules/database/src/std/rec/aoRecord.c @@ -574,9 +574,9 @@ static long writeValue(aoRecord *prec) status = dbPutLink(&prec->siol, DBR_DOUBLE, &prec->oval, 1); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/aoRecord.dbd.pod b/modules/database/src/std/rec/aoRecord.dbd.pod index f2361df7e..c54cb2c4f 100644 --- a/modules/database/src/std/rec/aoRecord.dbd.pod +++ b/modules/database/src/std/rec/aoRecord.dbd.pod @@ -70,7 +70,7 @@ output value PVAL is added to it. =head4 Drive Limits The output value is now clipped to the range DRVL to DRVH inclusive, provided -that DRVH > DRVL. +that DRVH E DRVL. The result is copied into both the VAL and PVAL fields. =head4 Limit Rate of Change @@ -164,9 +164,7 @@ OUT field must specify the address of the I/O card. In addition, the DTYP field must contain the name of the device support module. Be aware that the address format differs according to the I/O bus used. See Address Specification for information on the format of hardware -addresses. The user can see a list of the device support modules -currently supported at the user's local site by using the dbst utility -in R3.13. +addresses. For soft records the output link can be a database link, a channel access link, or a constant value. If the link is a constant, no output @@ -573,7 +571,7 @@ information on these fields. prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } field(IVOA,DBF_MENU) { prompt("INVALID output action") @@ -620,7 +618,7 @@ terminated. For compatibility with old device supports that don't know EOFF, if both EOFF and ESLO have their default value, EOFF is set to EGUL. -If device support includes init_record, it is called. +If device support includes C, it is called. INIT is set TRUE. This causes PBRK, LBRK, and smoothing to be re-initialized. If "backwards" linear conversion is requested, then VAL @@ -647,10 +645,6 @@ called. INIT is set TRUE. This causes PBRK, LBRK, and smoothing to be re-initialized. -=item get_value - -Fills in the values of struct valueDes so that they refer to VAL. - =item get_alarm_double Sets the following values: @@ -930,7 +924,7 @@ OUT link type must be either a CONSTANT, DB_LINK, or CA_LINK. This module writes the current value of OVAL. If the OUT link type is PV_LINK, then dbCaAddInlink is called by -init_record. init_record always returns a value of 2, which means that +C. C always returns a value of 2, which means that no conversion will ever be attempted. write_ao calls recGblPutLinkValue to write the current value of VAL. diff --git a/modules/database/src/std/rec/biRecord.c b/modules/database/src/std/rec/biRecord.c index be700a56a..9c0ddb3c0 100644 --- a/modules/database/src/std/rec/biRecord.c +++ b/modules/database/src/std/rec/biRecord.c @@ -304,9 +304,9 @@ static long readValue(biRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/biRecord.dbd.pod b/modules/database/src/std/rec/biRecord.dbd.pod index fbf343ad4..62bcf3bf2 100644 --- a/modules/database/src/std/rec/biRecord.dbd.pod +++ b/modules/database/src/std/rec/biRecord.dbd.pod @@ -69,9 +69,7 @@ If the binary input record gets its value from hardware, the address of the card must be entered in the INP field, and the name of the device support module must be entered in the DTYP field. See L
    for information on the format of the hardware address. Be aware that the format -differs between types of cards. You can see a list of device support -modules currently supported at the user's local site by using C -utility (R3.13). +differs between types of cards. For records that specify C or C device support routines, the INP field can be a channel or a database link, or a @@ -94,18 +92,18 @@ the device support module reads a value directly into VAL or the C device support is used. The value can also be fetched as one of the strings specified in the ZNAM or ONAM fields. The ZNAM field has a string that corresponds to the 0 state, so when the value is fetched as -this string, C will return a 0. The ONAM field hold the +this string, C will return a 0. The ONAM field hold the string that corresponds to the 1 state, so when the value is fetched as -this string, C returns a 1. +this string, C returns a 1. =fields ZNAM, ONAM =head3 Operator Display Parameters These parameters are used to present meaningful data to the operator. The -C record support routine can retrieve the state string -corresponding to the VAL's state. If the value is 1, C will -return the string in the ONAM field; and if 0, C will return +C record support routine can retrieve the state string +corresponding to the VAL's state. If the value is 1, C will +return the string in the ONAM field; and if 0, C will return the ZNAM string. See L for more on the record name (NAME) @@ -149,7 +147,7 @@ The LALM fields holds the value of the last occurence of the change of state alarm. It is used to implement the change of state alarm, and thus only has meaning if COSV is MAJOR or MINOR. -The MSLT field is used by the C record support routine to +The MSLT field is used by the C record support routine to determine if archive and value change monitors are invoked. They are if MSLT is not equal to VAL. @@ -164,7 +162,7 @@ these fields. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(INP,DBF_INLINK) { prompt("Input Specification") promptgroup("40 - Input") @@ -286,14 +284,14 @@ these fields. prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } =head2 Record Support =head3 Record Support Routines -=head2 C + long init_record(struct dbCommon *precord, int pass); This routine initializes SIMM with the value of SIML if SIML type is a CONSTANT link or creates a channel access link if SIML type is PV_LINK. @@ -303,25 +301,21 @@ This routine next checks to see that device support is available and a device support routine is defined. If neither exist, an error is issued and processing is terminated. -If device support includes C, it is called. +If device support includes C, it is called. -=head2 C + long process(struct dbCommon *precord); -See next section. +See L below. -=head2 C - -Fills in the values of struct valueDes so that they refer to VAL. - -=head2 C + long get_enum_str(const struct dbAddr *paddr, char *pbuffer); Retrieves ASCII string corresponding to VAL. -=head2 C + long get_enum_strs(const struct dbAddr *paddr, struct dbr_enumStrs *p); Retrieves ASCII strings for ZNAM and ONAM. -=head2 C + long put_enum_str(const struct dbAddr *paddr, const char *pbuffer); Check if string matches ZNAM or ONAM, and if it does, sets VAL. @@ -329,7 +323,7 @@ Check if string matches ZNAM or ONAM, and if it does, sets VAL. Routine process implements the following algorithm: -=over 1 +=over =item 1. Check to see that the appropriate device support module exists. If it @@ -338,7 +332,7 @@ the PACT field still set to TRUE. This ensures that processes will no longer be called for this record. Thus error storms will not occur. =item 2. -C is called. See L for details. +C is called. See L for details. =item 3. If PACT has been changed to TRUE, the device support read routine has @@ -350,7 +344,7 @@ Convert. =back -=over 1 +=over =item * status = read_bi @@ -359,7 +353,7 @@ status = read_bi PACT = TRUE =item * -TIME = tslocaltime +C is called. =item * if status is 0, then set VAL=(0,1) if RVAL is (0, not 0) and UDF = False. @@ -369,7 +363,7 @@ if status is 2, set status = 0 =back -=over 1 +=over =item 5. Check alarms: This routine checks to see if the new VAL causes the alarm @@ -381,7 +375,7 @@ Check if monitors should be invoked: =back -=over 1 +=over =item * Alarm monitors are invoked if the alarm status or severity has changed. @@ -397,7 +391,7 @@ NSEV and NSTA are reset to 0. =back -=over 1 +=over =item 7. Scan forward link if necessary, set PACT FALSE, and return. @@ -410,7 +404,7 @@ Scan forward link if necessary, set PACT FALSE, and return. Each binary input record must have an associated set of device support routines. The primary resposibility of the device support routines is to -obtain a new raw input value whenever C is called. The device +obtain a new raw input value whenever C is called. The device support routines are primarily interested in the following fields: =fields PACT, DPVT, UDF, NSEV, NSTA, VAL, INP, RVAL, MASK @@ -419,27 +413,37 @@ support routines are primarily interested in the following fields: Device support consists of the following routines: -=head2 C + long report(int level); -Not currently used. +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. -=head2 C + long init(int after); -This routine is called once during IOC initialization. +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. -=head2 C + long init_record(struct dbCommon *precord); This routine is optional. If provided, it is called by the record support -C routine. +C routine. -=head2 C + long get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt); -This routine is called by the C system each time the record is +This routine is called by the ioEventScan system each time the record is added or deleted from an I/O event scan list. C has the value (0,1) if the record is being (added to, deleted from) and I/O event list. It must be provided for any device type that can use the ioEvent scanner. -=head2 C + long read_bi(struct dbCommon *precord); This routine must provide a new input value. It returns the following values: @@ -466,25 +470,25 @@ link type must be either CONSTANT, DB_LINK, or CA_LINK. =head3 Soft Channel -C always returns a value of 2, which means that no conversion is +C always returns a value of 2, which means that no conversion is performed. If the INP link type is CONSTANT, then the constant value is stored in VAL -by C, and the UDF is set to FALSE. VAL can be changed via -C requests. If the INP link type is PV_LINK, the C is -called by C. +by C, and the UDF is set to FALSE. VAL can be changed via +C requests. If the INP link type is PV_LINK, the C is +called by C. -C calls C to read the current value of VAL. +C calls C to read the current value of VAL. See L for details. -If the return status of C is zero, then C sets -UDF to FALSE. The status of C is returned. +If the return status of C is zero, then C sets +UDF to FALSE. The status of C is returned. =head3 Raw Soft Channel This module is like the previous except that values are read into RVAL. -C returns a value of 0. Thus the record processing routine will +C returns a value of 0. Thus the record processing routine will force VAL to be 0 or 1. =cut diff --git a/modules/database/src/std/rec/boRecord.c b/modules/database/src/std/rec/boRecord.c index 186182311..4cfe62d48 100644 --- a/modules/database/src/std/rec/boRecord.c +++ b/modules/database/src/std/rec/boRecord.c @@ -98,7 +98,7 @@ struct bodset { /* binary output dset */ /* control block for callback*/ typedef struct myCallback { - CALLBACK callback; + epicsCallback callback; struct dbCommon *precord; }myCallback; @@ -106,7 +106,7 @@ static void checkAlarms(boRecord *); static void monitor(boRecord *); static long writeValue(boRecord *); -static void myCallbackFunc(CALLBACK *arg) +static void myCallbackFunc(epicsCallback *arg) { myCallback *pcallback; boRecord *prec; @@ -439,9 +439,9 @@ static long writeValue(boRecord *prec) status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/boRecord.dbd.pod b/modules/database/src/std/rec/boRecord.dbd.pod index fe0a98e6e..6b6d1800c 100644 --- a/modules/database/src/std/rec/boRecord.dbd.pod +++ b/modules/database/src/std/rec/boRecord.dbd.pod @@ -65,9 +65,9 @@ C or C. If C is specified, the value in the VAL field can be set externally via dbPuts at run-time. If C is specified, the VAL field's value is obtained from the address specified in the desired output location (DOL) field which can be a -database link, a channel access link, or a constant. To achieve continuous -control, a database link to a control algorithm record should be entered in -the DOL field. +database link or a channel access link, but not a constant. To achieve +continuous control, a database link to a control algorithm record should be +entered in the DOL field. L
    presents more information on database addresses and links. L explaines the effect of database @@ -130,8 +130,7 @@ It must specify the address of an I/O card if the record sends its output to hardware, and the DTYP field must contain the corresponding device support module. Be aware that the address format differs according to the I/O bus used. See L
    for information on the format of -hardware addresses. You can see a list of device support modules currently -supported at the user's local site by using the C utility in R3.13. +hardware addresses. Otherwise, if the record is configured to use the soft device support modules, then it can be either a database link, a channel access link, or a @@ -143,9 +142,9 @@ this chapter for more on output to other records. =head3 Operator Display Parameters These parameters are used to present meaningful data to the operator, The -C record support routine can retrieve the state string -corresponding to the VAL's state. So, if the value is 1, C -will return the string in the ONAM field: and if 0, C will +C record support routine can retrieve the state string +corresponding to the VAL's state. So, if the value is 1, C +will return the string in the ONAM field: and if 0, C will return the ZNAM string. See L for more on the record name (NAME) @@ -194,7 +193,7 @@ The LALM field holds the value of the last occurrence of the change of state alarm. It is used to implement the change of state alarm, and thus only has meaning if COSV is MINOR or MAJOR. -The MLST is used by the C record support routine to determine if +The MLST is used by the C record support routine to determine if archive and value change monitors are invoked. They are if MLST is not equal to VAL. @@ -366,7 +365,7 @@ information on these fields. prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } field(IVOA,DBF_MENU) { prompt("INVALID outpt action") @@ -400,17 +399,13 @@ exist, and error message is issued and processing is terminated. If DOL is a constant, then VAL is initialized to 1 if its value is nonzero or initialzed to 0 if DOL is zero, and UDF is set to FALSE. -If device support includes C, it is called. VAL is set using +If device support includes C, it is called. VAL is set using RVAL, and UDF is set to FALSE. =head2 C See next section. -=head2 C - -Fills in the values of struct valueDes so that they refer to VAL. - =head2 C Retrieves ASCII string corresponding to VAL. @@ -443,7 +438,7 @@ If PACT is FALSE =over =item * -If DOL is DB_LINK and OMSL is CLOSED_LOOP +If DOL holds a link and OMSL is C =over @@ -527,27 +522,37 @@ Scan forward link if necessary, set PACT FALSE, and return Each binary output record must have an associated set of device support routines. The primary responsibility of the device support routines is to -write a new value whenever C is called. The device support routines +write a new value whenever C is called. The device support routines are primarily interested in the following fields: =fields PACT, DPVT, NSEV, NSTA, VAL, OUT, RVAL, MASK, RBV -=head3 Decive Support Routines +=head3 Device Support Routines Device support consists of the following routines: -=head2 C +=head4 long report(int level) -Not currently used. +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. -=head2 C +=head4 long init(int after) -This routine is called once during IOC initialization. +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. =head2 C This routine is optional. If provided, it is called by record support -C routine. It should determine MASK if it is needed. +C routine. It should determine MASK if it is needed. =over @@ -593,10 +598,10 @@ link type must be either CONSTANT, DB_LINK, or CA_LINK. This module writes the current value of VAL. -If the OUT link type is PV_LINK, then C is called by -C. C always returns a value of 2, which means -that no conversion will ever be attempted. C calls -C to write the current value of VAL. See L +If the OUT link type is PV_LINK, then C is called by +C. C always returns a value of 2, which means +that no conversion will ever be attempted. C calls +C to write the current value of VAL. See L for details. =head3 Raw Soft Channel diff --git a/modules/database/src/std/rec/calcRecord.dbd.pod b/modules/database/src/std/rec/calcRecord.dbd.pod index c50667fb3..243c81eee 100644 --- a/modules/database/src/std/rec/calcRecord.dbd.pod +++ b/modules/database/src/std/rec/calcRecord.dbd.pod @@ -261,22 +261,22 @@ ATAN: Arc tangent =over 1 =item * ->= : Greater than or equal to +C<<< >= >>> : Greater than or equal to =item * -> : Greater than +C<<< > >>> : Greater than =item * -<= : Less than or equal to +C<<< <= >>> : Less than or equal to =item * -< : Less than +C<<< < >>> : Less than =item * -# : Not equal to +C<<< # >>> : Not equal to =item * -= : Equal to +C<<< = >>> : Equal to =back @@ -285,13 +285,13 @@ ATAN: Arc tangent =over 1 =item * -&& : And +C<&&> : And =item * -|| : Or +C<||> : Or =item * -! : Not +C : Not =back @@ -300,10 +300,10 @@ ATAN: Arc tangent =over 1 =item * -| : Bitwise Or +C<|> : Bitwise Or =item * -& : Bitwise And +C<&> : Bitwise And =item * OR : Bitwise Or @@ -315,13 +315,13 @@ AND : Bitwise And XOR : Bitwise Exclusive Or =item * -~ : One's Complement +C<~> : One's Complement =item * -<< : Left shift +C<<< << >>> : Left shift =item * ->> : Right shift +C<<< >> >>> : Right shift =back @@ -330,7 +330,7 @@ XOR : Bitwise Exclusive Or =over 1 =item * -:= : assigns a value (right hand side) to a variable (i.e. field) +C<:=> : assigns a value (right hand side) to a variable (i.e. field) =back @@ -360,35 +360,35 @@ C =over 1 =item * -Result is A + B + 10 +Result is C =back =head3 Relational -C<(A + B) < (C + D)> +C<<< (A + B) < (C + D) >>> =over 1 =item * -Result is 1 if (A + B) < (C + D) +Result is 1 if C<<< (A + B) < (C + D) >>> =item * -Result is 0 if (A + B) >= (C + D) +Result is 0 if C<<< (A + B) >= (C + D) >>> =back =head3 Question Mark -C<(A + B) < (C + D) ? E : F + L + 10> +C<<< (A + B) < (C + D) ? E : F + L + 10 >>> =over 1 =item * -Result is E if (A + B) < (C + D) +Result is C if C<<< (A + B) < (C + D) >>> =item * -Result is F + L + 10 if (A + B) >= (C + D) +Result is C if C<<< (A + B) >= (C + D) >>> =back @@ -412,7 +412,7 @@ C<(A + B) < (C + D) ? E : VAL> =head3 Logical -C +C =over 1 @@ -851,10 +851,6 @@ See next section. This is called if CALC is changed. C calls postfix. -=head2 C - -Fills in the values of struct valueDes so that the refer to VAL. - =head2 C Retrieves EGU. diff --git a/modules/database/src/std/rec/calcoutRecord.c b/modules/database/src/std/rec/calcoutRecord.c index 8b5525527..d9f66af3c 100644 --- a/modules/database/src/std/rec/calcoutRecord.c +++ b/modules/database/src/std/rec/calcoutRecord.c @@ -117,8 +117,8 @@ typedef struct calcoutDSET { #define CA_LINKS_NOT_OK 2 typedef struct rpvtStruct { - CALLBACK doOutCb; - CALLBACK checkLinkCb; + epicsCallback doOutCb; + epicsCallback checkLinkCb; short cbScheduled; short caLinkStat; /* NO_CA_LINKS, CA_LINKS_ALL_OK, CA_LINKS_NOT_OK */ } rpvtStruct; @@ -128,7 +128,7 @@ static void monitor(calcoutRecord *prec); static int fetch_values(calcoutRecord *prec); static void execOutput(calcoutRecord *prec); static void checkLinks(calcoutRecord *prec); -static void checkLinksCallback(CALLBACK *arg); +static void checkLinksCallback(epicsCallback *arg); static long writeValue(calcoutRecord *prec); int calcoutRecDebug; @@ -702,7 +702,7 @@ static int fetch_values(calcoutRecord *prec) return(status); } -static void checkLinksCallback(CALLBACK *arg) +static void checkLinksCallback(epicsCallback *arg) { calcoutRecord *prec; @@ -760,7 +760,7 @@ static void checkLinks(calcoutRecord *prec) prpvt->caLinkStat = NO_CA_LINKS; if (!prpvt->cbScheduled && caLinkNc) { - /* Schedule another CALLBACK */ + /* Schedule another epicsCallback */ prpvt->cbScheduled = 1; callbackRequestDelayed(&prpvt->checkLinkCb, .5); } diff --git a/modules/database/src/std/rec/calcoutRecord.dbd.pod b/modules/database/src/std/rec/calcoutRecord.dbd.pod index 6289f9043..a59eaa348 100644 --- a/modules/database/src/std/rec/calcoutRecord.dbd.pod +++ b/modules/database/src/std/rec/calcoutRecord.dbd.pod @@ -293,22 +293,22 @@ ATAN: Arc tangent =over 1 =item * ->= : Greater than or equal to +C<<< >= >>> : Greater than or equal to =item * -> : Greater than +C<<< > >>> : Greater than =item * -<= : Less than or equal to +C<<< <= >>> : Less than or equal to =item * -< : Less than +C<<< < >>> : Less than =item * -# : Not equal to +C<<< # >>> : Not equal to =item * -= : Equal to +C<<< = >>> : Equal to =back @@ -332,10 +332,10 @@ ATAN: Arc tangent =over 1 =item * -| : Bitwise Or +C<|> : Bitwise Or =item * -& : Bitwise And +C<&> : Bitwise And =item * OR : Bitwise Or @@ -347,13 +347,13 @@ AND : Bitwise And XOR : Bitwise Exclusive Or =item * -~ : One's Complement +C<~> : One's Complement =item * -<< : Left shift +C<<< << >>> : Left shift =item * ->> : Right shift +C<<< >> >>> : Right shift =back @@ -362,11 +362,11 @@ XOR : Bitwise Exclusive Or =over 1 =item * -:= : assigns a value (right hand side) to a variable (i.e. field) +C<:=> : assigns a value (right hand side) to a variable (i.e. field) =back -=head3 Parentheses and Comma +=head3 Parentheses, Comma, and Semicolon The open and close parentheses are supported. Nested parentheses are supported. @@ -374,6 +374,10 @@ supported. The comma is supported when used to separate the arguments of a binary function. +The semicolon is used to separate expressions. Although only one +traditional calculation expression is allowed, multiple assignment +expressions are allowed. + =head3 Conditional Expression The C language's question mark operator is supported. The format is: @@ -388,41 +392,59 @@ C =over 1 =item * -Result is A + B + 10 +Result is C =back =head3 Relational -C<(A + B) < (C + D)> +C<<< (A + B) < (C + D) >>> =over 1 =item * -Result is 1 if (A + B) < (C + D) +Result is 1 if C<<< (A + B) < (C + D) >>> =item * -Result is 0 if (A + B) >= (C + D) +Result is 0 if C<<< (A + B) >= (C + D) >>> =back =head3 Question Mark -C<(A + B) < (C + D) ? E : F + L + 10> +C<<< (A + B) < (C + D) ? E : F + L + 10 >>> =over 1 =item * -Result is E if (A + B) < (C + D) +Result is C if C<<< (A + B) < (C + D) >>> =item * -Result is F + L + 10 if (A + B) >= (C + D) +Result is C if C<<< (A + B) >= (C + D) >>> + +=back + +Prior to Base 3.14.9 it was legal to omit the : and the second (else) part +of the conditional, like this: + +C<(A + B)<(C + D) ? E> + +=over 1 + +=item +Result is E if (A + B)<(C + D) + +=item +Result is unchanged if (A + B)>=(C + D) + +From 3.14.9 onwards, this expression must be written as +C<(A + B) < (C + D) ? E : VAL> =back =head3 Logical -C +C =over 1 @@ -447,6 +469,18 @@ Convert result to floating point =back +=head3 Assignment + +C + +=over 1 + +=item * +Causes the Calc record to output the successive values of a sine curve in +1 degree intervals. + +=back + =head3 Output Parameters These parameters specify and control the output capabilities of the Calcout @@ -471,7 +505,7 @@ C -- write output every time VAL changes, i.e., every time the result of the expression changes. =item * -C -- when record is preocessed, write output if VAL is zero. +C -- when record is processed, write output if VAL is zero. =item * C -- when record is processed, write output if VAL is @@ -497,9 +531,9 @@ output is executed. The field is a menu field with two options: If C is specified, when the record writes its output it will write the result of the expression in the CALC field, that is, it will write the value of the VAL field. If C is specified, -the record will instead write the result of the expresion in the OCAL +the record will instead write the result of the expression in the OCAL field, which is contained in the OVAL field. The OCAL field is exactly like -the CALC field and has the same fuctionality it can contain the string +the CALC field and has the same functionality it can contain the string representation of an expression which is evaluated at run-time. Thus, if necessary, the record can use the result of the CALC expression to determine if data should be written and can use the result of the OCAL @@ -514,7 +548,7 @@ the wait is over. The field DLYA is equal to 1 during the delay period. The resolution of the delay entry system dependent. The IVOA field specifies what action to take with the OUT link if the -Calcout record eneters an INVALID alarm status. The options are +Calcout record enters an INVALID alarm status. The options are C, C, and C. If the IVOA field is C, the data entered into the IVOV field is written to the OUT link if the record alarm severity is @@ -529,7 +563,7 @@ are also meant to represent the status of the record at run-time. The EGU field contains a string of up to 16 characters which is supplied by the user and which describes the values being operated upon. The string is -retrieved whenever the routine C is called. The EGU string is +retrieved whenever the routine C is called. The EGU string is solely for an operator's sake and does not have to be used. The HOPR and LOPR fields on;y refer to the limits if the VAL, HIHI, HIGH, @@ -568,7 +602,7 @@ The CLCV and OLCV fields indicate the validity of the expression in the CALC and OCAL fields respectfully. If the expression in invalid, the field is set to one. -The DYLA field is set to one during the delay specified in ODLY. +The DLYA field is set to one during the delay specified in ODLY. See L for more information on the record name (NAME) and description (DESC) fields. @@ -583,7 +617,7 @@ record support routines. The Calculation alarm is called by the record processing routine when the CALC expression is an invalid one, upon which an error message is generated. -The following alarm parametersi, which are configured by the user, define the +The following alarm parameters, which are configured by the user, define the limit alarms for the VAL field and the severity corresponding to those conditions. @@ -599,7 +633,7 @@ common to all record types. These parameters are used to determine when to send monitors for the value fields. These monitors are sent when the value field exceeds the last monitored field by the appropriate deadband, the ADEL for archiver monitors -and the MDEL field for all aother types of monitors. If these fields have a +and the MDEL field for all other types of monitors. If these fields have a value of zero, every time the value changes, monitors are triggered; if they have a value of -1, every time the record is scanned, monitors are triggered. See L for a complete explanation of @@ -1146,10 +1180,6 @@ See next section. This is called id CALC or OCAL is changed. C calls postfix. -=head2 C - -Fills in the values of struct valueDes so that they refer to VAL. - =head2 C Retrieves EGU. @@ -1163,13 +1193,13 @@ Retrieves PREC. Sets the upper display and lower display limits for a field. If the field is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the field has upper and lower limits defined they will be used, else the -upper and lower macimum values for the field type will be used. +upper and lower maximum values for the field type will be used. =head2 C Sets the upper control and lower control limits for a field. If the VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the -field has upper and lower limits defimed they will be used, else the upper +field has upper and lower limits defined they will be used, else the upper and lower maximum values for the field will be used. =head2 C @@ -1211,7 +1241,7 @@ honors the alarm hysteresis factor (HYST). Thus the value must change by at least HYST before the alarm status and severity changes. =item 4. -Determin if the Output Execution Option (OOPT) is met. If it met, either +Determine if the Output Execution Option (OOPT) is met. If it met, either execute the output link (and output event) immediately (if ODLY = 0), or schedule a callback after the specified interval. See the explanation for the C routine below. @@ -1237,7 +1267,7 @@ NSEV and NSTA are reset to 0 =back =item 6. -If no output delay was specified, scan forwark link if necessaru, set PACT +If no output delay was specified, scan forward link if necessary, set PACT FALSE, and return. =back @@ -1260,7 +1290,7 @@ put the value of OVAL to the OUT link and post the event in OEVT (if non-zero). =item 4. -If an output delay was implemented, process the forwark link. +If an output delay was implemented, process the forward link. =back diff --git a/modules/database/src/std/rec/compressRecord.dbd.pod b/modules/database/src/std/rec/compressRecord.dbd.pod index 265cdfe8a..3bc3416a7 100644 --- a/modules/database/src/std/rec/compressRecord.dbd.pod +++ b/modules/database/src/std/rec/compressRecord.dbd.pod @@ -4,10 +4,10 @@ # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# in file LICENSE that is included with this distribution. #************************************************************************* -=title Compress Record (compress) +=title Compression Record (compress) The data compression record is used to collect and compress data from arrays. When the INP field references a data array field, it immediately compresses the @@ -62,11 +62,299 @@ menu(bufferingALG) { } recordtype(compress) { -=fields VAL +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scanning Parameters + +The compression record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in +L. In addition, L +explains how these fields are used. Since the compression record supports no +direct interfaces to hardware, its SCAN field cannot specify C<<< I/O Intr >>>. + +=head3 Algorithms and Related Parameters + +The user specifies the algorithm to be used in the ALG field. There are six possible +algorithms which can be specified as follows: + +=head4 Menu compressALG + +=menu compressALG + +The following fields determine what channel to read and how to compress the data: + +=fields ALG, INP, NSAM, N, ILIL, IHIL, OFF, RES + +As stated above, the ALG field specifies which algorithm to be performed on the data. + +The INP should be a database or channel access link. Though INP can be a constant, +the data compression algorithms are supported only when INP is a database link. See +L
    for information on specifying links. + + +IHIL and ILIL can be set to provide an initial value filter on the input array. +If ILIL E IHIL, the input elements will be skipped until a value is found +that is in the range of ILIL to IHIL. Note that ILIL and IHIL are used only in +C<<< N to 1 >>> algorithms. + +OFF provides the offset to the current beginning of the array data. +Note that OFF is used only in C<<< N to 1 >>> algorithms. + +The RES field can be accessed at run time to cause the algorithm to reset +itself before the maximum number of samples are reached. + +=head4 Algorithms + +B algorithm keeps a circular buffer of length NSAM. +Each time the record is processed, it gets the data referenced by INP and puts +it into the circular buffer referenced by VAL. The INP can refer to both scalar or +array data and VAL is just a time ordered circular buffer of values obtained +from INP. +Note that N, ILIL, IHIL and OFF are not used in C<<< Circular Buffer >>> algorithm. + +B takes an average of every element of the array obtained from +INP over time; that is, the entire array referenced by INP is retrieved, and for +each element, the new average is calculated and placed in the corresponding +element of the value buffer. The retrieved array is truncated to be of length +NSAM. N successive arrays are averaged and placed in the buffer. Thus, VAL[0] +holds the average of the first element of INP over N samples, VAL[1] holds the +average of the next element of INP over N samples, and so on. The following +shows the equation: + +=for comment Latex form of equation bellow : VAL[i] \leftarrow \frac{1}{N}\sum_{n=1}^NINP_{n}[i] + +=begin html + + + +=end html + +B If any of the C<<< N to 1 >>> algorithms are chosen, then VAL is a circular +buffer of NSAM samples. +The actual algorithm depends on whether INP references a scalar or an array. + +If INP refers to a scalar, then N successive time ordered samples of INP are taken. +After the Nth sample is obtained, a new value determined by the algorithm +(Lowest, Highest, or Average), is written to the circular buffer referenced by +VAL. If C<<< Low Value >>> the lowest value of all the samples is written; if +C<<< High Value >>> the highest value is written; and if C<<< Average >>>, the +average of all the samples are written. The C<<< Median >>> setting behaves +like C<<< Average >>> with scalar input data. + +If INP refers to an array, then the following applies: + +=over + +=item C<<< N to 1 Low Value >>> + +Compress N to 1 samples, keeping the lowest value. + +=item C<<< N to 1 High Value >>> + +Compress N to 1 samples, keeping the highest value. + +=item C<<< N to 1 Average >>> + +Compress N to 1 samples, taking the average value. + +=item C<<< N to 1 Median >>> + +Compress N to 1 samples, taking the median value. + +=back + +The compression record keeps NSAM data samples. + +The field N determines the number of elements to compress into each result. + +Thus, if NSAM was 3, and N was also equal to 3, then the algorithms would work +as in the following diagram: + +=begin html + + + +=end html + + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the record either textually or +graphically. + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +The EGU field should be given a string that describes the value of VAL, but is +used whenever the C<<< get_units >>> record support routine is called. + +The HOPR and LOPR fields only specify the upper and lower display limits for +VAL, HIHI, HIGH, LOLO and LOW fields. + +PREC controls the floating-point precision whenever C<<< get_precision >>> is +called, and the field being referenced is the VAL field (i.e., one of the values +contained in the circular buffer). + +See L +for more on the record name (NAME) and description (DESC) fields. + + +=head3 Alarm Parameters + +The compression record has the alarm parameters common to all record types +described in L. + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the data +compression algorithm. They are not configurable by the user, though some are +accessible at run-time. They can represent the current state of the waveform or +of the record whose field is referenced by the INP field. + +=fields NUSE, OUSE, BPTR, SPTR, WPTR, CVB, INPN, INX + +NUSE and OUSE hold the current and previous number of elements stored in VAL. + +BPTR is a pointer that refers to the buffer referenced by VAL. + +SPTR points to an array that is used for array averages. + +WPTR is used by the dbGetlinks routines. + +=head2 Record Support + +=head3 Record Support Routines + + long init_record(struct dbCommon *precord, int pass) + +Space for all necessary arrays is allocated. The addresses are stored in the +appropriate fields in the record. + + long process(struct dbCommon *precord) + +See L below. + + long special(struct dbAddr *paddr, int after) + +This routine is called when RSET, ALG, or N are set. It performs a reset. + + long cvt_dbaddr(struct dbAddr *paddr) + +This is called by dbNameToAddr. It makes the dbAddr structure refer to the +actual buffer holding the result. + + long get_array_info(struct dbAddr *paddr, long *no_elements, long *offset) + +Obtains values from the circular buffer referenced by VAL. + + long put_array_info(struct dbAddr *paddr, long nNew); + +Writes values into the circular buffer referenced by VAL. + + long get_units(struct dbAddr *paddr, char *units); + +Retrieves EGU. + + long get_precision(const struct dbAddr *paddr, long *precision); + +Retrieves PREC. + + long get_graphic_double(struct dbAddr *paddr, struct dbr_grDouble *p); + +Sets the upper display and lower display limits for a field. If the field is +VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + + long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *p); + +Sets the upper control and the lower control limits for a field. If the field is +VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +If INP is not a database link, check monitors and the forward link and return. + +=item 2. + +Get the current data referenced by INP. + +=item 3. + +Perform the appropriate algorithm: + +=over + +=item * + +Average: Read N successive instances of INP and perform an element by element +average. Until N instances have been obtained it just return without checking +monitors or the forward link. When N instances have been obtained complete the +algorithm, store the result in the VAL array, check monitors and the forward +link, and return. + +=item * + +Circular Buffer: Write the values obtained from INP into the VAL array as a +circular buffer, check monitors and the forward link, and return. + +=item * + +N to 1 xxx when INP refers to a scalar: Obtain N successive values from INP and +apply the N to 1 xxx algorithm to these values. Until N values are obtained +monitors and forward links are not triggered. When N successive values have been +obtained, complete the algorithm, check monitors and trigger the forward link, +and return. + +=item * + +N to 1 xxx when INP refers to an array: The ILIL and IHIL are honored if ILIL +E IHIL. The input array is divided into subarrays of length N. The specified +N to 1 xxx compression algorithm is applied to each sub-array and the result +stored in the array referenced by VAL. The monitors and forward link are +checked. + +=back + +=item 4. + +If success, set UDF to FALSE. + +=item 5. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_NOACCESS) { prompt("Value") asl(ASL0) diff --git a/modules/database/src/std/rec/dfanoutRecord.dbd.pod b/modules/database/src/std/rec/dfanoutRecord.dbd.pod index 0d0487666..8943bf9b9 100644 --- a/modules/database/src/std/rec/dfanoutRecord.dbd.pod +++ b/modules/database/src/std/rec/dfanoutRecord.dbd.pod @@ -128,7 +128,7 @@ value on the VAL field. The HOPR and LOPR fields determine the upper and lower display limits for graphic displays and the upper and lower control limits for control displays. They apply to the VAL, HIHI, HIGH, LOW, and LOLO fields. The -record support routines C or C +record support routines C and C retrieve HOPR and LOPR. See L for more on the record name (NAME) @@ -379,11 +379,6 @@ and the DOL link, a non-zero value is returned if an error occurs. See next section. -=head2 C - -This routine fills in the members of C with the VAL fields -value and characteristics. - =head2 C The routine copies the string specified in the EGU field to the location @@ -399,13 +394,13 @@ routine is called. =head2 C -Same as the C routine except that it uses the +Same as the C routine except that it uses the C structure. =head2 C This sets the members of the C structure to the specified -alarm limits if the referenced field is VAL: +alarm limits when the referenced field is VAL: =over @@ -427,26 +422,32 @@ is called. =over =item 1. -The C routine first retrieves a value for DOL and places it in -VAL if OMSL is set to colsed loop mode. If an error occurs, then UDF is set -to FALSE. +The C routine first checks that DOL is not a constant link and +that OMSL is set to "closed_loop". If so, it retrieves a value through DOL +and places it into VAL. If no errors occur, UDF is set to FALSE. =item 2. -PACT is set TRUE +PACT is set TRUE, and the record's timestamp is set. =item 3. -VAL is then sent to all the records specified in the OUTA-OUTH fields by -calling C for each link. +A value is fetched from SELL and placed into SELN. =item 4. -Alarms are checked and monitors are called if conditions apply. +Alarms ranges are checked against the contents of the VAL field. =item 5. -The data fanout's own forward link is then processed. +VAL is then sent through the OUTA-OUTH links by calling C for +each link, conditional on the setting of SELM and the value in SELN. =item 6. -PACT is set FALSE, and the C routine returns. A -1 is returned -if there was an error writing values to one of the output links. +Value and archive monitors are posted on the VAL field if appropriate based on +the settings of MDEL and ADEL respectively. + +=item 7. +The data fanout's forward link FLNK is processed. + +=item 6. +PACT is set FALSE, and the C routine returns. =back diff --git a/modules/database/src/std/rec/eventRecord.c b/modules/database/src/std/rec/eventRecord.c index dbaef0114..c10c90240 100644 --- a/modules/database/src/std/rec/eventRecord.c +++ b/modules/database/src/std/rec/eventRecord.c @@ -199,9 +199,9 @@ static long readValue(eventRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/eventRecord.dbd b/modules/database/src/std/rec/eventRecord.dbd deleted file mode 100644 index 57306f5f5..000000000 --- a/modules/database/src/std/rec/eventRecord.dbd +++ /dev/null @@ -1,82 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(event) { - include "dbCommon.dbd" - field(VAL,DBF_STRING) { - prompt("Event Name To Post") - promptgroup("40 - Input") - special(SPC_MOD) - asl(ASL0) - size(40) - } - %#include "dbScan.h" - field(EPVT, DBF_NOACCESS) { - prompt("Event private") - special(SPC_NOMOD) - interest(4) - extra("EVENTPVT epvt") - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup("40 - Input") - interest(1) - } - field(SIOL,DBF_INLINK) { - prompt("Simulation Input Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SVAL,DBF_STRING) { - prompt("Simulation Value") - size(40) - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } -} diff --git a/modules/database/src/std/rec/eventRecord.dbd.pod b/modules/database/src/std/rec/eventRecord.dbd.pod new file mode 100644 index 000000000..c783e984f --- /dev/null +++ b/modules/database/src/std/rec/eventRecord.dbd.pod @@ -0,0 +1,305 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Event Record (event) + +The normal use for this record type is to post an event and/or process a +forward link. Device support for this record can provide a hardware interrupt +handler routine for I/O Event-scanned records. + +=head2 Parameter Fields + +The records in this field fall into the following groups of parameters: + +=over + +=item * + +scan parameters + +=item * + +read parameters + +=item * + +event number parameters + +=item * + +simulation mode parameters + +=back + +=recordtype event + +=cut + +recordtype(event) { + include "dbCommon.dbd" + +=head3 Scan Parameters + +The event record has the standard fields for specifying under what circumstances +it will be processed. If the SCAN field specifies C, then device +support will provide an interrupt handler, posting an event number when an I/O +interrupt occurs. These fields are listed in L. In addition, +L explains how the scanning fields work. Note that I/O +event scanning is only supported for those card types that interrupt. + +=head3 Event Number Parameters + +The VAL field contains the event number read by the device support routines. It +is this number which is posted. For records that use C device +support, it can be configured before run-time or set via dbPuts. + +=fields VAL + +=cut + + field(VAL,DBF_STRING) { + prompt("Event Name To Post") + promptgroup("40 - Input") + special(SPC_MOD) + asl(ASL0) + size(40) + } + %#include "dbScan.h" + field(EPVT, DBF_NOACCESS) { + prompt("Event private") + special(SPC_NOMOD) + interest(4) + extra("EVENTPVT epvt") + } + +=head3 Input Specification + +The device support routines use the address in this record to obtain input. For +records that provide an interrupt handler, the INP field should specify the +address of the I/O card, and the DTYP field should specify a valid device +support module. Be aware that the address format differs according to the card +type used. See L
    for information on the format of +hardware addresses and specifying links. + +For soft records, the INP field can be a constant, a database link, or a channel +access link. For soft records, the DTYP field should specify C. + +=fields INP, DTYP + +=cut + + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup("40 - Input") + interest(1) + } + +=head3 Operator Display Parameters + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The Event record has the alarm parameters common to all record types. L lists other fields related to alarms that are common to all record +types. + +=head3 Simulation Mode Parameters + +The following fields are used to operate the event record in the simulation +mode. See L for more information on these +fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS + +=cut + + field(SIOL,DBF_INLINK) { + prompt("Sim Input Specifctn") + promptgroup("90 - Simulate") + interest(1) + } + field(SVAL,DBF_STRING) { + prompt("Simulation Value") + size(40) + } + field(SIML,DBF_INLINK) { + prompt("Sim Mode Location") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Sim mode Alarm Svrty") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM with the value of SIML if SIML type is a CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +If device support includes C, it is called. + +=head4 process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +readValue is called. See L for more information. + +=item 2. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 3. + +If VAL E 0, post event number VAL. + +=item 4. + +Check to see if monitors should be invoked. Alarm monitors are invoked if the +alarm status or severity has chanet to 0. + +=item 5. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=head2 Device Support + +=head3 Fields of Interest To Device Support + +Each record must have an associated set of device support routines. The device +support routines are primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, INP, PRIO + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the record is +being (added to, deleted from) an I/O event list. It must be provided for any +device type that can use the ioEvent scanner. + +=head4 read_event + + read_event(precord) + +This routine returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C device support module is available. The INP link type must +be either CONSTANT, DB_LINK, or CA_LINK. + +If the INP link type is CONSTANT, then the constant value is stored into VAL by +C, and UDF is set to FALSE. If the INP link type is PV_LINK, then +dbCaAddInlink is called by C. + +C calls recGblGetLinkValue to read the current value of VAL. See +L for details on soft input. + +=cut + +} diff --git a/modules/database/src/std/rec/fanoutRecord.dbd b/modules/database/src/std/rec/fanoutRecord.dbd deleted file mode 100644 index 251d63a11..000000000 --- a/modules/database/src/std/rec/fanoutRecord.dbd +++ /dev/null @@ -1,129 +0,0 @@ -#************************************************************************* -# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -menu(fanoutSELM) { - choice(fanoutSELM_All,"All") - choice(fanoutSELM_Specified,"Specified") - choice(fanoutSELM_Mask,"Mask") -} -recordtype(fanout) { - include "dbCommon.dbd" - field(VAL,DBF_LONG) { - prompt("Used to trigger") - asl(ASL0) - pp(TRUE) - } - field(SELM,DBF_MENU) { - prompt("Select Mechanism") - promptgroup("30 - Action") - interest(1) - menu(fanoutSELM) - } - field(SELN,DBF_USHORT) { - prompt("Link Selection") - interest(1) - initial("1") - } - field(SELL,DBF_INLINK) { - prompt("Link Selection Loc") - promptgroup("30 - Action") - interest(1) - } - field(OFFS,DBF_SHORT) { - prompt("Offset for Specified") - promptgroup("30 - Action") - interest(1) - initial("0") - } - field(SHFT,DBF_SHORT) { - prompt("Shift for Mask mode") - promptgroup("30 - Action") - interest(1) - initial("-1") - } - field(LNK0,DBF_FWDLINK) { - prompt("Forward Link 0") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK1,DBF_FWDLINK) { - prompt("Forward Link 1") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK2,DBF_FWDLINK) { - prompt("Forward Link 2") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK3,DBF_FWDLINK) { - prompt("Forward Link 3") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK4,DBF_FWDLINK) { - prompt("Forward Link 4") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK5,DBF_FWDLINK) { - prompt("Forward Link 5") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK6,DBF_FWDLINK) { - prompt("Forward Link 6") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK7,DBF_FWDLINK) { - prompt("Forward Link 7") - promptgroup("51 - Output 0-7") - interest(1) - } - field(LNK8,DBF_FWDLINK) { - prompt("Forward Link 8") - promptgroup("52 - Output 8-F") - interest(1) - } - field(LNK9,DBF_FWDLINK) { - prompt("Forward Link 9") - promptgroup("52 - Output 8-F") - interest(1) - } - field(LNKA,DBF_FWDLINK) { - prompt("Forward Link 10") - promptgroup("52 - Output 8-F") - interest(1) - } - field(LNKB,DBF_FWDLINK) { - prompt("Forward Link 11") - promptgroup("52 - Output 8-F") - interest(1) - } - field(LNKC,DBF_FWDLINK) { - prompt("Forward Link 12") - promptgroup("52 - Output 8-F") - interest(1) - } - field(LNKD,DBF_FWDLINK) { - prompt("Forward Link 13") - promptgroup("52 - Output 8-F") - interest(1) - } - field(LNKE,DBF_FWDLINK) { - prompt("Forward Link 14") - promptgroup("52 - Output 8-F") - interest(1) - } - field(LNKF,DBF_FWDLINK) { - prompt("Forward Link 15") - promptgroup("52 - Output 8-F") - interest(1) - } -} diff --git a/modules/database/src/std/rec/fanoutRecord.dbd.pod b/modules/database/src/std/rec/fanoutRecord.dbd.pod new file mode 100644 index 000000000..11a9ad32e --- /dev/null +++ b/modules/database/src/std/rec/fanoutRecord.dbd.pod @@ -0,0 +1,314 @@ +#************************************************************************* +# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Fanout Record (fanout) + +The fanout record uses several forward processing links to force multiple +passive records to scan. When more than one record needs to be scanned as the +result of a record being processed, the forward link of that record can specify +a fanout record. The fanout record can specify up to sixteen other records to +process. If more than sixteen are needed, one of the forward links in the fanout +record (or its FLNK field) can point to another fanout record. + +B The dfanout or +data fanout record can, on the other hand, send data to other records. + +=head2 Parameter Fields + +The fanout record's fields fall into the following categories: + +=over + +=item * + +scan parameters + +=item * + +operator display parameters + +=item * + +run-time parameters. + +=back + +=recordtype fanout + +=cut + +menu(fanoutSELM) { + choice(fanoutSELM_All,"All") + choice(fanoutSELM_Specified,"Specified") + choice(fanoutSELM_Mask,"Mask") +} + +recordtype(fanout) { + include "dbCommon.dbd" + +=head3 Scan Parameters + +The forward link fields of the fanout record (LNK0-LNK9, LNKA-LNKF) specify +records to be scanned. The records to be processed must specify C in +their SCAN fields; otherwise the forward link will not cause them to process. +Also when specifying database links for the fanout record, the user needs only +to specify the record name. As no value is being sent or retrieved, a field name +is only required when the link will be over Channel Access, in which case the +field PROC must be named. + +The SELM, SELN, and SELL fields specify the order of processing for the forward +links. The select mechanism menu field (SELM) has three choices: + +=menu fanoutSELM + +How the SELM value affects which links to process and in which order is as +follows: + +=over + +=item * + +B +Links are processed in numerical order - LNK0, LNK1, etc. + +=item * + +B The sum of the values in the SELN and OFFS fields is used as the +specifier of which link to process. For instance, with OFFS=0 and SELN=1, the +record targeted by LNK1 will be processed. + +=item * + +B The individual bits in SELN are shifted by SHFT bits (negative means +shift left) and the result used to select which links to process as follows: + +=over + +=item * + +If bit 0 (LSB) is set, LNK0 is processed. + +=item * + +If bit 1 is set, LNK2 is processed. + +=item * + +If bit 2 is set, LNK3 is processed, etc. + +=back + +=back + +SELN reads its value from SELL. SELL can be a constant, a database link, or a +channel access link. If a constant, SELN is initialized with the constant value +and can be changed via dbPuts. For database/channel access links, SELN is +retrieved from SELL each time the record is processed and can also be changed +via dbPuts. + +The Fanout record also has the standard scanning fields common to all records. +These fields are listed in L. In addition, +L explains in more detail how forward links and the +scanning algorithms work. + +=fields SELM, SELN, SELL, OFFS, SHFT, LNK0, LNK1, LNK2, LNK3, LNK4, LNK5, LNK6, LNK7, LNK8, LNK9, LNKA, LNKB, LNKC, LNKD, LNKE, LNKF + +=cut + + field(VAL,DBF_LONG) { + prompt("Used to trigger") + asl(ASL0) + pp(TRUE) + } + field(SELM,DBF_MENU) { + prompt("Select Mechanism") + promptgroup("30 - Action") + interest(1) + menu(fanoutSELM) + } + field(SELN,DBF_USHORT) { + prompt("Link Selection") + interest(1) + initial("1") + } + field(SELL,DBF_INLINK) { + prompt("Link Selection Loc") + promptgroup("30 - Action") + interest(1) + } + field(OFFS,DBF_SHORT) { + prompt("Offset for Specified") + promptgroup("30 - Action") + interest(1) + initial("0") + } + field(SHFT,DBF_SHORT) { + prompt("Shift for Mask mode") + promptgroup("30 - Action") + interest(1) + initial("-1") + } + field(LNK0,DBF_FWDLINK) { + prompt("Forward Link 0") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK1,DBF_FWDLINK) { + prompt("Forward Link 1") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK2,DBF_FWDLINK) { + prompt("Forward Link 2") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK3,DBF_FWDLINK) { + prompt("Forward Link 3") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK4,DBF_FWDLINK) { + prompt("Forward Link 4") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK5,DBF_FWDLINK) { + prompt("Forward Link 5") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK6,DBF_FWDLINK) { + prompt("Forward Link 6") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK7,DBF_FWDLINK) { + prompt("Forward Link 7") + promptgroup("51 - Output 0-7") + interest(1) + } + field(LNK8,DBF_FWDLINK) { + prompt("Forward Link 8") + promptgroup("52 - Output 8-F") + interest(1) + } + field(LNK9,DBF_FWDLINK) { + prompt("Forward Link 9") + promptgroup("52 - Output 8-F") + interest(1) + } + field(LNKA,DBF_FWDLINK) { + prompt("Forward Link 10") + promptgroup("52 - Output 8-F") + interest(1) + } + field(LNKB,DBF_FWDLINK) { + prompt("Forward Link 11") + promptgroup("52 - Output 8-F") + interest(1) + } + field(LNKC,DBF_FWDLINK) { + prompt("Forward Link 12") + promptgroup("52 - Output 8-F") + interest(1) + } + field(LNKD,DBF_FWDLINK) { + prompt("Forward Link 13") + promptgroup("52 - Output 8-F") + interest(1) + } + field(LNKE,DBF_FWDLINK) { + prompt("Forward Link 14") + promptgroup("52 - Output 8-F") + interest(1) + } + field(LNKF,DBF_FWDLINK) { + prompt("Forward Link 15") + promptgroup("52 - Output 8-F") + interest(1) + } + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. See +L for more on these fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The Fanout record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head3 Run-time Parameters + +The VAL field performs no specific function, but a Channel Access put to it will +cause the record to process. + +=fields VAL + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SELN with the value of SELL, if SELL type is CONSTANT +link, or creates a channel access link if SELL type is PV_LINK. + +=head4 process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +PACT is set to TRUE. + +=item 2. + +The link selection SELN is fetched. + +=item 3. + +Depending on the selection mechanism, the link selection forward links are +processed, and UDF is set to FALSE. + +=item 4. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 5. + +Scan forward link field FLNK if used, set PACT FALSE, and return. + +=back + +=cut + +} diff --git a/modules/database/src/std/rec/histogramRecord.c b/modules/database/src/std/rec/histogramRecord.c index cac81ffd0..82fc91a68 100644 --- a/modules/database/src/std/rec/histogramRecord.c +++ b/modules/database/src/std/rec/histogramRecord.c @@ -100,7 +100,7 @@ struct histogramdset { /* histogram input dset */ /* control block for callback*/ typedef struct myCallback { - CALLBACK callback; + epicsCallback callback; histogramRecord *prec; } myCallback; @@ -110,7 +110,7 @@ static void monitor(histogramRecord *); static long readValue(histogramRecord *); -static void wdogCallback(CALLBACK *arg) +static void wdogCallback(epicsCallback *arg) { myCallback *pcallback; histogramRecord *prec; @@ -403,9 +403,9 @@ static long readValue(histogramRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/histogramRecord.dbd b/modules/database/src/std/rec/histogramRecord.dbd index 545ae3fcc..304038bf1 100644 --- a/modules/database/src/std/rec/histogramRecord.dbd +++ b/modules/database/src/std/rec/histogramRecord.dbd @@ -154,7 +154,7 @@ recordtype(histogram) { prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } field(HOPR,DBF_ULONG) { prompt("High Operating Range") diff --git a/modules/database/src/std/rec/image/compress-1.png b/modules/database/src/std/rec/image/compress-1.png new file mode 100644 index 000000000..3001ce9f5 Binary files /dev/null and b/modules/database/src/std/rec/image/compress-1.png differ diff --git a/modules/database/src/std/rec/image/compress-2.png b/modules/database/src/std/rec/image/compress-2.png new file mode 100644 index 000000000..5ce46e041 Binary files /dev/null and b/modules/database/src/std/rec/image/compress-2.png differ diff --git a/modules/database/src/std/rec/int64inRecord.c b/modules/database/src/std/rec/int64inRecord.c index c76d96c67..8ce241000 100644 --- a/modules/database/src/std/rec/int64inRecord.c +++ b/modules/database/src/std/rec/int64inRecord.c @@ -420,9 +420,9 @@ static long readValue(int64inRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/int64inRecord.dbd.pod b/modules/database/src/std/rec/int64inRecord.dbd.pod index c85992f05..edb19a73f 100644 --- a/modules/database/src/std/rec/int64inRecord.dbd.pod +++ b/modules/database/src/std/rec/int64inRecord.dbd.pod @@ -313,7 +313,7 @@ simulation mode. prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } } diff --git a/modules/database/src/std/rec/int64outRecord.c b/modules/database/src/std/rec/int64outRecord.c index da5a76d8f..e9170f9a9 100644 --- a/modules/database/src/std/rec/int64outRecord.c +++ b/modules/database/src/std/rec/int64outRecord.c @@ -396,9 +396,9 @@ static long writeValue(int64outRecord *prec) status = dbPutLink(&prec->siol, DBR_INT64, &prec->val, 1); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/int64outRecord.dbd.pod b/modules/database/src/std/rec/int64outRecord.dbd.pod index f76541489..1b5003efe 100644 --- a/modules/database/src/std/rec/int64outRecord.dbd.pod +++ b/modules/database/src/std/rec/int64outRecord.dbd.pod @@ -350,7 +350,7 @@ simulation mode. prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } =head3 Invalid Alarm Output Action diff --git a/modules/database/src/std/rec/longinRecord.c b/modules/database/src/std/rec/longinRecord.c index f72ac9137..d52464137 100644 --- a/modules/database/src/std/rec/longinRecord.c +++ b/modules/database/src/std/rec/longinRecord.c @@ -428,9 +428,9 @@ static long readValue(longinRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/longinRecord.dbd b/modules/database/src/std/rec/longinRecord.dbd deleted file mode 100644 index f0e5a8de5..000000000 --- a/modules/database/src/std/rec/longinRecord.dbd +++ /dev/null @@ -1,188 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(longin) { - include "dbCommon.dbd" - field(VAL,DBF_LONG) { - prompt("Current value") - promptgroup("40 - Input") - asl(ASL0) - pp(TRUE) - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup("40 - Input") - interest(1) - } - field(EGU,DBF_STRING) { - prompt("Engineering Units") - promptgroup("80 - Display") - interest(1) - size(16) - prop(YES) - } - field(HOPR,DBF_LONG) { - prompt("High Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(LOPR,DBF_LONG) { - prompt("Low Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(HIHI,DBF_LONG) { - prompt("Hihi Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOLO,DBF_LONG) { - prompt("Lolo Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(HIGH,DBF_LONG) { - prompt("High Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOW,DBF_LONG) { - prompt("Low Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(HHSV,DBF_MENU) { - prompt("Hihi Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LLSV,DBF_MENU) { - prompt("Lolo Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HSV,DBF_MENU) { - prompt("High Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LSV,DBF_MENU) { - prompt("Low Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HYST,DBF_LONG) { - prompt("Alarm Deadband") - promptgroup("70 - Alarm") - interest(1) - } - field(AFTC, DBF_DOUBLE) { - prompt("Alarm Filter Time Constant") - promptgroup("70 - Alarm") - interest(1) - } - field(AFVL, DBF_DOUBLE) { - prompt("Alarm Filter Value") - special(SPC_NOMOD) - interest(3) - } - field(ADEL,DBF_LONG) { - prompt("Archive Deadband") - promptgroup("80 - Display") - interest(1) - } - field(MDEL,DBF_LONG) { - prompt("Monitor Deadband") - promptgroup("80 - Display") - interest(1) - } - field(LALM,DBF_LONG) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(ALST,DBF_LONG) { - prompt("Last Value Archived") - special(SPC_NOMOD) - interest(3) - } - field(MLST,DBF_LONG) { - prompt("Last Val Monitored") - special(SPC_NOMOD) - interest(3) - } - field(SIOL,DBF_INLINK) { - prompt("Simulation Input Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SVAL,DBF_LONG) { - prompt("Simulation Value") - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } -} diff --git a/modules/database/src/std/rec/longinRecord.dbd.pod b/modules/database/src/std/rec/longinRecord.dbd.pod new file mode 100644 index 000000000..cf2a3a395 --- /dev/null +++ b/modules/database/src/std/rec/longinRecord.dbd.pod @@ -0,0 +1,485 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Long Input Record (longin) + +The normal use for the long input record or "longin" record is to retrieve a +long integer value of up to 32 bits. Device support routines are provided to +support direct interfaces to hardware. In addition, the C<<< Soft Channel >>> +device module is provided to obtain input via database or channel access links +or via dbPutField or dbPutLink requests. + +=recordtype longin + +=cut + +recordtype(longin) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The long input record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in L. In addition, L explains how these fields are +used. Note that I/O event scanning is only supported for those card types +that interrupt. + +=head3 Read Parameters + +The device support routines use the INP field to obtain the record's input. For +records that obtain their input from devices, the INP field must contain the +address of the I/O card, and the DTYP field must specify the proper device +support module. Be aware that the address format differs according to the +I/O bus used. + +For soft records, the INP can be a constant, a database link, or a channel +access link. The value is read directly into VAL. The C<<< Soft Channel >>> +device support module is available for longin records. See L
    for information on the format of hardware addresses and a +database links. + +=fields VAL, INP, DTYP + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. These +fields are used to display the value and other parameters of the long input +either textually or graphically. + +EGU is a string of up to 16 characters describing the units that the long input +measures. It is retrieved by the C<<< get_units >>> record support routine. + +The HOPR and LOPR fields set the upper and lower display limits for the VAL, +HIHI, HIGH, LOW, and LOLO fields. Both the C<<< get_graphic_double >>> and C<<< +get_control_double >>> record support routines retrieve these fields. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields EGU, HOPR, LOPR, NAME, DESC + +=head3 Alarm Parameters + +The possible alarm conditions for long inputs are the SCAN, READ, and limit +alarms. The SCAN and READ alarms are called by the record or device support +routines. + +The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW +fields using numerical values. For each of these fields, there is a +corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. The +HYST field can be used to specify a deadband around each limit. See L for a complete explanation of alarms and these fields. L lists other fields related to a alarms that are common to all record +types. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the value +field. The monitors are sent when the value field exceeds the last monitored +field (see the next section) by the appropriate deadband. If these fields have a +value of zero, everytime the value changes, a monitor will be triggered; if they +have a value of -1, everytime the record is scanned, monitors are triggered. The +ADEL field is used by archive monitors and the MDEL field for all other types of +monitors. See L for a complete explanation of monitors. + +=fields ADEL, MDEL + +=head3 Run-time and Simulation Mode Parameters + +The LALM, MLST, and ALST fields are used to implement the hysteresis factors for +monitor callbacks. Only if the difference between these fields and the +corresponding value field is greater than the appropriate delta (MDEL, ADEL, +HYST)--only then are monitors triggered. For instance, only if the difference +between VAL and MLST is greater than MDEL are the monitors triggered for VAL. + +=fields LALM, ALST, MLST + +The following fields are used to operate the long input in the simulation mode. +See L for more information on these fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a device +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated. + +If device support includes C, it is called. + +=head4 process + +See next section. + +=head4 get_units + +Retrieves EGU. + +=head4 get_graphic_double + +Sets the upper display and lower display limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_control_double + +Sets the upper control and the lower control limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_alarm_double + +Sets the following values: + + upper_alarm_limit = HIHI + upper_warning_limit = HIGH + lower_warning_limit = LOW + lower_alarm_limit = LOLO + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +readValue is called. See L for more information. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. It also honors the +alarm hysteresis factor (HYST). Thus the value must change by more than HYST +before the alarm status and severity is lowered. + +=item 5. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if ADEL and MDEL conditions are +met. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each long input record must have an associated set of device support routines. +The primary responsibility of the device support routines is to obtain a new +input value whenever read_longin is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, VAL, INP + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 read_longin + + read_longin(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. A new value is placed in VAL. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C<<< Soft Channel >>> device support module places a value directly in VAL. + +If the INP link type is constant, then the constant value is stored into VAL by +C, and UDF is set to FALSE. If the INP link type is PV_LINK, then +dbCaAddInlink is called by C. + +C<<< read_longin >>> calls recGblGetLinkValue to read the current value of VAL. +See L for more information + +If the return status of C<<< recGblGetLinkValue >>> is zero then read_longin +sets UDF to FALSE. read_longin returns the status of C. + + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_LONG) { + prompt("Current value") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup("40 - Input") + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Engineering Units") + promptgroup("80 - Display") + interest(1) + size(16) + prop(YES) + } + field(HOPR,DBF_LONG) { + prompt("High Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(LOPR,DBF_LONG) { + prompt("Low Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(HIHI,DBF_LONG) { + prompt("Hihi Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_LONG) { + prompt("Lolo Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_LONG) { + prompt("High Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_LONG) { + prompt("Low Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HYST,DBF_LONG) { + prompt("Alarm Deadband") + promptgroup("70 - Alarm") + interest(1) + } + field(AFTC, DBF_DOUBLE) { + prompt("Alarm Filter Time Constant") + promptgroup("70 - Alarm") + interest(1) + } + field(AFVL, DBF_DOUBLE) { + prompt("Alarm Filter Value") + special(SPC_NOMOD) + interest(3) + } + field(ADEL,DBF_LONG) { + prompt("Archive Deadband") + promptgroup("80 - Display") + interest(1) + } + field(MDEL,DBF_LONG) { + prompt("Monitor Deadband") + promptgroup("80 - Display") + interest(1) + } + field(LALM,DBF_LONG) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_LONG) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_LONG) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + field(SIOL,DBF_INLINK) { + prompt("Sim Input Specifctn") + promptgroup("90 - Simulate") + interest(1) + } + field(SVAL,DBF_LONG) { + prompt("Simulation Value") + } + field(SIML,DBF_INLINK) { + prompt("Sim Mode Location") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Sim mode Alarm Svrty") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } +} diff --git a/modules/database/src/std/rec/longoutRecord.c b/modules/database/src/std/rec/longoutRecord.c index 5e13e09b9..06e3b6e21 100644 --- a/modules/database/src/std/rec/longoutRecord.c +++ b/modules/database/src/std/rec/longoutRecord.c @@ -401,9 +401,9 @@ static long writeValue(longoutRecord *prec) status = dbPutLink(&prec->siol, DBR_LONG, &prec->val, 1); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/longoutRecord.dbd b/modules/database/src/std/rec/longoutRecord.dbd deleted file mode 100644 index 626be1645..000000000 --- a/modules/database/src/std/rec/longoutRecord.dbd +++ /dev/null @@ -1,211 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(longout) { - include "dbCommon.dbd" - field(VAL,DBF_LONG) { - prompt("Desired Output") - promptgroup("50 - Output") - asl(ASL0) - pp(TRUE) - } - field(OUT,DBF_OUTLINK) { - prompt("Output Specification") - promptgroup("50 - Output") - interest(1) - } - field(DOL,DBF_INLINK) { - prompt("Desired Output Loc") - promptgroup("40 - Input") - interest(1) - } - field(OMSL,DBF_MENU) { - prompt("Output Mode Select") - promptgroup("50 - Output") - interest(1) - menu(menuOmsl) - } - field(EGU,DBF_STRING) { - prompt("Engineering Units") - promptgroup("80 - Display") - interest(1) - size(16) - prop(YES) - } - field(DRVH,DBF_LONG) { - prompt("Drive High Limit") - promptgroup("30 - Action") - pp(TRUE) - interest(1) - prop(YES) - } - field(DRVL,DBF_LONG) { - prompt("Drive Low Limit") - promptgroup("30 - Action") - pp(TRUE) - interest(1) - prop(YES) - } - field(HOPR,DBF_LONG) { - prompt("High Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(LOPR,DBF_LONG) { - prompt("Low Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(HIHI,DBF_LONG) { - prompt("Hihi Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOLO,DBF_LONG) { - prompt("Lolo Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(HIGH,DBF_LONG) { - prompt("High Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOW,DBF_LONG) { - prompt("Low Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(HHSV,DBF_MENU) { - prompt("Hihi Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LLSV,DBF_MENU) { - prompt("Lolo Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HSV,DBF_MENU) { - prompt("High Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LSV,DBF_MENU) { - prompt("Low Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HYST,DBF_LONG) { - prompt("Alarm Deadband") - promptgroup("70 - Alarm") - interest(1) - } - field(ADEL,DBF_LONG) { - prompt("Archive Deadband") - promptgroup("80 - Display") - interest(1) - } - field(MDEL,DBF_LONG) { - prompt("Monitor Deadband") - promptgroup("80 - Display") - interest(1) - } - field(LALM,DBF_LONG) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(ALST,DBF_LONG) { - prompt("Last Value Archived") - special(SPC_NOMOD) - interest(3) - } - field(MLST,DBF_LONG) { - prompt("Last Val Monitored") - special(SPC_NOMOD) - interest(3) - } - field(SIOL,DBF_OUTLINK) { - prompt("Simulation Output Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } - field(IVOA,DBF_MENU) { - prompt("INVALID output action") - promptgroup("50 - Output") - interest(2) - menu(menuIvoa) - } - field(IVOV,DBF_LONG) { - prompt("INVALID output value") - promptgroup("50 - Output") - interest(2) - } -} diff --git a/modules/database/src/std/rec/longoutRecord.dbd.pod b/modules/database/src/std/rec/longoutRecord.dbd.pod new file mode 100644 index 000000000..276f3046f --- /dev/null +++ b/modules/database/src/std/rec/longoutRecord.dbd.pod @@ -0,0 +1,589 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Long Output Record (longout) + +The normal use for the long output or "longout" record type is to store long +integer values of up to 32 bits and write them to hardware devices. The C<<< +Soft Channel >>> device support layer can also be used to write values to +other records via database or channel access links. The OUT field determines how +the record is used. The record supports alarm limits and graphics and control +limits. + +=recordtype longout + +=cut + +recordtype(longout) { + +=head2 Parameter Fields + +The fields in this record fall into the following categories: + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=head3 Scan Parameters + +The longout record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. Note +that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Desired Output Parameters + +The record must specify where the desired output originates, i.e., the 32 bit +integer value it is to write. The output mode select (OMSL) field determines +whether the output originates from another record or from database access. When +set to C<<< closed_loop >>>, the desired output is retrieved from the link +specified in the desired output (DOL) field (which can specify either a database +or channel access link) and placed into the VAL field. When set to C<<< +supervisory >>>, the desired output can be written into the VAL field via dpPuts +at run-time. + +A third type of value for the DOL field is a constant in which case, when the +record is initialized, the VAL field will be initialized with this constant +value. + +The VAL field's value will be clipped within limits specified in the fields DRVH +and DRVL if these have been configured by the database designer: + + DRVL <= VAL <= DRVH + +Note: These limits are only enforced as long as DRVH E DRVL. If they are not +set or DRVH E= DRVL they will not be used. + +=fields DOL, OMSL, DRVH, DRVL, VAL + +=head3 Write Parameters + +The OUT link field determines where the record is to send its output. For +records that write values to hardware devices, the OUT output link field must +specify the address of the I/O card, and the DTYP field must specify the +name of the corresponding device support module. + +For soft records, the OUT output link can be a constant, a database link, or a +channel access link. If the link is a constant, the result is no output. The +DTYP field must then specify the C<<< Soft Channel >>> device support routine. + +See L
    for information on the format of hardware addresses +and database links. + +=fields OUT, DTYP + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_LONG) { + prompt("Desired Output") + promptgroup("50 - Output") + asl(ASL0) + pp(TRUE) + } + field(OUT,DBF_OUTLINK) { + prompt("Output Specification") + promptgroup("50 - Output") + interest(1) + } + field(DOL,DBF_INLINK) { + prompt("Desired Output Loc") + promptgroup("40 - Input") + interest(1) + } + field(OMSL,DBF_MENU) { + prompt("Output Mode Select") + promptgroup("50 - Output") + interest(1) + menu(menuOmsl) + } + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the long output either textually or +graphically. + +EGU is a string of up to 16 characters describing the units that the long output +measures. It is retrieved by the C<<< get_units >>> record support routine. + +The HOPR and LOPR fields set the upper and lower display limits for the VAL, +HIHI, HIGH, LOW, and LOLO fields. Both the C<<< get_graphic_double >>> and C<<< +get_control_double >>> record support routines retrieve these fields. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields EGU, HOPR, LOPR, NAME, DESC + +=cut + + field(EGU,DBF_STRING) { + prompt("Engineering Units") + promptgroup("80 - Display") + interest(1) + size(16) + prop(YES) + } + field(DRVH,DBF_LONG) { + prompt("Drive High Limit") + promptgroup("30 - Action") + pp(TRUE) + interest(1) + prop(YES) + } + field(DRVL,DBF_LONG) { + prompt("Drive Low Limit") + promptgroup("30 - Action") + pp(TRUE) + interest(1) + prop(YES) + } + field(HOPR,DBF_LONG) { + prompt("High Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(LOPR,DBF_LONG) { + prompt("Low Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + +=head3 Alarm Parameters + +The possible alarm conditions for long inputs are the SCAN, READ, INVALID, and +limit alarms. The SCAN and READ alarms are not configurable by the user because +their severity is always MAJOR. The INVALID alarm is called by the record +support routine when the record or device support routines cannot write the +record's output. The IVOA field specifies the action to take in this case. + +The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW +fields using floating-point values. For each of these fields, there is a +corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. The +HYST field contains the alarm deadband around each limit alarm. + +See the See L for a complete explanation of alarms and +these fields. For an explanation of the IVOA and IVOV fields, see L. L lists other fields related to a alarms that are common +to all record types. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV + +=cut + + field(HIHI,DBF_LONG) { + prompt("Hihi Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_LONG) { + prompt("Lolo Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_LONG) { + prompt("High Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_LONG) { + prompt("Low Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HYST,DBF_LONG) { + prompt("Alarm Deadband") + promptgroup("70 - Alarm") + interest(1) + } + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the value +field. The monitors are sent when the value field exceeds the last monitored +field by the appropriate delta. If these fields have a value of zero, everytime +the value changes, a monitor will be triggered; if they have a value of -1, +everytime the record is scanned, monitors are triggered. The ADEL field is the +delta for archive monitors, and the MDEL field is the delta for all other types +of monitors. See L for a complete explanation of +monitors. + +=fields ADEL, MDEL + +=cut + + field(ADEL,DBF_LONG) { + prompt("Archive Deadband") + promptgroup("80 - Display") + interest(1) + } + field(MDEL,DBF_LONG) { + prompt("Monitor Deadband") + promptgroup("80 - Display") + interest(1) + } + field(LALM,DBF_LONG) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_LONG) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_LONG) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + +=head3 Run-time and Simulation Mode Parameters + +The LALM, MLST, and ALST fields are used to implement the hysteresis factors for +monitor callbacks. Only if the difference between these fields and the +corresponding value field is greater than the appropriate delta (MDEL, ADEL, +HYST)--only then are monitors triggered. For instance, only if the difference +between VAL and MLST is greater than MDEL are the monitors triggered for VAL. + +=fields LALM, ALST, MLST + +The following fields are used to operate the long output in the simulation mode. +See L for more information on the simulation +mode fields + +=fields SIOL, SIML, SIMM, SIMS + +=cut + + field(SIOL,DBF_OUTLINK) { + prompt("Sim Output Specifctn") + promptgroup("90 - Simulate") + interest(1) + } + field(SIML,DBF_INLINK) { + prompt("Sim Mode Location") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Sim mode Alarm Svrty") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + field(IVOA,DBF_MENU) { + prompt("INVALID output action") + promptgroup("50 - Output") + interest(2) + menu(menuIvoa) + } + field(IVOV,DBF_LONG) { + prompt("INVALID output value") + promptgroup("50 - Output") + interest(2) + } + + +=begin html + +


    + +=end html + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available. The routine +next checks to see if the device support write routine is defined. + +If either device support or the device support write routine does not exist, an +error message is issued and processing is terminated. + +If DOL is a constant, then VAL is initialized to its value and UDF is set to +FALSE. If DOL type is a PV_LINK then dbCaAddInlink is called to create a channel +access link. + +If device support includes C, it is called. + +=head4 process + +See next section. + +=head4 get_units + +Retrieves EGU. + +=head4 get_graphic_double + +Sets the upper display and lower display limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_control_double + +Sets the upper control and the lower control limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_alarm_double + +Sets the following values: + + upper_alarm_limit = HIHI + upper_warning_limit = HIGH + lower_warning_limit = LOW + lower_alarm_limit = LOLO + + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE and OMSL is CLOSED_LOOP recGblGetLinkValue is called to read +the current value of VAL. See L for more information. If the +return status of recGblGetLinkValue is zero then UDF is set to FALSE. + +=item 3. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. It also honors the +alarm hysteresis factor (HYST). Thus the value must change by more than HYST +before the alarm status and severity is lowered. + +=item 4. + +Check severity and write the new value. See L for +information on how INVALID alarms affect output records. + +=item 5. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 6. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if ADEL and MDEL conditions are +met. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 7. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each long output record must have an associated set of device support routines. +The primary responsibility of the device support routines is to output a new +value whenever write_longout is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, OUT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 write_longout + + write_longout(precord) + +This routine must output a new value. It returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C<<< Soft Channel >>> module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_longout calls recGblPutLinkValue to write the current value of VAL. + +See L for a further explanation. + +=cut + +} #end of the DBD file diff --git a/modules/database/src/std/rec/lsiRecord.c b/modules/database/src/std/rec/lsiRecord.c index 261313f07..7396946d4 100644 --- a/modules/database/src/std/rec/lsiRecord.c +++ b/modules/database/src/std/rec/lsiRecord.c @@ -241,9 +241,9 @@ static long readValue(lsiRecord *prec) if (status == 0) prec->udf = FALSE; prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/lsiRecord.dbd b/modules/database/src/std/rec/lsiRecord.dbd index 689366f98..21f2ba43d 100644 --- a/modules/database/src/std/rec/lsiRecord.dbd +++ b/modules/database/src/std/rec/lsiRecord.dbd @@ -110,6 +110,6 @@ recordtype(lsi) { prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } } diff --git a/modules/database/src/std/rec/lsoRecord.c b/modules/database/src/std/rec/lsoRecord.c index dcbe1500c..9485e3810 100644 --- a/modules/database/src/std/rec/lsoRecord.c +++ b/modules/database/src/std/rec/lsoRecord.c @@ -282,9 +282,9 @@ static long writeValue(lsoRecord *prec) status = dbPutLinkLS(&prec->siol, prec->val, prec->len); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/lsoRecord.dbd b/modules/database/src/std/rec/lsoRecord.dbd index 8d3a64edc..880139a3c 100644 --- a/modules/database/src/std/rec/lsoRecord.dbd +++ b/modules/database/src/std/rec/lsoRecord.dbd @@ -134,6 +134,6 @@ recordtype(lso) { prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } } diff --git a/modules/database/src/std/rec/mbbiDirectRecord.c b/modules/database/src/std/rec/mbbiDirectRecord.c index 779b732d4..88d805c7c 100644 --- a/modules/database/src/std/rec/mbbiDirectRecord.c +++ b/modules/database/src/std/rec/mbbiDirectRecord.c @@ -277,9 +277,9 @@ static long readValue(mbbiDirectRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/mbbiDirectRecord.dbd b/modules/database/src/std/rec/mbbiDirectRecord.dbd deleted file mode 100644 index bb432e58f..000000000 --- a/modules/database/src/std/rec/mbbiDirectRecord.dbd +++ /dev/null @@ -1,263 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(mbbiDirect) { - include "dbCommon.dbd" - field(VAL,DBF_LONG) { - prompt("Current Value") - promptgroup("40 - Input") - asl(ASL0) - pp(TRUE) - } - field(NOBT,DBF_SHORT) { - prompt("Number of Bits") - promptgroup("40 - Input") - special(SPC_NOMOD) - interest(1) - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup("40 - Input") - interest(1) - } - field(RVAL,DBF_ULONG) { - prompt("Raw Value") - pp(TRUE) - } - field(ORAW,DBF_ULONG) { - prompt("Prev Raw Value") - special(SPC_NOMOD) - interest(3) - } - field(MASK,DBF_ULONG) { - prompt("Hardware Mask") - special(SPC_NOMOD) - interest(1) - } - field(MLST,DBF_LONG) { - prompt("Last Value Monitored") - special(SPC_NOMOD) - interest(3) - } - field(SHFT,DBF_USHORT) { - prompt("Shift") - promptgroup("40 - Input") - interest(1) - } - field(SIOL,DBF_INLINK) { - prompt("Simulation Input Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SVAL,DBF_LONG) { - prompt("Simulation Value") - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuSimm) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } - field(B0,DBF_UCHAR) { - prompt("Bit 0") - pp(TRUE) - interest(1) - } - field(B1,DBF_UCHAR) { - prompt("Bit 1") - pp(TRUE) - interest(1) - } - field(B2,DBF_UCHAR) { - prompt("Bit 2") - pp(TRUE) - interest(1) - } - field(B3,DBF_UCHAR) { - prompt("Bit 3") - pp(TRUE) - interest(1) - } - field(B4,DBF_UCHAR) { - prompt("Bit 4") - pp(TRUE) - interest(1) - } - field(B5,DBF_UCHAR) { - prompt("Bit 5") - pp(TRUE) - interest(1) - } - field(B6,DBF_UCHAR) { - prompt("Bit 6") - pp(TRUE) - interest(1) - } - field(B7,DBF_UCHAR) { - prompt("Bit 7") - pp(TRUE) - interest(1) - } - field(B8,DBF_UCHAR) { - prompt("Bit 8") - pp(TRUE) - interest(1) - } - field(B9,DBF_UCHAR) { - prompt("Bit 9") - pp(TRUE) - interest(1) - } - field(BA,DBF_UCHAR) { - prompt("Bit 10") - pp(TRUE) - interest(1) - } - field(BB,DBF_UCHAR) { - prompt("Bit 11") - pp(TRUE) - interest(1) - } - field(BC,DBF_UCHAR) { - prompt("Bit 12") - pp(TRUE) - interest(1) - } - field(BD,DBF_UCHAR) { - prompt("Bit 13") - pp(TRUE) - interest(1) - } - field(BE,DBF_UCHAR) { - prompt("Bit 14") - pp(TRUE) - interest(1) - } - field(BF,DBF_UCHAR) { - prompt("Bit 15") - pp(TRUE) - interest(1) - } - field(B10,DBF_UCHAR) { - prompt("Bit 16") - pp(TRUE) - interest(1) - } - field(B11,DBF_UCHAR) { - prompt("Bit 17") - pp(TRUE) - interest(1) - } - field(B12,DBF_UCHAR) { - prompt("Bit 18") - pp(TRUE) - interest(1) - } - field(B13,DBF_UCHAR) { - prompt("Bit 19") - pp(TRUE) - interest(1) - } - field(B14,DBF_UCHAR) { - prompt("Bit 20") - pp(TRUE) - interest(1) - } - field(B15,DBF_UCHAR) { - prompt("Bit 21") - pp(TRUE) - interest(1) - } - field(B16,DBF_UCHAR) { - prompt("Bit 22") - pp(TRUE) - interest(1) - } - field(B17,DBF_UCHAR) { - prompt("Bit 23") - pp(TRUE) - interest(1) - } - field(B18,DBF_UCHAR) { - prompt("Bit 24") - pp(TRUE) - interest(1) - } - field(B19,DBF_UCHAR) { - prompt("Bit 25") - pp(TRUE) - interest(1) - } - field(B1A,DBF_UCHAR) { - prompt("Bit 26") - pp(TRUE) - interest(1) - } - field(B1B,DBF_UCHAR) { - prompt("Bit 27") - pp(TRUE) - interest(1) - } - field(B1C,DBF_UCHAR) { - prompt("Bit 28") - pp(TRUE) - interest(1) - } - field(B1D,DBF_UCHAR) { - prompt("Bit 29") - pp(TRUE) - interest(1) - } - field(B1E,DBF_UCHAR) { - prompt("Bit 30") - pp(TRUE) - interest(1) - } - field(B1F,DBF_UCHAR) { - prompt("Bit 31") - pp(TRUE) - interest(1) - } -} diff --git a/modules/database/src/std/rec/mbbiDirectRecord.dbd.pod b/modules/database/src/std/rec/mbbiDirectRecord.dbd.pod new file mode 100644 index 000000000..5b1c4da09 --- /dev/null +++ b/modules/database/src/std/rec/mbbiDirectRecord.dbd.pod @@ -0,0 +1,588 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Multi-Bit Binary Input Direct Record (mbbiDirect) + +The mbbiDirect record retrieves a 32-bit hardware value and converts it to +an array of 32 unsigned characters, each representing a bit of the word. +These fields (B0-B9, BA-BF, B10-B19, B1A-B1F) are set to 1 if the corresponding +bit is set, and 0 if not. + +This record's operation is similar to that of the multi-bit binary input record, +and it has many fields in common with it. This record also has two available +soft device support modules: C and C. + +=recordtype mbbiDirect + +=cut + +recordtype(mbbiDirect) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The mbbiDirect record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in L. In addition, L explains how these fields are +used. Note that I/O event scanning is only supported for those card types +that interrupt. + +=head3 Read and Convert Parameters + +The device support routines obtain the record's input from the device or link +specified in the INP field. For records that obtain their input from devices, +the INP field must contain the address of the I/O card, and the DTYP field +must specify the proper device support module. Be aware that the address format +differs according to the I/O bus used. See L
    for +information on the format of hardware addresses. + +Two soft device support modules can be specified in DTYP C and +C<<< Raw Soft Channel >>>. + +C<<< Raw Soft Channel >>> reads the value into RVAL, +upon which the normal conversion process is undergone. C<<< Soft Channel >>> +reads any unsigned integer directly into VAL. For a soft mbbiDirect record, the +INP field can be a constant, a database, or a channel access link. If INP is a +constant, then the VAL is initialized to the INP value but can be changed at +run-time via dbPutField or dbPutLink. See L
    for +information on how to database links. + +For records that don't use C<<< Soft Channel >>> device support, RVAL is used to +determine VAL as follows: + +=over + +=item 1. RVAL is assigned to a temporary variable I = RVAL + +=item 2. I is shifted right SHFT number of bits. + +=item 3. VAL is set equal to I. + +=back + +Each of the fields, B0-BF and B10-B1F, represents one bit of the word. + +=fields VAL, INP, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B1A, B1B, B1C, B1D, B1E, B1F + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_LONG) { + prompt("Current Value") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + } + field(NOBT,DBF_SHORT) { + prompt("Number of Bits") + promptgroup("40 - Input") + special(SPC_NOMOD) + interest(1) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup("40 - Input") + interest(1) + } + field(RVAL,DBF_ULONG) { + prompt("Raw Value") + pp(TRUE) + } + field(ORAW,DBF_ULONG) { + prompt("Prev Raw Value") + special(SPC_NOMOD) + interest(3) + } + field(MASK,DBF_ULONG) { + prompt("Hardware Mask") + special(SPC_NOMOD) + interest(1) + } + field(MLST,DBF_LONG) { + prompt("Last Value Monitored") + special(SPC_NOMOD) + interest(3) + } + field(SHFT,DBF_USHORT) { + prompt("Shift") + promptgroup("40 - Input") + interest(1) + } + +=head3 Run-time and Simulation Mode Parameters + +These parameters are used by the run-time code for processing the mbbi direct +record. They are not configurable prior to run-time. + +MASK is used by device support routine to read hardware register. Record support +sets low order NOBT bits in MASK. Device support can shift this value. + +MLST holds the value when the last monitor for value change was triggered. + +=fields NOBT, ORAW, MASK, MLST + +The following fields are used to operate the mbbiDirect record in the simulation +mode. See L for more information on these +fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS, SSCN, SDLY + +=cut + + field(SIOL,DBF_INLINK) { + prompt("Simulation Input Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SVAL,DBF_LONG) { + prompt("Simulation Value") + } + field(SIML,DBF_INLINK) { + prompt("Simulation Mode Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuSimm) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + +=head3 Alarm Parameters + +The possible alarm conditions for multi-bit binary input direct records are the +SCAN and READ alarms. These alarms are not configurable by the user since they +are always of MAJOR severity. See L for a complete +explanation of Scan and Read alarms. No fields exist for the mbbi direct record +to have state alarms. + +L lists other fields related to a alarms that are common to all +record types. + +=cut + + field(B0,DBF_UCHAR) { + prompt("Bit 0") + pp(TRUE) + interest(1) + } + field(B1,DBF_UCHAR) { + prompt("Bit 1") + pp(TRUE) + interest(1) + } + field(B2,DBF_UCHAR) { + prompt("Bit 2") + pp(TRUE) + interest(1) + } + field(B3,DBF_UCHAR) { + prompt("Bit 3") + pp(TRUE) + interest(1) + } + field(B4,DBF_UCHAR) { + prompt("Bit 4") + pp(TRUE) + interest(1) + } + field(B5,DBF_UCHAR) { + prompt("Bit 5") + pp(TRUE) + interest(1) + } + field(B6,DBF_UCHAR) { + prompt("Bit 6") + pp(TRUE) + interest(1) + } + field(B7,DBF_UCHAR) { + prompt("Bit 7") + pp(TRUE) + interest(1) + } + field(B8,DBF_UCHAR) { + prompt("Bit 8") + pp(TRUE) + interest(1) + } + field(B9,DBF_UCHAR) { + prompt("Bit 9") + pp(TRUE) + interest(1) + } + field(BA,DBF_UCHAR) { + prompt("Bit 10") + pp(TRUE) + interest(1) + } + field(BB,DBF_UCHAR) { + prompt("Bit 11") + pp(TRUE) + interest(1) + } + field(BC,DBF_UCHAR) { + prompt("Bit 12") + pp(TRUE) + interest(1) + } + field(BD,DBF_UCHAR) { + prompt("Bit 13") + pp(TRUE) + interest(1) + } + field(BE,DBF_UCHAR) { + prompt("Bit 14") + pp(TRUE) + interest(1) + } + field(BF,DBF_UCHAR) { + prompt("Bit 15") + pp(TRUE) + interest(1) + } + field(B10,DBF_UCHAR) { + prompt("Bit 16") + pp(TRUE) + interest(1) + } + field(B11,DBF_UCHAR) { + prompt("Bit 17") + pp(TRUE) + interest(1) + } + field(B12,DBF_UCHAR) { + prompt("Bit 18") + pp(TRUE) + interest(1) + } + field(B13,DBF_UCHAR) { + prompt("Bit 19") + pp(TRUE) + interest(1) + } + field(B14,DBF_UCHAR) { + prompt("Bit 20") + pp(TRUE) + interest(1) + } + field(B15,DBF_UCHAR) { + prompt("Bit 21") + pp(TRUE) + interest(1) + } + field(B16,DBF_UCHAR) { + prompt("Bit 22") + pp(TRUE) + interest(1) + } + field(B17,DBF_UCHAR) { + prompt("Bit 23") + pp(TRUE) + interest(1) + } + field(B18,DBF_UCHAR) { + prompt("Bit 24") + pp(TRUE) + interest(1) + } + field(B19,DBF_UCHAR) { + prompt("Bit 25") + pp(TRUE) + interest(1) + } + field(B1A,DBF_UCHAR) { + prompt("Bit 26") + pp(TRUE) + interest(1) + } + field(B1B,DBF_UCHAR) { + prompt("Bit 27") + pp(TRUE) + interest(1) + } + field(B1C,DBF_UCHAR) { + prompt("Bit 28") + pp(TRUE) + interest(1) + } + field(B1D,DBF_UCHAR) { + prompt("Bit 29") + pp(TRUE) + interest(1) + } + field(B1E,DBF_UCHAR) { + prompt("Bit 30") + pp(TRUE) + interest(1) + } + field(B1F,DBF_UCHAR) { + prompt("Bit 31") + pp(TRUE) + interest(1) + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a device +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated. + +Clears MASK and then sets the NOBT low order bits. + +If device support includes C, it is called. + +refresh_bits is then called to refresh all the bit fields based on a hardware +value. + +=head4 process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +readValue is called. See L for information. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Convert. + +=over + +=item * status = read_mbbiDirect + +=item * PACT = TRUE + +=item * C is called. + +=item * If status is 0, then determine VAL + +=over + +=item * Set rval = RVAL + +=item * Shift rval right SHFT bits + +=item * Set VAL = RVAL + +=back + +=item * If status is 1, return 0 + +=item * If status is 2, set status = 0 + +=back + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * Alarm monitors are invoked if the alarm status or severity has changed. + +=item * Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * Monitors for RVAL are checked whenever other monitors are invoked. + +=item * NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each input record must have an associated set of device support routines. + +The primary responsibility of the device support routines is to obtain a new raw +input value whenever read_mbbiDirect is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, NOBT, VAL, INP, RVAL, MASK, SHFT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. If it uses MASK, it should shift it as necessary and +also give SHFT a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an IEO event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an IEO event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 read_mbbiDirect + + read_mbbiDirect(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. A new raw value is placed in RVAL. The record support module +determines VAL from RVAL and SHFT. + +=item * + +2: Success, but don't modify VAL. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +Two soft device support modules, C<<< Soft Channel >>> and C<<< Raw Soft Channel +>>>, are provided for multi-bit binary input direct records not related to +actual hardware devices. The INP link type must be either CONSTANT, DB_LINK, or +CA_LINK. + +=head4 Soft Channel + +For this module, read_mbbiDirect always returns a value of 2, which means that +no conversion is performed. + +If the INP link type is constant, then the constant value is stored into VAL by +C, and UDF is set to FALSE. VAL can be changed via dbPut +requests. If the INP link type is PV_LINK, then dbCaAddInlink is called by +C. + +read_mbbiDirect calls recGblGetLinkValue to read the current value of VAL. + +See L for a further explanation. + +If the return status of recGblGetLinkValue is zero, then read_mbbi sets UDF to +FALSE. The status of recGblGetLinkValue is returned. + +=head4 Raw Soft Channel + +This module is like the previous except that values are read into RVAL, VAL is +computed from RVAL, and read_mbbiDirect returns a value of 0. Thus the record +processing routine will determine VAL in the normal way. + +=cut + +} diff --git a/modules/database/src/std/rec/mbbiRecord.c b/modules/database/src/std/rec/mbbiRecord.c index 5995288e0..0202594c5 100644 --- a/modules/database/src/std/rec/mbbiRecord.c +++ b/modules/database/src/std/rec/mbbiRecord.c @@ -409,9 +409,9 @@ static long readValue(mbbiRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/mbbiRecord.dbd b/modules/database/src/std/rec/mbbiRecord.dbd deleted file mode 100644 index 52f18e43d..000000000 --- a/modules/database/src/std/rec/mbbiRecord.dbd +++ /dev/null @@ -1,505 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(mbbi) { - include "dbCommon.dbd" - field(VAL,DBF_ENUM) { - prompt("Current Value") - promptgroup("40 - Input") - asl(ASL0) - pp(TRUE) - } - field(NOBT,DBF_USHORT) { - prompt("Number of Bits") - promptgroup("40 - Input") - special(SPC_NOMOD) - interest(1) - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup("40 - Input") - interest(1) - } - field(ZRVL,DBF_ULONG) { - prompt("Zero Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(ONVL,DBF_ULONG) { - prompt("One Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TWVL,DBF_ULONG) { - prompt("Two Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(THVL,DBF_ULONG) { - prompt("Three Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FRVL,DBF_ULONG) { - prompt("Four Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FVVL,DBF_ULONG) { - prompt("Five Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(SXVL,DBF_ULONG) { - prompt("Six Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(SVVL,DBF_ULONG) { - prompt("Seven Value") - promptgroup("41 - Input 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(EIVL,DBF_ULONG) { - prompt("Eight Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(NIVL,DBF_ULONG) { - prompt("Nine Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TEVL,DBF_ULONG) { - prompt("Ten Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(ELVL,DBF_ULONG) { - prompt("Eleven Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TVVL,DBF_ULONG) { - prompt("Twelve Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TTVL,DBF_ULONG) { - prompt("Thirteen Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FTVL,DBF_ULONG) { - prompt("Fourteen Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FFVL,DBF_ULONG) { - prompt("Fifteen Value") - promptgroup("42 - Input 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(ZRST,DBF_STRING) { - prompt("Zero String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(ONST,DBF_STRING) { - prompt("One String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TWST,DBF_STRING) { - prompt("Two String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(THST,DBF_STRING) { - prompt("Three String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FRST,DBF_STRING) { - prompt("Four String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FVST,DBF_STRING) { - prompt("Five String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(SXST,DBF_STRING) { - prompt("Six String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(SVST,DBF_STRING) { - prompt("Seven String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(EIST,DBF_STRING) { - prompt("Eight String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(NIST,DBF_STRING) { - prompt("Nine String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TEST,DBF_STRING) { - prompt("Ten String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(ELST,DBF_STRING) { - prompt("Eleven String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TVST,DBF_STRING) { - prompt("Twelve String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TTST,DBF_STRING) { - prompt("Thirteen String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FTST,DBF_STRING) { - prompt("Fourteen String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FFST,DBF_STRING) { - prompt("Fifteen String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(ZRSV,DBF_MENU) { - prompt("State Zero Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(ONSV,DBF_MENU) { - prompt("State One Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TWSV,DBF_MENU) { - prompt("State Two Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(THSV,DBF_MENU) { - prompt("State Three Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FRSV,DBF_MENU) { - prompt("State Four Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FVSV,DBF_MENU) { - prompt("State Five Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(SXSV,DBF_MENU) { - prompt("State Six Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(SVSV,DBF_MENU) { - prompt("State Seven Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(EISV,DBF_MENU) { - prompt("State Eight Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(NISV,DBF_MENU) { - prompt("State Nine Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TESV,DBF_MENU) { - prompt("State Ten Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(ELSV,DBF_MENU) { - prompt("State Eleven Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TVSV,DBF_MENU) { - prompt("State Twelve Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TTSV,DBF_MENU) { - prompt("State Thirteen Sevr") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FTSV,DBF_MENU) { - prompt("State Fourteen Sevr") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FFSV,DBF_MENU) { - prompt("State Fifteen Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(AFTC, DBF_DOUBLE) { - prompt("Alarm Filter Time Constant") - promptgroup("70 - Alarm") - interest(1) - } - field(AFVL, DBF_DOUBLE) { - prompt("Alarm Filter Value") - special(SPC_NOMOD) - interest(3) - } - field(UNSV,DBF_MENU) { - prompt("Unknown State Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(COSV,DBF_MENU) { - prompt("Change of State Svr") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(RVAL,DBF_ULONG) { - prompt("Raw Value") - pp(TRUE) - } - field(ORAW,DBF_ULONG) { - prompt("Prev Raw Value") - special(SPC_NOMOD) - interest(3) - } - field(MASK,DBF_ULONG) { - prompt("Hardware Mask") - special(SPC_NOMOD) - interest(1) - } - field(MLST,DBF_USHORT) { - prompt("Last Value Monitored") - special(SPC_NOMOD) - interest(3) - } - field(LALM,DBF_USHORT) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(SDEF,DBF_SHORT) { - prompt("States Defined") - special(SPC_NOMOD) - interest(3) - } - field(SHFT,DBF_USHORT) { - prompt("Shift") - promptgroup("40 - Input") - interest(1) - } - field(SIOL,DBF_INLINK) { - prompt("Simulation Input Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SVAL,DBF_ULONG) { - prompt("Simulation Value") - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuSimm) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } -} diff --git a/modules/database/src/std/rec/mbbiRecord.dbd.pod b/modules/database/src/std/rec/mbbiRecord.dbd.pod new file mode 100644 index 000000000..b4ab1b402 --- /dev/null +++ b/modules/database/src/std/rec/mbbiRecord.dbd.pod @@ -0,0 +1,928 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Multi-Bit Binary Input Record (mbbi) + +The normal use for the multi-bit binary input record is to read contiguous, +multiple bit inputs from hardware. The binary value represents a state from a +range of up to 16 states. The multi-bit input record interfaces with devices +that use more than one bit. + +Most device support modules obtain values from hardware and place the value in +RVAL. For these device support modules record processing uses RVAL to determine +the current state (VAL is given a value between 0 and 15). Device support +modules may optionally read a value directly into VAL. + +Soft device modules are provided to obtain input via database or channel access +links or via dbPutField or dbPutLink requests. Two soft device support modules +are provided: C<<< Soft Channel >>> allows VAL to be an arbitrary unsigned short +integer. C<<< Raw Soft Channel >>> reads the value into RVAL just like normal +device support modules. + +=recordtype mbbi + +=cut + +recordtype(mbbi) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The multi-bit binary input record has the standard fields for specifying under +what circumstances it will be processed. These fields are listed in L. In addition, L explains how these fields are +used. Note that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Read and Convert Parameters + +The device support routines obtain the record's input from the device or link +specified in the INP field. For records that obtain their input from devices, +the INP field must contain the address of the I/O card, and the DTYP field must +specify the proper device support module. Be aware that the address format +differs according to the I/O bus used. See L
    for +information on the format of hardware addresses. + +Two soft device support modules can be specified in DTYP C and +C<<< Raw Soft Channel >>>. + +C<<< Raw Soft Channel >>> reads the value into RVAL, +upon which the normal conversion process is undergone. C<<< Soft Channel >>> +reads any unsigned integer directly into VAL. For a soft mbbi record, the INP +field can be a constant, a database, or a channel access link. If INP is a +constant, then the VAL is initialized to the constant value but can be changed +at run-time via dbPutField or dbPutLink. See L
    for +information on the format of database addresses. + +MASK is used by the raw soft channel read routine, and by typical device support +read routines, to select only the desired bits when reading the hardware +register. It is initialized to ((1 EE NOBT) - 1) by record +initialization. The user can configure the NOBT field, but the device support +routines may set it, in which case the value given to it by the user is simply +overridden. The device support routines may also override MASK or shift it +left by SHFT bits. If MASK is non-zero, only the bits specified by MASK will +appear in RVAL. + +Unless the device support routine specifies no conversion, RVAL is used to +determine VAL as follows: + +=over + +=item 1. + +RVAL is assigned to a temporary variable -- rval = RVAL + +=item 2. + +rval is shifted right SHFT number of bits. + +=item 3. + +A match is sought between rval and one of the state value fields, ZRVL-FFVL. + +=back + +Each of the fields, ZRVL-FFVL, represents one of the possible sixteen states +(not all sixteen have to be used). + +Alternatively, the input value can be read as a string, in which case, a match +is sought with one of the strings specified in the ZRST-FFST fields. Then RVAL +is set equal to the corresponding value for that string, and the conversion +process occurs. + +=fields VAL, INP, MASK, NOBT, RVAL, SHFT, ZRVL, ONVL, TWVL, THVL, FRVL, FVVL, SXVL, SVVL, EIVL, NIVL, TEVL, ELVL, TVVL, TTVL, FTVL, FFVL + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the mbbi record either textually or +graphically. The ZRST-FFST fields contain strings describing one of the possible +states of the record. The C<<< get_enum_str >>> and C<<< get_enum_strs >>> +record routines retrieve these strings for the operator. C<<< Get_enum_str >>> +gets the string corresponding to the value set in VAL, and C<<< get_enum_strs +>>> retrieves all the strings. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC, ZRST, ONST, TWST, THST, FRST, FVST, SXST, SVST, EIST, NIST, TEST, ELST, TVST, TTST, FTST, FFST + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_ENUM) { + prompt("Current Value") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + } + field(NOBT,DBF_USHORT) { + prompt("Number of Bits") + promptgroup("40 - Input") + special(SPC_NOMOD) + interest(1) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup("40 - Input") + interest(1) + } + field(ZRVL,DBF_ULONG) { + prompt("Zero Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(ONVL,DBF_ULONG) { + prompt("One Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TWVL,DBF_ULONG) { + prompt("Two Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(THVL,DBF_ULONG) { + prompt("Three Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FRVL,DBF_ULONG) { + prompt("Four Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FVVL,DBF_ULONG) { + prompt("Five Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(SXVL,DBF_ULONG) { + prompt("Six Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(SVVL,DBF_ULONG) { + prompt("Seven Value") + promptgroup("41 - Input 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(EIVL,DBF_ULONG) { + prompt("Eight Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(NIVL,DBF_ULONG) { + prompt("Nine Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TEVL,DBF_ULONG) { + prompt("Ten Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(ELVL,DBF_ULONG) { + prompt("Eleven Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TVVL,DBF_ULONG) { + prompt("Twelve Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TTVL,DBF_ULONG) { + prompt("Thirteen Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FTVL,DBF_ULONG) { + prompt("Fourteen Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FFVL,DBF_ULONG) { + prompt("Fifteen Value") + promptgroup("42 - Input 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(ZRST,DBF_STRING) { + prompt("Zero String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(ONST,DBF_STRING) { + prompt("One String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TWST,DBF_STRING) { + prompt("Two String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(THST,DBF_STRING) { + prompt("Three String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FRST,DBF_STRING) { + prompt("Four String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FVST,DBF_STRING) { + prompt("Five String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(SXST,DBF_STRING) { + prompt("Six String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(SVST,DBF_STRING) { + prompt("Seven String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(EIST,DBF_STRING) { + prompt("Eight String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(NIST,DBF_STRING) { + prompt("Nine String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TEST,DBF_STRING) { + prompt("Ten String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(ELST,DBF_STRING) { + prompt("Eleven String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TVST,DBF_STRING) { + prompt("Twelve String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TTST,DBF_STRING) { + prompt("Thirteen String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FTST,DBF_STRING) { + prompt("Fourteen String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FFST,DBF_STRING) { + prompt("Fifteen String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + +=head3 Alarm Parameters + +The possible alarm conditions for multi-bit binary inputs are the SCAN, READ, +and state alarms. The state alarms are configured in the below severity fields. +These fields have the usual possible values for severity fields: NO_ALARM, +MINOR, and MAJOR. + +The unknown state severity (UNSV) field, if set to MINOR or MAJOR, triggers an +alarm when the record support routine cannot find a matching value in the state +value fields for C<<< rval >>>. + +The change of state severity (COSV) field triggers an alarm when any change of +state occurs, if set to MAJOR or MINOR. + +The other fields, when set to MAJOR or MINOR, trigger an alarm when VAL equals +the corresponding state. See the See L for a complete +explanation of discrete alarms and these fields. L lists other +fields related to a alarms that are common to all record types. + +=fields UNSV, COSV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV + +=cut + + field(ZRSV,DBF_MENU) { + prompt("State Zero Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(ONSV,DBF_MENU) { + prompt("State One Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TWSV,DBF_MENU) { + prompt("State Two Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(THSV,DBF_MENU) { + prompt("State Three Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FRSV,DBF_MENU) { + prompt("State Four Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FVSV,DBF_MENU) { + prompt("State Five Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(SXSV,DBF_MENU) { + prompt("State Six Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(SVSV,DBF_MENU) { + prompt("State Seven Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(EISV,DBF_MENU) { + prompt("State Eight Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(NISV,DBF_MENU) { + prompt("State Nine Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TESV,DBF_MENU) { + prompt("State Ten Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(ELSV,DBF_MENU) { + prompt("State Eleven Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TVSV,DBF_MENU) { + prompt("State Twelve Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TTSV,DBF_MENU) { + prompt("State Thirteen Sevr") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FTSV,DBF_MENU) { + prompt("State Fourteen Sevr") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FFSV,DBF_MENU) { + prompt("State Fifteen Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(AFTC, DBF_DOUBLE) { + prompt("Alarm Filter Time Constant") + promptgroup("70 - Alarm") + interest(1) + } + field(AFVL, DBF_DOUBLE) { + prompt("Alarm Filter Value") + special(SPC_NOMOD) + interest(3) + } + field(UNSV,DBF_MENU) { + prompt("Unknown State Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(COSV,DBF_MENU) { + prompt("Change of State Svr") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the multi-bit +binary input. + +ORAW is used by record processing to hold the prior RVAL for use in determining +when to post a monitor event for the RVAL field. + +The LALM field implements the change of state alarm severity by holding the +value of VAL when the previous change of state alarm was issued. + +MLST holds the value when the last monitor for value change was triggered. + +SDEF is used by record support to save time if no states are defined. + +=fields ORAW, LALM, MLST, SDEF + +=cut + + field(RVAL,DBF_ULONG) { + prompt("Raw Value") + pp(TRUE) + } + field(ORAW,DBF_ULONG) { + prompt("Prev Raw Value") + special(SPC_NOMOD) + interest(3) + } + field(MASK,DBF_ULONG) { + prompt("Hardware Mask") + special(SPC_NOMOD) + interest(1) + } + field(MLST,DBF_USHORT) { + prompt("Last Value Monitored") + special(SPC_NOMOD) + interest(3) + } + field(LALM,DBF_USHORT) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(SDEF,DBF_SHORT) { + prompt("States Defined") + special(SPC_NOMOD) + interest(3) + } + field(SHFT,DBF_USHORT) { + prompt("Shift") + promptgroup("40 - Input") + interest(1) + } + +=head3 Simulation Mode Parameters + +The following fields are used to operate the mbbi record in the simulation mode. +See L for more information on these fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS, SSCN, SDLY + +=cut + + field(SIOL,DBF_INLINK) { + prompt("Simulation Input Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SVAL,DBF_ULONG) { + prompt("Simulation Value") + } + field(SIML,DBF_INLINK) { + prompt("Simulation Mode Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuSimm) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a device +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated. + +Clears MASK and then sets the NOBT low order bits. + +If device support includes C, it is called. + +init_common is then called to determine if any states are defined. If states are +defined, SDEF is set to TRUE. + +=head4 process + +See next section. + +=head4 special + +Calls init_common to compute SDEF when any of the fields ZRVL, ... FFVL change +value. + +=head4 get_enum_str + +Retrieves ASCII string corresponding to VAL. + +=head4 get_enum_strs + +Retrieves ASCII strings for ZRST,...FFST. + +=head4 put_enum_str + +Checks if string matches ZRST,...FFST and if it does, sets VAL. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +readValue is called. See L for more information. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Convert: + +=over + +=item * status=read_mbbi + +=item * PACT = TRUE + +=item * C is called. + +=item * If status is 0, then determine VAL + +=over + +=item * Set rval = RVAL + +=item * Shift rval right SHFT bits + +=back + +=item * If at least one state value is defined + +=over + +=item * Set UDF to TRUE + +=back + +=item * If RVAL is ZRVL,...,FFVL then set + +=over + +=item * VAL equals index of state + +=item * UDF set to FALSE + +=back + +=item * Else set VAL = undefined + +=over + +=item * Else set VAL = RVAL + +=back + +=item * Set UDF to FALSE + +=over + +=item * If status is 1, return 0 + +=item * If status is 2, set status = 0 + +=back + +=back + +=item 5. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. + +=item 6. + +Check to see if monitors should be invoked. + +=over + +=item * Alarm monitors are invoked if the alarm status or severity has changed. + +=item * Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * Monitors for RVAL are checked whenever other monitors are invoked. + +=item * NSEV and NSTA are reset to 0. + +=back + +=item 7. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each input record must have an associated set of device support routines. + +The primary responsibility of the device support routines is to obtain a new raw +input value whenever read_mbbi is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, NOBT, VAL, INP, RVAL, MASK, SHFT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. If it uses MASK, it should shift it as necessary and +also give SHFT a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the record is +being (added to, deleted from) an I/O event list. It must be provided for any +device type that can use the I/O Event scanner. + +=head4 read_mbbi + + read_mbbi(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. A new raw value is placed in RVAL. The record support module +determines VAL from RVAL, SHFT, and ZEVL ... FFVL. + +=item * + +2: Success, but don't modify VAL. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +Two soft device support modules C<<< Soft Channel >>> and C<<< Raw Soft Channel +>>> are provided for multi-bit binary input records not related to actual +hardware devices. The INP link type must be either CONSTANT, DB_LINK, or +CA_LINK. + +=head4 Soft Channel + +read_mbbi always returns a value of 2, which means that no conversion is +performed. + +If the INP link type is constant, then the constant value is stored into VAL by +C, and UDF is set to FALSE. VAL can be changed via dbPut +requests. If the INP link type is PV_LINK, then dbCaAddInlink is called by +C. + +read_mbbi calls recGblGetLinkValue to read the current value of VAL. See L. + +If the return status of recGblGetLinkValue is zero, then read_mbbi sets UDF to +FALSE. The status of recGblGetLinkValue is returned. + +=head4 Raw Soft Channel + +This module is like the previous except that values are read into RVAL, VAL is +computed from RVAL, and read_mbbi returns a value of 0. Thus the record +processing routine will determine VAL in the normal way. + +=cut + +} diff --git a/modules/database/src/std/rec/mbboDirectRecord.c b/modules/database/src/std/rec/mbboDirectRecord.c index dcc2b3c33..5c2dd9403 100644 --- a/modules/database/src/std/rec/mbboDirectRecord.c +++ b/modules/database/src/std/rec/mbboDirectRecord.c @@ -375,9 +375,9 @@ static long writeValue(mbboDirectRecord *prec) status = dbPutLink(&prec->siol, DBR_ULONG, &prec->val, 1); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/mbboDirectRecord.dbd b/modules/database/src/std/rec/mbboDirectRecord.dbd deleted file mode 100644 index a6a43b4f0..000000000 --- a/modules/database/src/std/rec/mbboDirectRecord.dbd +++ /dev/null @@ -1,358 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(mbboDirect) { - include "dbCommon.dbd" - field(VAL,DBF_LONG) { - prompt("Word") - promptgroup("50 - Output") - asl(ASL0) - pp(TRUE) - } - field(OMSL,DBF_MENU) { - prompt("Output Mode Select") - promptgroup("50 - Output") - special(SPC_RESET) - pp(TRUE) - interest(1) - menu(menuOmsl) - } - field(NOBT,DBF_SHORT) { - prompt("Number of Bits") - promptgroup("50 - Output") - special(SPC_NOMOD) - interest(1) - } - field(DOL,DBF_INLINK) { - prompt("Desired Output Loc") - promptgroup("40 - Input") - interest(1) - } - field(OUT,DBF_OUTLINK) { - prompt("Output Specification") - promptgroup("50 - Output") - interest(1) - } - field(RVAL,DBF_ULONG) { - prompt("Raw Value") - special(SPC_NOMOD) - pp(TRUE) - } - field(ORAW,DBF_ULONG) { - prompt("Prev Raw Value") - special(SPC_NOMOD) - interest(3) - } - field(RBV,DBF_ULONG) { - prompt("Readback Value") - special(SPC_NOMOD) - } - field(ORBV,DBF_ULONG) { - prompt("Prev Readback Value") - special(SPC_NOMOD) - interest(3) - } - field(MASK,DBF_ULONG) { - prompt("Hardware Mask") - special(SPC_NOMOD) - interest(1) - } - field(MLST,DBF_LONG) { - prompt("Last Value Monitored") - special(SPC_NOMOD) - interest(3) - } - field(SHFT,DBF_USHORT) { - prompt("Shift") - promptgroup("50 - Output") - interest(1) - } - field(SIOL,DBF_OUTLINK) { - prompt("Simulation Output Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } - field(IVOA,DBF_MENU) { - prompt("INVALID outpt action") - promptgroup("50 - Output") - interest(2) - menu(menuIvoa) - } - field(IVOV,DBF_LONG) { - prompt("INVALID output value") - promptgroup("50 - Output") - interest(2) - } - field(B0,DBF_UCHAR) { - prompt("Bit 0") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B1,DBF_UCHAR) { - prompt("Bit 1") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B2,DBF_UCHAR) { - prompt("Bit 2") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B3,DBF_UCHAR) { - prompt("Bit 3") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B4,DBF_UCHAR) { - prompt("Bit 4") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B5,DBF_UCHAR) { - prompt("Bit 5") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B6,DBF_UCHAR) { - prompt("Bit 6") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B7,DBF_UCHAR) { - prompt("Bit 7") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B8,DBF_UCHAR) { - prompt("Bit 8") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B9,DBF_UCHAR) { - prompt("Bit 9") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(BA,DBF_UCHAR) { - prompt("Bit 10") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(BB,DBF_UCHAR) { - prompt("Bit 11") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(BC,DBF_UCHAR) { - prompt("Bit 12") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(BD,DBF_UCHAR) { - prompt("Bit 13") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(BE,DBF_UCHAR) { - prompt("Bit 14") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(BF,DBF_UCHAR) { - prompt("Bit 15") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B10,DBF_UCHAR) { - prompt("Bit 16") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B11,DBF_UCHAR) { - prompt("Bit 17") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B12,DBF_UCHAR) { - prompt("Bit 18") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B13,DBF_UCHAR) { - prompt("Bit 19") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B14,DBF_UCHAR) { - prompt("Bit 20") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B15,DBF_UCHAR) { - prompt("Bit 21") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B16,DBF_UCHAR) { - prompt("Bit 22") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B17,DBF_UCHAR) { - prompt("Bit 23") - promptgroup("53 - Output 16-23") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B18,DBF_UCHAR) { - prompt("Bit 24") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B19,DBF_UCHAR) { - prompt("Bit 25") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B1A,DBF_UCHAR) { - prompt("Bit 26") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B1B,DBF_UCHAR) { - prompt("Bit 27") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B1C,DBF_UCHAR) { - prompt("Bit 28") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B1D,DBF_UCHAR) { - prompt("Bit 29") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B1E,DBF_UCHAR) { - prompt("Bit 30") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } - field(B1F,DBF_UCHAR) { - prompt("Bit 31") - promptgroup("54 - Output 24-31") - special(SPC_MOD) - pp(TRUE) - interest(1) - } -} diff --git a/modules/database/src/std/rec/mbboDirectRecord.dbd.pod b/modules/database/src/std/rec/mbboDirectRecord.dbd.pod new file mode 100644 index 000000000..ca49bcd53 --- /dev/null +++ b/modules/database/src/std/rec/mbboDirectRecord.dbd.pod @@ -0,0 +1,672 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Multi-Bit Binary Output Direct Record (mbboDirect) + +The mbboDirect record performs the opposite function to that of the mbbiDirect +record. It accumulates bits (in the fields B0 - BF) as unsigned characters, and +converts them to a word which is then written out to hardware. If a bit field is +non-zero, it is interpreted as a binary 1. On the other hand, if it is zero, it +is interpreted as a binary 0. + +=recordtype mbboDirect + +=cut + +recordtype(mbboDirect) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The mbboDirect record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. Note +that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Desired Output Parameters + +The mbboDirect record, like all output records, must specify where its output +originates. The output mode select field (OMSL) determines whether the output +originates from another record or from database access. When set to C<<< +closed_loop >>>, the desired output is retrieved from the link specified in the +desired output (DOL) field--which can specify either a database or channel +access link--and placed into the VAL field. When set to C<<< supervisory >>>, +the DOL field is ignored and the current value of VAL is used. The desired +output can be written into the VAL field via dpPuts at run-time when the record +is in C<<< supervisory >>> mode. DOL can also be a constant, in which case VAL +is initialized to the constant value. Note that OMSL cannot be C<<< closed_loop +>>> when DOL is a constant. See L
    for information on how +to specify database links. + +VAL is then converted to RVAL in the routine described in the next section. +However, the C<<< Soft Channel >>> device support module for the mbboDirect +record writes the VAL field's value without any conversion. + +=fields OMSL, DOL, VAL + +=head3 Convert and Write Parameters + +For records that are to write values to hardware devices, the OUT output link +must contain the address of the I/O card, and the DTYP field must specify +the proper device support module. Be aware that the address format differs +according to the I/O bus used. See L
    for information +on the format of hardware addresses. + +If the mbboDirect record does not use the C<<< Soft Channel >>> device support +module, then VAL is converted to RVAL, and RVAL is the actual 16-bit word sent +out. RVAL is set equal to VAL and then shifted left by the number of bits +specified in the SHFT field (the SHFT value is set by device support and is not +configurable by the user). RVAL is then sent out to the location specified in +the OUT field. + +For mbboDirect records that specify a database link, a channel access link, or a +constant, the DTYP field must specify either one of two soft device support +routines--{Soft Channel} or C<<< Raw Soft Channel >>>. The difference between +the two is that C<<< Soft Channel >>> writes the desired output value from VAL +directly to the output link while C<<< Raw Soft Channel >>> writes the value +from RVAL to the output link after it has undergone the conversion described +above. See L
    for information on how to specify database +links. + +=fields OUT, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF + +=head3 Operator Display Parameters + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_LONG) { + prompt("Word") + promptgroup("50 - Output") + asl(ASL0) + pp(TRUE) + } + field(OMSL,DBF_MENU) { + prompt("Output Mode Select") + promptgroup("50 - Output") + special(SPC_RESET) + pp(TRUE) + interest(1) + menu(menuOmsl) + } + field(NOBT,DBF_SHORT) { + prompt("Number of Bits") + promptgroup("50 - Output") + special(SPC_NOMOD) + interest(1) + } + field(DOL,DBF_INLINK) { + prompt("Desired Output Loc") + promptgroup("40 - Input") + interest(1) + } + field(OUT,DBF_OUTLINK) { + prompt("Output Specification") + promptgroup("50 - Output") + interest(1) + } + field(RVAL,DBF_ULONG) { + prompt("Raw Value") + special(SPC_NOMOD) + pp(TRUE) + } + field(ORAW,DBF_ULONG) { + prompt("Prev Raw Value") + special(SPC_NOMOD) + interest(3) + } + field(RBV,DBF_ULONG) { + prompt("Readback Value") + special(SPC_NOMOD) + } + field(ORBV,DBF_ULONG) { + prompt("Prev Readback Value") + special(SPC_NOMOD) + interest(3) + } + field(MASK,DBF_ULONG) { + prompt("Hardware Mask") + special(SPC_NOMOD) + interest(1) + } + field(MLST,DBF_LONG) { + prompt("Last Value Monitored") + special(SPC_NOMOD) + interest(3) + } + field(SHFT,DBF_USHORT) { + prompt("Shift") + promptgroup("50 - Output") + interest(1) + } + +=head3 Run-time and Simulation Mode Parameters + +These parameters are used by the run-time code for processing the mbbo Direct +record. + +MASK is used by device support routine to read the hardware register. Record +support sets low order NOBT bits. Device support can shift this value. + +MLST holds the value when the last monitor for value change was triggered. + +=fields NOBT, ORAW, MASK, MLST + +The following fields are used to operate the mbboDirect record in the simulation +mode. See L for more information on the simulation mode fields. + +=fields SIOL, SIML, SIMM, SIMS, SSCN, SDLY + +=cut + + field(SIOL,DBF_OUTLINK) { + prompt("Simulation Output Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIML,DBF_INLINK) { + prompt("Simulation Mode Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + +=head3 Alarm Parameters + +The possible alarm conditions for mbboDirect records are the SCAN, READ, and +INVALID alarms. The SCAN and READ alarms are not configurable by the user since +they are always of MAJOR severity. See L for a complete +explanation of Scan and Read alarms. + +The IVOA field specifies an action to take when the INVALID alarm is triggered. +There are three possible actions: C<<< Continue normally >>>, C<<< Don't drive +outputs >>>, or C<<< Set output to IVOV >>>. When C<<< Set output to IVOV >>> is +specified and a INVALID alarm is triggered, the record will write the value in +the IVOV field to output. See L for more +information. L lists other fields related to a alarms that are +common to all record types. + +=fields IVOA, IVOV + +=cut + + field(IVOA,DBF_MENU) { + prompt("INVALID outpt action") + promptgroup("50 - Output") + interest(2) + menu(menuIvoa) + } + field(IVOV,DBF_LONG) { + prompt("INVALID output value") + promptgroup("50 - Output") + interest(2) + } + + field(B0,DBF_UCHAR) { + prompt("Bit 0") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B1,DBF_UCHAR) { + prompt("Bit 1") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B2,DBF_UCHAR) { + prompt("Bit 2") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B3,DBF_UCHAR) { + prompt("Bit 3") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B4,DBF_UCHAR) { + prompt("Bit 4") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B5,DBF_UCHAR) { + prompt("Bit 5") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B6,DBF_UCHAR) { + prompt("Bit 6") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B7,DBF_UCHAR) { + prompt("Bit 7") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B8,DBF_UCHAR) { + prompt("Bit 8") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B9,DBF_UCHAR) { + prompt("Bit 9") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(BA,DBF_UCHAR) { + prompt("Bit 10") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(BB,DBF_UCHAR) { + prompt("Bit 11") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(BC,DBF_UCHAR) { + prompt("Bit 12") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(BD,DBF_UCHAR) { + prompt("Bit 13") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(BE,DBF_UCHAR) { + prompt("Bit 14") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(BF,DBF_UCHAR) { + prompt("Bit 15") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B10,DBF_UCHAR) { + prompt("Bit 16") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B11,DBF_UCHAR) { + prompt("Bit 17") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B12,DBF_UCHAR) { + prompt("Bit 18") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B13,DBF_UCHAR) { + prompt("Bit 19") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B14,DBF_UCHAR) { + prompt("Bit 20") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B15,DBF_UCHAR) { + prompt("Bit 21") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B16,DBF_UCHAR) { + prompt("Bit 22") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B17,DBF_UCHAR) { + prompt("Bit 23") + promptgroup("53 - Output 16-23") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B18,DBF_UCHAR) { + prompt("Bit 24") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B19,DBF_UCHAR) { + prompt("Bit 25") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B1A,DBF_UCHAR) { + prompt("Bit 26") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B1B,DBF_UCHAR) { + prompt("Bit 27") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B1C,DBF_UCHAR) { + prompt("Bit 28") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B1D,DBF_UCHAR) { + prompt("Bit 29") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B1E,DBF_UCHAR) { + prompt("Bit 30") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + field(B1F,DBF_UCHAR) { + prompt("Bit 31") + promptgroup("54 - Output 24-31") + special(SPC_MOD) + pp(TRUE) + interest(1) + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available.The routine +next checks to see if the device support write routine is defined. If either +device support or the device support write routine does not exist, an error +message is issued and processing is terminated. + +If DOL is a constant, then VAL is initialized to its value and UDF is set to +FALSE. + +MASK is cleared and then the NOBT low order bits are set. + +If device support includes C, it is called. + +If device support returns success, VAL is then set from RVAL and UDF is set to +FALSE. + +=head4 Process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE + +=over + +=item * If DOL is DB_LINK and OMSL is CLOSED_LOOP + +=over + +=item * Get value from DOL + +=item * Set PACT to FALSE + +=back + +=back + +=item 3. + +Convert + +=over + +=item * If PACT is FALSE, compute RVAL + +=over + +=item * Set RVAL = VAL + +=item * Shift RVAL left SHFT bits + +=back + +=item * Status=write_mbboDirect + +=back + +=item 4. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * Alarm monitors are invoked if the alarm status or severity has changed. + +=item * Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * Monitors for RVAL and RBV are checked whenever other monitors are invoked. + +=item * NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each mbboDirect record must have an associated set of device support routines. +The primary responsibility of the device support routines is to obtain a new raw +mbbo value whenever write_mbboDirect is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, NOBT, OUT, RVAL, RBV, MASK, SHFT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. If MASK is used, it should be shifted if necessary and +SHFT given a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 write_mbboDirect + + write_mbboDirect(precord) + +This routine must output a new value. It returns the following values: + +=over + +=item * 0: Success. + +=item * Other: Error. + +=back + +=head3 Device Support For Soft Records + +This C<<< SOft Channel >>> module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_mbboDirect calls recGblPutLinkValue to write the current value of VAL. + +See L. + +=cut + +} diff --git a/modules/database/src/std/rec/mbboRecord.c b/modules/database/src/std/rec/mbboRecord.c index e70838071..2488552ba 100644 --- a/modules/database/src/std/rec/mbboRecord.c +++ b/modules/database/src/std/rec/mbboRecord.c @@ -458,9 +458,9 @@ static long writeValue(mbboRecord *prec) status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/mbboRecord.dbd b/modules/database/src/std/rec/mbboRecord.dbd deleted file mode 100644 index 5475029df..000000000 --- a/modules/database/src/std/rec/mbboRecord.dbd +++ /dev/null @@ -1,526 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(mbbo) { - include "dbCommon.dbd" - field(VAL,DBF_ENUM) { - prompt("Desired Value") - promptgroup("50 - Output") - special(SPC_DBADDR) - asl(ASL0) - pp(TRUE) - #=read Yes - #=write Yes - } - field(DOL,DBF_INLINK) { - prompt("Desired Output Loc") - promptgroup("40 - Input") - interest(1) - } - field(OMSL,DBF_MENU) { - prompt("Output Mode Select") - promptgroup("50 - Output") - interest(1) - menu(menuOmsl) - } - field(NOBT,DBF_USHORT) { - prompt("Number of Bits") - promptgroup("50 - Output") - special(SPC_NOMOD) - interest(1) - } - field(OUT,DBF_OUTLINK) { - prompt("Output Specification") - promptgroup("50 - Output") - interest(1) - } - field(ZRVL,DBF_ULONG) { - prompt("Zero Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(ONVL,DBF_ULONG) { - prompt("One Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TWVL,DBF_ULONG) { - prompt("Two Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(THVL,DBF_ULONG) { - prompt("Three Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FRVL,DBF_ULONG) { - prompt("Four Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FVVL,DBF_ULONG) { - prompt("Five Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(SXVL,DBF_ULONG) { - prompt("Six Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(SVVL,DBF_ULONG) { - prompt("Seven Value") - promptgroup("51 - Output 0-7") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(EIVL,DBF_ULONG) { - prompt("Eight Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(NIVL,DBF_ULONG) { - prompt("Nine Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TEVL,DBF_ULONG) { - prompt("Ten Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(ELVL,DBF_ULONG) { - prompt("Eleven Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TVVL,DBF_ULONG) { - prompt("Twelve Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(TTVL,DBF_ULONG) { - prompt("Thirteen Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FTVL,DBF_ULONG) { - prompt("Fourteen Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(FFVL,DBF_ULONG) { - prompt("Fifteen Value") - promptgroup("52 - Output 8-15") - special(SPC_MOD) - pp(TRUE) - base(HEX) - interest(1) - } - field(ZRST,DBF_STRING) { - prompt("Zero String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(ONST,DBF_STRING) { - prompt("One String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TWST,DBF_STRING) { - prompt("Two String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(THST,DBF_STRING) { - prompt("Three String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FRST,DBF_STRING) { - prompt("Four String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FVST,DBF_STRING) { - prompt("Five String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(SXST,DBF_STRING) { - prompt("Six String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(SVST,DBF_STRING) { - prompt("Seven String") - promptgroup("81 - Display 0-7") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(EIST,DBF_STRING) { - prompt("Eight String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(NIST,DBF_STRING) { - prompt("Nine String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TEST,DBF_STRING) { - prompt("Ten String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(ELST,DBF_STRING) { - prompt("Eleven String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TVST,DBF_STRING) { - prompt("Twelve String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(TTST,DBF_STRING) { - prompt("Thirteen String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FTST,DBF_STRING) { - prompt("Fourteen String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(FFST,DBF_STRING) { - prompt("Fifteen String") - promptgroup("82 - Display 8-15") - special(SPC_MOD) - pp(TRUE) - interest(1) - size(26) - } - field(ZRSV,DBF_MENU) { - prompt("State Zero Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(ONSV,DBF_MENU) { - prompt("State One Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TWSV,DBF_MENU) { - prompt("State Two Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(THSV,DBF_MENU) { - prompt("State Three Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FRSV,DBF_MENU) { - prompt("State Four Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FVSV,DBF_MENU) { - prompt("State Five Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(SXSV,DBF_MENU) { - prompt("State Six Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(SVSV,DBF_MENU) { - prompt("State Seven Severity") - promptgroup("71 - Alarm 0-7") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(EISV,DBF_MENU) { - prompt("State Eight Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(NISV,DBF_MENU) { - prompt("State Nine Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TESV,DBF_MENU) { - prompt("State Ten Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(ELSV,DBF_MENU) { - prompt("State Eleven Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TVSV,DBF_MENU) { - prompt("State Twelve Severity") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(TTSV,DBF_MENU) { - prompt("State Thirteen Sevr") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FTSV,DBF_MENU) { - prompt("State Fourteen Sevr") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(FFSV,DBF_MENU) { - prompt("State Fifteen Sevr") - promptgroup("72 - Alarm 8-15") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(UNSV,DBF_MENU) { - prompt("Unknown State Sevr") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(COSV,DBF_MENU) { - prompt("Change of State Sevr") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(RVAL,DBF_ULONG) { - prompt("Raw Value") - pp(TRUE) - } - field(ORAW,DBF_ULONG) { - prompt("Prev Raw Value") - special(SPC_NOMOD) - interest(3) - } - field(RBV,DBF_ULONG) { - prompt("Readback Value") - special(SPC_NOMOD) - } - field(ORBV,DBF_ULONG) { - prompt("Prev Readback Value") - special(SPC_NOMOD) - interest(3) - } - field(MASK,DBF_ULONG) { - prompt("Hardware Mask") - special(SPC_NOMOD) - interest(1) - } - field(MLST,DBF_USHORT) { - prompt("Last Value Monitored") - special(SPC_NOMOD) - interest(3) - } - field(LALM,DBF_USHORT) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(SDEF,DBF_SHORT) { - prompt("States Defined") - special(SPC_NOMOD) - interest(3) - } - field(SHFT,DBF_USHORT) { - prompt("Shift") - promptgroup("50 - Output") - interest(1) - } - field(SIOL,DBF_OUTLINK) { - prompt("Simulation Output Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } - field(IVOA,DBF_MENU) { - prompt("INVALID outpt action") - promptgroup("50 - Output") - interest(2) - menu(menuIvoa) - } - field(IVOV,DBF_USHORT) { - prompt("INVALID output value") - promptgroup("50 - Output") - interest(2) - } -} diff --git a/modules/database/src/std/rec/mbboRecord.dbd.pod b/modules/database/src/std/rec/mbboRecord.dbd.pod new file mode 100644 index 000000000..2196aa5a2 --- /dev/null +++ b/modules/database/src/std/rec/mbboRecord.dbd.pod @@ -0,0 +1,969 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Multi-Bit Binary Output Record (mbbo) + +The normal use for the mbbo record type is to send a binary value (representing +one of up to 16 states) to a Digital Output module. It is used for any device +that uses more than one contiguous bit to control it. The mbbo record can also +be used to write discrete values to other records via database or channel access +links. + +=recordtype mbbo + +=cut + +recordtype(mbbo) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The mbbo record has the standard fields for specifying under what circumstances +it will be processed. These fields are listed in L. In addition, +L explains how these fields are used. Note that I/O +event scanning is only supported for those card types that interrupt. + +=head3 Desired Output Parameters + +The multi-bit binary output record, like all output records, must specify where +its output originates. The output mode select (OMSL) field determines whether +the output originates from another record or from database access (i.e., the +operator). When set to C<<< closed_loop >>>, the desired output is retrieved +from the link specified in the desired output (DOL) field--which can specify +either a database or channel access link--and placed into the VAL field. When +set to C<<< supervisory >>>, the DOL field is ignored and the current value of +VAL is simply written. VAL can be changed via dpPuts at run-time when OMSL is +C<<< supervisory >>>. The DOL field can also be a constant, in which case the +VAL field is initialized to the constant value. If DOL is a constant, OMSL +cannot be set to C<<< closed_loop >>>. + +The VAL field itself usually consists of an index that specifies one of the +states. The actual output written is the value of RVAL, which is converted from +VAL following the routine explained in the next section. However, records that +use the C<<< Soft Channel >>> device support module write the VAL field's value +without any conversion. + +=fields OMSL, DOL, VAL + +=head3 Convert and Write Parameters + +The device support routines write the desired output to the location specified +in the OUT field. If the record uses soft device support, OUT can contain a +constant, a database link, or a channel access link; however, if OUT is a +constant, no value will be written. + +For records that write their values to hardware devices, the OUT output link +must specify the address of the I/O card, and the DTYP field must specify +the corresponding device support module. Be aware that the address format +differs according to the I/O bus used. See L
    for +information on the format of hardware addresses. + +For mbbo records that write to hardware, the value written to the output +location is the value contained in RVAL, which is converted from VAL, VAL +containing an index of one of the 16 states (0-15). RVAL is then set to the +corresponding state value, the value in one of the fields ZRVL through FFVL. +Then this value is shifted left according to the number in the SHFT field so +that the value is in the correct position for the bits being used (the SHFT +value is set by device support and is not configurable by the user). + +The state value fields ZRVL through FFVL must be configured by the user before +run-time. When the state values are not defined, the states defined (SDEF) field +is set to FALSE at initialization time by the record routines. When SDEF is +FALSE, then the record processing routine does not try to find a match, RVAL is +set equal to VAL, the bits are shifted using the number in SHFT, and the value +is written thus. + +If the OUT output link specifies a database link, channel access link, or +constant, then the DTYP field must specify either one of the two soft device +support modules-- C<<< Soft Channel >>> or C<<< Raw Soft Channel >>>. C<<< Soft +>>> C<<< Channel >>> writes the value of VAL to the output link, without any +conversion, while C<<< Raw Soft Channel >>> writes the value from RVAL after it +has undergone the above conversion. See L
    for information +on specifying links. + +Note also that when a string is retrieved as the desired output, a record +support routine is provided (C<<< put_enum_str() >>>) that will check to see +if the string matches one of the strings in the ZRST through FFST fields. If a +match is found, RVAL is set equal to the corresponding state value of that +string. + +=fields OUT, DTYP, RVAL, SHFT, SDEF, ZRVL, ONVL, TWVL, THVL, FRVL, FVVL, SXVL, SVVL, EIVL, NIVL, TEVL, ELVL, TVVL, TTVL, FTVL, FFVL + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. These +fields are used to display the value and other parameters of the mbbo record +either textually or graphically. The ZRST-FFST fields contain strings describing +each of the corresponding states. The C<<< get_enum_str() >>> and +C<<< get_enum_strs() >>> record routines retrieve these strings for the +operator. C<<< get_enum_str() >>> gets the string corresponding to the value in +VAL, and C<<< get_enum_strs() >>> retrieves all the strings. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC, ZRST, ONST, TWST, THST, FRST, FVST, SXST, SVST, EIST, NIST, TEST, ELST, TVST, TTST, FTST, FFST + +=head3 Alarm Parameters + +The possible alarm conditions for multi-bit binary outputs are the SCAN, READ, +INVALID, and state alarms. The SCAN and READ alarms are called by the support +modules and are not configurable by the user, as their severity is always MAJOR. + +The IVOA field specifies an action to take from a number of possible choices +when the INVALID alarm is triggered. The IVOV field contains a value to be +written once the INVALID alarm has been triggered if C<<< Set output to IVOV >>> +has been chosen in the IVOA field. The severity of the INVALID alarm is not +configurable by the user. + +The state alarms are configured in the below severity fields. These fields have +the usual possible values for severity fields: NO_ALARM, MINOR, and MAJOR. + +The unknown state severity field (UNSV), if set to MINOR or MAJOR, triggers an +alarm when the record support routine cannot find a matching value in the state +value fields for VAL or when VAL is out of range. + +The change of state severity field (COSV) triggers an alarm when the record's +state changes, if set to MAJOR or MINOR. + +The state severity (ZRSV-FFSV) fields, when set to MAJOR or MINOR, trigger an +alarm when VAL equals the corresponding field. + +See L for a complete explanation of discrete alarms and +these fields. See L for an explanation of the IVOA +and IVOV fields. L lists other fields related to a alarms that are +common to all record types. + +=fields UNSV, COSV, IVOA, IVOV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV + +=head3 Run-Time and Simulation Mode Parameters + +These parameters are used by the run-time code for processing the multi-bit +binary output. + +MASK is used by device support routine to read the hardware register. Record +support sets low order of MASK the number of bits specified in NOBT. Device +support can shift this value. + +The LALM field implements the change of state alarm severity by holding the +value of VAL when the previous change of state alarm was issued. + +MLST holds the value when the last monitor for value change was triggered. + +SDEF is used by record support to save time if no states are defined; it is used +for converting VAL to RVAL. + +=fields NOBT, ORAW, MASK, LALM, MLST, SDEF + +The following fields are used to operate the mbbo record in the simulation mode. +See L for more information on the simulation +mode fields. + +=fields SIOL, SIML, SIMM, SIMS, SSCN, SDLY + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_ENUM) { + prompt("Desired Value") + promptgroup("50 - Output") + special(SPC_DBADDR) + asl(ASL0) + pp(TRUE) + #=read Yes + #=write Yes + } + field(DOL,DBF_INLINK) { + prompt("Desired Output Loc") + promptgroup("40 - Input") + interest(1) + } + field(OMSL,DBF_MENU) { + prompt("Output Mode Select") + promptgroup("50 - Output") + interest(1) + menu(menuOmsl) + } + field(NOBT,DBF_USHORT) { + prompt("Number of Bits") + promptgroup("50 - Output") + special(SPC_NOMOD) + interest(1) + } + field(OUT,DBF_OUTLINK) { + prompt("Output Specification") + promptgroup("50 - Output") + interest(1) + } + field(ZRVL,DBF_ULONG) { + prompt("Zero Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(ONVL,DBF_ULONG) { + prompt("One Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TWVL,DBF_ULONG) { + prompt("Two Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(THVL,DBF_ULONG) { + prompt("Three Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FRVL,DBF_ULONG) { + prompt("Four Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FVVL,DBF_ULONG) { + prompt("Five Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(SXVL,DBF_ULONG) { + prompt("Six Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(SVVL,DBF_ULONG) { + prompt("Seven Value") + promptgroup("51 - Output 0-7") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(EIVL,DBF_ULONG) { + prompt("Eight Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(NIVL,DBF_ULONG) { + prompt("Nine Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TEVL,DBF_ULONG) { + prompt("Ten Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(ELVL,DBF_ULONG) { + prompt("Eleven Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TVVL,DBF_ULONG) { + prompt("Twelve Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(TTVL,DBF_ULONG) { + prompt("Thirteen Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FTVL,DBF_ULONG) { + prompt("Fourteen Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(FFVL,DBF_ULONG) { + prompt("Fifteen Value") + promptgroup("52 - Output 8-15") + special(SPC_MOD) + pp(TRUE) + base(HEX) + interest(1) + } + field(ZRST,DBF_STRING) { + prompt("Zero String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(ONST,DBF_STRING) { + prompt("One String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TWST,DBF_STRING) { + prompt("Two String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(THST,DBF_STRING) { + prompt("Three String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FRST,DBF_STRING) { + prompt("Four String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FVST,DBF_STRING) { + prompt("Five String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(SXST,DBF_STRING) { + prompt("Six String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(SVST,DBF_STRING) { + prompt("Seven String") + promptgroup("81 - Display 0-7") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(EIST,DBF_STRING) { + prompt("Eight String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(NIST,DBF_STRING) { + prompt("Nine String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TEST,DBF_STRING) { + prompt("Ten String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(ELST,DBF_STRING) { + prompt("Eleven String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TVST,DBF_STRING) { + prompt("Twelve String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(TTST,DBF_STRING) { + prompt("Thirteen String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FTST,DBF_STRING) { + prompt("Fourteen String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(FFST,DBF_STRING) { + prompt("Fifteen String") + promptgroup("82 - Display 8-15") + special(SPC_MOD) + pp(TRUE) + interest(1) + size(26) + } + field(ZRSV,DBF_MENU) { + prompt("State Zero Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(ONSV,DBF_MENU) { + prompt("State One Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TWSV,DBF_MENU) { + prompt("State Two Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(THSV,DBF_MENU) { + prompt("State Three Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FRSV,DBF_MENU) { + prompt("State Four Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FVSV,DBF_MENU) { + prompt("State Five Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(SXSV,DBF_MENU) { + prompt("State Six Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(SVSV,DBF_MENU) { + prompt("State Seven Severity") + promptgroup("71 - Alarm 0-7") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(EISV,DBF_MENU) { + prompt("State Eight Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(NISV,DBF_MENU) { + prompt("State Nine Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TESV,DBF_MENU) { + prompt("State Ten Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(ELSV,DBF_MENU) { + prompt("State Eleven Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TVSV,DBF_MENU) { + prompt("State Twelve Severity") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(TTSV,DBF_MENU) { + prompt("State Thirteen Sevr") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FTSV,DBF_MENU) { + prompt("State Fourteen Sevr") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(FFSV,DBF_MENU) { + prompt("State Fifteen Sevr") + promptgroup("72 - Alarm 8-15") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(UNSV,DBF_MENU) { + prompt("Unknown State Sevr") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(COSV,DBF_MENU) { + prompt("Change of State Sevr") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(RVAL,DBF_ULONG) { + prompt("Raw Value") + pp(TRUE) + } + field(ORAW,DBF_ULONG) { + prompt("Prev Raw Value") + special(SPC_NOMOD) + interest(3) + } + field(RBV,DBF_ULONG) { + prompt("Readback Value") + special(SPC_NOMOD) + } + field(ORBV,DBF_ULONG) { + prompt("Prev Readback Value") + special(SPC_NOMOD) + interest(3) + } + field(MASK,DBF_ULONG) { + prompt("Hardware Mask") + special(SPC_NOMOD) + interest(1) + } + field(MLST,DBF_USHORT) { + prompt("Last Value Monitored") + special(SPC_NOMOD) + interest(3) + } + field(LALM,DBF_USHORT) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(SDEF,DBF_SHORT) { + prompt("States Defined") + special(SPC_NOMOD) + interest(3) + } + field(SHFT,DBF_USHORT) { + prompt("Shift") + promptgroup("50 - Output") + interest(1) + } + field(SIOL,DBF_OUTLINK) { + prompt("Simulation Output Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIML,DBF_INLINK) { + prompt("Simulation Mode Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + field(IVOA,DBF_MENU) { + prompt("INVALID outpt action") + promptgroup("50 - Output") + interest(2) + menu(menuIvoa) + } + field(IVOV,DBF_USHORT) { + prompt("INVALID output value") + promptgroup("50 - Output") + interest(2) + } +} + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available. The routine +next checks to see if the device support write routine is defined. If either +device support or the device support write routine does not exist, an error +message is issued and processing is terminated. + +If DOL is a constant, then VAL is initialized to its value and UDF is set to +FALSE. + +MASK is cleared and then the NOBT low order bits are set. + +If device support includes C, it is called. + +init_common is then called to determine if any states are defined. If states are +defined, SDEF is set to TRUE. + +If device support returns success, VAL is then set from RVAL and UDF is set to +FALSE. + +=head4 process + +See next section. + +=head4 special + +Computes SDEF when any of the fields ZRVL,...FFVL change value. + +=head4 get_value + +Fills in the values of struct valueDes so that they refer to VAL. + +=head4 get_enum_str + +Retrieves ASCII string corresponding to VAL. + +=head4 get_enum_strs + +Retrieves ASCII strings for ZRST,...FFST. + +=head4 put_enum_str + +Checks if string matches ZRST,...FFST and if it does, sets VAL. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will not longer be called for +this record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE + +=over + +=item * + +If DOL is DB_LINK and OMSL is CLOSED_LOOP + +=over + +=item * + +Get value from DOL + +=item * + +Set UDF to FALSE + +=item * + +Check for link alarm + +=back + +=item * + +If any state values are defined + +=over + +=item * + +If VAL E 15, then raise alarm and go to 4 + +=item * + +Else using VAL as index set RVAL = one of ZRVL,...FFVL + +=back + +=item * + +Else set RVAL = VAL + +=item * + +Shift RVAL left SHFT bits + +=back + +=item 3. + +Convert + +=over + +=item * + +If PACT is FALSE, compute RVAL + +=over + +=item * + +If VAL is 0,...,15, set RVAL from ZRVL,...,FFVL + +=item * + +If VAL out of range, set RVAL = undefined + +=back + +=item * + +Status = write_mbbo + +=back + +=item 4. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. + +=item 5. + +Check severity and write the new value. See L and L for more information. + +=item 6. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 7. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * + +Monitors for RVAL and RBV are checked whenever other monitors are invoked. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 8. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each mbbo record must have an associated set of device support routines. The +primary responsibility of the device support routines is to obtain a new raw +mbbo value whenever write_mbbo is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, NOBT, OUT, RVAL, RBV, MASK, SHFT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support's +C routine. If MASK is used, it should be shifted if necessary and SHFT +given a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 write_mbbo + + write_mbbo(precord) + +This routine must output a new value. It returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +=head4 Soft Channel + +The C<<< Soft Channel >>> module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_mbbo calls recGblPutLinkValue to write the current value of VAL. See +L for more information. + +=head4 Raw Soft Channel + +This module writes RVAL to the location specified in the output link. It returns +a 0. + +=cut diff --git a/modules/database/src/std/rec/permissiveRecord.dbd b/modules/database/src/std/rec/permissiveRecord.dbd deleted file mode 100644 index 7eb04bf95..000000000 --- a/modules/database/src/std/rec/permissiveRecord.dbd +++ /dev/null @@ -1,38 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(permissive) { - include "dbCommon.dbd" - field(LABL,DBF_STRING) { - prompt("Button Label") - promptgroup("80 - Display") - pp(TRUE) - interest(1) - size(20) - } - field(VAL,DBF_USHORT) { - prompt("Status") - promptgroup("40 - Input") - asl(ASL0) - pp(TRUE) - } - field(OVAL,DBF_USHORT) { - prompt("Old Status") - special(SPC_NOMOD) - interest(3) - } - field(WFLG,DBF_USHORT) { - prompt("Wait Flag") - pp(TRUE) - } - field(OFLG,DBF_USHORT) { - prompt("Old Flag") - special(SPC_NOMOD) - interest(3) - } -} diff --git a/modules/database/src/std/rec/permissiveRecord.dbd.pod b/modules/database/src/std/rec/permissiveRecord.dbd.pod new file mode 100644 index 000000000..5ad979f74 --- /dev/null +++ b/modules/database/src/std/rec/permissiveRecord.dbd.pod @@ -0,0 +1,128 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Permissive Record (permissive) + +The permissive record is for communication between a server and a client. An +example would be a sequence program server and an operator interface client. By +using multiple permissive records a sequence program can communicate its current +state to the client. + +B + +=recordtype permissive + +=cut + +recordtype(permissive) { + include "dbCommon.dbd" + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The permissive record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in +L. In addition, L explains how these +fields are used. Since the permissive record supports no direct interfaces to +hardware, its SCAN field cannot be C<<< I/O Intr >>>. + +=head3 Client-server Parameters + +The client and server communicate through the VAL and watchdog flag (WFLG) +fields. At initialization, both fields are set equal to 0, which means OFF. The +server sets WFLG equal to ON when it is ready to accept a request. The client +monitors WFLG and when WFLG equals 1, the client-server action is performed (a +private matter between server and client). + +When WFLG is off--when the server is busy--the client program may turn the VAL +field from OFF to ON. After the server finishes its task, it will notice that +VAL is ON and will turn both WFLG and VAL OFF and performs the requested +service. + +Note that when WFLG is ON, the client program ''must not'' turn VAL to on. + +=fields VAL, WFLG + +=cut + + field(VAL,DBF_USHORT) { + prompt("Status") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + } + field(WFLG,DBF_USHORT) { + prompt("Wait Flag") + pp(TRUE) + } + +=head3 Operator Display Parameters + +The label field (LABL) contains a string given to it that should describe the +record in further detail. In addition to the DESC field. See +L for more on the record name (NAME) and +description (DESC) fields. + +=fields LABL, NAME, DESC + +=cut + + field(LABL,DBF_STRING) { + prompt("Button Label") + promptgroup("80 - Display") + pp(TRUE) + interest(1) + size(20) + } + +=head3 Alarm Parameters + +The Permissive record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head3 Run-time Parameters + +These fields are used to trigger monitors for each field. Monitors for the VAL +field are triggered when OVAL, the old value field, does not equal VAL. +Likewise, OFLG causes monitors to be invoked for WFLG when WFLG does not equal +OLFG. + +=fields OVAL, OFLG + +=cut + + field(OVAL,DBF_USHORT) { + prompt("Old Status") + special(SPC_NOMOD) + interest(3) + } + field(OFLG,DBF_USHORT) { + prompt("Old Flag") + special(SPC_NOMOD) + interest(3) + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 process + + long (*process)(struct dbCommon *precord) + +C<<< process() >>> sets UDF to FALSE, triggers monitors on VAL and WFLG when +they change, and scans the forward link if necessary. + +=cut + +} diff --git a/modules/database/src/std/rec/selRecord.dbd b/modules/database/src/std/rec/selRecord.dbd deleted file mode 100644 index 724482704..000000000 --- a/modules/database/src/std/rec/selRecord.dbd +++ /dev/null @@ -1,323 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -menu(selSELM) { - choice(selSELM_Specified,"Specified") - choice(selSELM_High_Signal,"High Signal") - choice(selSELM_Low_Signal,"Low Signal") - choice(selSELM_Median_Signal,"Median Signal") -} -recordtype(sel) { - include "dbCommon.dbd" - field(VAL,DBF_DOUBLE) { - prompt("Result") - promptgroup("40 - Input") - asl(ASL0) - special(SPC_NOMOD) - } - field(SELM,DBF_MENU) { - prompt("Select Mechanism") - promptgroup("30 - Action") - menu(selSELM) - } - field(SELN,DBF_USHORT) { - prompt("Index value") - } - field(PREC,DBF_SHORT) { - prompt("Display Precision") - promptgroup("80 - Display") - interest(1) - } - field(NVL,DBF_INLINK) { - prompt("Index Value Location") - promptgroup("30 - Action") - interest(1) - } - field(INPA,DBF_INLINK) { - prompt("Input A") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPB,DBF_INLINK) { - prompt("Input B") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPC,DBF_INLINK) { - prompt("Input C") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPD,DBF_INLINK) { - prompt("Input D") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPE,DBF_INLINK) { - prompt("Input E") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPF,DBF_INLINK) { - prompt("Input F") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPG,DBF_INLINK) { - prompt("Input G") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPH,DBF_INLINK) { - prompt("Input H") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPI,DBF_INLINK) { - prompt("Input I") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPJ,DBF_INLINK) { - prompt("Input J") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPK,DBF_INLINK) { - prompt("Input K") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPL,DBF_INLINK) { - prompt("Input L") - promptgroup("42 - Input G-L") - interest(1) - } - field(EGU,DBF_STRING) { - prompt("Engineering Units") - promptgroup("80 - Display") - interest(1) - size(16) - prop(YES) - } - field(HOPR,DBF_DOUBLE) { - prompt("High Operating Rng") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(LOPR,DBF_DOUBLE) { - prompt("Low Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(HIHI,DBF_DOUBLE) { - prompt("Hihi Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOLO,DBF_DOUBLE) { - prompt("Lolo Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(HIGH,DBF_DOUBLE) { - prompt("High Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOW,DBF_DOUBLE) { - prompt("Low Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(HHSV,DBF_MENU) { - prompt("Hihi Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(LLSV,DBF_MENU) { - prompt("Lolo Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(HSV,DBF_MENU) { - prompt("High Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(LSV,DBF_MENU) { - prompt("Low Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(HYST,DBF_DOUBLE) { - prompt("Alarm Deadband") - promptgroup("70 - Alarm") - interest(1) - } - field(ADEL,DBF_DOUBLE) { - prompt("Archive Deadband") - promptgroup("80 - Display") - interest(1) - } - field(MDEL,DBF_DOUBLE) { - prompt("Monitor Deadband") - promptgroup("80 - Display") - interest(1) - } - field(A,DBF_DOUBLE) { - prompt("Value of Input A") - pp(TRUE) - } - field(B,DBF_DOUBLE) { - prompt("Value of Input B") - pp(TRUE) - } - field(C,DBF_DOUBLE) { - prompt("Value of Input C") - pp(TRUE) - } - field(D,DBF_DOUBLE) { - prompt("Value of Input D") - pp(TRUE) - } - field(E,DBF_DOUBLE) { - prompt("Value of Input E") - pp(TRUE) - } - field(F,DBF_DOUBLE) { - prompt("Value of Input F") - pp(TRUE) - } - field(G,DBF_DOUBLE) { - prompt("Value of Input G") - pp(TRUE) - } - field(H,DBF_DOUBLE) { - prompt("Value of Input H") - pp(TRUE) - } - field(I,DBF_DOUBLE) { - prompt("Value of Input I") - pp(TRUE) - } - field(J,DBF_DOUBLE) { - prompt("Value of Input J") - pp(TRUE) - } - field(K,DBF_DOUBLE) { - prompt("Value of Input K") - pp(TRUE) - } - field(L,DBF_DOUBLE) { - prompt("Value of Input L") - pp(TRUE) - } - field(LA,DBF_DOUBLE) { - prompt("Prev Value of A") - special(SPC_NOMOD) - interest(3) - } - field(LB,DBF_DOUBLE) { - prompt("Prev Value of B") - special(SPC_NOMOD) - interest(3) - } - field(LC,DBF_DOUBLE) { - prompt("Prev Value of C") - special(SPC_NOMOD) - interest(3) - } - field(LD,DBF_DOUBLE) { - prompt("Prev Value of D") - special(SPC_NOMOD) - interest(3) - } - field(LE,DBF_DOUBLE) { - prompt("Prev Value of E") - special(SPC_NOMOD) - interest(3) - } - field(LF,DBF_DOUBLE) { - prompt("Prev Value of F") - special(SPC_NOMOD) - interest(3) - } - field(LG,DBF_DOUBLE) { - prompt("Prev Value of G") - special(SPC_NOMOD) - interest(3) - } - field(LH,DBF_DOUBLE) { - prompt("Prev Value of H") - special(SPC_NOMOD) - interest(3) - } - field(LI,DBF_DOUBLE) { - prompt("Prev Value of I") - special(SPC_NOMOD) - interest(3) - } - field(LJ,DBF_DOUBLE) { - prompt("Prev Value of J") - special(SPC_NOMOD) - interest(3) - } - field(LK,DBF_DOUBLE) { - prompt("Prev Value of K") - special(SPC_NOMOD) - interest(3) - } - field(LL,DBF_DOUBLE) { - prompt("Prev Value of L") - special(SPC_NOMOD) - interest(3) - } - field(LALM,DBF_DOUBLE) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(ALST,DBF_DOUBLE) { - prompt("Last Value Archived") - special(SPC_NOMOD) - interest(3) - } - field(MLST,DBF_DOUBLE) { - prompt("Last Val Monitored") - special(SPC_NOMOD) - interest(3) - } - field(NLST,DBF_USHORT) { - prompt("Last Index Monitored") - special(SPC_NOMOD) - interest(3) - } -} diff --git a/modules/database/src/std/rec/selRecord.dbd.pod b/modules/database/src/std/rec/selRecord.dbd.pod new file mode 100644 index 000000000..fe8301db6 --- /dev/null +++ b/modules/database/src/std/rec/selRecord.dbd.pod @@ -0,0 +1,594 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Select Record (sel) + +The select record computes a value based on input obtained from up to 12 +locations. The selection algorithm can be one of the following: C<<< Specified +>>>, C<<< High Signal >>>, C<<< Low Signal >>>, C<<< Median Signal >>>. Each +input can be a constant, a database link, or a channel access link. + +=recordtype sel + +=cut + +menu(selSELM) { + choice(selSELM_Specified,"Specified") + choice(selSELM_High_Signal,"High Signal") + choice(selSELM_Low_Signal,"Low Signal") + choice(selSELM_Median_Signal,"Median Signal") +} +recordtype(sel) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The select record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in +L. In addition, L +explains how these fields work. + +=head3 Read Parameters + +The INPA-L links determine where the selection record retrieves the values from +which it is to select or compute its final value. The INPA-L links are input +links configured by the user to be either constants, channel access links, or +database links. If channel access or database links, a value is retrieved for +each link and placed in the corresponding value field, A-L. If any input link is +a constant, the value field for that link will be initialized with the constant +value given to it and can be modified via dbPuts. See L
    +for information on how to specify database links. + +Any links not defined are ignored by the selection record and its algorithm. An +undefined link is any constant link whose value is 0. At initialization time, +the corresponding value links for such fields are set to NaN, which means +MISSING. The value field of an undefined link can be changed at run-time from +NaN to another value in order to define the link and its field. Note that all +undefined links must be recognized as such if the selection algorithm is to work +as expected. + +=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL, A, B, C, D, E, F, G, H, I, J, K, L + +=head3 Select Parameters + +The selection algorithm is determined by three fields configurable by the user: +the select mechanism (SELM) field, the select number (SELN) field, and the index +value location (NVL) field. + +The SELM field has four choices, i.e., four algorithms as follows: + +=head4 Menu selSELM + +=menu selSELM + +The selection record's VAL field is determined differently for each algorithm. +For C<<< Specified >>>, the VAL field is set equal to the value field (A, B, C, +D, E, F, G, H, I, J, K, or L) specified by the SELN field. The SELN field +contains a +number from 0-11 which corresponds to the value field to be used (0 means use A; +1 means use B, etc.). How the NVL field is configured determines, in turn, +SELN's value. NVL is an input link from which a value for SELN can be retrieved, +Like most other input links NVL can be a constant, or a channel access or +database link. If NVL is a link, SELN is retrieved from the location in NVL. If +a constant, SELN is initialized to the value given to the constant and can be +changed via dbPuts. See L
    for information on how to +specify database links. + +The C<<< High Signal >>>, C<<< Low Signal >>>, and C<<< Median Signal >>> +algorithms do not use SELN or NVL. If C<<< High Signal >>> is chosen, VAL is set +equal to the highest value out of all the defined value fields (A-L). If C<<< +Low Signal >>> is chosen, VAL is set equal to lowest value of all the defined +fields (A-L). And if C<<< Median Signal >>> is chosen, VAL is set equal to the +median value of the defined value fields (A-L). (Note that these algorithms +select from the value fields; they do not select from the value field index. For +instance, C<<< Low Signal >>> will not select the A field's value unless the +value itself is the lowest of all the defined values.) + +=fields SELM, SELN, NVL + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the select record either textually or +graphically. + +EGU is a string of up to 16 characters describing the units that the selection +record manipulates. It is retrieved by the C<<< get_units >>> record support +routine. + +The HOPR and LOPR fields set the upper and lower display limits for the VAL, +HIHI, HIGH, LOW, and LOLO fields. Both the C<<< get_graphic_double >>> and C<<< +get_control_double >>> record support routines retrieve these fields. + +The PREC field determines the floating point precision with which to display +VAL. It is used whenever the C<<< get_precision >>> record support routine is +called. + +See L for more on the record name (NAME) +and description (DESC) fields. + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +=head3 Alarm Parameters + +The possible alarm conditions for select records are the SCAN, READ, and limit +alarms. The SCAN and READ alarms are called by the record or device support +routines. The limit alarms are configured by the user in the HIHI, LOLO, HIGH, +and LOW fields using numerical values. They specify conditions for the VAL +field. For each of these fields, there is a corresponding severity field which +can be either NO_ALARM, MINOR, or MAJOR. See L +for a complete explanation of alarms and these fields. L +lists other fields related to a alarms that are common to all record types. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST + +=head3 Monitor Parameters + +These fields are configurable by the user. They are used as deadbands for the +archiver and monitor calls for the VAL field. Unless, VAL changes by more than +the value specified by each, then the respective monitors will not be called. If +these fields have a value of zero, everytime the VAL changes, monitors are +triggered; if they have a value of -1, everytime the record is processed, +monitors are triggered. L +gives a complete explanation of alarms and deadbands. + +=fields ADEL, MDEL + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the selection +record. They are not configurable prior to run-time, nor are they modifiable at +run-time. They represent the current state of the record. The record support +routines use some of them for more efficient processing. + +The VAL field is the result of the selection record's processing. It can be +accessed in the normal way by another record or through database access, but is +not modifiable except by the record itself. The LALM, ALST, and the MLST are +used to implement the HYST, ADEL, and MDEL hysteresis factors for the alarms, +archiver, and monitors, respectively. + +The LA-LL fields are used to implement the monitors for each of the value +fields, A-L. They represent previous input values. For example, unless LA is not +equal to A, no monitor is invoked for A. + +=fields VAL, LALM, ALST, MLST, LA, LB, LC, LD, LE, LF, LG, LH, LI, LJ, LK, LL + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +IF NVL is a constant, SELN is set to its value. If NVL is a PV_LINK a channel +access link is created. + +For each constant input link, the corresponding value field is initialized with +the constant value (or NaN if the constant has the value 0). + +For each input link that is of type PV_LINK, a database or channel access link +is created. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head4 get_units + + long (*get_units)(struct dbAddr *paddr, char *units) + +Retrieves EGU. + +=head4 get_precision + + long (*get_precision)(const struct dbAddr *paddr, long *precision) + +Retrieves PREC. + +=head4 get_graphic_double + + long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p) + +Sets the upper display and lower display limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_control_double + + long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p) + +Sets the upper control and the lower control limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_alarm_double + + long (*get_alarm_double)(struct dbAddr *paddr, struct dbr_alDouble *p) + +Sets the following values: + + upper_alarm_limit = HIHI + upper_warning_limit = HIGH + lower_warning_limit = LOW + lower_alarm_limit = LOLO + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +If NVL is a database or channel access link, SELN is obtained from NVL. Fetch +all values if database or channel access links. If SELM is SELECTED, then only +the selected link is fetched. + +=item 2. + +Implement the appropriate selection algorithm. For SELECT_HIGH, SELECT_LOW, and +SELECT_MEDIAN, input fields are ignored if they are undefined. If success, UDF +is set to FALSE. + +=item 3. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA, and LALM are set. It also honors the +alarm hysteresis factor (HYST). Thus the value must change by more than HYST +before the alarm status and severity is lowered. + +=item 4. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if ADEL and MDEL conditions are +met + +=item * + +Monitors for A-L are checked whenever other monitors are invoked + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 5. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_DOUBLE) { + prompt("Result") + promptgroup("40 - Input") + asl(ASL0) + special(SPC_NOMOD) + } + field(SELM,DBF_MENU) { + prompt("Select Mechanism") + promptgroup("30 - Action") + menu(selSELM) + } + field(SELN,DBF_USHORT) { + prompt("Index value") + } + field(PREC,DBF_SHORT) { + prompt("Display Precision") + promptgroup("80 - Display") + interest(1) + } + field(NVL,DBF_INLINK) { + prompt("Index Value Location") + promptgroup("30 - Action") + interest(1) + } + field(INPA,DBF_INLINK) { + prompt("Input A") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPB,DBF_INLINK) { + prompt("Input B") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPC,DBF_INLINK) { + prompt("Input C") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPD,DBF_INLINK) { + prompt("Input D") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPE,DBF_INLINK) { + prompt("Input E") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPF,DBF_INLINK) { + prompt("Input F") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPG,DBF_INLINK) { + prompt("Input G") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPH,DBF_INLINK) { + prompt("Input H") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPI,DBF_INLINK) { + prompt("Input I") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPJ,DBF_INLINK) { + prompt("Input J") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPK,DBF_INLINK) { + prompt("Input K") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPL,DBF_INLINK) { + prompt("Input L") + promptgroup("42 - Input G-L") + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Engineering Units") + promptgroup("80 - Display") + interest(1) + size(16) + prop(YES) + } + field(HOPR,DBF_DOUBLE) { + prompt("High Operating Rng") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(LOPR,DBF_DOUBLE) { + prompt("Low Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(HIHI,DBF_DOUBLE) { + prompt("Hihi Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_DOUBLE) { + prompt("Lolo Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_DOUBLE) { + prompt("High Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_DOUBLE) { + prompt("Low Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(HYST,DBF_DOUBLE) { + prompt("Alarm Deadband") + promptgroup("70 - Alarm") + interest(1) + } + field(ADEL,DBF_DOUBLE) { + prompt("Archive Deadband") + promptgroup("80 - Display") + interest(1) + } + field(MDEL,DBF_DOUBLE) { + prompt("Monitor Deadband") + promptgroup("80 - Display") + interest(1) + } + field(A,DBF_DOUBLE) { + prompt("Value of Input A") + pp(TRUE) + } + field(B,DBF_DOUBLE) { + prompt("Value of Input B") + pp(TRUE) + } + field(C,DBF_DOUBLE) { + prompt("Value of Input C") + pp(TRUE) + } + field(D,DBF_DOUBLE) { + prompt("Value of Input D") + pp(TRUE) + } + field(E,DBF_DOUBLE) { + prompt("Value of Input E") + pp(TRUE) + } + field(F,DBF_DOUBLE) { + prompt("Value of Input F") + pp(TRUE) + } + field(G,DBF_DOUBLE) { + prompt("Value of Input G") + pp(TRUE) + } + field(H,DBF_DOUBLE) { + prompt("Value of Input H") + pp(TRUE) + } + field(I,DBF_DOUBLE) { + prompt("Value of Input I") + pp(TRUE) + } + field(J,DBF_DOUBLE) { + prompt("Value of Input J") + pp(TRUE) + } + field(K,DBF_DOUBLE) { + prompt("Value of Input K") + pp(TRUE) + } + field(L,DBF_DOUBLE) { + prompt("Value of Input L") + pp(TRUE) + } + field(LA,DBF_DOUBLE) { + prompt("Prev Value of A") + special(SPC_NOMOD) + interest(3) + } + field(LB,DBF_DOUBLE) { + prompt("Prev Value of B") + special(SPC_NOMOD) + interest(3) + } + field(LC,DBF_DOUBLE) { + prompt("Prev Value of C") + special(SPC_NOMOD) + interest(3) + } + field(LD,DBF_DOUBLE) { + prompt("Prev Value of D") + special(SPC_NOMOD) + interest(3) + } + field(LE,DBF_DOUBLE) { + prompt("Prev Value of E") + special(SPC_NOMOD) + interest(3) + } + field(LF,DBF_DOUBLE) { + prompt("Prev Value of F") + special(SPC_NOMOD) + interest(3) + } + field(LG,DBF_DOUBLE) { + prompt("Prev Value of G") + special(SPC_NOMOD) + interest(3) + } + field(LH,DBF_DOUBLE) { + prompt("Prev Value of H") + special(SPC_NOMOD) + interest(3) + } + field(LI,DBF_DOUBLE) { + prompt("Prev Value of I") + special(SPC_NOMOD) + interest(3) + } + field(LJ,DBF_DOUBLE) { + prompt("Prev Value of J") + special(SPC_NOMOD) + interest(3) + } + field(LK,DBF_DOUBLE) { + prompt("Prev Value of K") + special(SPC_NOMOD) + interest(3) + } + field(LL,DBF_DOUBLE) { + prompt("Prev Value of L") + special(SPC_NOMOD) + interest(3) + } + field(LALM,DBF_DOUBLE) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_DOUBLE) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_DOUBLE) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + field(NLST,DBF_USHORT) { + prompt("Last Index Monitored") + special(SPC_NOMOD) + interest(3) + } +} diff --git a/modules/database/src/std/rec/seqRecord.c b/modules/database/src/std/rec/seqRecord.c index 86d05f254..8b88f80ac 100644 --- a/modules/database/src/std/rec/seqRecord.c +++ b/modules/database/src/std/rec/seqRecord.c @@ -31,7 +31,7 @@ static void processNextLink(seqRecord *prec); static long asyncFinish(seqRecord *prec); -static void processCallback(CALLBACK *arg); +static void processCallback(epicsCallback *arg); /* Create RSET - Record Support Entry Table*/ #define report NULL @@ -94,7 +94,7 @@ typedef struct linkGrp { /* The list of link-groups for processing */ typedef struct seqRecPvt { - CALLBACK callback; + epicsCallback callback; seqRecord *prec; linkGrp *grps[NUM_LINKS + 1]; /* List of link-groups */ int index; /* Where we are now */ @@ -241,7 +241,7 @@ static long asyncFinish(seqRecord *prec) } -static void processCallback(CALLBACK *arg) +static void processCallback(epicsCallback *arg) { seqRecPvt *pcb; seqRecord *prec; diff --git a/modules/database/src/std/rec/seqRecord.dbd b/modules/database/src/std/rec/seqRecord.dbd deleted file mode 100644 index 826f3ecf6..000000000 --- a/modules/database/src/std/rec/seqRecord.dbd +++ /dev/null @@ -1,365 +0,0 @@ -#************************************************************************* -# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -menu(seqSELM) { - choice(seqSELM_All,"All") - choice(seqSELM_Specified,"Specified") - choice(seqSELM_Mask,"Mask") -} -recordtype(seq) { - include "dbCommon.dbd" - field(VAL,DBF_LONG) { - prompt("Used to trigger") - asl(ASL0) - pp(TRUE) - } - field(SELM,DBF_MENU) { - prompt("Select Mechanism") - promptgroup("30 - Action") - interest(1) - menu(seqSELM) - } - field(SELN,DBF_USHORT) { - prompt("Link Selection") - interest(1) - initial("1") - } - field(SELL,DBF_INLINK) { - prompt("Link Selection Loc") - promptgroup("30 - Action") - interest(1) - } - field(OFFS,DBF_SHORT) { - prompt("Offset for Specified") - promptgroup("30 - Action") - interest(1) - initial("0") - } - field(SHFT,DBF_SHORT) { - prompt("Shift for Mask mode") - promptgroup("30 - Action") - interest(1) - initial("-1") - } - field(OLDN,DBF_USHORT) { - prompt("Old Selection") - interest(4) - } - field(PREC,DBF_SHORT) { - prompt("Display Precision") - promptgroup("80 - Display") - interest(1) - } - field(DLY0,DBF_DOUBLE) { - prompt("Delay 0") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL0,DBF_INLINK) { - prompt("Input link 0") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO0,DBF_DOUBLE) { - prompt("Value 0") - interest(1) - } - field(LNK0,DBF_OUTLINK) { - prompt("Output Link 0") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY1,DBF_DOUBLE) { - prompt("Delay 1") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL1,DBF_INLINK) { - prompt("Input link1") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO1,DBF_DOUBLE) { - prompt("Value 1") - interest(1) - } - field(LNK1,DBF_OUTLINK) { - prompt("Output Link 1") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY2,DBF_DOUBLE) { - prompt("Delay 2") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL2,DBF_INLINK) { - prompt("Input link 2") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO2,DBF_DOUBLE) { - prompt("Value 2") - interest(1) - } - field(LNK2,DBF_OUTLINK) { - prompt("Output Link 2") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY3,DBF_DOUBLE) { - prompt("Delay 3") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL3,DBF_INLINK) { - prompt("Input link 3") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO3,DBF_DOUBLE) { - prompt("Value 3") - interest(1) - } - field(LNK3,DBF_OUTLINK) { - prompt("Output Link 3") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY4,DBF_DOUBLE) { - prompt("Delay 4") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL4,DBF_INLINK) { - prompt("Input link 4") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO4,DBF_DOUBLE) { - prompt("Value 4") - interest(1) - } - field(LNK4,DBF_OUTLINK) { - prompt("Output Link 4") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY5,DBF_DOUBLE) { - prompt("Delay 5") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL5,DBF_INLINK) { - prompt("Input link 5") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO5,DBF_DOUBLE) { - prompt("Value 5") - interest(1) - } - field(LNK5,DBF_OUTLINK) { - prompt("Output Link 5") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY6,DBF_DOUBLE) { - prompt("Delay 6") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL6,DBF_INLINK) { - prompt("Input link 6") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO6,DBF_DOUBLE) { - prompt("Value 6") - interest(1) - } - field(LNK6,DBF_OUTLINK) { - prompt("Output Link 6") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY7,DBF_DOUBLE) { - prompt("Delay 7") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DOL7,DBF_INLINK) { - prompt("Input link 7") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DO7,DBF_DOUBLE) { - prompt("Value 7") - interest(1) - } - field(LNK7,DBF_OUTLINK) { - prompt("Output Link 7") - promptgroup("41 - Link 0-7") - interest(1) - } - field(DLY8,DBF_DOUBLE) { - prompt("Delay 8") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOL8,DBF_INLINK) { - prompt("Input link 8") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DO8,DBF_DOUBLE) { - prompt("Value 8") - interest(1) - } - field(LNK8,DBF_OUTLINK) { - prompt("Output Link 8") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DLY9,DBF_DOUBLE) { - prompt("Delay 9") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOL9,DBF_INLINK) { - prompt("Input link 9") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DO9,DBF_DOUBLE) { - prompt("Value 9") - interest(1) - } - field(LNK9,DBF_OUTLINK) { - prompt("Output Link 9") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DLYA,DBF_DOUBLE) { - prompt("Delay 10") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOLA,DBF_INLINK) { - prompt("Input link 10") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOA,DBF_DOUBLE) { - prompt("Value 10") - interest(1) - } - field(LNKA,DBF_OUTLINK) { - prompt("Output Link 10") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DLYB,DBF_DOUBLE) { - prompt("Delay 11") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOLB,DBF_INLINK) { - prompt("Input link 11") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOB,DBF_DOUBLE) { - prompt("Value 11") - interest(1) - } - field(LNKB,DBF_OUTLINK) { - prompt("Output Link 11") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DLYC,DBF_DOUBLE) { - prompt("Delay 12") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOLC,DBF_INLINK) { - prompt("Input link 12") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOC,DBF_DOUBLE) { - prompt("Value 12") - interest(1) - } - field(LNKC,DBF_OUTLINK) { - prompt("Output Link 12") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DLYD,DBF_DOUBLE) { - prompt("Delay 13") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOLD,DBF_INLINK) { - prompt("Input link 13") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOD,DBF_DOUBLE) { - prompt("Value 13") - interest(1) - } - field(LNKD,DBF_OUTLINK) { - prompt("Output Link 13") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DLYE,DBF_DOUBLE) { - prompt("Delay 14") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOLE,DBF_INLINK) { - prompt("Input link 14") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOE,DBF_DOUBLE) { - prompt("Value 14") - interest(1) - } - field(LNKE,DBF_OUTLINK) { - prompt("Output Link 14") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DLYF,DBF_DOUBLE) { - prompt("Delay 15") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOLF,DBF_INLINK) { - prompt("Input link 15") - promptgroup("42 - Link 8-F") - interest(1) - } - field(DOF,DBF_DOUBLE) { - prompt("Value 15") - interest(1) - } - field(LNKF,DBF_OUTLINK) { - prompt("Output Link 15") - promptgroup("42 - Link 8-F") - interest(1) - } -} - -variable(seqDLYprecision, int) -variable(seqDLYlimit, double) diff --git a/modules/database/src/std/rec/seqRecord.dbd.pod b/modules/database/src/std/rec/seqRecord.dbd.pod new file mode 100644 index 000000000..00c1229e9 --- /dev/null +++ b/modules/database/src/std/rec/seqRecord.dbd.pod @@ -0,0 +1,593 @@ +#************************************************************************* +# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Sequence Record (seq) + +The Sequence record is used to trigger the processing of up to ten other records +and send values to those records. It is similar to the fanout record, except +that it will fetch an input value and write an output value instead of simply +processing a collection of forward links. It can also specify one of several +selection algorithms that determine which values to write. It has no associated +device support. + +=recordtype seq + +=cut + +menu(seqSELM) { + choice(seqSELM_All,"All") + choice(seqSELM_Specified,"Specified") + choice(seqSELM_Mask,"Mask") +} + +recordtype(seq) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The sequence record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. + +=head3 Desired Output Parameters + +These fields determine where the record retrieves the values it is to write to +other records. All of these values are not necessarily used, depending on the +selection algorithm. + +The sequence record can retrieve up to 16 values from 16 locations. The user +specifies the locations in the Desired Output Link fields (DOL0-DOLF), which can +be either constants, database links, or channel access links. If a Desired +Output Link is a constant, the corresponding value field for that link is +initialized to the constant value and ''cannot'' be changed via dbputs. +Otherwise, if the Desired Output Link is a database or channel access link, a +value is fetched from the link each time the record is processed (provided that +the output link is part of the record's selection algorithm). See L
    for information on how to specify database links. + +The value fetched from the Desired Output Links are stored in the corresponding +Desired Output Value fields (DO0-DOF). These fields can be initialized to a +constant value, but they cannot be changed via dbPuts. + +=head4 Desired Output Link Fields + +=fields DOL0, DOL1, DOL2, DOL3, DOL4, DOL5, DOL6, DOL7, DOL8, DOL9, DOLA, DOLB, DOLC, DOLD, DOLE, DOLF + +=head4 Desired Output Value Fields + +=fields DO0, DO1, DO2, DO3, DO4, DO5, DO6, DO7, DO8, DO9, DOA, DOB, DOC, DOD, DOE, DOF + +=head3 Output Parameters + +When the record is processed, the desired output values are retrieved for the +links in the record's selection algorithm and are written to the corresponding +output link (LNK0-LNKF). These output links can be database links or channel +access links; they cannot be device addresses. There are sixteen output links, one +for each desired output link. Only those that are defined are used. + +=fields LNK0, LNK1, LNK2, LNK3, LNK4, LNK5, LNK6, LNK7, LNK8, LNK9, LNKA, LNKB, LNKC, LNKD, LNKE, LNKF + +=head3 Selection Algorithm Parameters + +When the sequence record is processed, it uses a selection algorithm similar to +that of the selection record to decide which links to process.The select +mechanism field (SELM) has three algorithms to choose from: C<<< All >>>, +C<<>> or C<<< Mask >>>. + +=head4 Record fields related to the Selection Algorithm + +=fields SELM, SELN, SELL, SHFT, OFFS + +=head4 Fields Description + +B + +=menu seqSELM + +See L below; + +B + +This field can be initialized as a CONSTANT or as a LINK to any other record. SELN will fetch its value from this field when the seq record is processed. +Thus, when using I or I modes, the links that seq will process can be dinamically changed by the record pointed by SELL. + +B + +When B> this is the index number of the link that will be processed, used in combination with the C field: + + SELN = SELN + OFFS + + +I<(By default, the OFFS is initalized to ZERO)> + +When B> this field is the bitmask that will be used to determine which links will be processed by the seq record, +in combination with the C field: + + if (SHFT >= 0) + SELN = SELN << -SHFT + else + SELN = SELN >> SHFT + +I<(By default, the SHFT is initalized to -1)> + +=head4 B + +The first versions of seq record had DO, DOL, LNK and DLY fields starting with index ONE (DO1, DOL1, LNK1 and DLY1). +New version of the seq record now supports 16 links, starting by index ZERO (DO0, DOL0, LNK0 and DLY0). The SHFT and OFFS fields +were introduced to keep compatibility of old databases that used seq record with its links indexed from one onwards. + +B + +=head4 Selection Algorithms Description + +B + +The C<<< All >>> algorithm causes the record to process each input and output +link each time the record is processed, in order from 0 to 15. So when SELM is +C<<< All >>>, the desired output value from DOL0 will fetched and sent to LNK0, +then the desired output value from DOL1 will be fetched and sent to the location +in LNK1, and so on until the last input and output link DOF and LNKF. (Note that +undefined links are not used.) If DOLI is a constant, the current value +field is simply used and the desired output link is ignored. The SELN field is +not used when C<<< All >>> is the algorithm. + +B + +When the C<<< Specified >>> algorithm is chosen, each time the record is +processed it gets the integer value in the Link Selection (SELN) field and uses +that as the index of the link to process. For instance, if SELN is 4, the +desired output value from DO4 will be retrieved and sent to LNK4. If DOLI is +a constant, DOI is simply used without the value being fetched from the +input link. + +B + +When C<<< Mask >>> is chosen, the record uses the individual bits of the SELN +field to determine the links to process. When bit 0 of SELN is set, the value +from DO0 will be written to the location in LNK0; when bit 1 is set, the valud +from DO1 will be written to the location in LNK1 etc. Thus for example if SELN +is 3, the record will retrieve the values from DO0 and DO1 and write them to the +locations in LNK0 and LNK1, respectively. If SELN is 63, DO0...DO5 will be +written to LNK0...LNK5. + + +=head3 Delay Parameters + +The delay parameters consist of 16 fields, one for each I/O link discussed +above. These fields can be configured to cause the record to delay processing +the link. For instance, if the user gives the DLY1 field a value of 3.0, each +time the record is processed at run-time, the record will delay processing the +DOL1, DOV1, and LNK1 fields for three seconds. That is, the desired output value +will not be fetched and written to the output link until three seconds have +lapsed. + +=fields DLY0, DLY1, DLY2, DLY3, DLY4, DLY5, DLY6, DLY7, DLY8, DLY9, DLYA, DLYB, DLYC, DLYD, DLYE, DLYF + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. The +Precision field (PREC) determines the decimal precision for the VAL field when +it is displayed. It is used when the C<<< get_precision >>> record routine is +called. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields PREC, NAME, DESC + +=head3 Alarm Parameters + +The sequence record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head2 Record Support + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +First, PACT is set to TRUE, and the link selection is fetched. Depending on the +selection mechanism, the link selection output links are processed in order from +LNK0 to LNKF. When LNKI is processed, the corresponding DLYI value is +used to generate a delay via watchdog timer. + +=item 2. + +After DLYI seconds have expired, the input value is fetched from DOI (if +DOLI is constant) or DOLI (if DOLI is a database link or channel +access link) and written to LNKI. + +=item 3. + +When all links are completed, an asynchronous completion call back to dbProcess +is made (see the Application Developer's Guide for more information on +asynchronous processing.) + +=item 4. + +Then UDF is set to FALSE. + +=item 5. + +Monitors are checked. + +=item 6. + +The forward link is scanned, PACT is set FALSE, and the process routine returns. + +=back + +For the delay mechanism to operate properly, the record is processed +asynchronously. The only time the record will not be processed asynchronously is +when there are no non-NULL output links selected (i.e. when it has nothing to +do.) The processing of the links is done via callback tasks at the priority set +in the PRIO field in dbCommon (see the Application Developer's Guide for more +information on call + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_LONG) { + prompt("Used to trigger") + asl(ASL0) + pp(TRUE) + } + field(SELM,DBF_MENU) { + prompt("Select Mechanism") + promptgroup("30 - Action") + interest(1) + menu(seqSELM) + } + field(SELN,DBF_USHORT) { + prompt("Link Selection") + interest(1) + initial("1") + } + field(SELL,DBF_INLINK) { + prompt("Link Selection Loc") + promptgroup("30 - Action") + interest(1) + } + field(OFFS,DBF_SHORT) { + prompt("Offset for Specified") + promptgroup("30 - Action") + interest(1) + initial("0") + } + field(SHFT,DBF_SHORT) { + prompt("Shift for Mask mode") + promptgroup("30 - Action") + interest(1) + initial("-1") + } + field(OLDN,DBF_USHORT) { + prompt("Old Selection") + interest(4) + } + field(PREC,DBF_SHORT) { + prompt("Display Precision") + promptgroup("80 - Display") + interest(1) + } + field(DLY0,DBF_DOUBLE) { + prompt("Delay 0") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL0,DBF_INLINK) { + prompt("Input link 0") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO0,DBF_DOUBLE) { + prompt("Value 0") + interest(1) + } + field(LNK0,DBF_OUTLINK) { + prompt("Output Link 0") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY1,DBF_DOUBLE) { + prompt("Delay 1") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL1,DBF_INLINK) { + prompt("Input link1") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO1,DBF_DOUBLE) { + prompt("Value 1") + interest(1) + } + field(LNK1,DBF_OUTLINK) { + prompt("Output Link 1") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY2,DBF_DOUBLE) { + prompt("Delay 2") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL2,DBF_INLINK) { + prompt("Input link 2") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO2,DBF_DOUBLE) { + prompt("Value 2") + interest(1) + } + field(LNK2,DBF_OUTLINK) { + prompt("Output Link 2") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY3,DBF_DOUBLE) { + prompt("Delay 3") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL3,DBF_INLINK) { + prompt("Input link 3") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO3,DBF_DOUBLE) { + prompt("Value 3") + interest(1) + } + field(LNK3,DBF_OUTLINK) { + prompt("Output Link 3") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY4,DBF_DOUBLE) { + prompt("Delay 4") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL4,DBF_INLINK) { + prompt("Input link 4") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO4,DBF_DOUBLE) { + prompt("Value 4") + interest(1) + } + field(LNK4,DBF_OUTLINK) { + prompt("Output Link 4") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY5,DBF_DOUBLE) { + prompt("Delay 5") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL5,DBF_INLINK) { + prompt("Input link 5") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO5,DBF_DOUBLE) { + prompt("Value 5") + interest(1) + } + field(LNK5,DBF_OUTLINK) { + prompt("Output Link 5") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY6,DBF_DOUBLE) { + prompt("Delay 6") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL6,DBF_INLINK) { + prompt("Input link 6") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO6,DBF_DOUBLE) { + prompt("Value 6") + interest(1) + } + field(LNK6,DBF_OUTLINK) { + prompt("Output Link 6") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY7,DBF_DOUBLE) { + prompt("Delay 7") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DOL7,DBF_INLINK) { + prompt("Input link 7") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DO7,DBF_DOUBLE) { + prompt("Value 7") + interest(1) + } + field(LNK7,DBF_OUTLINK) { + prompt("Output Link 7") + promptgroup("41 - Link 0-7") + interest(1) + } + field(DLY8,DBF_DOUBLE) { + prompt("Delay 8") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOL8,DBF_INLINK) { + prompt("Input link 8") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DO8,DBF_DOUBLE) { + prompt("Value 8") + interest(1) + } + field(LNK8,DBF_OUTLINK) { + prompt("Output Link 8") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DLY9,DBF_DOUBLE) { + prompt("Delay 9") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOL9,DBF_INLINK) { + prompt("Input link 9") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DO9,DBF_DOUBLE) { + prompt("Value 9") + interest(1) + } + field(LNK9,DBF_OUTLINK) { + prompt("Output Link 9") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DLYA,DBF_DOUBLE) { + prompt("Delay 10") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOLA,DBF_INLINK) { + prompt("Input link 10") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOA,DBF_DOUBLE) { + prompt("Value 10") + interest(1) + } + field(LNKA,DBF_OUTLINK) { + prompt("Output Link 10") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DLYB,DBF_DOUBLE) { + prompt("Delay 11") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOLB,DBF_INLINK) { + prompt("Input link 11") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOB,DBF_DOUBLE) { + prompt("Value 11") + interest(1) + } + field(LNKB,DBF_OUTLINK) { + prompt("Output Link 11") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DLYC,DBF_DOUBLE) { + prompt("Delay 12") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOLC,DBF_INLINK) { + prompt("Input link 12") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOC,DBF_DOUBLE) { + prompt("Value 12") + interest(1) + } + field(LNKC,DBF_OUTLINK) { + prompt("Output Link 12") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DLYD,DBF_DOUBLE) { + prompt("Delay 13") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOLD,DBF_INLINK) { + prompt("Input link 13") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOD,DBF_DOUBLE) { + prompt("Value 13") + interest(1) + } + field(LNKD,DBF_OUTLINK) { + prompt("Output Link 13") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DLYE,DBF_DOUBLE) { + prompt("Delay 14") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOLE,DBF_INLINK) { + prompt("Input link 14") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOE,DBF_DOUBLE) { + prompt("Value 14") + interest(1) + } + field(LNKE,DBF_OUTLINK) { + prompt("Output Link 14") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DLYF,DBF_DOUBLE) { + prompt("Delay 15") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOLF,DBF_INLINK) { + prompt("Input link 15") + promptgroup("42 - Link 8-F") + interest(1) + } + field(DOF,DBF_DOUBLE) { + prompt("Value 15") + interest(1) + } + field(LNKF,DBF_OUTLINK) { + prompt("Output Link 15") + promptgroup("42 - Link 8-F") + interest(1) + } +} + +variable(seqDLYprecision, int) +variable(seqDLYlimit, double) diff --git a/modules/database/src/std/rec/stateRecord.dbd.pod b/modules/database/src/std/rec/stateRecord.dbd.pod new file mode 100644 index 000000000..2e582c292 --- /dev/null +++ b/modules/database/src/std/rec/stateRecord.dbd.pod @@ -0,0 +1,88 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title State Record (state) + +The state record is a means for a state program to communicate with the operator +interface. Its only function is to provide a place in the database through which +the state program can inform the operator interface of its state by storing an +arbitrary ASCII string in its VAL field. + +B + +=recordtype state + +=cut + +recordtype(state) { + include "dbCommon.dbd" + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The state record has the standard fields for specifying under what circumstances +it will be processed. These fields are listed in L. In addition, +L explains how these fields are used. + +=head3 Operator Display Parameters + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The state record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head3 Run-time Parameters + +These parameters are used by the application code to convey the state of the +program to the operator interface. The VAL field holds the string retrieved from +the state program. The OVAL is used to implement monitors for the VAL field. +When the string in OVAL differs from the one in VAL, monitors are triggered. +They represent the current state of the sequence program. + +=fields VAL, OVAL + +=cut + + field(VAL,DBF_STRING) { + prompt("Value") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + size(20) + } + field(OVAL,DBF_STRING) { + prompt("Prev Value") + special(SPC_NOMOD) + interest(3) + size(20) + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 process + + long (*process)(struct dbCommon *precord) + +C triggers monitors on VAL when it changes and scans the forward +link if necessary. + +=cut + +} diff --git a/modules/database/src/std/rec/stringinRecord.c b/modules/database/src/std/rec/stringinRecord.c index 0785a819b..fdc1f2642 100644 --- a/modules/database/src/std/rec/stringinRecord.c +++ b/modules/database/src/std/rec/stringinRecord.c @@ -219,9 +219,9 @@ static long readValue(stringinRecord *prec) } prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/stringinRecord.dbd b/modules/database/src/std/rec/stringinRecord.dbd deleted file mode 100644 index ec7b2d570..000000000 --- a/modules/database/src/std/rec/stringinRecord.dbd +++ /dev/null @@ -1,98 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -menu(stringinPOST) { - choice(stringinPOST_OnChange,"On Change") - choice(stringinPOST_Always,"Always") -} -recordtype(stringin) { - include "dbCommon.dbd" - field(VAL,DBF_STRING) { - prompt("Current Value") - promptgroup("40 - Input") - asl(ASL0) - pp(TRUE) - size(40) - } - field(OVAL,DBF_STRING) { - prompt("Previous Value") - special(SPC_NOMOD) - interest(3) - size(40) - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup("40 - Input") - interest(1) - } - field(MPST,DBF_MENU) { - prompt("Post Value Monitors") - promptgroup("80 - Display") - interest(1) - menu(stringinPOST) - } - field(APST,DBF_MENU) { - prompt("Post Archive Monitors") - promptgroup("80 - Display") - interest(1) - menu(stringinPOST) - } - field(SIOL,DBF_INLINK) { - prompt("Simulation Input Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SVAL,DBF_STRING) { - prompt("Simulation Value") - pp(TRUE) - size(40) - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } -} diff --git a/modules/database/src/std/rec/stringinRecord.dbd.pod b/modules/database/src/std/rec/stringinRecord.dbd.pod new file mode 100644 index 000000000..17e0c101b --- /dev/null +++ b/modules/database/src/std/rec/stringinRecord.dbd.pod @@ -0,0 +1,319 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title String Input Record (stringin) + +The string input record retrieves an arbitrary ASCII string of up to 40 +characters. Several device support routines are available, all of which are soft +device support for retrieving values from other records or other software +components. + +=recordtype stringin + +=cut + +menu(stringinPOST) { + choice(stringinPOST_OnChange,"On Change") + choice(stringinPOST_Always,"Always") +} +recordtype(stringin) { + include "dbCommon.dbd" + field(VAL,DBF_STRING) { + prompt("Current Value") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + size(40) + } + field(OVAL,DBF_STRING) { + prompt("Previous Value") + special(SPC_NOMOD) + interest(3) + size(40) + } + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The string input record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. + +=head3 Read Parameters + +The INP field determines where the string input record gets its string. It can +be a database or channel access link, or a constant. If constant, the VAL field +is initialized with the constant and can be changed via dbPuts. Otherwise, the +string is read from the specified location each time the record is processed and +placed in the VAL field. The maximum number of characters that the string in VAL +can be is 40. In addition, the appropriate device support module must be entered +into the DTYP field. + +See L
    for information on specifying links. + +=fields VAL, INP, DTYP + +=cut + + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup("40 - Input") + interest(1) + } + +=head3 Monitor Parameters + +These parameters are used to specify when the monitor post should be sent by +C routine. There are two possible choices: + +=head4 Menu stringinPOST + +=menu stringinPOST + +APST is used for archiver monitors and MPST is for all other type of monitors. + +=fields MPST, APST + +=cut + + field(MPST,DBF_MENU) { + prompt("Post Value Monitors") + promptgroup("80 - Display") + interest(1) + menu(stringinPOST) + } + field(APST,DBF_MENU) { + prompt("Post Archive Monitors") + promptgroup("80 - Display") + interest(1) + menu(stringinPOST) + } + +=head3 Operator Display Parameters + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The string input record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head3 Run-time and Simulation Mode Parameters + +The old value field (OVAL) of the string input is used to implement value change +monitors for VAL. If VAL is not equal to OVAL, then monitors are triggered. + +=fields OVAL + + +The following fields are used to operate the string input in the simulation +mode. See L for more information on simulation mode fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS, SSCN, SDLY + +=cut + + field(SIOL,DBF_INLINK) { + prompt("Simulation Input Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SVAL,DBF_STRING) { + prompt("Simulation Value") + pp(TRUE) + size(40) + } + field(SIML,DBF_INLINK) { + prompt("Simulation Mode Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a record +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated. + +If device support includes an C routine it is called. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +readValue is called. See L for more information on simulation +mode fields and how they affect input. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +C is called. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if OVAL is not equal to VAL. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
    +
    +
    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each stringin input record must have an associated set of device support +routines. The primary responsibility of the device support routines is to obtain +a new ASCII string value whenever read_stringin is called. The device support +routines are primarily interested in the following fields: + +=fields PACT, DPVT, UDF, VAL, INP + +=head3 Device Support Routines (devSiSoft.c) + +=head4 init_record + + long init_record(stringinRecord *prec) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 read_stringin + + long read_stringin(stringinRecord *prec) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * 0: Success. A new ASCII string is stored into VAL. + +=item * Other: Error. + +=back + +=head3 Device Support for Soft Records + +The C<<< Soft Channel >>> module places a value directly in VAL. + +If the INP link type is constant, the double constant, if non-zero, is converted +to a string and stored into VAL by C, and UDF is set to FALSE. If +the INP link type is PV_LINK, then dbCaAddInlink is called by C. + +read_stringin calls recGblGetLinkValue to read the current value of VAL. See +L. + +If the return status of recGblGetLinkValue is zero, then read_stringin sets UDF +to FALSE. The status of recGblGetLinkValue is returned. + +=cut + +} diff --git a/modules/database/src/std/rec/stringoutRecord.c b/modules/database/src/std/rec/stringoutRecord.c index 49f5aecc8..ddf302848 100644 --- a/modules/database/src/std/rec/stringoutRecord.c +++ b/modules/database/src/std/rec/stringoutRecord.c @@ -247,9 +247,9 @@ static long writeValue(stringoutRecord *prec) status = dbPutLink(&prec->siol, DBR_STRING, &prec->val, 1); prec->pact = FALSE; } else { /* !prec->pact && delay >= 0. */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { - pvt = calloc(1, sizeof(CALLBACK)); /* very lazy allocation of callback structure */ + pvt = calloc(1, sizeof(epicsCallback)); /* very lazy allocation of callback structure */ prec->simpvt = pvt; } if (pvt) callbackRequestProcessCallbackDelayed(pvt, prec->prio, prec, prec->sdly); diff --git a/modules/database/src/std/rec/stringoutRecord.dbd b/modules/database/src/std/rec/stringoutRecord.dbd deleted file mode 100644 index 358340c6d..000000000 --- a/modules/database/src/std/rec/stringoutRecord.dbd +++ /dev/null @@ -1,116 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -menu(stringoutPOST) { - choice(stringoutPOST_OnChange,"On Change") - choice(stringoutPOST_Always,"Always") -} -recordtype(stringout) { - include "dbCommon.dbd" - field(VAL,DBF_STRING) { - prompt("Current Value") - promptgroup("50 - Output") - asl(ASL0) - pp(TRUE) - size(40) - } - field(OVAL,DBF_STRING) { - prompt("Previous Value") - special(SPC_NOMOD) - interest(3) - size(40) - } - field(DOL,DBF_INLINK) { - prompt("Desired Output Loc") - promptgroup("40 - Input") - interest(1) - } - field(OMSL,DBF_MENU) { - prompt("Output Mode Select") - promptgroup("50 - Output") - interest(1) - menu(menuOmsl) - } - field(OUT,DBF_OUTLINK) { - prompt("Output Specification") - promptgroup("50 - Output") - interest(1) - } - field(MPST,DBF_MENU) { - prompt("Post Value Monitors") - promptgroup("80 - Display") - interest(1) - menu(stringoutPOST) - } - field(APST,DBF_MENU) { - prompt("Post Archive Monitors") - promptgroup("80 - Display") - interest(1) - menu(stringoutPOST) - } - field(SIOL,DBF_OUTLINK) { - prompt("Simulation Output Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIML,DBF_INLINK) { - prompt("Simulation Mode Link") - promptgroup("90 - Simulate") - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - special(SPC_MOD) - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Simulation Mode Severity") - promptgroup("90 - Simulate") - interest(2) - menu(menuAlarmSevr) - } - field(OLDSIMM,DBF_MENU) { - prompt("Prev. Simulation Mode") - special(SPC_NOMOD) - interest(4) - menu(menuSimm) - } - field(SSCN,DBF_MENU) { - prompt("Sim. Mode Scan") - promptgroup("90 - Simulate") - interest(1) - menu(menuScan) - initial("65535") - } - field(SDLY,DBF_DOUBLE) { - prompt("Sim. Mode Async Delay") - promptgroup("90 - Simulate") - interest(2) - initial("-1.0") - } - %#include "callback.h" - field(SIMPVT,DBF_NOACCESS) { - prompt("Sim. Mode Private") - special(SPC_NOMOD) - interest(4) - extra("CALLBACK *simpvt") - } - field(IVOA,DBF_MENU) { - prompt("INVALID output action") - promptgroup("50 - Output") - interest(2) - menu(menuIvoa) - } - field(IVOV,DBF_STRING) { - prompt("INVALID output value") - promptgroup("50 - Output") - interest(2) - size(40) - } -} diff --git a/modules/database/src/std/rec/stringoutRecord.dbd.pod b/modules/database/src/std/rec/stringoutRecord.dbd.pod new file mode 100644 index 000000000..0d63d5f61 --- /dev/null +++ b/modules/database/src/std/rec/stringoutRecord.dbd.pod @@ -0,0 +1,384 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title String Output Record (stringout) + +The stringout record is used to write an arbitrary ASCII string of up to 40 +characters to other records or software variables. + +=recordtype stringout + +=cut + +include "menuIvoa.dbd" + +menu(stringoutPOST) { + choice(stringoutPOST_OnChange,"On Change") + choice(stringoutPOST_Always,"Always") +} +recordtype(stringout) { + include "dbCommon.dbd" + field(VAL,DBF_STRING) { + prompt("Current Value") + promptgroup("50 - Output") + asl(ASL0) + pp(TRUE) + size(40) + } + field(OVAL,DBF_STRING) { + prompt("Previous Value") + special(SPC_NOMOD) + interest(3) + size(40) + } + + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The string output record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in +L. +In addition, L +explains how these fields are used. + +=head3 Desired Output Parameters + +The string output record must specify from where it gets its desired output +string. The first field that determines where the desired output originates is +the output mode select (OSML) field, which can have two possible value: C<<< +closed_loop >>> or C<<< supervisory >>>. If C<<< supervisory >>> is specified, +DOL is ignored, the current value of VAL is written, and the VAL can be changed +externally via dbPuts at run-time. If C<<< closed_loop >>> is specified, the VAL +field's value is obtained from the address specified in the desired output +location field (DOL) which can be either a database link or a channel access +link. + +DOL can also be a constant in addition to a link, in which case VAL is +initialized to the constant value. However, your string constant may be +interpreted as a CA link name, so if you want to initialize your string output +record, it's best to use the VAL field. Note that if DOL is a constant, OMSL +cannot be C<<< closed_loop. >>> See +L
    +for information on specifying links. + +=fields VAL, DOL, OMSL + +=cut + + field(DOL,DBF_INLINK) { + prompt("Desired Output Loc") + promptgroup("40 - Input") + interest(1) + } + field(OMSL,DBF_MENU) { + prompt("Output Mode Select") + promptgroup("50 - Output") + interest(1) + menu(menuOmsl) + } + +=head3 Write Parameters + +The output link specified in the OUT field specifies where the string output +record is to write its string. The link can be a database or channel access +link. If the OUT field is a constant, no output will be written. See L
    for information on specifying links. + +In addition, the appropriate device support module must be entered into the DTYP +field. + +=fields OUT, DTYP + +=cut + + field(OUT,DBF_OUTLINK) { + prompt("Output Specification") + promptgroup("50 - Output") + interest(1) + } + +=head3 Monitor Parameters + +These parameters are used to specify when the monitor post should be sent by +C routine. There are two possible choices: + +=head4 Menu stringoutPOST + +=menu stringoutPOST + +APST is used for archiver monitors and MPST is for all other type of monitors. + +=fields MPST, APST + +=cut + + field(MPST,DBF_MENU) { + prompt("Post Value Monitors") + promptgroup("80 - Display") + interest(1) + menu(stringoutPOST) + } + field(APST,DBF_MENU) { + prompt("Post Archive Monitors") + promptgroup("80 - Display") + interest(1) + menu(stringoutPOST) + } + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. These +fields are used to display the value and other parameters of the string output +either textually or graphically. + +See L +for more on the record name (NAME) and description (DESC) fields. + +=fields NAME, DESC + +=head3 Run-time and Simulation Mode Parameters + +The old value field (OVAL) of the string input is used to implement value change +monitors for VAL. If VAL is not equal to OVAL, then monitors are triggered. + +=fields OVAL + +The following fields are used to operate the string output in the simulation +mode. See +L +for more information on these fields. + +=fields SIOL, SIML, SIMM, SIMS, SSCN, SDLY + +=cut + + field(SIOL,DBF_OUTLINK) { + prompt("Simulation Output Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIML,DBF_INLINK) { + prompt("Simulation Mode Link") + promptgroup("90 - Simulate") + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + special(SPC_MOD) + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup("90 - Simulate") + interest(2) + menu(menuAlarmSevr) + } + field(OLDSIMM,DBF_MENU) { + prompt("Prev. Simulation Mode") + special(SPC_NOMOD) + interest(4) + menu(menuSimm) + } + field(SSCN,DBF_MENU) { + prompt("Sim. Mode Scan") + promptgroup("90 - Simulate") + interest(1) + menu(menuScan) + initial("65535") + } + field(SDLY,DBF_DOUBLE) { + prompt("Sim. Mode Async Delay") + promptgroup("90 - Simulate") + interest(2) + initial("-1.0") + } + %#include "callback.h" + field(SIMPVT,DBF_NOACCESS) { + prompt("Sim. Mode Private") + special(SPC_NOMOD) + interest(4) + extra("epicsCallback *simpvt") + } + +=head3 Alarm Parameters + +The possible alarm conditions for the string output record are the SCAN, READ, +and INVALID alarms. The severity of the first two is always MAJOR and not +configurable. + +The IVOA field specifies an action to take when the INVALID alarm is triggered. +There are three possible actions: + +=head4 Menu menuIvoa + +=menu menuIvoa + +When C<<< Set output to IVOV >>>, the value contained in the IVOV field is +written to the output link during an alarm condition. See +L +for more information on the IVOA and IVOV fields. +L +lists other fields related to a alarms that are common to all record types. + +=fields IVOA, IVOV + +=cut + + field(IVOA,DBF_MENU) { + prompt("INVALID output action") + promptgroup("50 - Output") + interest(2) + menu(menuIvoa) + } + field(IVOV,DBF_STRING) { + prompt("INVALID output value") + promptgroup("50 - Output") + interest(2) + size(40) + } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available. The routine +next checks to see if the device support write routine is defined. If either +device support or the device support write routine does not exist, an error +message is issued and processing is terminated. + +If DOL is a constant, then the type double constant, if non-zero, is converted +to a string and stored into VAL and UDF is set to FALSE. If DOL type is a +PV_LINK then dbCaAddInlink is called to create a channel access link. + +If device support includes C, it is called. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE and OMSL is CLOSED_LOOP, recGblGetLinkValue is called to read +the current value of VAL. See L. +If the return status of recGblGetLinkValue is zero then UDF is set to FALSE. + +=item 3. + +Check severity and write the new value. See +L +and L +for details on how the simulation mode and the INVALID alarm conditions affect output. + +=item 4. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if OVAL is not equal to VAL. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
    +
    +
    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each stringout output record must have an associated set of device support +routines. The primary responsibility of the device support routines is to write +a new value whenever write_stringout is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, VAL, OUT + +=head3 Device Support Routines (devSoSoft.c) + +=head4 write_stringout + + long write_stringout(stringoutRecord *prec) + +This routine must output a new value. It returns the following values: + +=over + +=item * 0: Success. + +=item * Other: Error. + +=back + +=head3 Device Support for Soft Records + +The C<<< Soft Channel >>> device support module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_so calls recGblPutLinkValue to write the current value of VAL. See +L. + +=cut + +} diff --git a/modules/database/src/std/rec/subArrayRecord.dbd b/modules/database/src/std/rec/subArrayRecord.dbd deleted file mode 100644 index 7814a2e48..000000000 --- a/modules/database/src/std/rec/subArrayRecord.dbd +++ /dev/null @@ -1,90 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(subArray) { - include "dbCommon.dbd" - field(VAL,DBF_NOACCESS) { - prompt("Value") - asl(ASL0) - special(SPC_DBADDR) - pp(TRUE) - extra("void * val") - #=type Set by FTVL - #=read Yes - #=write Yes - } - field(PREC,DBF_SHORT) { - prompt("Display Precision") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(FTVL,DBF_MENU) { - prompt("Field Type of Value") - promptgroup("30 - Action") - special(SPC_NOMOD) - interest(1) - menu(menuFtype) - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup("40 - Input") - interest(1) - } - field(EGU,DBF_STRING) { - prompt("Engineering Units") - promptgroup("80 - Display") - interest(1) - size(16) - prop(YES) - } - field(HOPR,DBF_DOUBLE) { - prompt("High Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(LOPR,DBF_DOUBLE) { - prompt("Low Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(MALM,DBF_ULONG) { - prompt("Maximum Elements") - promptgroup("30 - Action") - special(SPC_NOMOD) - interest(1) - initial("1") - } - field(NELM,DBF_ULONG) { - prompt("Number of Elements") - promptgroup("30 - Action") - pp(TRUE) - initial("1") - } - field(INDX,DBF_ULONG) { - prompt("Substring Index") - promptgroup("30 - Action") - pp(TRUE) - } - field(BUSY,DBF_SHORT) { - prompt("Busy Indicator") - special(SPC_NOMOD) - } - field(NORD,DBF_LONG) { - prompt("Number elements read") - special(SPC_NOMOD) - } - field(BPTR,DBF_NOACCESS) { - prompt("Buffer Pointer") - special(SPC_NOMOD) - interest(4) - extra("void * bptr") - } -} diff --git a/modules/database/src/std/rec/subArrayRecord.dbd.pod b/modules/database/src/std/rec/subArrayRecord.dbd.pod new file mode 100644 index 000000000..c47f2d003 --- /dev/null +++ b/modules/database/src/std/rec/subArrayRecord.dbd.pod @@ -0,0 +1,397 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Sub-Array Record (subArray) + +The normal use for the subArray record type is to obtain sub-arrays from +waveform records. Setting either the number of elements (NELM) or index (INDX) +fields causes the record to be processed anew so that applications in which the +length and position of a sub-array in a waveform record vary dynamically can be +implemented using standard EPICS operator interface tools. + +The first element of the sub-array, that at location INDX in the referenced +waveform record, can be displayed as a scalar, or the entire subarray (of length +NELM) can be displayed in the same way as a waveform record. If there are fewer +than NELM elements in the referenced waveform after the INDX, only the number of +elements actually available are returned, and the number of elements read field +(NORD) is set to reflect this. This record type does not support writing new +values into waveform records. + +=recordtype subArray + +=cut + +recordtype(subArray) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The subArray record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in +L. +In addition, L explains how these fields are used. + +=head3 Read Parameters + +The subArray's input link (INP) should be configured to reference the Waveform +record. It should specify the VAL field of a Waveform record. The INP field can +be a channel access link, in addition to a database link. See +L
    +for information on specifying links. + +In addition, the DTYP field must specify a device support module. Currently, the +only device support module is C<<< Soft Channel >>>. + +=fields INP, DTYP + +=head3 Array Parameters + +These parameters determine the number of array elements (the array length) and +the data type of those elements. The Field Type of Value (FTVL) field determines +the data type of the array. + +The user specifies the maximum number of elements allowed in the subarray in the +MALM field. Generally, the number should be equal to the number of elements of +the Waveform array (found in the Waveform's NELM field). The MALM field is used +to allocate memory. The subArray's Number of Elements (NELM) field is where the +user specifies the actual number of elements that the subArray will contain. It +should of course be no greater than MALM; if it is, the record processing +routine sets it equal to MALM. + +The INDX field determines the offset of the subArray record's array in relation +to the Waveform's. For instance, if INDX is 2, then the subArray will read NELM +elements starting with the third element of the Waveform's array. Thus, it +equals the index number of the Waveform's array. + +The actual sub-array is referenced by the VAL field. + +=fields FTVL, VAL, MALM, NELM, INDX + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the subarray record either textually +or graphically. + +EGU is a string of up to 16 characters describing the engineering units (if any) +of the values which the subArray holds. It is retrieved by the C<<< get_units +>>> record support routine. + +The HOPR and LOPR fields set the upper and lower display limits for the +sub-array elements. Both the C<<< get_graphic_double >>> and C<<< +get_control_double >>> record support routines retrieve these fields. + +The PREC field determines the floating point precision with which to display +VAL. It is used whenever the C<<< get_precision >>> record support routine is +called. + +See L +for more on the record name (NAME) and description (DESC) fields. + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +=head3 Alarm Parameters + +The subarray record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head3 Run-time Parameters + +These fields are not configurable by the user. They are used for the record's +internal processing or to represent the current state of the record. + +The NORD field holds a counter of the number of elements read into the array. It +can be less than NELM even after the array is full if NELM exceeds the number of +existing elements in the referenced array, i.e., the Waveform's array. + +BPTR contains a pointer to the record's array. + +=fields NORD, BPTR + +=begin html + +
    +
    +
    + +=end html + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +Using MALM and FTVL, space for the array is allocated. The array address is +stored in BPTR. This routine checks to see that device support is available and +a device support read routine is defined. If either does not exist, an error +message is issued and processing is terminated. If device support includes +C, it is called. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head4 cvt_dbaddr + + long (*cvt_dbaddr)(struct dbAddr *paddr) + +This is called by dbNameToAddr. It makes the dbAddr structure refer to the +actual buffer holding the result. + +=head4 get_array_info + + long (*get_array_info)(struct dbAddr *paddr, long *no_elements, long *offset) + +Retrieves NELM. + +=head4 put_array_info + + long (*put_array_info)(struct dbAddr *paddr, long nNew) + +Sets NORD. + +=head4 get_graphic_double + + long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p) + +For the elements in the array, this routine routines HOPR and LOPR. For the INDX +field, this routine returns MALM - 1 and 0. For NELM, it returns MALM and 1. For +other fields, it calls C<<< recGblGetGraphicDouble() >>>. + +=head4 get_control_double + + long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p) + +For array elements, this routine retrieves HOPR and LOPR. Otherwise, C<<< +recGblGetControlDouble() >>> is called. + +=head4 get_units + + long (*get_units)(struct dbAddr *paddr, char *units) + +Retrieves EGU. + +=head4 get_precision + + long (*get_precision)(const struct dbAddr *paddr, long *precision) + +Retrieves PREC. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +Sanity check NELM and INDX. If NELM is greater than MALM it is set to MALM. If +INDX is greater than or equal to MALM it is set to MALM-1. + +=item 3. + +Call device support read routine. This routine is expected to place the desired +sub-array at the beginning of the buffer and set NORD to the number of elements +of the sub-array that were read. + +=item 4. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed writing the new value. In this case, the processing +routine merely returns, leaving PACT TRUE. Otherwise, process sets PACT TRUE at +this time. This asynchronous processing logic is not currently used but has been +left in place. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are always invoked. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
    +
    +
    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +The device support routines are primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, INP, FTVL, MALM, NELM, INDX, BPTR, NORD + +=head3 Device Support Routines (devSASoft.c) + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + long init_record(subArrayRecord *prec) + +This routine is called by the record support C routine. + +=head4 read_sa + + long read_sa(subArrayRecord *prec) + +Enough of the source waveform is read into BPTR, from the beginning of the +source, to include the requested sub-array. The sub-array is then copied to the +beginning of the buffer. NORD is set to indicate how many elements of the +sub-array were acquired. + +=head3 Device Support For Soft Records + +Only the device support module C<<< Soft Channel >>> is currently provided. The +INP link type must be either DB_LINK or CA_LINK. + +=head4 Soft Channel + +INP is expected to point to a waveform record. + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_NOACCESS) { + prompt("Value") + asl(ASL0) + special(SPC_DBADDR) + pp(TRUE) + extra("void * val") + #=type Set by FTVL + #=read Yes + #=write Yes + } + field(PREC,DBF_SHORT) { + prompt("Display Precision") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(FTVL,DBF_MENU) { + prompt("Field Type of Value") + promptgroup("30 - Action") + special(SPC_NOMOD) + interest(1) + menu(menuFtype) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup("40 - Input") + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Engineering Units") + promptgroup("80 - Display") + interest(1) + size(16) + prop(YES) + } + field(HOPR,DBF_DOUBLE) { + prompt("High Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(LOPR,DBF_DOUBLE) { + prompt("Low Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(MALM,DBF_ULONG) { + prompt("Maximum Elements") + promptgroup("30 - Action") + special(SPC_NOMOD) + interest(1) + initial("1") + } + field(NELM,DBF_ULONG) { + prompt("Number of Elements") + promptgroup("30 - Action") + pp(TRUE) + initial("1") + } + field(INDX,DBF_ULONG) { + prompt("Substring Index") + promptgroup("30 - Action") + pp(TRUE) + } + field(BUSY,DBF_SHORT) { + prompt("Busy Indicator") + special(SPC_NOMOD) + } + field(NORD,DBF_LONG) { + prompt("Number elements read") + special(SPC_NOMOD) + } + field(BPTR,DBF_NOACCESS) { + prompt("Buffer Pointer") + special(SPC_NOMOD) + interest(4) + extra("void * bptr") + } +} diff --git a/modules/database/src/std/rec/subRecord.dbd b/modules/database/src/std/rec/subRecord.dbd deleted file mode 100644 index 48cfc1385..000000000 --- a/modules/database/src/std/rec/subRecord.dbd +++ /dev/null @@ -1,328 +0,0 @@ -#************************************************************************* -# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(sub) { - include "dbCommon.dbd" - field(VAL,DBF_DOUBLE) { - prompt("Result") - asl(ASL0) - pp(TRUE) - } - field(INAM,DBF_STRING) { - prompt("Init Routine Name") - promptgroup("30 - Action") - special(SPC_NOMOD) - interest(1) - size(40) - } - field(SNAM,DBF_STRING) { - prompt("Subroutine Name") - promptgroup("30 - Action") - special(SPC_MOD) - interest(1) - size(40) - } - %struct subRecord; - %typedef long (*SUBFUNCPTR)(struct subRecord *); - field(SADR,DBF_NOACCESS) { - prompt("Subroutine Address") - special(SPC_NOMOD) - interest(4) - extra("SUBFUNCPTR sadr") - } - field(INPA,DBF_INLINK) { - prompt("Input A") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPB,DBF_INLINK) { - prompt("Input B") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPC,DBF_INLINK) { - prompt("Input C") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPD,DBF_INLINK) { - prompt("Input D") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPE,DBF_INLINK) { - prompt("Input E") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPF,DBF_INLINK) { - prompt("Input F") - promptgroup("41 - Input A-F") - interest(1) - } - field(INPG,DBF_INLINK) { - prompt("Input G") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPH,DBF_INLINK) { - prompt("Input H") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPI,DBF_INLINK) { - prompt("Input I") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPJ,DBF_INLINK) { - prompt("Input J") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPK,DBF_INLINK) { - prompt("Input K") - promptgroup("42 - Input G-L") - interest(1) - } - field(INPL,DBF_INLINK) { - prompt("Input L") - promptgroup("42 - Input G-L") - interest(1) - } - field(EGU,DBF_STRING) { - prompt("Engineering Units") - promptgroup("80 - Display") - interest(1) - size(16) - prop(YES) - } - field(HOPR,DBF_DOUBLE) { - prompt("High Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(LOPR,DBF_DOUBLE) { - prompt("Low Operating Range") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(HIHI,DBF_DOUBLE) { - prompt("Hihi Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOLO,DBF_DOUBLE) { - prompt("Lolo Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(HIGH,DBF_DOUBLE) { - prompt("High Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(LOW,DBF_DOUBLE) { - prompt("Low Alarm Limit") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - } - field(PREC,DBF_SHORT) { - prompt("Display Precision") - promptgroup("80 - Display") - interest(1) - prop(YES) - } - field(BRSV,DBF_MENU) { - prompt("Bad Return Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HHSV,DBF_MENU) { - prompt("Hihi Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(LLSV,DBF_MENU) { - prompt("Lolo Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(HSV,DBF_MENU) { - prompt("High Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(LSV,DBF_MENU) { - prompt("Low Severity") - promptgroup("70 - Alarm") - pp(TRUE) - interest(1) - prop(YES) - menu(menuAlarmSevr) - } - field(HYST,DBF_DOUBLE) { - prompt("Alarm Deadband") - promptgroup("70 - Alarm") - interest(1) - } - field(ADEL,DBF_DOUBLE) { - prompt("Archive Deadband") - promptgroup("80 - Display") - interest(1) - } - field(MDEL,DBF_DOUBLE) { - prompt("Monitor Deadband") - promptgroup("80 - Display") - interest(1) - } - field(A,DBF_DOUBLE) { - prompt("Value of Input A") - pp(TRUE) - } - field(B,DBF_DOUBLE) { - prompt("Value of Input B") - pp(TRUE) - } - field(C,DBF_DOUBLE) { - prompt("Value of Input C") - pp(TRUE) - } - field(D,DBF_DOUBLE) { - prompt("Value of Input D") - pp(TRUE) - } - field(E,DBF_DOUBLE) { - prompt("Value of Input E") - pp(TRUE) - } - field(F,DBF_DOUBLE) { - prompt("Value of Input F") - pp(TRUE) - } - field(G,DBF_DOUBLE) { - prompt("Value of Input G") - pp(TRUE) - } - field(H,DBF_DOUBLE) { - prompt("Value of Input H") - pp(TRUE) - } - field(I,DBF_DOUBLE) { - prompt("Value of Input I") - pp(TRUE) - } - field(J,DBF_DOUBLE) { - prompt("Value of Input J") - pp(TRUE) - } - field(K,DBF_DOUBLE) { - prompt("Value of Input K") - pp(TRUE) - } - field(L,DBF_DOUBLE) { - prompt("Value of Input L") - pp(TRUE) - } - field(LA,DBF_DOUBLE) { - prompt("Prev Value of A") - special(SPC_NOMOD) - interest(3) - } - field(LB,DBF_DOUBLE) { - prompt("Prev Value of B") - special(SPC_NOMOD) - interest(3) - } - field(LC,DBF_DOUBLE) { - prompt("Prev Value of C") - special(SPC_NOMOD) - interest(3) - } - field(LD,DBF_DOUBLE) { - prompt("Prev Value of D") - special(SPC_NOMOD) - interest(3) - } - field(LE,DBF_DOUBLE) { - prompt("Prev Value of E") - special(SPC_NOMOD) - interest(3) - } - field(LF,DBF_DOUBLE) { - prompt("Prev Value of F") - special(SPC_NOMOD) - interest(3) - } - field(LG,DBF_DOUBLE) { - prompt("Prev Value of G") - special(SPC_NOMOD) - interest(3) - } - field(LH,DBF_DOUBLE) { - prompt("Prev Value of H") - special(SPC_NOMOD) - interest(3) - } - field(LI,DBF_DOUBLE) { - prompt("Prev Value of I") - special(SPC_NOMOD) - interest(3) - } - field(LJ,DBF_DOUBLE) { - prompt("Prev Value of J") - special(SPC_NOMOD) - interest(3) - } - field(LK,DBF_DOUBLE) { - prompt("Prev Value of K") - special(SPC_NOMOD) - interest(3) - } - field(LL,DBF_DOUBLE) { - prompt("Prev Value of L") - special(SPC_NOMOD) - interest(3) - } - field(LALM,DBF_DOUBLE) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(ALST,DBF_DOUBLE) { - prompt("Last Value Archived") - special(SPC_NOMOD) - interest(3) - } - field(MLST,DBF_DOUBLE) { - prompt("Last Value Monitored") - special(SPC_NOMOD) - interest(3) - } -} diff --git a/modules/database/src/std/rec/subRecord.dbd.pod b/modules/database/src/std/rec/subRecord.dbd.pod new file mode 100644 index 000000000..98166c383 --- /dev/null +++ b/modules/database/src/std/rec/subRecord.dbd.pod @@ -0,0 +1,729 @@ +#************************************************************************* +# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title Subroutine Record (sub) + +The subroutine record is used to call a C initialization routine and a recurring +scan routine. There is no device support for this record. + +=recordtype sub + +=cut + +recordtype(sub) { + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The subroutine record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in +L. In addition, L +explains how these fields are used. + +=head3 Read Parameters + +The subroutine record has twelve input links (INPA-INPL), each of which has a +corresponding value field (A-L). These fields are used to retrieve and store +values that can be passed to the subroutine that the record calls. + +The input links can be either channel access or database links, or constants. +When constants, the corresponding value field for the link is initialized with +the constant value and the field's value can be changed at run-time via dbPuts. +Otherwise, the values for (A-F) are fetched from the input links when the record +is processed. See L
    for information on specifying links. + +=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL, A, B, C, D, E, F, G, H, I, J, K, L + +=head3 Subroutine Connection + +These fields are used to connect to the C subroutine. The name of the subroutine +should be entered in the SNAM field. + +=fields INAM, SNAM + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the subroutine either textually or +graphically. + +EGU is a string of up to 16 characters that could describe any units used by the +subroutine record. It is retrieved by the C<<< get_units >>> record support +routine. + +The HOPR and LOPR fields set the upper and lower display limits for the VAL, +A-L, LA-LL, HIHI, LOLO, LOW, and HIGH fields. Both the C<<< get_graphic_double +>>> and C<<< get_control_double >>> record support routines retrieve these +fields. + +The PREC field determines the floating point precision with which to display +VAL. It is used whenever the C<<< get_precision >>> record support routine is +called. + +See L +for more on the record name (NAME) and description (DESC) fields. + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +=head3 Alarm Parameters + +The possible alarm conditions for subroutine records are the SCAN, READ, limit +alarms, and an alarm that can be triggered if the subroutine returns a negative +value. The SCAN and READ alarms are called by the record or device support +routines. The limit alarms are configured by the user in the HIHI, LOLO, HIGH, +and LOW fields using numerical values. They apply to the VAL field. For each of +these fields, there is a corresponding severity field which can be either +NO_ALARM, MINOR, or MAJOR. + +The BRSV field is where the user can set the alarm severity in case the +subroutine returns a negative value. See L +for a complete explanation of alarms and these fields. L +lists other fields related to a alarms that are common to all record types. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, BRSV, HYST + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the VAL +field. The appropriate monitors are invoked when VAL differs from the values in +the ALST and MLST run-time fields, i.e., when the value of VAL changes by more +than the deadband specified in these fields. The ADEL and MDEL fields specify a +minimum delta which the change must surpass before the value-change monitors are +invoked. If these fields have a value of zero, everytime the value changes, a +monitor will be triggered; if they have a value of -1, everytime the record is +processed, monitors are triggered. The ADEL field is used by archive monitors +and the MDEL field for all other types of monitors. See L +for a complete explanation of monitors and deadbands. + +=fields ADEL, MDEL + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the subroutine +record. They are not configured using a database configuration tool. They +represent the current state of the record. Many of them are used by the record +processing routines or the monitors. + +VAL should be set by the subroutine. SADR holds the subroutine address and is +set by the record processing routine. + +The rest of these fields--LALM, ALST, MLST, and the LA-LL fields--are used to +implement the monitors. For example, when LA is not equal to A, the value-change +monitors are called for that field. + +=fields VAL, SADR, LALM, ALST, MLST, LA, LB, LC, LD, LE, LF, LG, LH, LI, LJ, LK, LL + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +For each constant input link, the corresponding value field is initialized with +the constant value. For each input link that is of type PV_LINK, a channel +access link is created. + +If an initialization subroutine is defined, it is located and called. + +The processing subroutine is located and its address stored in SADR. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head4 get_units + + long (*get_units)(struct dbAddr *paddr, char *units) + +Retrieves EGU. + +=head4 get_precision + + long (*get_precision)(const struct dbAddr *paddr, long *precision) + +Retrieves PREC when VAL is the field being referenced. Otherwise, calls C<<< +recGblGetPrec() >>>. + +=head4 get_graphic_double + + long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p) + +Sets the upper display and lower display limits for a field. If the field is +VAL, A-L, LA-LL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, +else if the field has upper and lower limits defined they will be used, else the +upper and lower maximum values for the field type will be used. + +=head4 get_control_double + + long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p) + +Sets the upper control and the lower control limits for a field. If the field is +VAL, A-L, LA-LL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, +else if the field has upper and lower limits defined they will be used, else the +upper and lower maximum values for the field type will be used. + +=head4 get_alarm_double + + long (*get_alarm_double)(struct dbAddr *paddr, struct dbr_alDouble *p) + +Sets the following values: + + upper_alarm_limit = HIHI + upper_warning_limit = HIGH + lower_warning_limit = LOW + lower_alarm_limit = LOLO + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +If PACT is FALSE then fetch all arguments. + +=item 2. + +Call the subroutine and check return value. + +=over + +=item * + +Call subroutine + +=item * + +Set PACT TRUE + +=item * + +If return value is 1, return + +=back + +=item 3. + +Check alarms. This routine checks to see if the new VAL causes the alarm status and severity to change. If so, NSEV, NSTA and LALM are set. It also honors the alarm hysteresis factor (HYST). Thus the value must change by more than HYST before the alarm status and severity is lowered. + +=item 4. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if ADEL and MDEL conditions are +met. + +=item * + +Monitors for A-L are invoked if value has changed. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 5. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=head3 Example Synchronous Subroutine + +This is an example subroutine that merely increments VAL each time process is +called. + + #include + #include + #include + #include + #include + + static long subInit(struct subRecord *psub) + { + printf("subInit was called\n"); + return 0; + } + + static long subProcess(struct subRecord *psub) + { + psub->val++; + return 0; + } + + epicsRegisterFunction(subInit); + epicsRegisterFunction(subProcess); + + +=head3 Example Asynchronous Subroutine + +This example for a VxWorks IOC shows an asynchronous subroutine. It uses +(actually misuses) fields A and B. Field A is taken as the number of seconds +until asynchronous completion. Field B is a flag to decide if messages should be +printed. Lets assume A E 0 and B = 1. The following sequence of actions will +occcur: + +=over + +=item 1. + +subProcess is called with pact FALSE. It performs the following steps. + +=over + +=item * + +Computes, from A, the number of ticks until asynchronous completion should +occur. + +=item * + +Prints a message stating that it is requesting an asynchronous callback. + +=item * + +Calls the vxWorks watchdog start routine. + +=item * + +Sets pact TRUE and returns a value of 0. This tells record support to complete +without checking alarms, monitors, or the forward link. + +=back + +=item 2. + +When the time expires, the system wide callback task calls myCallback. +myCallback locks the record, calls process, and unlocks the record. + +=item 3. + +Process again calls subProcess, but now pact is TRUE. Thus the following is +done: + +=over + +=item * + +VAL is incremented. + +=item * + +A completion message is printed. + +=item * + +subProcess returns 0. The record processing routine will complete record +processing. + +=back + +=back + + #include + #include + #include + #include + #include + #include + #include + + /* control block for callback*/ + struct callback { + epicsCallback callback; + struct dbCommon *precord; + WDOG_ID wd_id; + }; + + void myCallback(struct callback *pcallback) + { + struct dbCommon *precord=pcallback->precord; + struct rset *prset=(struct rset *)(precord->rset); + dbScanLock(precord); + (*prset->process)(precord); + dbScanUnlock(precord); + } + + long subInit(struct subRecord *psub) + { + struct callback *pcallback; + pcallback = (struct callback *)(calloc(1,sizeof(struct callback))); + psub->dpvt = (void *)pcallback; + callbackSetCallback(myCallback,pcallback); + pcallback->precord = (struct dbCommon *)psub; + pcallback->wd_id = wdCreate(); + printf("subInit was called\n"); + return 0; + } + + long subProcess(struct subRecord *psub) + { + struct callback *pcallback=(struct callback *)(psub->dpvt); + /* sub.inp must be a CONSTANT*/ + if (psub->pact) { + psub->val++; + if (psub->b) + printf("%s subProcess Completed\n", psub->name); + return 0; + } else { + int wait_time = (long)(psub->a * vxTicksPerSecond); + if (wait_time <= 0){ + if (psub->b) + printf("%s subProcess sync processing\n", psub->name); + psub->pact = TRUE; + return 0; + } + if (psub->b){ + callbackSetPriority(psub->prio, pcallback); + printf("%s Starting async processing\n", psub->name); + wdStart(pcallback->wd_id, wait_time, callbackRequest, (int)pcallback); + return 1; + } + } + return 0; + } + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_DOUBLE) { + prompt("Result") + asl(ASL0) + pp(TRUE) + } + field(INAM,DBF_STRING) { + prompt("Init Routine Name") + promptgroup("30 - Action") + special(SPC_NOMOD) + interest(1) + size(40) + } + field(SNAM,DBF_STRING) { + prompt("Subroutine Name") + promptgroup("30 - Action") + special(SPC_MOD) + interest(1) + size(40) + } + %struct subRecord; + %typedef long (*SUBFUNCPTR)(struct subRecord *); + field(SADR,DBF_NOACCESS) { + prompt("Subroutine Address") + special(SPC_NOMOD) + interest(4) + extra("SUBFUNCPTR sadr") + } + field(INPA,DBF_INLINK) { + prompt("Input A") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPB,DBF_INLINK) { + prompt("Input B") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPC,DBF_INLINK) { + prompt("Input C") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPD,DBF_INLINK) { + prompt("Input D") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPE,DBF_INLINK) { + prompt("Input E") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPF,DBF_INLINK) { + prompt("Input F") + promptgroup("41 - Input A-F") + interest(1) + } + field(INPG,DBF_INLINK) { + prompt("Input G") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPH,DBF_INLINK) { + prompt("Input H") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPI,DBF_INLINK) { + prompt("Input I") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPJ,DBF_INLINK) { + prompt("Input J") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPK,DBF_INLINK) { + prompt("Input K") + promptgroup("42 - Input G-L") + interest(1) + } + field(INPL,DBF_INLINK) { + prompt("Input L") + promptgroup("42 - Input G-L") + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Engineering Units") + promptgroup("80 - Display") + interest(1) + size(16) + prop(YES) + } + field(HOPR,DBF_DOUBLE) { + prompt("High Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(LOPR,DBF_DOUBLE) { + prompt("Low Operating Range") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(HIHI,DBF_DOUBLE) { + prompt("Hihi Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_DOUBLE) { + prompt("Lolo Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_DOUBLE) { + prompt("High Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_DOUBLE) { + prompt("Low Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + } + field(PREC,DBF_SHORT) { + prompt("Display Precision") + promptgroup("80 - Display") + interest(1) + prop(YES) + } + field(BRSV,DBF_MENU) { + prompt("Bad Return Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + prop(YES) + menu(menuAlarmSevr) + } + field(HYST,DBF_DOUBLE) { + prompt("Alarm Deadband") + promptgroup("70 - Alarm") + interest(1) + } + field(ADEL,DBF_DOUBLE) { + prompt("Archive Deadband") + promptgroup("80 - Display") + interest(1) + } + field(MDEL,DBF_DOUBLE) { + prompt("Monitor Deadband") + promptgroup("80 - Display") + interest(1) + } + field(A,DBF_DOUBLE) { + prompt("Value of Input A") + pp(TRUE) + } + field(B,DBF_DOUBLE) { + prompt("Value of Input B") + pp(TRUE) + } + field(C,DBF_DOUBLE) { + prompt("Value of Input C") + pp(TRUE) + } + field(D,DBF_DOUBLE) { + prompt("Value of Input D") + pp(TRUE) + } + field(E,DBF_DOUBLE) { + prompt("Value of Input E") + pp(TRUE) + } + field(F,DBF_DOUBLE) { + prompt("Value of Input F") + pp(TRUE) + } + field(G,DBF_DOUBLE) { + prompt("Value of Input G") + pp(TRUE) + } + field(H,DBF_DOUBLE) { + prompt("Value of Input H") + pp(TRUE) + } + field(I,DBF_DOUBLE) { + prompt("Value of Input I") + pp(TRUE) + } + field(J,DBF_DOUBLE) { + prompt("Value of Input J") + pp(TRUE) + } + field(K,DBF_DOUBLE) { + prompt("Value of Input K") + pp(TRUE) + } + field(L,DBF_DOUBLE) { + prompt("Value of Input L") + pp(TRUE) + } + field(LA,DBF_DOUBLE) { + prompt("Prev Value of A") + special(SPC_NOMOD) + interest(3) + } + field(LB,DBF_DOUBLE) { + prompt("Prev Value of B") + special(SPC_NOMOD) + interest(3) + } + field(LC,DBF_DOUBLE) { + prompt("Prev Value of C") + special(SPC_NOMOD) + interest(3) + } + field(LD,DBF_DOUBLE) { + prompt("Prev Value of D") + special(SPC_NOMOD) + interest(3) + } + field(LE,DBF_DOUBLE) { + prompt("Prev Value of E") + special(SPC_NOMOD) + interest(3) + } + field(LF,DBF_DOUBLE) { + prompt("Prev Value of F") + special(SPC_NOMOD) + interest(3) + } + field(LG,DBF_DOUBLE) { + prompt("Prev Value of G") + special(SPC_NOMOD) + interest(3) + } + field(LH,DBF_DOUBLE) { + prompt("Prev Value of H") + special(SPC_NOMOD) + interest(3) + } + field(LI,DBF_DOUBLE) { + prompt("Prev Value of I") + special(SPC_NOMOD) + interest(3) + } + field(LJ,DBF_DOUBLE) { + prompt("Prev Value of J") + special(SPC_NOMOD) + interest(3) + } + field(LK,DBF_DOUBLE) { + prompt("Prev Value of K") + special(SPC_NOMOD) + interest(3) + } + field(LL,DBF_DOUBLE) { + prompt("Prev Value of L") + special(SPC_NOMOD) + interest(3) + } + field(LALM,DBF_DOUBLE) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_DOUBLE) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_DOUBLE) { + prompt("Last Value Monitored") + special(SPC_NOMOD) + interest(3) + } +} diff --git a/modules/database/src/std/rec/waveformRecord.c b/modules/database/src/std/rec/waveformRecord.c index 19f4fbf7b..8d210183c 100644 --- a/modules/database/src/std/rec/waveformRecord.c +++ b/modules/database/src/std/rec/waveformRecord.c @@ -364,10 +364,10 @@ static long readValue(waveformRecord *prec) prec->pact = FALSE; } else { /* !prec->pact && delay >= 0 */ - CALLBACK *pvt = prec->simpvt; + epicsCallback *pvt = prec->simpvt; if (!pvt) { /* very lazy allocation of callback structure */ - pvt = calloc(1, sizeof(CALLBACK)); + pvt = calloc(1, sizeof(epicsCallback)); prec->simpvt = pvt; } if (pvt) diff --git a/modules/database/src/std/rec/waveformRecord.dbd.pod b/modules/database/src/std/rec/waveformRecord.dbd.pod index 82561d076..ce488ef0f 100644 --- a/modules/database/src/std/rec/waveformRecord.dbd.pod +++ b/modules/database/src/std/rec/waveformRecord.dbd.pod @@ -4,34 +4,21 @@ # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# in file LICENSE that is included with this distribution. #************************************************************************* =title Waveform Record (waveform) -... - -=head2 Record-specific Menus - -=head3 Menu waveformPOST - -The MPST and APST fields use this menu to determine when to post new value -and archive monitors respectively. - -=menu waveformPOST - -... - -=head2 Parameter Fields - -The record-specific fields are described below. +The waveform record type is used to interface waveform digitizers. The record +stores its data in arrays. The array can contain any of the supported data +types. =recordtype waveform -... - =cut +include "menuFtype.dbd" + menu(waveformPOST) { choice(waveformPOST_Always,"Always") choice(waveformPOST_OnChange,"On Change") @@ -39,11 +26,377 @@ menu(waveformPOST) { recordtype(waveform) { -=fields VAL, FTVL, MPST, APST +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The waveform record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in L. In addition, L explains how these fields are +used. Note that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Read Parameters + +These fields are configurable by the user to specify how and from where the +record reads its data. How the INP field is configured determines where the +waveform gets its input. It can be a hardware address, a channel access or +database link, or a constant. Only in records that use soft device support can +the INP field be a channel access link, a database link, or a constant. +Otherwise, the INP field must be a hardware address. See L
    for information on the format of hardware addresses and database +links. + +=head4 Fields related to waveform reading + +=fields DTYP, INP, NELM, FTVL, RARM + +The DTYP field must contain the name of the appropriate device support module. +The values retrieved from the input link are placed in an array referenced by +VAL. (If the INP link is a constant, elements can be placed in the array via +dbPuts.) NELM specifies the number of elements that the array will hold, while +FTVL specifies the data type of the elements. +The RARM field causes the device to re-arm when this field is set to 1. + +=head4 Possible data types for FTVL + +=menu menuFtype + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the waveform either textually or +graphically. + +=head4 Fields related to I + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +EGU is a string of up to 16 characters describing the units that the waveform +measures. It is retrieved by the C<<< get_units >>> record support routine. + +The HOPR and LOPR fields set the upper and lower display limits for array +elements referenced by the VAL field. Both the C<<< get_graphic_double >>> and +C<<< get_control_double >>> record support routines retrieve these fields. + +The PREC field determines the floating point precision with which to display the +array values. It is used whenever the C<<< get_precision >>> record support +routine is called. + +See L for more on the record name (NAME) and +description (DESC) fields. + + +=head3 Alarm Parameters + +The waveform record has the alarm parameters common to all record types. L lists other fields related to a alarms that are common to all record +types. + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the VAL +field. The APST and MPST fields are a menu with choices "Always" and "On +Change". The default is "Always", thus monitors will normally be sent every time +the record processes. Selecting "On Change" causes a 32-bit hash of the VAL +field buffer to be calculated and compared with the previous hash value every +time the record processes; the monitor will only be sent if the hash is +different, indicating that the buffer has changed. Note that there is a small +chance that two different value buffers might result in the same hash value, so +for critical systems "Always" may be a better choice, even though it re-sends +duplicate data. + +=head4 Record fields related to I + +=fields APST, MPST, HASH + +=head4 Menu choices for C and C fields + +=menu waveformPOST + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the waveform. They +are not configured using a configuration tool. Only the VAL field is modifiable +at run-time. + +VAL references the array where the waveform stores its data. The BPTR field +holds the address of the array. + +The NORD field holds a counter of the number of elements that have been read +into the array. It is reset to 0 when the device is rearmed. The BUSY field +indicates if the device is armed but has not yet been digitized. + +=fields VAL, BPTR, NORD, BUSY + +The following fields are used to operate the waveform in the simulation mode. +See L for more information on the simulation mode fields. + +=fields SIOL, SIML, SIMM, SIMS + +=begin html + +
    +
    +
    + +=end html + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + + static long init_record(waveformRecord *prec, int pass) + +Using NELM and FTVL space for the array is allocated. The array address is +stored in the record. + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. VAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a device +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated + +If device support includes C, it is called. + +=head4 process + + static long process(waveformRecord *prec) + +See L section below. + +=head4 cvt_dbaddr + + static long cvt_dbaddr(DBADDR *paddr) + +This is called by dbNameToAddr. It makes the dbAddr structure refer to the +actual buffer holding the result. + +=head4 get_array_info + + static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) + +Obtains values from the array referenced by VAL. + +=head4 put_array_info + + static long put_array_info(DBADDR *paddr, long nNew) + +Writes values into the array referenced by VAL. + +=head4 get_units + + static long get_units(DBADDR *paddr, char *units) + +Retrieves EGU. + +=head4 get_prec + + static long get_precision(DBADDR *paddr, long *precision) + +Retrieves PREC if field is VAL field. Otherwise, calls C<<< recGblGetPrec() >>>. + +=head4 get_graphic_double + + static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) + +Sets the upper display and lower display limits for a field. If the field is VAL +the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + +Sets the following values: + + upper_disp_limit = HOPR + lower_disp_limit = LOPR + +=head4 get_control_double + + static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) + +Sets the upper control and the lower control limits for a field. If the field is +VAL the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + +Sets the following values + + upper_ctrl_limit = HOPR + lower_ctrl_limit = LOPR + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +Call device support read routine. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed writing the new value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if APST or MPST are Always or if +the result of the hash calculation is different. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 5. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
    +
    +
    + +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each waveform record must have an associated set of device support routines. The +primary responsibility of the device support routines is to obtain a new array +value whenever read_wf is called. The device support routines are primarily +interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, INP, NELM, FTVL, RARM, BPTR, NORD, BUSY + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 read_wf + + read_wf(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C<<< Soft Channel >>> device support module is provided to read values from +other records and store them in arrays. If INP is a constant link, then read_wf +does nothing. In this case, the record can be used to hold arrays written via +dbPuts. If INP is a database or channel access link, the new array value is read +from the link. NORD is set. + +This module places a value directly in VAL. + +If the INP link type is constant, then NORD is set to zero. If the INP link type +is PV_LINK, then dbCaAddInlink is called by C. + +read_wf calls recGblGetLinkValue which performs the following steps: + +=over + +=item * + +If the INP link type is CONSTANT recGblGetLinkValue does nothing. + +=item * + +If the INP link type is DB_LINK, then dbGetLink is called to obtain a new input +value. If dbGetLink returns an error, a LINK_ALARM with a severity of +INVALID_ALARM is raised. + +=item * + +If the INP link type is CA_LINK, then dbCaGetLink is called to obtain a new +input value. If dbCaGetLink returns an error, a LINK_ALARM with a severity of +INVALID_ALARM is raised. + +=item * + +NORD is set to the number of values returned and read_wf returns. + +=back =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_NOACCESS) { prompt("Value") asl(ASL0) @@ -164,7 +517,7 @@ recordtype(waveform) { prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("CALLBACK *simpvt") + extra("epicsCallback *simpvt") } field(MPST,DBF_MENU) { prompt("Post Value Monitors") diff --git a/modules/database/src/std/softIoc/softMain.cpp b/modules/database/src/std/softIoc/softMain.cpp index 8400a6554..85a3b730d 100644 --- a/modules/database/src/std/softIoc/softMain.cpp +++ b/modules/database/src/std/softIoc/softMain.cpp @@ -9,225 +9,244 @@ /* Author: Andrew Johnson Date: 2003-04-08 */ -/* Usage: - * softIoc [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf] - * [-m macro=value,macro2=value2] [-d file.db] - * [-x prefix] [st.cmd] - * - * If used the -D option must come first, and specify the - * path to the softIoc.dbd file. The compile-time install - * location is saved in the binary as a default. - * - * Usage information will be printed if -h is given, then - * the program will exit normally. - * - * The -S option prevents an interactive shell being started - * after all arguments have been processed. - * - * Previous versions accepted a -s option to cause a shell - * to be started; this option is still accepted but ignored - * since a command shell is now started by default. - * - * Access Security can be enabled with the -a option giving - * the name of the configuration file; if any macros were - * set with -m before the -a option was given, they will be - * used as access security substitution macros. - * - * Any number of -m and -d arguments can be interspersed; - * the macros are applied to the following .db files. Each - * later -m option causes earlier macros to be discarded. - * - * The -x option loads the softIocExit.db with the macro - * IOC set to the string provided. This database contains - * a subroutine record named $(IOC):exit which has its field - * SNAM set to "exit". When this record is processed, the - * subroutine that runs will call epicsExit() with the value - * of the field A determining whether the exit status is - * EXIT_SUCCESS if (A == 0.0) or EXIT_FAILURE (A != 0.0). - * - * A st.cmd file is optional. If any databases were loaded - * the st.cmd file will be run *after* iocInit. To perform - * iocsh commands before iocInit, all database loading must - * be performed by the script itself, or by the user from - * the interactive IOC shell. - */ - -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "registryFunction.h" #include "epicsThread.h" #include "epicsExit.h" #include "epicsStdio.h" +#include "epicsString.h" #include "dbStaticLib.h" #include "subRecord.h" #include "dbAccess.h" #include "asDbLib.h" #include "iocInit.h" #include "iocsh.h" +#include "osiFileName.h" #include "epicsInstallDir.h" extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase); -#define DBD_FILE EPICS_BASE "/dbd/softIoc.dbd" -#define EXIT_FILE EPICS_BASE "/db/softIocExit.db" +#ifndef EPICS_BASE +// so IDEs knows EPICS_BASE is a string constant +# define EPICS_BASE "/" +# error -DEPICS_BASE required +#endif -const char *arg0; -const char *base_dbd = DBD_FILE; -const char *exit_db = EXIT_FILE; +#define DBD_BASE "dbd" OSI_PATH_SEPARATOR "softIoc.dbd" +#define EXIT_BASE "db" OSI_PATH_SEPARATOR "softIocExit.db" +#define DBD_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR DBD_BASE +#define EXIT_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR EXIT_BASE +#define DBD_FILE EPICS_BASE OSI_PATH_SEPARATOR DBD_BASE +#define EXIT_FILE EPICS_BASE OSI_PATH_SEPARATOR EXIT_BASE +namespace { static void exitSubroutine(subRecord *precord) { epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE); } -static void usage(int status) { - printf("Usage: %s [-D softIoc.dbd] [-h] [-S] [-a ascf]\n", arg0); - puts("\t[-m macro=value,macro2=value2] [-d file.db]"); - puts("\t[-x prefix] [st.cmd]"); - puts("Compiled-in path to softIoc.dbd is:"); - printf("\t%s\n", base_dbd); - epicsExit(status); +void usage(const char *arg0, const std::string& base_dbd) { + std::cout<<"Usage: "< If used, must come first. Specify the path to the softIoc.dbdfile." + " The compile-time install location is saved in the binary as a default.\n" + "\n" + " -h Print this mesage and exit.\n" + "\n" + " -S Prevents an interactive shell being started.\n" + "\n" + " -s Previously caused a shell to be started. Now accepted and ignored.\n" + "\n" + " -a Access Security configuration file. Macro substitution is\n" + " performed.\n" + "\n" + " -m =,... Set/replace macro definitions used by subsequent -d and\n" + " -a.\n" + "\n" + " -d Load records from file (dbLoadRecords). Macro substitution is\n" + " performed.\n" + "\n" + " -x Load softIocExit.db. Provides a record \":exit\".\n" + " Put 0 to exit with success, or non-zero to exit with an error.\n" + "\n" + "Any number of -m and -d arguments can be interspersed; the macros are applied\n" + "to the following .db files. Each later -m option causes earlier macros to be\n" + "discarded.\n" + "\n" + "A st.cmd file is optional. If any databases were loaded the st.cmd file will\n" + "be run *after* iocInit. To perform iocsh commands before iocInit, all database\n" + "loading must be performed by the script itself, or by the user from the\n" + "interactive IOC shell.\n" + "\n" + "Compiled-in path to softIoc.dbd is:\n" + "\t"<(base_dbd); - char *macros = NULL; - char xmacro[PVNAME_STRINGSZ + 4]; - int startIocsh = 1; /* default = start shell */ - int loadedDb = 0; - - arg0 = strrchr(*argv, '/'); - if (!arg0) { - arg0 = *argv; - } else { - ++arg0; /* skip the '/' */ - } - - --argc, ++argv; - - /* Do this here in case the dbd file not available */ - if (argc>0 && **argv=='-' && (*argv)[1]=='h') { - usage(EXIT_SUCCESS); - } - - if (argc>1 && **argv=='-' && (*argv)[1]=='D') { - dbd_file = *++argv; - argc -= 2; - ++argv; - } - - if (dbLoadDatabase(dbd_file, NULL, NULL)) { - epicsExit(EXIT_FAILURE); - } - - softIoc_registerRecordDeviceDriver(pdbbase); - registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine); + try { + std::string dbd_file(DBD_FILE), + exit_file(EXIT_FILE), + macros, // scratch space for macros (may be given more than once) + xmacro; + bool interactive = true; + bool loadedDb = false; - while (argc>1 && **argv == '-') { - switch ((*argv)[1]) { - case 'a': - if (macros) asSetSubstitutions(macros); - asSetFilename(*++argv); - --argc; - break; - - case 'd': - if (dbLoadRecords(*++argv, macros)) { - epicsExit(EXIT_FAILURE); - } - loadedDb = 1; - --argc; - break; - - case 'h': - usage(EXIT_SUCCESS); - - case 'm': - macros = *++argv; - --argc; - break; - - case 'S': - startIocsh = 0; - break; - - case 's': - break; - - case 'x': - epicsSnprintf(xmacro, sizeof xmacro, "IOC=%s", *++argv); - if (dbLoadRecords(exit_db, xmacro)) { - epicsExit(EXIT_FAILURE); - } - loadedDb = 1; - --argc; - break; - - default: - printf("%s: option '%s' not recognized\n", arg0, *argv); - usage(EXIT_FAILURE); - } - --argc; - ++argv; + // attempt to compute relative paths + { + std::string prefix; + char *cprefix = epicsGetExecDir(); + if(cprefix) { + try { + prefix = cprefix; + free(cprefix); + } catch(...) { + free(cprefix); + throw; + } + } + + dbd_file = prefix + DBD_FILE_REL; + exit_file = prefix + EXIT_FILE_REL; + } + + int opt; + + while ((opt = getopt(argc, argv, "ha:D:d:m:Ssx:")) != -1) { + switch (opt) { + case 'h': /* Print usage */ + usage(argv[0], dbd_file); + epicsExit(0); + return 0; + default: + usage(argv[0], dbd_file); + std::cerr<<"Unknown argument: -"<0 && **argv=='-') { - switch((*argv)[1]) { - case 'a': - case 'd': - case 'm': - case 'x': - printf("%s: missing argument to option '%s'\n", arg0, *argv); - usage(EXIT_FAILURE); - - case 'h': - usage(EXIT_SUCCESS); - - case 'S': - startIocsh = 0; - break; - - case 's': - break; - - default: - printf("%s: option '%s' not recognized\n", arg0, *argv); - usage(EXIT_FAILURE); - } - --argc; - ++argv; - } - - if (loadedDb) { - iocInit(); - epicsThreadSleep(0.2); - } - - /* run user's startup script */ - if (argc>0) { - if (iocsh(*argv)) epicsExit(EXIT_FAILURE); - epicsThreadSleep(0.2); - loadedDb = 1; /* Give it the benefit of the doubt... */ - } - - /* start an interactive shell if it was requested */ - if (startIocsh) { - iocsh(NULL); - } else { - if (loadedDb) { - epicsThreadExitMain(); - } else { - printf("%s: Nothing to do!\n", arg0); - usage(EXIT_FAILURE); - } - } - epicsExit(EXIT_SUCCESS); - /*Note that the following statement will never be executed*/ - return 0; } diff --git a/modules/database/src/template/Makefile b/modules/database/src/template/Makefile index 6259b6fca..8dfc6c6f3 100644 --- a/modules/database/src/template/Makefile +++ b/modules/database/src/template/Makefile @@ -1,4 +1,4 @@ -TOP=../.. +TOP=../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/src/tools/DBD/Breaktable.pm b/modules/database/src/tools/DBD/Breaktable.pm index c14ab8d65..6fb39e142 100644 --- a/modules/database/src/tools/DBD/Breaktable.pm +++ b/modules/database/src/tools/DBD/Breaktable.pm @@ -1,8 +1,9 @@ package DBD::Breaktable; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); use Carp; +use strict; sub init { my ($this, $name) = @_; diff --git a/modules/database/src/tools/DBD/Device.pm b/modules/database/src/tools/DBD/Device.pm index 1e6d0684c..8e6bd23ad 100644 --- a/modules/database/src/tools/DBD/Device.pm +++ b/modules/database/src/tools/DBD/Device.pm @@ -1,6 +1,8 @@ package DBD::Device; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; my %link_types = ( CONSTANT => qr/$RXnum/, diff --git a/modules/database/src/tools/DBD/Driver.pm b/modules/database/src/tools/DBD/Driver.pm index ddbae8f38..f0a963cbc 100644 --- a/modules/database/src/tools/DBD/Driver.pm +++ b/modules/database/src/tools/DBD/Driver.pm @@ -1,6 +1,8 @@ package DBD::Driver; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; sub init { return shift->SUPER::init(shift, "driver support (drvet)"); diff --git a/modules/database/src/tools/DBD/Function.pm b/modules/database/src/tools/DBD/Function.pm index 4a4a4cbfe..69150f40d 100644 --- a/modules/database/src/tools/DBD/Function.pm +++ b/modules/database/src/tools/DBD/Function.pm @@ -1,6 +1,8 @@ package DBD::Function; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; sub init { return shift->SUPER::init(shift, "function"); diff --git a/modules/database/src/tools/DBD/Link.pm b/modules/database/src/tools/DBD/Link.pm index 4a4568e82..17affb882 100644 --- a/modules/database/src/tools/DBD/Link.pm +++ b/modules/database/src/tools/DBD/Link.pm @@ -1,6 +1,8 @@ package DBD::Link; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; sub init { my ($this, $name, $jlif) = @_; diff --git a/modules/database/src/tools/DBD/Menu.pm b/modules/database/src/tools/DBD/Menu.pm index e5521ed49..943dcc398 100644 --- a/modules/database/src/tools/DBD/Menu.pm +++ b/modules/database/src/tools/DBD/Menu.pm @@ -1,6 +1,8 @@ package DBD::Menu; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; sub init { my ($this, $name) = @_; @@ -14,7 +16,7 @@ sub init { sub add_choice { my ($this, $name, $value) = @_; $name = $this->identifier($name, "Choice name"); - foreach $pair ($this->choices) { + foreach my $pair ($this->choices) { dieContext("Duplicate menu choice name '$name'") if ($pair->[0] eq $name); dieContext("Duplicate menu choice string '$value'") @@ -57,14 +59,17 @@ sub equals { sub toDeclaration { my $this = shift; my $name = $this->name; + my $macro_name = "${name}_NUM_CHOICES"; my @choices = map { sprintf " %-31s /* %s */", @{$_}[0], escapeCcomment(@{$_}[1]); } $this->choices; my $num = scalar @choices; - return "typedef enum {\n" . + return "#ifndef $macro_name\n" . + "typedef enum {\n" . join(",\n", @choices) . "\n} $name;\n" . - "#define ${name}_NUM_CHOICES $num\n\n"; + "#define $macro_name $num\n" . + "#endif\n\n"; } sub toDefinition { diff --git a/modules/database/src/tools/DBD/Recfield.pm b/modules/database/src/tools/DBD/Recfield.pm index 3e109d2d1..22c8d1da8 100644 --- a/modules/database/src/tools/DBD/Recfield.pm +++ b/modules/database/src/tools/DBD/Recfield.pm @@ -1,6 +1,8 @@ package DBD::Recfield; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; # The hash value is a regexp that matches all legal values of this field # NB: The regexps are not currently used, and are wrong for some types. @@ -187,7 +189,7 @@ sub toDeclaration { package DBD::Recfield::DBF_STRING; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -197,6 +199,7 @@ sub legal_value { sub check_valid { my ($this) = @_; + my $name = $this->name; dieContext("Size missing for DBF_STRING field '$name'") unless exists $this->attributes->{'size'}; $this->SUPER::check_valid; @@ -218,7 +221,7 @@ sub toDeclaration { package DBD::Recfield::DBF_CHAR; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -238,7 +241,7 @@ sub toDeclaration { package DBD::Recfield::DBF_UCHAR; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -258,7 +261,7 @@ sub toDeclaration { package DBD::Recfield::DBF_SHORT; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -278,7 +281,7 @@ sub toDeclaration { package DBD::Recfield::DBF_USHORT; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -298,7 +301,7 @@ sub toDeclaration { package DBD::Recfield::DBF_LONG; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -316,7 +319,7 @@ sub toDeclaration { package DBD::Recfield::DBF_ULONG; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -335,7 +338,7 @@ sub toDeclaration { package DBD::Recfield::DBF_INT64; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -353,7 +356,7 @@ sub toDeclaration { package DBD::Recfield::DBF_UINT64; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -372,7 +375,7 @@ sub toDeclaration { package DBD::Recfield::DBF_FLOAT; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -389,7 +392,7 @@ sub toDeclaration { package DBD::Recfield::DBF_DOUBLE; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -406,7 +409,7 @@ sub toDeclaration { package DBD::Recfield::DBF_ENUM; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { return 1; @@ -422,7 +425,7 @@ sub toDeclaration { package DBD::Recfield::DBF_MENU; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { # FIXME: If we know the menu name and the menu exists, check further @@ -431,6 +434,7 @@ sub legal_value { sub check_valid { my ($this) = @_; + my $name = $this->name; dieContext("Menu name missing for DBF_MENU field '$name'") unless defined($this->attribute("menu")); $this->SUPER::check_valid; @@ -446,7 +450,7 @@ sub toDeclaration { package DBD::Recfield::DBF_DEVICE; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { return 1; @@ -462,7 +466,7 @@ sub toDeclaration { package DBD::Recfield::DBF_INLINK; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { return 1; @@ -478,7 +482,7 @@ sub toDeclaration { package DBD::Recfield::DBF_OUTLINK; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { return 1; @@ -494,7 +498,7 @@ sub toDeclaration { package DBD::Recfield::DBF_FWDLINK; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { return 1; @@ -510,7 +514,7 @@ sub toDeclaration { package DBD::Recfield::DBF_NOACCESS; use DBD::Base; -@ISA = qw(DBD::Recfield); +our @ISA = qw(DBD::Recfield); sub legal_value { my ($this, $value) = @_; @@ -519,6 +523,7 @@ sub legal_value { sub check_valid { my ($this) = @_; + my $name = $this->name; dieContext("Type information missing for DBF_NOACCESS field '$name'") unless defined($this->attribute("extra")); $this->SUPER::check_valid; diff --git a/modules/database/src/tools/DBD/Recordtype.pm b/modules/database/src/tools/DBD/Recordtype.pm index 649c6a21b..2edbe463a 100644 --- a/modules/database/src/tools/DBD/Recordtype.pm +++ b/modules/database/src/tools/DBD/Recordtype.pm @@ -1,8 +1,9 @@ package DBD::Recordtype; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); use Carp; +use strict; sub init { my ($this, $name) = @_; diff --git a/modules/database/src/tools/DBD/Registrar.pm b/modules/database/src/tools/DBD/Registrar.pm index 29d12cd11..b4d6cabe3 100644 --- a/modules/database/src/tools/DBD/Registrar.pm +++ b/modules/database/src/tools/DBD/Registrar.pm @@ -1,6 +1,8 @@ package DBD::Registrar; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; sub init { return shift->SUPER::init(shift, "registrar function"); diff --git a/modules/database/src/tools/DBD/Variable.pm b/modules/database/src/tools/DBD/Variable.pm index cd1b0a334..ee606c6fc 100644 --- a/modules/database/src/tools/DBD/Variable.pm +++ b/modules/database/src/tools/DBD/Variable.pm @@ -1,6 +1,8 @@ package DBD::Variable; use DBD::Base; -@ISA = qw(DBD::Base); +our @ISA = qw(DBD::Base); + +use strict; my %valid_types = ( # C type name => corresponding iocshArg type identifier diff --git a/modules/database/src/tools/EPICS/IOC.pm b/modules/database/src/tools/EPICS/IOC.pm index 9eae9d4fd..611d906e6 100644 --- a/modules/database/src/tools/EPICS/IOC.pm +++ b/modules/database/src/tools/EPICS/IOC.pm @@ -29,7 +29,7 @@ EPICS::IOC - Manage an EPICS IOC my @records = $ioc->dbl; my @values = map { $ioc->dbgf($_); } @records; - $ioc->kill; + $ioc->exit; =head1 DESCRIPTION @@ -58,7 +58,8 @@ use IO::Select; Calling C creates an C object that can be used to start and interact with a single IOC. After this IOC has been shut down (by calling its -C method) the C object may be reused for another IOC. +C or C methods) the C object may be reused for another +IOC. =back @@ -162,9 +163,9 @@ sub pid { =item started () -Returns a true value if the IOC has been started and not yet killed. This state -will not change if the IOC dies by itself, it indicates that the start method -has been called without the kill method. +Returns a true value if the IOC has been started and not yet closed. This state +will not change if the IOC dies by itself, it indicates that the C +method has been called but not the C method. =cut @@ -209,17 +210,24 @@ undef value will be returned. sub _getline { my $self = shift; + my $pid = $self->pid; + return undef + unless $self->started; - my $line = readline $self->{stdout}; + # Save, could be closed by a timeout during readline + my $stdout = $self->{stdout}; + my $debug = $self->{debug}; + + my $line = readline $stdout; if (defined $line) { $line =~ s/[\r\n]+ $//x; # chomp broken on Windows? - printf "#%d >> %s\n", $self->{pid}, $line if $self->{debug}; + printf "#%d >> %s\n", $pid, $line if $debug; } - elsif (eof($self->{stdout})) { - printf "#%d >> \n", $self->{pid} if $self->{debug}; + elsif (eof($stdout)) { + printf "#%d >> \n", $pid if $debug; } else { - printf "#%d Error: %s\n", $self->{pid}, $! if $self->{debug}; + printf "#%d Error: %s\n", $pid, $! if $debug; } return $line; } @@ -253,7 +261,7 @@ sub _getlines { =item _geterrors ( ) Returns a list of lines output by the IOC to stderr since last called. Only -complete lines are included, and trailing newlines have been removed. +complete lines are included, with trailing newline char's removed. NOTE: This doesn't work on Windows because it uses select which Perl doesn't support on that OS, but it doesn't seem to cause any problems for short-lived @@ -266,7 +274,8 @@ sub _geterrors { my @errors; while ($self->{select}->can_read(0.01)) { - sysread $self->{stderr}, my $errbuf, 1024; + my $n = sysread $self->{stderr}, my $errbuf, 1024; + return @errors unless $n; # $n is 0 on EOF push @errors, split m/\n/, $self->{errbuf} . $errbuf, -1; last unless @errors; $self->{errbuf} = pop @errors; @@ -323,56 +332,82 @@ sub cmd { return @response; } -=item kill () +=item exit () -The C method attempts to stop an IOC that is still running in several -ways. First it sends an C command to the IOC shell. Next it closes the -IOC's stdin stream which will trigger an end-of-file on that stream, and it -fetches any remaining lines from the IOC's stdout stream before closing both -that and the stderr stream. Finally (unless running on MS-Windows) it sends a -SIGTERM signal to the child process and waits for it to clean up. +The C method attempts to stop and clean up after an IOC that is still +running. It sends an C command to the IOC shell (without waiting for a +response), then calls the C method to finish the task of shutting down +the IOC process and tidying up after it. =cut -sub kill { - my $self = shift; +sub exit { + my $self = $_[0]; return () unless $self->started; $self->_send("exit\n"); # Don't wait + goto &close; +} + +=item close () + +The C method first closes the IOC's stdin stream, which will trigger an +end-of-file to the IOC shell, then it fetches any remaining lines from the +IOC's stdout stream before closing both that and the stderr stream. Finally +(unless we're running on MS-Windows) it sends a SIGTERM signal to the child +process and waits for it to clean up. A list containing the final output from +the IOC's stdout stream is returned. + +=cut + +sub close { + my $self = shift; + + return () + unless $self->started; + + my $pid = $self->{pid}; + my $debug = $self->{debug}; + + printf "#%d << \n", $pid if $debug; close $self->{stdin}; - $self->{stdin} = gensym; my @response = $self->_getlines; # No terminator close $self->{stdout}; - $self->{stdout} = gensym; $self->{select}->remove($self->{stderr}); close $self->{stderr}; + + # Reset these before we call waitpid in case of timeout + $self->{pid} = undef; + $self->{stdin} = gensym; + $self->{stdout} = gensym; $self->{stderr} = gensym; - if ($^O ne "MSWin32") { - kill 'TERM', $self->{pid}; - waitpid $self->{pid}, 0; + if ($^O ne 'MSWin32') { + printf "#%d killing ... ", $pid if $debug; + kill 'TERM', $pid; + waitpid $pid, 0; + printf "%d dead.\n", $pid if $debug; } - $self->{pid} = undef; return @response; } =item DESTROY () -C objects have a destructor which calls the C method, but it -is not recommended that this be relied on to terminate an IOC process. Better to -use an C block and/or trap the necessary signals to explicitly kill the -IOC. +C objects have a destructor which calls the C method, but it +is not recommended that this be relied on to terminate an IOC process. Better +to use an C block and/or trap the necessary signals and explicitly +C or C the IOC. =cut sub DESTROY { - shift->kill; + shift->exit; } diff --git a/modules/database/src/tools/Makefile b/modules/database/src/tools/Makefile index e19c0c58f..f54ab9c07 100644 --- a/modules/database/src/tools/Makefile +++ b/modules/database/src/tools/Makefile @@ -4,7 +4,7 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* -TOP=../.. +TOP=../../../.. include $(TOP)/configure/CONFIG @@ -27,8 +27,6 @@ PERL_MODULES += DBD/Variable.pm PERL_MODULES += EPICS/IOC.pm HTMLS += EPICS/IOC.html -PERL_SCRIPTS += databaseModuleDirs.pm - PERL_SCRIPTS += makeIncludeDbd.pl PERL_SCRIPTS += dbdToMenuH.pl diff --git a/modules/database/src/tools/dbExpand.pl b/modules/database/src/tools/dbExpand.pl index 25cab26cc..6596e4361 100644 --- a/modules/database/src/tools/dbExpand.pl +++ b/modules/database/src/tools/dbExpand.pl @@ -12,9 +12,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use DBD; use DBD::Parser; diff --git a/modules/database/src/tools/dbdExpand.pl b/modules/database/src/tools/dbdExpand.pl index a87ef47bb..74e81eb76 100644 --- a/modules/database/src/tools/dbdExpand.pl +++ b/modules/database/src/tools/dbdExpand.pl @@ -10,9 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use DBD; use DBD::Parser; diff --git a/modules/database/src/tools/dbdReport.pl b/modules/database/src/tools/dbdReport.pl index 0d4c85494..3f2269d8b 100644 --- a/modules/database/src/tools/dbdReport.pl +++ b/modules/database/src/tools/dbdReport.pl @@ -8,9 +8,7 @@ #************************************************************************* use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use DBD; use DBD::Parser; diff --git a/modules/database/src/tools/dbdToHtml.pl b/modules/database/src/tools/dbdToHtml.pl index e9711f757..b9c6eae9a 100644 --- a/modules/database/src/tools/dbdToHtml.pl +++ b/modules/database/src/tools/dbdToHtml.pl @@ -10,9 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use DBD; use DBD::Parser; @@ -129,14 +127,23 @@ open my $out, '>', $opt_o or my $podHtml; my $idify; +my $contentType = + ''; if ($::XHTML) { $podHtml = Pod::Simple::XHTML->new(); $podHtml->html_doctype(<< '__END_DOCTYPE'); - + __END_DOCTYPE + if ($podHtml->can('html_charset')) { + $podHtml->html_charset('UTF-8'); + } + else { + # Older version of Pod::Simple::XHTML without html_charset() + $podHtml->html_header_tags($contentType); + } $podHtml->html_header_tags($podHtml->html_header_tags . "\n"); @@ -145,6 +152,7 @@ __END_DOCTYPE return $podHtml->idify($title, 1); } } else { # Fall back to HTML + $Pod::Simple::HTML::Content_decl = $contentType; $podHtml = Pod::Simple::HTML->new(); $podHtml->html_css('style.css'); diff --git a/modules/database/src/tools/dbdToMenuH.pl b/modules/database/src/tools/dbdToMenuH.pl index ac4345b42..76aff7dac 100644 --- a/modules/database/src/tools/dbdToMenuH.pl +++ b/modules/database/src/tools/dbdToMenuH.pl @@ -8,9 +8,7 @@ #************************************************************************* use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use EPICS::Getopts; use File::Basename; diff --git a/modules/database/src/tools/dbdToRecordtypeH.pl b/modules/database/src/tools/dbdToRecordtypeH.pl index b1eb77d93..891b5b5c5 100644 --- a/modules/database/src/tools/dbdToRecordtypeH.pl +++ b/modules/database/src/tools/dbdToRecordtypeH.pl @@ -8,9 +8,7 @@ #************************************************************************* use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use EPICS::Getopts; use File::Basename; diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl index 02bb9b772..9e81c9875 100644 --- a/modules/database/src/tools/registerRecordDeviceDriver.pl +++ b/modules/database/src/tools/registerRecordDeviceDriver.pl @@ -12,9 +12,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use DBD; use DBD::Parser; @@ -277,7 +275,7 @@ static const iocshFuncDef rrddFuncDef = {"$subname", 1, rrddArgs}; static void rrddCallFunc(const iocshArgBuf *) { - $subname(*iocshPpdbbase); + iocshSetError($subname(*iocshPpdbbase)); } } // extern "C" diff --git a/modules/database/test/Makefile b/modules/database/test/Makefile index 0f2c64263..b54d01757 100644 --- a/modules/database/test/Makefile +++ b/modules/database/test/Makefile @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG DIRS += ioc/db diff --git a/modules/database/test/ioc/db/Makefile b/modules/database/test/ioc/db/Makefile index b94161d7d..2ecc7e820 100644 --- a/modules/database/test/ioc/db/Makefile +++ b/modules/database/test/ioc/db/Makefile @@ -6,12 +6,14 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in the file LICENSE that is included with this distribution. #************************************************************************* +CURDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +TOP = ../../../../.. -TOP = ../../.. include $(TOP)/configure/CONFIG # Allow access to private headers in db/ -USR_CPPFLAGS = -I $(TOP)/src/ioc/db +USR_CPPFLAGS += -I $(CURDIR)/../../../src/ioc/db +USR_CPPFLAGS += -DUSE_TYPED_RSET TESTLIBRARY = dbTestIoc diff --git a/modules/database/test/ioc/db/callbackParallelTest.c b/modules/database/test/ioc/db/callbackParallelTest.c index f8d0c3981..a985cd2d8 100644 --- a/modules/database/test/ioc/db/callbackParallelTest.c +++ b/modules/database/test/ioc/db/callbackParallelTest.c @@ -44,8 +44,8 @@ #define TEST_DELAY(i) ((i / NUM_CALLBACK_PRIORITIES) * DELAY_QUANTUM) typedef struct myPvt { - CALLBACK cb1; - CALLBACK cb2; + epicsCallback cb1; + epicsCallback cb2; epicsTimeStamp pass1Time; epicsTimeStamp pass2Time; double delay; @@ -55,7 +55,7 @@ typedef struct myPvt { epicsEventId finished; -static void myCallback(CALLBACK *pCallback) +static void myCallback(epicsCallback *pCallback) { myPvt *pmyPvt; @@ -74,7 +74,7 @@ static void myCallback(CALLBACK *pCallback) } } -static void finalCallback(CALLBACK *pCallback) +static void finalCallback(epicsCallback *pCallback) { myCallback(pCallback); epicsEventSignal(finished); diff --git a/modules/database/test/ioc/db/callbackTest.c b/modules/database/test/ioc/db/callbackTest.c index 3ccc2c2f3..4b7e24d78 100644 --- a/modules/database/test/ioc/db/callbackTest.c +++ b/modules/database/test/ioc/db/callbackTest.c @@ -44,8 +44,8 @@ #define TEST_DELAY(i) ((i / NUM_CALLBACK_PRIORITIES) * DELAY_QUANTUM) typedef struct myPvt { - CALLBACK cb1; - CALLBACK cb2; + epicsCallback cb1; + epicsCallback cb2; epicsTimeStamp pass1Time; epicsTimeStamp pass2Time; double delay; @@ -56,7 +56,7 @@ typedef struct myPvt { epicsEventId finished; -static void myCallback(CALLBACK *pCallback) +static void myCallback(epicsCallback *pCallback) { myPvt *pmyPvt; @@ -75,7 +75,7 @@ static void myCallback(CALLBACK *pCallback) } } -static void finalCallback(CALLBACK *pCallback) +static void finalCallback(epicsCallback *pCallback) { myCallback(pCallback); epicsEventSignal(finished); diff --git a/modules/database/test/ioc/db/dbChArrTest.cpp b/modules/database/test/ioc/db/dbChArrTest.cpp index 8a788bed6..8255fdc39 100644 --- a/modules/database/test/ioc/db/dbChArrTest.cpp +++ b/modules/database/test/ioc/db/dbChArrTest.cpp @@ -36,7 +36,7 @@ #include "iocInit.h" #include "iocsh.h" #include "dbChannel.h" -#include "epicsUnitTest.h" +#include "dbUnitTest.h" #include "testMain.h" #include "osiFileName.h" @@ -197,50 +197,33 @@ static void check(short dbr_type) { dbChannelDelete(pch); } -static dbEventCtx evtctx; - -extern "C" { -static void dbChArrTestCleanup(void* junk) -{ - dbFreeBase(pdbbase); - registryFree(); - pdbbase=0; - - db_close_events(evtctx); - - dbmfFreeChunks(); -} -} - MAIN(dbChArrTest) { testPlan(102); /* Prepare the IOC */ + testdbPrepare(); epicsEnvSet("EPICS_CA_SERVER_PORT", server_port); - if (dbReadDatabase(&pdbbase, "dbChArrTest.dbd", - "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR - "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL)) - testAbort("Database description not loaded"); + testdbReadDatabase("dbChArrTest.dbd", + "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR + "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL); dbChArrTest_registerRecordDeviceDriver(pdbbase); - if (dbReadDatabase(&pdbbase, "dbChArrTest.db", - "." OSI_PATH_LIST_SEPARATOR "..", NULL)) - testAbort("Test database not loaded"); + testdbReadDatabase("dbChArrTest.db", + "." OSI_PATH_LIST_SEPARATOR "..", NULL); - epicsAtExit(&dbChArrTestCleanup,NULL); - - /* Start the IOC */ - - iocInit(); - evtctx = db_init_events(); + testIocInitOk(); check(DBR_LONG); check(DBR_DOUBLE); check(DBR_STRING); + testIocShutdownOk(); + + testdbCleanup(); + return testDone(); } diff --git a/modules/database/test/ioc/dbtemplate/Makefile b/modules/database/test/ioc/dbtemplate/Makefile index 4442a4ff8..dbb13f337 100644 --- a/modules/database/test/ioc/dbtemplate/Makefile +++ b/modules/database/test/ioc/dbtemplate/Makefile @@ -5,7 +5,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../../.. +TOP = ../../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/test/std/filters/Makefile b/modules/database/test/std/filters/Makefile index baf340ac7..c2849a3cd 100644 --- a/modules/database/test/std/filters/Makefile +++ b/modules/database/test/std/filters/Makefile @@ -7,10 +7,12 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../../.. +TOP = ../../../../.. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -DUSE_TYPED_RSET + TESTLIBRARY = Recs Recs_SRCS += xRecord.c @@ -57,6 +59,12 @@ syncTest_SRCS += filterTest_registerRecordDeviceDriver.cpp testHarness_SRCS += syncTest.c TESTS += syncTest +TESTPROD_HOST += decTest +decTest_SRCS += decTest.c +decTest_SRCS += filterTest_registerRecordDeviceDriver.cpp +testHarness_SRCS += decTest.c +TESTS += decTest + # epicsRunFilterTests runs all the test programs in a known working order. testHarness_SRCS += epicsRunFilterTests.c diff --git a/modules/database/test/std/filters/dbndTest.c b/modules/database/test/std/filters/dbndTest.c index b35b9a6cc..4d70f83ad 100644 --- a/modules/database/test/std/filters/dbndTest.c +++ b/modules/database/test/std/filters/dbndTest.c @@ -39,12 +39,14 @@ static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) { static void fl_setup(dbChannel *chan, db_field_log *pfl) { struct dbCommon *prec = dbChannelRecord(chan); + memset(pfl, 0, sizeof(db_field_log)); pfl->ctx = dbfl_context_read; pfl->type = dbfl_type_val; pfl->stat = prec->stat; pfl->sevr = prec->sevr; pfl->time = prec->time; pfl->field_type = dbChannelFieldType(chan); + pfl->field_size = dbChannelFieldSize(chan); pfl->no_elements = dbChannelElements(chan); /* * use memcpy to avoid a bus error on @@ -62,6 +64,7 @@ static void changeValue(db_field_log *pfl2, long val) { } static void mustPassOnce(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) { + int oldFree = db_available_logs(), newFree; db_field_log *pfl; changeValue(pfl2, val); @@ -71,18 +74,26 @@ static void mustPassOnce(dbChannel *pch, db_field_log *pfl2, char* m, double d, testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data"); pfl = dbChannelRunPreChain(pch, pfl2); testOk(NULL == pfl, "call 2 drops field_log"); + newFree = db_available_logs(); + testOk(newFree == oldFree + 1, "field_log was freed - %d+1 => %d", + oldFree, newFree); } static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) { + int oldFree = db_available_logs(), newFree; db_field_log *pfl; changeValue(pfl2, val); testDiag("mode=%s delta=%g filter must drop", m, d); pfl = dbChannelRunPreChain(pch, pfl2); testOk(NULL == pfl, "call 1 drops field_log"); + newFree = db_available_logs(); + testOk(newFree == oldFree + 1, "field_log was freed - %d+1 => %d", + oldFree, newFree); } static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) { + int oldFree = db_available_logs(), newFree; db_field_log *pfl; changeValue(pfl2, val); @@ -93,6 +104,9 @@ static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m, double d, pfl = dbChannelRunPreChain(pch, pfl2); testOk(pfl2 == pfl, "call 2 does not drop or replace field_log"); testOk(fl_equal(pfl, pfl2), "call 2 does not change field_log data"); + newFree = db_available_logs(); + testOk(newFree == oldFree, "field_log was not freed - %d => %d", + oldFree, newFree); } static void testHead (char* title) { @@ -113,8 +127,9 @@ MAIN(dbndTest) db_field_log *pfl2; db_field_log fl1; dbEventCtx evtctx; + int logsFree, logsFinal; - testPlan(59); + testPlan(77); testdbPrepare(); @@ -135,6 +150,11 @@ MAIN(dbndTest) testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{}}")), "dbChannel with plugin dbnd (delta=0) created"); testOk((ellCount(&pch->filters) == 1), "channel has one plugin"); + /* Start the free-list */ + db_delete_field_log(db_create_read_log(pch)); + logsFree = db_available_logs(); + testDiag("%d field_logs on free-list", logsFree); + memset(&fl, PATTERN, sizeof(fl)); fl1 = fl; node = ellFirst(&pch->filters); @@ -176,6 +196,8 @@ MAIN(dbndTest) dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Delta = -1: pass any update */ testHead("Delta = -1: pass any update"); @@ -192,6 +214,8 @@ MAIN(dbndTest) db_delete_field_log(pfl2); dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Delta = absolute */ testHead("Delta = absolute"); @@ -224,6 +248,8 @@ MAIN(dbndTest) dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Delta = relative */ testHead("Delta = relative"); @@ -275,6 +301,9 @@ MAIN(dbndTest) dbChannelDelete(pch); + logsFinal = db_available_logs(); + testOk(logsFree == logsFinal, "%d field_logs on free-list", logsFinal); + db_close_events(evtctx); testIocShutdownOk(); diff --git a/modules/database/test/std/filters/decTest.c b/modules/database/test/std/filters/decTest.c new file mode 100644 index 000000000..3b6784248 --- /dev/null +++ b/modules/database/test/std/filters/decTest.c @@ -0,0 +1,289 @@ +/*************************************************************************\ +* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2010 Brookhaven National Laboratory. +* Copyright (c) 2010 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Authors: Ralph Lange , + * Andrew Johnson + */ + +#include + +#include "dbStaticLib.h" +#include "dbAccessDefs.h" +#include "db_field_log.h" +#include "dbCommon.h" +#include "dbChannel.h" +#include "registry.h" +#include "chfPlugin.h" +#include "errlog.h" +#include "dbmf.h" +#include "epicsUnitTest.h" +#include "dbUnitTest.h" +#include "epicsTime.h" +#include "testMain.h" +#include "osiFileName.h" + +void filterTest_registerRecordDeviceDriver(struct dbBase *); + +static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) { + return !(memcmp(pfl1, pfl2, sizeof(db_field_log))); +} + +static void fl_setup(dbChannel *chan, db_field_log *pfl, long val) { + struct dbCommon *prec = dbChannelRecord(chan); + + memset(pfl, 0, sizeof(db_field_log)); + pfl->ctx = dbfl_context_event; + pfl->type = dbfl_type_val; + pfl->stat = prec->stat; + pfl->sevr = prec->sevr; + pfl->time = prec->time; + pfl->field_type = DBF_LONG; + pfl->field_size = sizeof(epicsInt32); + pfl->no_elements = 1; + /* + * use memcpy to avoid a bus error on + * union copy of char in the db at an odd + * address + */ + memcpy(&pfl->u.v.field, + dbChannelField(chan), + dbChannelFieldSize(chan)); + pfl->u.v.field.dbf_long = val; +} + +static void testHead (char* title) { + testDiag("--------------------------------------------------------"); + testDiag("%s", title); + testDiag("--------------------------------------------------------"); +} + +static void mustDrop(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(NULL == pfl2, "filter drops field_log (%s)", m); + testOk(newFree == oldFree + 1, "field_log was freed - %d+1 => %d", + oldFree, newFree); + + db_delete_field_log(pfl2); +} + +static void mustPass(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(pfl == pfl2, "filter passes field_log (%s)", m); + testOk(newFree == oldFree, "field_log was not freed - %d => %d", + oldFree, newFree); + + db_delete_field_log(pfl2); +} + +static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) { + ELLNODE *node; + chFilter *filter; + chPostEventFunc *cb_out = NULL; + void *arg_out = NULL; + db_field_log fl, fl1; + + testDiag("Test filter structure and open channel"); + + testOk((ellCount(&pch->filters) == 1), "channel has one plugin"); + + fl_setup(pch, &fl, 1); + fl1 = fl; + node = ellFirst(&pch->filters); + filter = CONTAINER(node, chFilter, list_node); + plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1); + testOk(cb_out && arg_out, + "register_pre registers one filter with argument"); + testOk(fl_equal(&fl1, &fl), + "register_pre does not change field_log data type"); + + testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dec opened"); + node = ellFirst(&pch->pre_chain); + filter = CONTAINER(node, chFilter, pre_node); + testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg != NULL), + "dec has one filter with argument in pre chain"); + testOk((ellCount(&pch->post_chain) == 0), + "sync has no filter in post chain"); +} + +MAIN(decTest) +{ + dbChannel *pch; + const chFilterPlugin *plug; + char myname[] = "dec"; + db_field_log *pfl[10]; + int i, logsFree, logsFinal; + dbEventCtx evtctx; + + testPlan(104); + + testdbPrepare(); + + testdbReadDatabase("filterTest.dbd", NULL, NULL); + + filterTest_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("xRecord.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + evtctx = db_init_events(); + + testOk(!!(plug = dbFindFilter(myname, strlen(myname))), + "plugin '%s' registered correctly", myname); + + /* N < 1 */ + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":-1}}")), + "dbChannel with dec (n=-1) failed"); + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":0}}")), + "dbChannel with dec (n=0) failed"); + /* Bad parms */ + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{}}")), + "dbChannel with dec (no parm) failed"); + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{\"x\":true}}")), + "dbChannel with dec (x=true) failed"); + + /* No Decimation (N=1) */ + + testHead("No Decimation (n=1)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":1}}")), + "dbChannel with plugin dec (n=1) created"); + + /* Start the free-list */ + db_delete_field_log(db_create_read_log(pch)); + logsFree = db_available_logs(); + testDiag("%d field_logs on free-list", logsFree); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 5; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 10 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustPass(pch, pfl[1], "i=1"); + mustPass(pch, pfl[2], "i=2"); + mustPass(pch, pfl[3], "i=3"); + mustPass(pch, pfl[4], "i=4"); + + dbChannelDelete(pch); + + testDiag("%d field_logs on free-list", db_available_logs()); + + /* Decimation (N=2) */ + + testHead("Decimation (n=2)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":2}}")), + "dbChannel with plugin dec (n=2) created"); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 10; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 20 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustDrop(pch, pfl[1], "i=1"); + mustPass(pch, pfl[2], "i=2"); + mustDrop(pch, pfl[3], "i=3"); + mustPass(pch, pfl[4], "i=4"); + mustDrop(pch, pfl[5], "i=5"); + mustPass(pch, pfl[6], "i=6"); + mustDrop(pch, pfl[7], "i=7"); + mustPass(pch, pfl[8], "i=8"); + mustDrop(pch, pfl[9], "i=9"); + + dbChannelDelete(pch); + + testDiag("%d field_logs on free-list", db_available_logs()); + + /* Decimation (N=3) */ + + testHead("Decimation (n=3)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":3}}")), + "dbChannel with plugin dec (n=3) created"); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 10; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 30 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustDrop(pch, pfl[1], "i=1"); + mustDrop(pch, pfl[2], "i=2"); + mustPass(pch, pfl[3], "i=3"); + mustDrop(pch, pfl[4], "i=4"); + mustDrop(pch, pfl[5], "i=5"); + mustPass(pch, pfl[6], "i=6"); + mustDrop(pch, pfl[7], "i=7"); + mustDrop(pch, pfl[8], "i=8"); + mustPass(pch, pfl[9], "i=9"); + + dbChannelDelete(pch); + + testDiag("%d field_logs on free-list", db_available_logs()); + + /* Decimation (N=4) */ + + testHead("Decimation (n=4)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":4}}")), + "dbChannel with plugin dec (n=4) created"); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 10; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 40 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustDrop(pch, pfl[1], "i=1"); + mustDrop(pch, pfl[2], "i=2"); + mustDrop(pch, pfl[3], "i=3"); + mustPass(pch, pfl[4], "i=4"); + mustDrop(pch, pfl[5], "i=5"); + mustDrop(pch, pfl[6], "i=6"); + mustDrop(pch, pfl[7], "i=7"); + mustPass(pch, pfl[8], "i=8"); + mustDrop(pch, pfl[9], "i=9"); + + dbChannelDelete(pch); + + logsFinal = db_available_logs(); + testOk(logsFree == logsFinal, "%d field_logs on free-list", logsFinal); + + db_close_events(evtctx); + + testIocShutdownOk(); + + testdbCleanup(); + + return testDone(); +} diff --git a/modules/database/test/std/filters/epicsRunFilterTests.c b/modules/database/test/std/filters/epicsRunFilterTests.c index 236364391..5737d77dc 100644 --- a/modules/database/test/std/filters/epicsRunFilterTests.c +++ b/modules/database/test/std/filters/epicsRunFilterTests.c @@ -17,6 +17,7 @@ int tsTest(void); int dbndTest(void); int syncTest(void); int arrTest(void); +int decTest(void); void epicsRunFilterTests(void) { @@ -26,6 +27,7 @@ void epicsRunFilterTests(void) runTest(dbndTest); runTest(syncTest); runTest(arrTest); + runTest(decTest); dbmfFreeChunks(); diff --git a/modules/database/test/std/filters/syncTest.c b/modules/database/test/std/filters/syncTest.c index 9af44afd7..9be23b05d 100644 --- a/modules/database/test/std/filters/syncTest.c +++ b/modules/database/test/std/filters/syncTest.c @@ -42,12 +42,14 @@ static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) { static void fl_setup(dbChannel *chan, db_field_log *pfl, long val) { struct dbCommon *prec = dbChannelRecord(chan); + memset(pfl, 0, sizeof(db_field_log)); pfl->ctx = dbfl_context_event; pfl->type = dbfl_type_val; pfl->stat = prec->stat; pfl->sevr = prec->sevr; pfl->time = prec->time; pfl->field_type = DBF_LONG; + pfl->field_size = sizeof(epicsInt32); pfl->no_elements = 1; /* * use memcpy to avoid a bus error on @@ -66,31 +68,92 @@ static void testHead (char* title) { testDiag("--------------------------------------------------------"); } -static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m) { - db_field_log *pfl = dbChannelRunPreChain(pch, pfl2); - testOk(NULL == pfl, "filter drops field_log (%s)", m); +/* + * Use mustDrop() and mustPass() to test filters with no memory + * of previous field_log pointers. + */ +static void mustDrop(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(NULL == pfl2, "filter drops field_log (%s)", m); + testOk(newFree == oldFree + 1, "a field_log was freed - %d+1 => %d", + oldFree, newFree); + + db_delete_field_log(pfl2); } -static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m) { - db_field_log *pfl; +static void mustPass(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(pfl == pfl2, "filter passes field_log (%s)", m); + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); + + db_delete_field_log(pfl2); +} + +/* + * Use mustStash() and mustSwap() to test filters that save + * field_log pointers and return them later. + * + * mustStash() expects the filter to save the current pointer + * (freeing any previously saved pointer) and return NULL. + * mustSwap() expects the filter to return the previously + * saved pointer and save the current pointer. + */ +static db_field_log *stashed; + +static void streamReset(void) { + stashed = NULL; +} + +static void mustStash(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(NULL == pfl2, "filter stashes field_log (%s)", m); + if (stashed) { + testOk(newFree == oldFree + 1, "a field_log was freed - %d+1 => %d", + oldFree, newFree); + } + else { + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); + } + stashed = pfl; + db_delete_field_log(pfl2); +} + +static void mustSwap(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(stashed == pfl2, "filter returns stashed field log (%s)", m); + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); + + stashed = pfl; + db_delete_field_log(pfl2); +} + +static void mustPassTwice(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(), newFree; + db_field_log *pfl2; testDiag("%s: filter must pass twice", m); - pfl = dbChannelRunPreChain(pch, pfl2); + pfl2 = dbChannelRunPreChain(pch, pfl); testOk(pfl2 == pfl, "call 1 does not drop or replace field_log"); - pfl = dbChannelRunPreChain(pch, pfl2); + pfl2 = dbChannelRunPreChain(pch, pfl); testOk(pfl2 == pfl, "call 2 does not drop or replace field_log"); -} - -static void mustPassOld(dbChannel *pch, db_field_log *old, db_field_log *cur, char* m) { - db_field_log *pfl = dbChannelRunPreChain(pch, cur); - - testOk(old == pfl, "filter passes previous field log (%s)", m); -} - -static void mustPass(dbChannel *pch, db_field_log *cur, char* m) { - db_field_log *pfl = dbChannelRunPreChain(pch, cur); - - testOk(cur == pfl, "filter passes field_log (%s)", m); + newFree = db_available_logs(); + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); } static void checkCtxRead(dbChannel *pch, dbStateId id) { @@ -138,10 +201,10 @@ MAIN(syncTest) const chFilterPlugin *plug; char myname[] = "sync"; db_field_log *pfl[10]; - int i; + int i, logsFree, logsFinal; dbEventCtx evtctx; - testPlan(139); + testPlan(214); testdbPrepare(); @@ -176,9 +239,14 @@ MAIN(syncTest) testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\",\"s\":\"red\"}}")), "dbChannel with plugin sync (m='while' s='red') created"); + /* Start the free-list */ + db_delete_field_log(db_create_read_log(pch)); + logsFree = db_available_logs(); + testDiag("%d field_logs on free-list", logsFree); + checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } @@ -198,11 +266,10 @@ MAIN(syncTest) mustDrop(pch, pfl[7], "state=FALSE, log7"); mustDrop(pch, pfl[8], "state=FALSE, log8"); - for (i = 0; i < 10; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode UNLESS */ testHead("Mode UNLESS (m='unless', s='red')"); @@ -211,7 +278,7 @@ MAIN(syncTest) checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } @@ -231,11 +298,10 @@ MAIN(syncTest) mustPass(pch, pfl[7], "state=FALSE, log7"); mustPass(pch, pfl[8], "state=FALSE, log8"); - for (i = 0; i < 10; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode BEFORE */ testHead("Mode BEFORE (m='before', s='red')"); @@ -251,24 +317,25 @@ MAIN(syncTest) testDiag("Test event stream"); + streamReset(); dbStateClear(red); - mustDrop(pch, pfl[0], "state=FALSE, log0"); - mustDrop(pch, pfl[1], "state=FALSE, log1"); - mustDrop(pch, pfl[2], "state=FALSE, log2"); + mustStash(pch, pfl[0], "state=FALSE, log0"); + mustStash(pch, pfl[1], "state=FALSE, log1"); + mustStash(pch, pfl[2], "state=FALSE, log2"); dbStateSet(red); - mustPassOld(pch, pfl[2], pfl[3], "state=TRUE, log3, pass=log2"); - mustDrop(pch, pfl[4], "state=TRUE, log4"); - mustDrop(pch, pfl[5], "state=TRUE, log5"); - mustDrop(pch, pfl[6], "state=TRUE, log6"); + mustSwap(pch, pfl[3], "state=TRUE, log3"); + mustStash(pch, pfl[4], "state=TRUE, log4"); + mustStash(pch, pfl[5], "state=TRUE, log5"); + mustStash(pch, pfl[6], "state=TRUE, log6"); dbStateClear(red); - mustDrop(pch, pfl[7], "state=FALSE, log7"); - mustDrop(pch, pfl[8], "state=FALSE, log8"); - mustDrop(pch, pfl[9], "state=FALSE, log9"); - - db_delete_field_log(pfl[2]); + mustStash(pch, pfl[7], "state=FALSE, log7"); + mustStash(pch, pfl[8], "state=FALSE, log8"); + mustStash(pch, pfl[9], "state=FALSE, log9"); dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode FIRST */ testHead("Mode FIRST (m='first', s='red')"); @@ -277,13 +344,14 @@ MAIN(syncTest) checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } testDiag("Test event stream"); + streamReset(); dbStateClear(red); mustDrop(pch, pfl[0], "state=FALSE, log0"); mustDrop(pch, pfl[1], "state=FALSE, log1"); @@ -297,11 +365,10 @@ MAIN(syncTest) mustDrop(pch, pfl[7], "state=FALSE, log7"); mustDrop(pch, pfl[8], "state=FALSE, log8"); - db_delete_field_log(pfl[3]); - db_delete_field_log(pfl[9]); - dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode LAST */ testHead("Mode LAST (m='last', s='red')"); @@ -317,24 +384,25 @@ MAIN(syncTest) testDiag("Test event stream"); + streamReset(); dbStateClear(red); - mustDrop(pch, pfl[0], "state=FALSE, log0"); - mustDrop(pch, pfl[1], "state=FALSE, log1"); - mustDrop(pch, pfl[2], "state=FALSE, log2"); + mustStash(pch, pfl[0], "state=FALSE, log0"); + mustStash(pch, pfl[1], "state=FALSE, log1"); + mustStash(pch, pfl[2], "state=FALSE, log2"); dbStateSet(red); - mustDrop(pch, pfl[3], "state=TRUE, log3"); - mustDrop(pch, pfl[4], "state=TRUE, log4"); - mustDrop(pch, pfl[5], "state=TRUE, log5"); + mustStash(pch, pfl[3], "state=TRUE, log3"); + mustStash(pch, pfl[4], "state=TRUE, log4"); + mustStash(pch, pfl[5], "state=TRUE, log5"); dbStateClear(red); - mustPassOld(pch, pfl[5], pfl[6], "state=TRUE, log6, pass=log5"); - mustDrop(pch, pfl[7], "state=FALSE, log7"); - mustDrop(pch, pfl[8], "state=FALSE, log8"); - mustDrop(pch, pfl[9], "state=FALSE, log9"); - - db_delete_field_log(pfl[5]); + mustSwap(pch, pfl[6], "state=TRUE, log6"); + mustStash(pch, pfl[7], "state=FALSE, log7"); + mustStash(pch, pfl[8], "state=FALSE, log8"); + mustStash(pch, pfl[9], "state=FALSE, log9"); dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode AFTER */ testHead("Mode AFTER (m='after', s='red')"); @@ -343,13 +411,14 @@ MAIN(syncTest) checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } testDiag("Test event stream"); + streamReset(); dbStateClear(red); mustDrop(pch, pfl[0], "state=FALSE, log0"); mustDrop(pch, pfl[1], "state=FALSE, log1"); @@ -363,11 +432,11 @@ MAIN(syncTest) mustDrop(pch, pfl[7], "state=FALSE, log7"); mustDrop(pch, pfl[8], "state=FALSE, log8"); - db_delete_field_log(pfl[6]); - db_delete_field_log(pfl[9]); - dbChannelDelete(pch); + logsFinal = db_available_logs(); + testOk(logsFree == logsFinal, "%d field_logs on free-list", logsFinal); + db_close_events(evtctx); testIocShutdownOk(); diff --git a/modules/database/test/std/link/Makefile b/modules/database/test/std/link/Makefile index 349645437..2971ffe2d 100644 --- a/modules/database/test/std/link/Makefile +++ b/modules/database/test/std/link/Makefile @@ -4,10 +4,12 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP=../../.. +TOP=../../../../.. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -DUSE_TYPED_RSET + TESTLIBRARY = Recs Recs_SRCS += ioRecord.c diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile index a0cf58c9a..a3152a02d 100644 --- a/modules/database/test/std/rec/Makefile +++ b/modules/database/test/std/rec/Makefile @@ -7,9 +7,12 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../../.. +TOP = ../../../../.. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -DUSE_TYPED_RSET +USR_CPPFLAGS += -DUSE_TYPED_DSET + TESTLIBRARY = dbRecStdTest dbRecStdTest_SRCS += asTestLib.c @@ -146,6 +149,13 @@ asyncproctest_SRCS += asyncproctest_registerRecordDeviceDriver.cpp TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db TESTS += asyncproctest +# dbHeader* is only a compile test +# no need to actually run +TESTPROD += dbHeaderTest +dbHeaderTest_SRCS += dbHeaderTest.cpp +TESTPROD += dbHeaderTestxx +dbHeaderTestxx_SRCS += dbHeaderTestxx.cpp + ifeq ($(T_A),$(EPICS_HOST_ARCH)) # Host-only tests of softIoc/softIocPVA, caget and pvget (if present) TESTS += netget diff --git a/modules/database/test/std/rec/dbHeaderTest.c b/modules/database/test/std/rec/dbHeaderTest.c new file mode 100644 index 000000000..0e2785a8f --- /dev/null +++ b/modules/database/test/std/rec/dbHeaderTest.c @@ -0,0 +1,244 @@ +/*************************************************************************\ +* Copyright (c) 2019 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* This test includes all public headers from libCom and database modules + * to ensure they are all syntaxtically correct in C and C++ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __rtems__ +# include +#endif +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +# include +# include +# include +#endif +#include +#include +#include +#include +#include +#include + +/* must be last */ +#include + +MAIN(dbHeaderTest) +{ + testPlan(1); + testPass("Compiled successfully"); + return testDone(); +} diff --git a/modules/database/test/std/rec/dbHeaderTestxx.cpp b/modules/database/test/std/rec/dbHeaderTestxx.cpp new file mode 100644 index 000000000..7e2632ef0 --- /dev/null +++ b/modules/database/test/std/rec/dbHeaderTestxx.cpp @@ -0,0 +1,2 @@ +// just compile as c++ +#include "dbHeaderTest.c" diff --git a/modules/database/test/std/rec/netget.plt b/modules/database/test/std/rec/netget.plt index 75a4f4565..075717d78 100644 --- a/modules/database/test/std/rec/netget.plt +++ b/modules/database/test/std/rec/netget.plt @@ -8,6 +8,9 @@ use lib '@TOP@/lib/perl'; use Test::More tests => 3; use EPICS::IOC; +# Set to 1 to echo all IOC and client communications +my $debug = 1; + $ENV{HARNESS_ACTIVE} = 1 if scalar @ARGV && shift eq '-tap'; # Keep traffic local and avoid duplicates over multiple interfaces @@ -23,15 +26,15 @@ $ENV{EPICS_PVAS_SERVER_PORT} = 55075; $ENV{EPICS_PVA_BROADCAST_PORT} = 55076; $ENV{EPICS_PVAS_INTF_ADDR_LIST} = 'localhost'; -my $bin = "@TOP@/bin/@ARCH@"; +my $bin = '@TOP@/bin/@ARCH@'; my $exe = ($^O =~ m/^(MSWin32|cygwin)$/x) ? '.exe' : ''; my $prefix = "test-$$"; my $ioc = EPICS::IOC->new(); -#$ioc->debug(1); +$ioc->debug($debug); $SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = sub { - $ioc->kill; + $ioc->exit; BAIL_OUT('Caught signal'); }; @@ -41,7 +44,7 @@ $SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = sub { sub kill_bail { my $doing = shift; return sub { - $ioc->kill; + $ioc->exit; BAIL_OUT("Timeout $doing"); } } @@ -87,6 +90,19 @@ like($version, qr/^ \d+ \. \d+ \. \d+ /x, "Got BaseVersion '$version' from iocsh"); +# Client Tests + +my $client = EPICS::IOC->new; +$client->debug($debug); + +sub close_client { + my $doing = shift; + return sub { + diag("Timeout $doing"); + $client->close; + } +} + # Channel Access SKIP: { @@ -104,10 +120,16 @@ SKIP: { # CA Client test watchdog { - my $caVersion = `$caget -w5 $pv`; + $client->start($caget, '-w5', $pv); + my $caVersion = $client->_getline; like($caVersion, qr/^ $pv \s+ \Q$version\E $/x, 'Got same BaseVersion from caget'); - } 10, kill_bail('doing caget'); + my @errors = $client->_geterrors; + note("Errors from caget:\n", + map(" $_\n", @errors)) + if scalar @errors; + $client->close; + } 15, close_client('doing caget'); } @@ -131,10 +153,16 @@ SKIP: { # PVA Client test watchdog { - my $pvaVersion = `$pvget -w5 $pv`; + $client->start($pvget, '-w5', $pv); + my $pvaVersion = $client->_getline; like($pvaVersion, qr/^ $pv \s .* \Q$version\E \s* $/x, 'Got same BaseVersion from pvget'); - } 10, kill_bail('doing pvget'); + my @errors = $client->_geterrors; + note("Errors from pvget:\n", + map(" $_\n", @errors)) + if scalar @errors; + $client->close; + } 10, close_client('doing pvget'); } -$ioc->kill; +$ioc->exit; diff --git a/modules/database/test/tools/Makefile b/modules/database/test/tools/Makefile index ac7f42071..2dd045e8e 100644 --- a/modules/database/test/tools/Makefile +++ b/modules/database/test/tools/Makefile @@ -5,7 +5,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../.. +TOP = ../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/test/tools/Menu.plt b/modules/database/test/tools/Menu.plt index 3d4f3f951..7cc178257 100644 --- a/modules/database/test/tools/Menu.plt +++ b/modules/database/test/tools/Menu.plt @@ -24,9 +24,11 @@ ok !$menu->legal_choice('Choice 3'), 'Third choice not legal'; is_deeply $menu->choice(2), undef, 'Third choice undefined'; like $menu->toDeclaration, qr/ ^ + \s* \# \s* ifndef \s+ test_NUM_CHOICES \s* \n \s* typedef \s+ enum \s+ \{ \s* \n \s* ch1 \s+ \/\* [^*]* \*\/, \s* \n \s* ch2 \s+ \/\* [^*]* \*\/ \s* \n \s* \} \s* test \s* ; \s* \n \s* \# \s* define \s+ test_NUM_CHOICES \s+ 2 \s* \n + \s* \# \s* endif \s* \n \s* $ /x, 'C declaration'; diff --git a/modules/libcom/.ci/travis-build.sh b/modules/libcom/.ci/travis-build.sh deleted file mode 100755 index 622979b9d..000000000 --- a/modules/libcom/.ci/travis-build.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -x - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 $EXTRA - -if [ "$TEST" != "NO" ] -then - make -j2 tapfiles - make -s test-results -fi diff --git a/modules/libcom/.ci/travis-prepare.sh b/modules/libcom/.ci/travis-prepare.sh deleted file mode 100755 index 9a4d23772..000000000 --- a/modules/libcom/.ci/travis-prepare.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/sh -set -e -x - -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/RELEASE.local -EPICS_BASE=$HOME/.source/epics-base -EOF - -install -d "$HOME/.source" -cd "$HOME/.source" - -git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base -(cd epics-base && git log -n1 ) - -EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch` - -# requires wine and g++-mingw-w64-i686 -if [ "$WINE" = "32" ] -then - echo "Cross mingw32" - sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw - cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw -CMPLR_PREFIX=i686-w64-mingw32- -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw -EOF -fi - -if [ "$STATIC" = "YES" ] -then - echo "Build static libraries/executables" - cat << EOF >> epics-base/configure/CONFIG_SITE -SHARED_LIBRARIES=NO -STATIC_BUILD=YES -EOF -fi - -case "$CMPLR" in -clang) - echo "Host compiler is clang" - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH -GNU = NO -CMPLR_CLASS = clang -CC = clang -CCC = clang++ -EOF - - # hack - sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon - - clang --version - ;; -*) - echo "Host compiler is default" - gcc --version - ;; -esac - -cat <> epics-base/configure/CONFIG_SITE -USR_CPPFLAGS += $USR_CPPFLAGS -USR_CFLAGS += $USR_CFLAGS -USR_CXXFLAGS += $USR_CXXFLAGS -EOF - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - echo "Cross RTEMS${RTEMS} for pc386" - install -d /home/travis/.cache - curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \ - | tar -C /home/travis/.cache -xj - - sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS -RTEMS_VERSION=$RTEMS -RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 -EOF - - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 -C epics-base $EXTRA diff --git a/modules/libcom/.travis.yml b/modules/libcom/.travis.yml deleted file mode 100644 index 8b1e2ab3e..000000000 --- a/modules/libcom/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: false -dist: trusty -language: c -compiler: - - gcc -addons: - apt: - packages: - - libreadline6-dev - - libncurses5-dev - - perl - - clang - - g++-mingw-w64-i686 -install: - - ./.ci/travis-prepare.sh -script: - - ./.ci/travis-build.sh -env: - - BRCORE=master - - CMPLR=clang - - USR_CXXFLAGS=-std=c++11 - - CMPLR=clang USR_CXXFLAGS=-std=c++11 - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO diff --git a/modules/libcom/Makefile b/modules/libcom/Makefile index 442a6f7d1..5a03a4348 100644 --- a/modules/libcom/Makefile +++ b/modules/libcom/Makefile @@ -7,11 +7,10 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = . +TOP = ../.. include $(TOP)/configure/CONFIG -DIRS += configure src -src_DEPEND_DIRS = configure +DIRS += src DIRS += RTEMS RTEMS_DEPEND_DIRS = src @@ -22,4 +21,4 @@ vxWorks_DEPEND_DIRS = src DIRS += test test_DEPEND_DIRS = RTEMS vxWorks -include $(TOP)/configure/RULES_TOP +include $(TOP)/configure/RULES_DIRS diff --git a/modules/libcom/RTEMS/Makefile b/modules/libcom/RTEMS/Makefile index 311c25024..b46889db1 100644 --- a/modules/libcom/RTEMS/Makefile +++ b/modules/libcom/RTEMS/Makefile @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG_LIBCOM_VERSION diff --git a/modules/libcom/RTEMS/rtems_config.c b/modules/libcom/RTEMS/rtems_config.c index 147c08b10..796b1049b 100644 --- a/modules/libcom/RTEMS/rtems_config.c +++ b/modules/libcom/RTEMS/rtems_config.c @@ -27,6 +27,7 @@ #endif #define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30) +#define CONFIGURE_MAXIMUM_BARRIERS rtems_resource_unlimited(30) #define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500) #define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20) #define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5) diff --git a/modules/libcom/RTEMS/rtems_init.c b/modules/libcom/RTEMS/rtems_init.c index c9194e38f..808aeac9d 100644 --- a/modules/libcom/RTEMS/rtems_init.c +++ b/modules/libcom/RTEMS/rtems_init.c @@ -52,8 +52,6 @@ /* * Prototypes for some functions not in header files */ -void tzset(void); -int fileno(FILE *); int main(int argc, char **argv); static void @@ -103,26 +101,6 @@ LogFatal (const char *msg, ...) delayedPanic (msg); } -/* - * Log RTEMS error and terminate - */ -void -LogRtemsFatal (const char *msg, rtems_status_code sc) -{ - errlogPrintf ("%s: %s\n", msg, rtems_status_text (sc)); - delayedPanic (msg); -} - -/* - * Log network error and terminate - */ -void -LogNetFatal (const char *msg, int err) -{ - errlogPrintf ("%s: %d\n", msg, err); - delayedPanic (msg); -} - void * mustMalloc(int size, const char *msg) { @@ -370,7 +348,7 @@ initialize_remote_filesystem(char **argv, int hasLocalFilesystem) } static -char rtems_etc_hosts[] = "127.0.0.1 localhost\n"; +const char rtems_etc_hosts[] = "127.0.0.1 localhost\n"; /* If it doesn't already exist, create /etc/hosts with an entry for 'localhost' */ static @@ -680,25 +658,11 @@ Init (rtems_task_argument ignored) printf ("***** Can't set time: %s\n", rtems_status_text (sc)); } if (getenv("TZ") == NULL) { - const char *tzp = envGetConfigParamPtr(&EPICS_TIMEZONE); - if (tzp == NULL) { - printf("Warning -- no timezone information available -- times will be displayed as GMT.\n"); - } - else { - char tz[10]; - int minWest, toDst = 0, fromDst = 0; - if(sscanf(tzp, "%9[^:]::%d:%d:%d", tz, &minWest, &toDst, &fromDst) < 2) { - printf("Warning: EPICS_TIMEZONE (%s) unrecognizable -- times will be displayed as GMT.\n", tzp); - } - else { - char posixTzBuf[40]; - char *p = posixTzBuf; - p += sprintf(p, "%cST%d:%.2d", tz[0], minWest/60, minWest%60); - if (toDst != fromDst) - p += sprintf(p, "%cDT", tz[0]); - epicsEnvSet("TZ", posixTzBuf); - } - } + const char *tzp = envGetConfigParamPtr(&EPICS_TZ); + if (!tzp || *tzp) + printf("Warning: No timezone information, times will be displayed in UTC.\n"); + else + epicsEnvSet("TZ", tzp); } tzset(); osdTimeRegister(); diff --git a/modules/libcom/configure/CONFIG b/modules/libcom/configure/CONFIG deleted file mode 100644 index 774ed251c..000000000 --- a/modules/libcom/configure/CONFIG +++ /dev/null @@ -1,44 +0,0 @@ -# CONFIG - Load build configuration data -# -# Do not make changes to this file! - -ifeq ($(strip $(EPICS_HOST_ARCH)),) - $(warning EPICS_HOST_ARCH is not set.) -endif - -# Allow user to override where the build rules come from -RULES = $(EPICS_BASE) - -# RELEASE files point to other application tops -include $(TOP)/configure/RELEASE --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common -ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) -endif - -ifeq ($(strip $(RULES)),) - ifeq ($(strip $(EPICS_BASE)),) - $(warning Build error: EPICS_BASE not set after including RELEASE files.) - else - $(warning Build error: EPICS_BASE set but RULES variable empty.) - endif - $(error Makefiles loaded: $(MAKEFILE_LIST)) - # Die before the include of $(CONFIG)/CONFIG below does -endif - -BUILDING_LIBCOM = DEFINED - -CONFIG = $(RULES)/configure -include $(CONFIG)/CONFIG - -# Override the Base definition: -INSTALL_LOCATION = $(TOP) - -# CONFIG_SITE files contain other build configuration settings -include $(TOP)/configure/CONFIG_SITE --include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common -ifdef T_A - -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) - -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif diff --git a/modules/libcom/configure/CONFIG_LIBCOM_VERSION b/modules/libcom/configure/CONFIG_LIBCOM_VERSION deleted file mode 100644 index f5d91037c..000000000 --- a/modules/libcom/configure/CONFIG_LIBCOM_VERSION +++ /dev/null @@ -1,4 +0,0 @@ -EPICS_LIBCOM_MAJOR_VERSION = 3 -EPICS_LIBCOM_MINOR_VERSION = 17 -EPICS_LIBCOM_MAINTENANCE_VERSION = 5 -EPICS_LIBCOM_DEVELOPMENT_FLAG = 0 diff --git a/modules/libcom/configure/CONFIG_SITE b/modules/libcom/configure/CONFIG_SITE deleted file mode 100644 index d78c7f514..000000000 --- a/modules/libcom/configure/CONFIG_SITE +++ /dev/null @@ -1,42 +0,0 @@ -# CONFIG_SITE - -# Make any application-specific changes to the EPICS build -# configuration variables in this file. -# -# Host/target specific settings can be specified in files named -# CONFIG_SITE.$(EPICS_HOST_ARCH).Common -# CONFIG_SITE.Common.$(T_A) -# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - -# CHECK_RELEASE controls the consistency checking of the support -# applications pointed to by the RELEASE* files. -# Normally CHECK_RELEASE should be set to YES. -# Set CHECK_RELEASE to NO to disable checking completely. -# Set CHECK_RELEASE to WARN to perform consistency checking but -# continue building even if conflicts are found. -CHECK_RELEASE = YES - -# Set this when you only want to compile this application -# for a subset of the cross-compiled target architectures -# that Base is built for. -#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 - -# To install files into a location other than $(TOP) define -# INSTALL_LOCATION here. -#INSTALL_LOCATION= - -# Set this when the IOC and build host use different paths -# to the install location. This may be needed to boot from -# a Microsoft FTP server say, or on some NFS configurations. -#IOCS_APPL_TOP = - -# For application debugging purposes, override the HOST_OPT and/ -# or CROSS_OPT settings from base/configure/CONFIG_SITE -#HOST_OPT = NO -#CROSS_OPT = NO - -# These allow developers to override the CONFIG_SITE variable -# settings without having to modify the configure/CONFIG_SITE -# file itself. --include $(TOP)/../CONFIG_SITE.local --include $(TOP)/configure/CONFIG_SITE.local diff --git a/modules/libcom/configure/Makefile b/modules/libcom/configure/Makefile deleted file mode 100644 index 85a7b5843..000000000 --- a/modules/libcom/configure/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -#************************************************************************* -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -TOP = .. - -include $(TOP)/configure/CONFIG - -TARGETS = $(CONFIG_TARGETS) -CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) - -CFG += CONFIG_LIBCOM_MODULE -CFG += CONFIG_LIBCOM_VERSION - -include $(TOP)/configure/RULES diff --git a/modules/libcom/configure/RELEASE b/modules/libcom/configure/RELEASE deleted file mode 100644 index 819b441e7..000000000 --- a/modules/libcom/configure/RELEASE +++ /dev/null @@ -1,38 +0,0 @@ -# RELEASE - Location of external support modules -# -# IF YOU CHANGE ANY PATHS in this file or make API changes to -# any modules it refers to, you should do a "make rebuild" in -# this application's top level directory. -# -# The EPICS build process does not check dependencies against -# any files from outside the application, so it is safest to -# rebuild it completely if any modules it depends on change. -# -# Host- or target-specific settings can be given in files named -# RELEASE.$(EPICS_HOST_ARCH).Common -# RELEASE.Common.$(T_A) -# RELEASE.$(EPICS_HOST_ARCH).$(T_A) -# -# This file is parsed by both GNUmake and an EPICS Perl script, -# so it may ONLY contain definititions of paths to other support -# modules, variable definitions that are used in module paths, -# and include statements that pull in other RELEASE files. -# Variables may be used before their values have been set. -# Build variables that are NOT used in paths should be set in -# the CONFIG_SITE file. - -# Variables and paths to dependent modules: -#MODULES = /path/to/modules -#MYMODULE = $(MODULES)/my-module - -# If building the EPICS modules individually, set these: -#EPICS_BASE = $(MODULES)/core-7.0.1 - -# Set RULES here if you want to use build rules from elsewhere: -#RULES = $(MODULES)/build-rules - -# These lines allow developers to override these RELEASE settings -# without having to modify this file directly. --include $(TOP)/../RELEASE.local --include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local --include $(TOP)/configure/RELEASE.local diff --git a/modules/libcom/configure/RULES b/modules/libcom/configure/RULES deleted file mode 100644 index 6d56e14e8..000000000 --- a/modules/libcom/configure/RULES +++ /dev/null @@ -1,6 +0,0 @@ -# RULES - -include $(CONFIG)/RULES - -# Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile diff --git a/modules/libcom/configure/RULES_DIRS b/modules/libcom/configure/RULES_DIRS deleted file mode 100644 index 3ba269dcc..000000000 --- a/modules/libcom/configure/RULES_DIRS +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_DIRS -include $(CONFIG)/RULES_DIRS diff --git a/modules/libcom/configure/RULES_TOP b/modules/libcom/configure/RULES_TOP deleted file mode 100644 index 2b8cbc6da..000000000 --- a/modules/libcom/configure/RULES_TOP +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_TOP -include $(CONFIG)/RULES_TOP diff --git a/modules/libcom/src/Makefile b/modules/libcom/src/Makefile index d61b26803..57533bafe 100644 --- a/modules/libcom/src/Makefile +++ b/modules/libcom/src/Makefile @@ -6,15 +6,14 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* +LIBCOM := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +TOP = ../../.. -TOP = .. include $(TOP)/configure/CONFIG # Uncomment this to remove the (benign) valgrind helper stubs #USR_CFLAGS += -DNVALGRIND -LIBCOM = $(TOP)/src - INC += valgrind/valgrind.h INC += libComVersion.h @@ -49,7 +48,7 @@ include $(LIBCOM)/yajl/Makefile # Library to build: LIBRARY=Com -Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32 +Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32 dbghelp Com_RCS = Com.rc diff --git a/modules/libcom/src/as/asLib.h b/modules/libcom/src/as/asLib.h index 261e5ed7d..528ce6ed9 100644 --- a/modules/libcom/src/as/asLib.h +++ b/modules/libcom/src/as/asLib.h @@ -21,6 +21,11 @@ extern "C" { #endif +/* 0 - Use (unverified) client provided host name string. + * 1 - Use actual client IP address. HAG() are resolved to IPs at ACF load time. + */ +epicsShareExtern int asCheckClientIP; + typedef struct asgMember *ASMEMBERPVT; typedef struct asgClient *ASCLIENTPVT; typedef int (*ASINPUTFUNCPTR)(char *buf,int max_size); @@ -165,8 +170,8 @@ typedef struct uag{ } UAG; /*Defs for Host Access Groups*/ typedef struct{ - ELLNODE node; - char *host; + ELLNODE node; + char host[1]; } HAGNAME; typedef struct hag{ ELLNODE node; diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index 3f5713efc..e19b63990 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -15,6 +15,8 @@ #include #define epicsExportSharedSymbols +#include "osiSock.h" +#include "epicsTypes.h" #include "epicsStdio.h" #include "dbDefs.h" #include "epicsThread.h" @@ -27,6 +29,8 @@ #include "postfix.h" #include "asLib.h" +int asCheckClientIP; + static epicsMutexId asLock; #define LOCK epicsMutexMustLock(asLock) #define UNLOCK epicsMutexUnlock(asLock) @@ -75,6 +79,7 @@ static long asAsgRuleCalc(ASGRULE *pasgrule,const char *calc); */ static void asInitializeOnce(void *arg) { + osiSockAttach(); asLock = epicsMutexMustCreate(); } long epicsShareAPI asInitialize(ASINPUTFUNCPTR inputfunction) @@ -1203,14 +1208,38 @@ static HAG *asHagAdd(const char *hagName) static long asHagAddHost(HAG *phag,const char *host) { HAGNAME *phagname; - int len, i; if (!phag) return 0; - len = strlen(host); - phagname = asCalloc(1, sizeof(HAGNAME) + len + 1); - phagname->host = (char *)(phagname + 1); - for (i = 0; i < len; i++) { - phagname->host[i] = (char)tolower((int)host[i]); + if(!asCheckClientIP) { + size_t i, len = strlen(host); + phagname = asCalloc(1, sizeof(*phagname) + len); + for (i = 0; i < len; i++) { + phagname->host[i] = (char)tolower((int)host[i]); + } + + } else { + struct sockaddr_in addr; + epicsUInt32 ip; + + if(aToIPAddr(host, 0, &addr)) { + static const char unresolved[] = "unresolved:"; + + errlogPrintf("ACF: Unable to resolve host '%s'\n", host); + + phagname = asCalloc(1, sizeof(*phagname) + sizeof(unresolved)-1+strlen(host)); + strcpy(phagname->host, unresolved); + strcat(phagname->host, host); + + } else { + ip = ntohl(addr.sin_addr.s_addr); + phagname = asCalloc(1, sizeof(*phagname) + 24); + epicsSnprintf(phagname->host, 24, + "%u.%u.%u.%u", + (ip>>24)&0xff, + (ip>>16)&0xff, + (ip>>8)&0xff, + (ip>>0)&0xff); + } } ellAdd(&phag->list, &phagname->node); return 0; diff --git a/modules/libcom/src/cppStd/Makefile b/modules/libcom/src/cppStd/Makefile index 782c4da25..29f9cfdd4 100644 --- a/modules/libcom/src/cppStd/Makefile +++ b/modules/libcom/src/cppStd/Makefile @@ -9,5 +9,4 @@ SRC_DIRS += $(LIBCOM)/cppStd INC += epicsAlgorithm.h -INC += epicsExcept.h diff --git a/modules/libcom/src/cppStd/epicsExcept.h b/modules/libcom/src/cppStd/epicsExcept.h deleted file mode 100644 index e68999735..000000000 --- a/modules/libcom/src/cppStd/epicsExcept.h +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ -// Author: Andrew Johnson & Jeff Hill -// Date: December 2000 - -#ifndef __EPICS_EXCEPT_H__ -#define __EPICS_EXCEPT_H__ - -#define epicsThrowHere(exc) \ - throw locationException(exc, __FILE__, __LINE__) - -class sourceLocation { -public: // Functions - sourceLocation(const char *fileName, int lineNumber); -// sourceLocation(const sourceLocation&); Copy constructable -// sourceLocation& operator=(const sourceLocation&); Assignable - - const char *fileName() const; - int lineNumber() const; - -private: // Hide compiler-generated member functions - sourceLocation(); // default constructor - -private: // Data - const char *file; - int line; -}; - -template -class locationException : public T, public sourceLocation { -public: - locationException(const T& exc, const char *fileName, int lineNumber); -}; - - -/* Example: - * if (status) epicsThrowHere(std::logic_error("operation failed!")); - * try { ... } catch(sourceLocation& where) { ... } - */ - -// END OF DECLARATIONS - -// INLINE FUNCTIONS - -// sourceFileLocation -inline sourceLocation::sourceLocation (const char *fileName, int lineNumber) : - file(fileName), line(lineNumber) {} - -inline const char* sourceLocation::fileName () const { - return this->file; -} - -inline int sourceLocation::lineNumber () const { - return this->line; -} - -// locationException -template -inline locationException::locationException - (const char *fileName, int lineNumber, const E& exc) : - T(exc), sourceLocation(fileName, lineNumber) {} - - -#endif // __EPICS_EXCEPT_H__ diff --git a/modules/libcom/src/env/Makefile b/modules/libcom/src/env/Makefile index 804426bc0..94322a228 100644 --- a/modules/libcom/src/env/Makefile +++ b/modules/libcom/src/env/Makefile @@ -12,7 +12,6 @@ SRC_DIRS += $(LIBCOM)/env vpath %.pl $(USR_VPATH) $(SRC_DIRS) PERL_SCRIPTS += bldEnvData.pl -PERL_SCRIPTS += libcomModuleDirs.pm INC += envDefs.h diff --git a/modules/libcom/src/env/RULES b/modules/libcom/src/env/RULES index 02df6aa7a..5ef766d57 100644 --- a/modules/libcom/src/env/RULES +++ b/modules/libcom/src/env/RULES @@ -8,7 +8,7 @@ # This is a Makefile fragment, see src/libCom/Makefile. envData.c: $(LIBCOM)/env/envDefs.h \ - $(INSTALL_HOST_BIN)/bldEnvData.pl $(INSTALL_HOST_BIN)/libcomModuleDirs.pm \ + $(INSTALL_HOST_BIN)/bldEnvData.pl \ $(CONFIG)/CONFIG_ENV $(CONFIG)/CONFIG_SITE_ENV \ $(wildcard $(CONFIG)/os/CONFIG_SITE_ENV.$(T_A)) $(PERL) $(INSTALL_HOST_BIN)/bldEnvData.pl $(QUIET_FLAG) -t $(T_A) \ diff --git a/modules/libcom/src/env/bldEnvData.pl b/modules/libcom/src/env/bldEnvData.pl index e3c21b772..693be65da 100644 --- a/modules/libcom/src/env/bldEnvData.pl +++ b/modules/libcom/src/env/bldEnvData.pl @@ -14,9 +14,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); -use libcomModuleDirs; -no lib $Bin; +use lib ("$Bin/../../lib/perl"); use Getopt::Std; use File::Basename; diff --git a/modules/libcom/src/env/envDefs.h b/modules/libcom/src/env/envDefs.h index 8be00a9ea..2490702a6 100644 --- a/modules/libcom/src/env/envDefs.h +++ b/modules/libcom/src/env/envDefs.h @@ -63,7 +63,7 @@ epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PORT; epicsShareExtern const ENV_PARAM EPICS_BUILD_COMPILER_CLASS; epicsShareExtern const ENV_PARAM EPICS_BUILD_OS_CLASS; epicsShareExtern const ENV_PARAM EPICS_BUILD_TARGET_ARCH; -epicsShareExtern const ENV_PARAM EPICS_TIMEZONE; +epicsShareExtern const ENV_PARAM EPICS_TZ; epicsShareExtern const ENV_PARAM EPICS_TS_NTP_INET; epicsShareExtern const ENV_PARAM EPICS_IOC_IGNORE_SERVERS; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_PORT; @@ -71,8 +71,6 @@ epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_INET; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_LIMIT; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_NAME; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_COMMAND; -epicsShareExtern const ENV_PARAM EPICS_CMD_PROTO_PORT; -epicsShareExtern const ENV_PARAM EPICS_AR_PORT; epicsShareExtern const ENV_PARAM IOCSH_PS1; epicsShareExtern const ENV_PARAM IOCSH_HISTSIZE; epicsShareExtern const ENV_PARAM IOCSH_HISTEDIT_DISABLE; diff --git a/modules/libcom/src/error/errSymLib.c b/modules/libcom/src/error/errSymLib.c index b220f2bc0..8f59718c8 100644 --- a/modules/libcom/src/error/errSymLib.c +++ b/modules/libcom/src/error/errSymLib.c @@ -192,7 +192,7 @@ void errSymLookup(long status, char * pBuf, size_t bufLength) { const char* msg = errSymLookupInternal(status); if(msg) { - strncpy(pBuf, msg, bufLength); + strncpy(pBuf, msg, bufLength-1); pBuf[bufLength-1] = '\0'; return; } diff --git a/modules/libcom/src/fdmgr/fdManager.cpp b/modules/libcom/src/fdmgr/fdManager.cpp index 00f4d4a87..3bbc64876 100644 --- a/modules/libcom/src/fdmgr/fdManager.cpp +++ b/modules/libcom/src/fdmgr/fdManager.cpp @@ -97,7 +97,7 @@ epicsShareFunc void fdManager::process (double delay) // more than once here so that fd activity get serviced // in a reasonable length of time. // - double minDelay = this->pTimerQueue->process(epicsTime::getCurrent()); + double minDelay = this->pTimerQueue->process(epicsTime::getMonotonic()); if ( minDelay >= delay ) { minDelay = delay; @@ -121,7 +121,7 @@ epicsShareFunc void fdManager::process (double delay) fd_set * pExceptSet = & this->fdSetsPtr[fdrException]; int status = select (this->maxFD, pReadSet, pWriteSet, pExceptSet, &tv); - this->pTimerQueue->process(epicsTime::getCurrent()); + this->pTimerQueue->process(epicsTime::getMonotonic()); if ( status > 0 ) { @@ -204,7 +204,7 @@ epicsShareFunc void fdManager::process (double delay) * of select() */ epicsThreadSleep(minDelay); - this->pTimerQueue->process(epicsTime::getCurrent()); + this->pTimerQueue->process(epicsTime::getMonotonic()); } this->processInProg = false; return; @@ -249,7 +249,7 @@ void fdRegId::show ( unsigned level ) const static_cast ( this ) ); if ( level > 1u ) { printf ( "\tfd = %d, type = %d\n", - this->fd, this->type ); + int(this->fd), this->type ); } } diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 0de90c87a..8e4d365f9 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -11,6 +11,8 @@ /* Heavily modified by Eric Norum Date: 03MAY2000 */ /* Adapted to C++ by Eric Norum Date: 18DEC2000 */ +#include + #include #include #include @@ -18,6 +20,7 @@ #include #define epicsExportSharedSymbols +#include "epicsMath.h" #include "errlog.h" #include "macLib.h" #include "epicsStdio.h" @@ -56,7 +59,7 @@ static char iocshVarID[] = "iocshVar"; extern "C" { static void varCallFunc(const iocshArgBuf *); } static epicsMutexId iocshTableMutex; static epicsThreadOnceId iocshOnceId = EPICS_THREAD_ONCE_INIT; -static epicsThreadPrivateId iocshMacroHandleId; +static epicsThreadPrivateId iocshContextId; /* * I/O redirection @@ -76,7 +79,7 @@ struct iocshRedirect { static void iocshOnce (void *) { iocshTableMutex = epicsMutexMustCreate (); - iocshMacroHandleId = epicsThreadPrivateCreate(); + iocshContextId = epicsThreadPrivateCreate(); } static void iocshInit (void) @@ -220,7 +223,7 @@ void epicsShareAPI iocshRegisterVariable (const iocshVarDef *piocshVarDef) const iocshVarDef * epicsShareAPI iocshFindVariable(const char *name) { struct iocshVariable *temp = (iocshVariable *) registryFind(iocshVarID, name); - return temp->pVarDef; + return temp ? temp->pVarDef : 0; } /* @@ -496,6 +499,39 @@ static void helpCallFunc(const iocshArgBuf *args) } } +typedef enum { + Continue, + Break, + Halt +} OnError; + +// per call to iocshBody() +struct iocshScope { + iocshScope *outer; + OnError onerr; + double timeout; + bool errored; + bool interactive; + iocshScope() :outer(0), onerr(Continue), timeout(0.0), errored(false), interactive(false) {} +}; + +// per thread executing iocshBody() +struct iocshContext { + MAC_HANDLE *handle; + iocshScope *scope; +}; + +int iocshSetError(int err) +{ + iocshContext *ctxt; + if (err && iocshContextId) { + ctxt = (iocshContext *) epicsThreadPrivateGet(iocshContextId); + + if(ctxt && ctxt->scope) ctxt->scope->errored = 1; + } + return err; +} + /* * The body of the command interpreter */ @@ -524,8 +560,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) void *readlineContext = NULL; int wasOkToBlock; static const char * pairs[] = {"", "environ", NULL, NULL}; - MAC_HANDLE *handle; + iocshScope scope; + iocshContext *context; char ** defines = NULL; + int ret = 0; iocshInit(); @@ -534,8 +572,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) */ if (commandLine == NULL) { if ((pathname == NULL) || (strcmp (pathname, "") == 0)) { - if ((prompt = envGetConfigParamPtr(&IOCSH_PS1)) == NULL) + if ((prompt = envGetConfigParamPtr(&IOCSH_PS1)) == NULL) { prompt = "epics> "; + } + scope.interactive = true; } else { fp = fopen (pathname, "r"); @@ -560,6 +600,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) fclose(fp); return -1; } + + } else { + // use of iocshCmd() implies "on error break" + scope.onerr = Break; } /* @@ -583,21 +627,25 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } } - /* - * Check for existing macro context or construct a new one. - */ - handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); - - if (handle == NULL) { - if (macCreateHandle(&handle, pairs)) { + // Check for existing context or construct a new one. + context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); + + if (!context) { + context = (iocshContext*)calloc(1, sizeof(*context)); + if (!context || macCreateHandle(&context->handle, pairs)) { errlogMessage("iocsh: macCreateHandle failed."); free(redirects); + free(context); return -1; } - epicsThreadPrivateSet(iocshMacroHandleId, (void *) handle); + epicsThreadPrivateSet(iocshContextId, (void *) context); } - + MAC_HANDLE *handle = context->handle; + + scope.outer = context->scope; + context->scope = &scope; + macPushScope(handle); macInstallMacros(handle, defines); @@ -608,6 +656,29 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Read commands till EOF or exit */ for (;;) { + if(!scope.interactive && scope.errored) { + if(scope.onerr==Continue) { + /* do nothing */ + + } else if(scope.onerr==Break) { + ret = -1; + fprintf(epicsGetStderr(), "iocsh Error: Break\n" ); + break; + + } else if(scope.onerr==Halt) { + ret = -1; + if(scope.timeout<=0.0 || isinf(scope.timeout)) { + fprintf(epicsGetStderr(), "iocsh Error: Halt\n" ); + epicsThreadSuspendSelf(); + break; + + } else { + fprintf(epicsGetStderr(), "iocsh Error: Waiting %.1f sec ...\n", scope.timeout); + epicsThreadSleep(scope.timeout); + } + } + } + /* * Read a line */ @@ -646,8 +717,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Expand macros */ free(line); - if ((line = macDefExpand(raw, handle)) == NULL) + if ((line = macDefExpand(raw, handle)) == NULL) { + scope.errored = true; continue; + } /* * Skip leading white-space coming from a macro @@ -660,9 +733,11 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Echo non-empty lines read from a script. * Comments delineated with '#-' aren't echoed. */ - if ((prompt == NULL) && *line && (commandLine == NULL)) - if ((c != '#') || (line[icin + 1] != '-')) + if ((prompt == NULL) && *line && (commandLine == NULL)) { + if ((c != '#') || (line[icin + 1] != '-')) { puts(line); + } + } /* * Ignore lines that became a comment or empty after macro expansion @@ -686,6 +761,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (newv == NULL) { fprintf (epicsGetStderr(), "Out of memory!\n"); argc = -1; + scope.errored = true; break; } argv = newv; @@ -759,8 +835,9 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } else { if (!sep) { - if (((c == '"') || (c == '\'')) && !backslash) + if (((c == '"') || (c == '\'')) && !backslash) { quote = c; + } if (redirect != NULL) { if (redirect->name != NULL) { argc = -1; @@ -781,16 +858,20 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } if (redirect != NULL) { showError(filename, lineno, "Illegal redirection."); + scope.errored = true; continue; } - if (argc < 0) + if (argc < 0) { break; + } if (quote != EOF) { showError(filename, lineno, "Unbalanced quote."); + scope.errored = true; continue; } if (backslash) { showError(filename, lineno, "Trailing backslash."); + scope.errored = true; continue; } if (inword) @@ -807,7 +888,8 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (openRedirect(filename, lineno, redirects) < 0) continue; startRedirect(filename, lineno, redirects); - iocshBody(commandFile, NULL, macros); + if(iocshBody(commandFile, NULL, macros)) + scope.errored = true; stopRedirect(filename, lineno, redirects); continue; } @@ -822,6 +904,9 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Set up redirection */ if ((openRedirect(filename, lineno, redirects) == 0) && (argc > 0)) { + // error unless a function is actually called. + // handles command not-found and arg parsing errors. + scope.errored = true; /* * Look up command */ @@ -834,7 +919,17 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) for (int iarg = 0 ; ; ) { if (iarg == piocshFuncDef->nargs) { startRedirect(filename, lineno, redirects); - (*found->def.func)(argBuf); + /* execute */ + scope.errored = false; + try { + (*found->def.func)(argBuf); + } catch(std::exception& e){ + fprintf(epicsGetStderr(), "c++ error: %s\n", e.what()); + scope.errored = true; + } catch(...) { + fprintf(epicsGetStderr(), "c++ error unknown\n"); + scope.errored = true; + } break; } if (iarg >= argBufCapacity) { @@ -874,9 +969,12 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } macPopScope(handle); - if (handle->level == 0) { + if (!scope.outer) { macDeleteHandle(handle); - epicsThreadPrivateSet(iocshMacroHandleId, NULL); + free(context); + epicsThreadPrivateSet(iocshContextId, NULL); + } else { + context->scope = scope.outer; } if (fp && (fp != stdin)) fclose (fp); @@ -891,7 +989,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (readlineContext) epicsReadlineEnd(readlineContext); epicsThreadSetOkToBlock(wasOkToBlock); - return 0; + return ret; } /* @@ -943,13 +1041,13 @@ iocshRun(const char *cmd, const char *macros) void epicsShareAPI iocshEnvClear(const char *name) { - MAC_HANDLE *handle; + iocshContext *context; - if (iocshMacroHandleId) { - handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); + if (iocshContextId) { + context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); - if (handle != NULL) { - macPutValue(handle, name, NULL); + if (context != NULL) { + macPutValue(context->handle, name, NULL); } } } @@ -1054,6 +1152,59 @@ static void iocshRunCallFunc(const iocshArgBuf *args) iocshRun(args[0].sval, args[1].sval); } +/* on */ +static const iocshArg onArg0 = { "'error' 'continue' | 'break' | 'wait' [value] | 'halt'", iocshArgArgv }; +static const iocshArg *onArgs[1] = {&onArg0}; +static const iocshFuncDef onFuncDef = {"on", 1, onArgs}; +static void onCallFunc(const iocshArgBuf *args) +{ + iocshContext *context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); + +#define USAGE() fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n") + + if(!context || !context->scope) { + // we are not called through iocshBody()... + + } else if(args->aval.ac<3 || strcmp(args->aval.av[1], "error")!=0) { + USAGE(); + + } else if(context->scope->interactive) { + fprintf(epicsGetStderr(), "Interactive shell ignores on error ...\n"); + + } else { + // don't fault on previous, ignored, errors + context->scope->errored = false; + + if(strcmp(args->aval.av[2], "continue")==0) { + context->scope->onerr = Continue; + + } else if(strcmp(args->aval.av[2], "break")==0) { + context->scope->onerr = Break; + + } else if(strcmp(args->aval.av[2], "halt")==0) { + context->scope->onerr = Halt; + context->scope->timeout = 0.0; + + } else if(strcmp(args->aval.av[2], "wait")==0) { + context->scope->onerr = Halt; + if(args->aval.ac<=3) { + USAGE(); + } else if(epicsParseDouble(args->aval.av[3], &context->scope->timeout, NULL)) { + context->scope->timeout = 5.0; + } else { + USAGE(); + fprintf(epicsGetStderr(), "Unable to parse 'on error wait' time %s\n", args->aval.av[3]); + } + + } else { + fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n"); + context->scope->errored = true; + } + } + +#undef USAGE +} + /* * Dummy internal commands -- register and install in command table * so they show up in the help display @@ -1083,6 +1234,7 @@ static void localRegister (void) iocshRegister(&iocshCmdFuncDef,iocshCmdCallFunc); iocshRegister(&iocshLoadFuncDef,iocshLoadCallFunc); iocshRegister(&iocshRunFuncDef,iocshRunCallFunc); + iocshRegister(&onFuncDef, onCallFunc); } } /* extern "C" */ diff --git a/modules/libcom/src/iocsh/iocsh.h b/modules/libcom/src/iocsh/iocsh.h index 84b38f224..a63af64ce 100644 --- a/modules/libcom/src/iocsh/iocsh.h +++ b/modules/libcom/src/iocsh/iocsh.h @@ -76,7 +76,7 @@ epicsShareFunc void epicsShareAPI iocshRegister( epicsShareFunc void epicsShareAPI iocshRegisterVariable ( const iocshVarDef *piocshVarDef); epicsShareFunc const iocshCmdDef * epicsShareAPI iocshFindCommand( - const char* name); + const char* name) EPICS_DEPRECATED; epicsShareFunc const iocshVarDef * epicsShareAPI iocshFindVariable( const char* name); @@ -84,11 +84,30 @@ epicsShareFunc const iocshVarDef * epicsShareAPI iocshFindVariable( /* This should only be called when iocsh is no longer needed*/ epicsShareFunc void epicsShareAPI iocshFree(void); +/** shorthand for @code iocshLoad(pathname, NULL) @endcode */ epicsShareFunc int epicsShareAPI iocsh(const char *pathname); +/** shorthand for @code iocshRun(cmd, NULL) @endcode */ epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd); +/** Read and evaluate IOC shell commands from the given file. + * @param pathname Path to script file + * @param macros NULL or a comma seperated list of macro definitions. eg. "VAR1=x,VAR2=y" + * @return 0 on success, non-zero on error + */ epicsShareFunc int epicsShareAPI iocshLoad(const char *pathname, const char* macros); +/** Evaluate a single IOC shell command + * @param cmd Command string. eg. "echo \"something or other\"" + * @param macros NULL or a comma seperated list of macro definitions. eg. "VAR1=x,VAR2=y" + * @return 0 on success, non-zero on error + */ epicsShareFunc int epicsShareAPI iocshRun(const char *cmd, const char* macros); +/** @brief Signal error from an IOC shell function. + * + * @param err 0 - success (no op), !=0 - error + * @return The err argument value. + */ +epicsShareFunc int iocshSetError(int err); + /* Makes macros that shadow environment variables work correctly with epicsEnvSet */ epicsShareFunc void epicsShareAPI iocshEnvClear(const char *name); diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index b105ea12f..c67804aef 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -12,6 +12,7 @@ #define epicsExportSharedSymbols #include "iocsh.h" +#include "asLib.h" #include "epicsStdioRedirect.h" #include "epicsString.h" #include "epicsTime.h" @@ -76,7 +77,7 @@ static const iocshFuncDef chdirFuncDef = {"cd",1,chdirArgs}; static void chdirCallFunc(const iocshArgBuf *args) { if (args[0].sval == NULL || - chdir(args[0].sval)) { + iocshSetError(chdir(args[0].sval))) { fprintf(stderr, "Invalid directory path, ignored\n"); } } @@ -393,6 +394,8 @@ static void installLastResortEventProviderCallFunc(const iocshArgBuf *args) installLastResortEventProvider(); } +static iocshVarDef asCheckClientIPDef[] = { { "asCheckClientIP", iocshArgInt, 0 }, { NULL, iocshArgInt, NULL } }; + void epicsShareAPI libComRegister(void) { iocshRegister(&dateFuncDef, dateCallFunc); @@ -425,4 +428,7 @@ void epicsShareAPI libComRegister(void) iocshRegister(&generalTimeReportFuncDef,generalTimeReportCallFunc); iocshRegister(&installLastResortEventProviderFuncDef, installLastResortEventProviderCallFunc); + + asCheckClientIPDef[0].pval = &asCheckClientIP; + iocshRegisterVariable(asCheckClientIPDef); } diff --git a/modules/libcom/src/log/Makefile b/modules/libcom/src/log/Makefile index 7d7a6b620..2dcfbc516 100644 --- a/modules/libcom/src/log/Makefile +++ b/modules/libcom/src/log/Makefile @@ -19,7 +19,7 @@ iocLogServer_SRCS = iocLogServer.c iocLogServer_LIBS = Com iocLogServer_SYS_LIBS_solaris += socket -iocLogServer_SYS_LIBS_WIN32 += user32 ws2_32 +iocLogServer_SYS_LIBS_WIN32 += user32 ws2_32 dbghelp SCRIPTS_HOST = S99logServer diff --git a/modules/libcom/src/log/iocLog.c b/modules/libcom/src/log/iocLog.c index 8cb1349a1..ba78041c8 100644 --- a/modules/libcom/src/log/iocLog.c +++ b/modules/libcom/src/log/iocLog.c @@ -77,7 +77,17 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void) } /* - * logClientDestroy() + * logClientSendMessage () + */ +static void logClientSendMessage ( logClientId id, const char * message ) +{ + if ( !iocLogDisable ) { + logClientSend (id, message); + } +} + +/* + * iocLogClientDestroy() */ static void iocLogClientDestroy (logClientId id) { @@ -149,3 +159,4 @@ logClientId epicsShareAPI logClientInit (void) { return iocLogClientInit (); } + diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 692ac3105..44883e3ed 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -21,6 +21,7 @@ #include #include +#define EPICS_PRIVATE_API #define epicsExportSharedSymbols #include "dbDefs.h" #include "epicsEvent.h" @@ -32,9 +33,13 @@ #include "epicsAssert.h" #include "epicsExit.h" #include "epicsSignal.h" +#include "epicsExport.h" #include "logClient.h" +int logClientDebug = 0; +epicsExportAddress (int, logClientDebug); + typedef struct { char msgBuf[0x4000]; struct sockaddr_in addr; @@ -46,6 +51,7 @@ typedef struct { epicsEventId shutdownNotify; unsigned connectCount; unsigned nextMsgIndex; + unsigned backlog; unsigned connected; unsigned shutdown; unsigned shutdownConfirm; @@ -65,10 +71,10 @@ static char* logClientPrefix = NULL; */ static void logClientClose ( logClient *pClient ) { -# ifdef DEBUG + if (logClientDebug) { fprintf (stderr, "log client: lingering for connection close..."); fflush (stderr); -# endif + } /* * mutex on @@ -90,9 +96,8 @@ static void logClientClose ( logClient *pClient ) */ epicsMutexUnlock (pClient->mutex); -# ifdef DEBUG + if (logClientDebug) fprintf (stderr, "done\n"); -# endif } /* @@ -161,31 +166,6 @@ static void logClientDestroy (logClientId id) free ( pClient ); } -/* - * logClientCheckConnection - */ -static void logClientCheckConnection( logClient * pClient ) -{ - epicsMutexMustLock ( pClient->mutex ); - while ( pClient->connected ) { - struct timeval timeout = { 0, 0 }; - fd_set set; - char buffer[256]; - - FD_ZERO ( &set ); - FD_SET ( pClient->sock, &set ); - if ( select ( pClient->sock + 1, &set, NULL, NULL, &timeout ) == 0) - break; - if ( recv ( pClient->sock, buffer, sizeof ( buffer ), 0 ) == 0 ) { - fprintf ( stderr, "log client: connection closed by server \"%s\"\n", - pClient->name ); - logClientClose ( pClient ); - break; - } - } - epicsMutexUnlock ( pClient->mutex ); -} - /* * This method requires the pClient->mutex be owned already. */ @@ -200,7 +180,6 @@ static void sendMessageChunk(logClient * pClient, const char * message) { if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected) { /* buffer is full, thus flush it */ - logClientCheckConnection( pClient ); logClientFlush ( pClient ); msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex; } @@ -218,7 +197,6 @@ static void sendMessageChunk(logClient * pClient, const char * message) { } } - /* * logClientSend () */ @@ -243,7 +221,8 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message ) void epicsShareAPI logClientFlush ( logClientId id ) { - unsigned nSent = 0u; + unsigned nSent; + int status = 0; logClient * pClient = ( logClient * ) id; @@ -253,32 +232,44 @@ void epicsShareAPI logClientFlush ( logClientId id ) epicsMutexMustLock ( pClient->mutex ); + nSent = pClient->backlog; while ( nSent < pClient->nextMsgIndex && pClient->connected ) { - int status = send ( pClient->sock, pClient->msgBuf + nSent, + status = send ( pClient->sock, pClient->msgBuf + nSent, pClient->nextMsgIndex - nSent, 0 ); - if ( status > 0 ) { - nSent += (unsigned) status; - } - else { - if ( ! pClient->shutdown ) { - char sockErrBuf[64]; - if ( status ) { - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - } - else { - strcpy ( sockErrBuf, "server initiated disconnect" ); - } - fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n", - pClient->name, sockErrBuf ); - } - logClientClose ( pClient ); - break; - } + if ( status < 0 ) break; + nSent += status; } - pClient->nextMsgIndex -= nSent; - if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { - memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], - pClient->nextMsgIndex ); + + if ( pClient->backlog > 0 && status >= 0 ) + { + /* On Linux send 0 bytes can detect EPIPE */ + /* NOOP on Windows, fails on vxWorks */ + errno = 0; + status = send ( pClient->sock, NULL, 0, 0 ); + if (!(errno == SOCK_ECONNRESET || errno == SOCK_EPIPE)) status = 0; + } + + if ( status < 0 ) { + if ( ! pClient->shutdown ) { + char sockErrBuf[128]; + epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); + fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n", + pClient->name, sockErrBuf ); + } + pClient->backlog = 0; + logClientClose ( pClient ); + } + else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { + int backlog = epicsSocketUnsentCount ( pClient->sock ); + if (backlog >= 0) { + pClient->backlog = backlog; + nSent -= backlog; + } + pClient->nextMsgIndex -= nSent; + if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { + memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], + pClient->nextMsgIndex ); + } } epicsMutexUnlock ( pClient->mutex ); } @@ -288,10 +279,10 @@ void epicsShareAPI logClientFlush ( logClientId id ) */ static void logClientMakeSock (logClient *pClient) { - -# ifdef DEBUG + if (logClientDebug) { fprintf (stderr, "log client: creating socket..."); -# endif + fflush (stderr); + } epicsMutexMustLock (pClient->mutex); @@ -300,7 +291,7 @@ static void logClientMakeSock (logClient *pClient) */ pClient->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, 0 ); if ( pClient->sock == INVALID_SOCKET ) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf ( stderr, "log client: no socket error %s\n", @@ -309,10 +300,8 @@ static void logClientMakeSock (logClient *pClient) epicsMutexUnlock (pClient->mutex); -# ifdef DEBUG + if (logClientDebug) fprintf (stderr, "done\n"); -# endif - } /* @@ -352,7 +341,7 @@ static void logClientConnect (logClient *pClient) } else { if ( pClient->connFailStatus != errnoCpy && ! pClient->shutdown ) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, @@ -378,12 +367,26 @@ static void logClientConnect (logClient *pClient) optval = TRUE; status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)); if (status<0) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf); } + /* + * we don't need full-duplex (clients only write), so we shutdown + * the read end of our socket + */ + status = shutdown (pClient->sock, SHUT_RD); + if (status < 0) { + char sockErrBuf[128]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + fprintf (stderr, "%s:%d shutdown(sock,SHUT_RD) error was \"%s\"\n", + __FILE__, __LINE__, sockErrBuf); + /* not fatal (although it shouldn't happen) */ + } + /* * set how long we will wait for the TCP state machine * to clean up when we issue a close(). This @@ -397,7 +400,7 @@ static void logClientConnect (logClient *pClient) lingerval.l_linger = 60*5; status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER, (char *) &lingerval, sizeof(lingerval)); if (status<0) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, "log client: unable to set linger options because \"%s\"\n", sockErrBuf); @@ -423,19 +426,14 @@ static void logClientRestart ( logClientId id ) /* SMP safe state inspection */ epicsMutexMustLock ( pClient->mutex ); while ( ! pClient->shutdown ) { - unsigned isConn, dataToSend; - - logClientCheckConnection( pClient ); + unsigned isConn; isConn = pClient->connected; - dataToSend = pClient->nextMsgIndex; epicsMutexUnlock ( pClient->mutex ); - if ( dataToSend ) { - if ( ! isConn ) logClientConnect ( pClient ); - logClientFlush ( pClient ); - } + if ( ! isConn ) logClientConnect ( pClient ); + logClientFlush ( pClient ); epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY); @@ -524,24 +522,21 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level) printf ("log client: disconnected from log server at \"%s\"\n", pClient->name); } - if (level>1) { - printf ("log client: sock=%s, connect cycles = %u\n", - pClient->sock==INVALID_SOCKET?"INVALID":"OK", - pClient->connectCount); - } - if (logClientPrefix) { printf ("log client: prefix is \"%s\"\n", logClientPrefix); } -} -/* - * logClientSendMessage (); deprecated - */ -void logClientSendMessage ( logClientId id, const char * message ) -{ - if ( !iocLogDisable ) { - logClientSend (id, message); + if (level>0) { + printf ("log client: sock %s, connect cycles = %u\n", + pClient->sock==INVALID_SOCKET?"INVALID":"OK", + pClient->connectCount); + } + if (level>1) { + printf ("log client: %u bytes in buffer\n", pClient->nextMsgIndex); + if (pClient->nextMsgIndex) + printf("-------------------------\n" + "%.*s-------------------------\n", + (int)(pClient->nextMsgIndex), pClient->msgBuf); } } diff --git a/modules/libcom/src/log/logClient.h b/modules/libcom/src/log/logClient.h index 1797bbb20..3b3f63add 100644 --- a/modules/libcom/src/log/logClient.h +++ b/modules/libcom/src/log/logClient.h @@ -38,7 +38,6 @@ epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix); /* deprecated interface; retained for backward compatibility */ /* note: implementations are in iocLog.c, not logClient.c */ epicsShareFunc logClientId epicsShareAPI logClientInit (void); -epicsShareFunc void logClientSendMessage (logClientId id, const char *message); #ifdef __cplusplus } diff --git a/modules/libcom/src/misc/epicsUnitTest.c b/modules/libcom/src/misc/epicsUnitTest.c index 4ac18ea1c..dce05983e 100644 --- a/modules/libcom/src/misc/epicsUnitTest.c +++ b/modules/libcom/src/misc/epicsUnitTest.c @@ -16,6 +16,10 @@ #include #include +#ifdef _WIN32 +# include +#endif + #define epicsExportSharedSymbols #include "epicsThread.h" #include "epicsMutex.h" @@ -25,6 +29,7 @@ #include "ellLib.h" #include "errlog.h" #include "cantProceed.h" +#include "epicsStackTrace.h" typedef struct { ELLNODE node; @@ -54,9 +59,44 @@ const char *testing = NULL; static epicsThreadOnceId onceFlag = EPICS_THREAD_ONCE_INIT; +#ifdef _WIN32 +/* + * if we return FALSE, _CrtDbgReport is called to print to file etc + * if we return TRUE, we are the only function called + */ +static int testReportHook(int reportType, char *message, int *returnValue) +{ + int nRet = 0; + switch (reportType) + { + case _CRT_ASSERT: + case _CRT_ERROR: + epicsStackTrace(); + break; + + default: + break; + } + if (returnValue) + { + *returnValue = 0; + } + return nRet; +} +#endif + static void testOnce(void *dummy) { testLock = epicsMutexMustCreate(); perlHarness = (getenv("HARNESS_ACTIVE") != NULL); +#ifdef _WIN32 + _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE |_CRTDBG_MODE_DEBUG ); + _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR ); + _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE |_CRTDBG_MODE_DEBUG ); + _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR ); + _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE |_CRTDBG_MODE_DEBUG ); + _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR ); + _CrtSetReportHook2( _CRT_RPTHOOK_INSTALL, testReportHook ); +#endif } void testPlan(int plan) { diff --git a/modules/libcom/src/misc/unixFileName.h b/modules/libcom/src/misc/unixFileName.h index 36e818c8f..9d7af252c 100644 --- a/modules/libcom/src/misc/unixFileName.h +++ b/modules/libcom/src/misc/unixFileName.h @@ -14,7 +14,29 @@ #ifndef unixFileNameH #define unixFileNameH +#include + +#ifdef __cplusplus +extern "C" { +#endif + #define OSI_PATH_LIST_SEPARATOR ":" #define OSI_PATH_SEPARATOR "/" +/** Return the absolute path of the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecName(void); + +/** Return the absolute path of the directory containing the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecDir(void); + +#ifdef __cplusplus +} +#endif + #endif /* unixFileNameH */ diff --git a/modules/libcom/src/osi/Makefile b/modules/libcom/src/osi/Makefile index ecbf4c23b..10eb98be0 100644 --- a/modules/libcom/src/osi/Makefile +++ b/modules/libcom/src/osi/Makefile @@ -77,7 +77,7 @@ Com_SRCS += epicsGeneralTime.c # Time providers Com_SRCS += osiClockTime.c -Com_SRCS_vxWorks += osiNTPTime.c +Com_SRCS_vxWorks += osiNTPTime.c tz2timezone.c Com_SRCS_RTEMS += osiNTPTime.c ifeq ($(OS_CLASS),vxWorks) @@ -86,6 +86,7 @@ endif Com_SRCS += osdSock.c Com_SRCS += osdSockAddrReuse.cpp +Com_SRCS += osdSockUnsentCount.c Com_SRCS += osiSock.c Com_SRCS += systemCallIntMech.cpp Com_SRCS += epicsSocketConvertErrnoToString.cpp @@ -123,6 +124,7 @@ Com_SRCS += osdMonotonic.c Com_SRCS += osdProcess.c Com_SRCS += osdNetIntf.c Com_SRCS += osdMessageQueue.c +Com_SRCS += osdgetexec.c Com_SRCS += devLibVME.c Com_SRCS += devLibVMEOSD.c diff --git a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h index 2053227e7..0498f6e27 100644 --- a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h +++ b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h @@ -33,10 +33,8 @@ /* * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete - * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification */ #define CXX_PLACEMENT_DELETE -#define CXX_THROW_SPECIFICATION #endif /* __cplusplus */ diff --git a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h index 13d91193c..3342308a9 100644 --- a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h +++ b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h @@ -24,11 +24,7 @@ # error compiler/gcc/compilerSpecific.h is not for use with the clang compiler #endif -#if __GNUC__ > 2 -# define EPICS_ALWAYS_INLINE __inline__ __attribute__((always_inline)) -#else -# define EPICS_ALWAYS_INLINE __inline__ -#endif +#define EPICS_ALWAYS_INLINE __inline__ __attribute__((always_inline)) /* Expands to a 'const char*' which describes the name of the current function scope */ #define EPICS_FUNCTION __PRETTY_FUNCTION__ @@ -44,16 +40,8 @@ /* * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete - * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification */ - -#if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95 ) -# define CXX_THROW_SPECIFICATION -#endif - -#if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 96 ) -# define CXX_PLACEMENT_DELETE -#endif +#define CXX_PLACEMENT_DELETE #endif /* __cplusplus */ @@ -63,11 +51,9 @@ #define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a))) /* - * Deprecation marker if possible + * Deprecation marker */ -#if (__GNUC__ > 2) -# define EPICS_DEPRECATED __attribute__((deprecated)) -#endif +#define EPICS_DEPRECATED __attribute__((deprecated)) /* * Unused marker diff --git a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h index 75bfa83fb..4e282db4b 100644 --- a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h +++ b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h @@ -20,11 +20,7 @@ # error compiler/msvc/compilerSpecific.h is only for use with the Microsoft compiler #endif -#if _MSC_VER >= 1200 #define EPICS_ALWAYS_INLINE __forceinline -#else -#define EPICS_ALWAYS_INLINE __inline -#endif /* Expands to a 'const char*' which describes the name of the current function scope */ #define EPICS_FUNCTION __FUNCTION__ @@ -42,13 +38,8 @@ * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification */ -#if _MSC_VER >= 1200 /* visual studio 6.0 or later */ -# define CXX_PLACEMENT_DELETE -#endif - -#if _MSC_VER > 1300 /* some release after visual studio 7 we hope */ -# define CXX_THROW_SPECIFICATION -#endif +#define CXX_PLACEMENT_DELETE +#define CXX_THROW_SPECIFICATION #endif /* __cplusplus */ diff --git a/modules/libcom/src/osi/compilerDependencies.h b/modules/libcom/src/osi/compilerDependencies.h index 3bd835c91..0b333d74e 100644 --- a/modules/libcom/src/osi/compilerDependencies.h +++ b/modules/libcom/src/osi/compilerDependencies.h @@ -20,18 +20,6 @@ #ifdef __cplusplus -/* - * usage: void func () epicsThrows (( std::bad_alloc, std::logic_error )) - * - * Note: now a widely accepted concensus (ref Meyers and C++ faq) is that - * one should avoid using throw specifications in C++ code - */ -#if defined ( CXX_THROW_SPECIFICATION ) -# define epicsThrows(X) throw X -#else -# define epicsThrows(X) -#endif - /* * usage: epicsPlacementDeleteOperator (( void *, myMemoryManager & )) */ diff --git a/modules/libcom/src/osi/epicsGeneralTime.c b/modules/libcom/src/osi/epicsGeneralTime.c index e5dd42201..87158d937 100644 --- a/modules/libcom/src/osi/epicsGeneralTime.c +++ b/modules/libcom/src/osi/epicsGeneralTime.c @@ -215,6 +215,14 @@ int epicsShareAPI epicsTimeGetCurrent(epicsTimeStamp *pDest) return status; } +int epicsTimeGetMonotonic ( epicsTimeStamp * pDest ) +{ + epicsUInt64 now = epicsMonotonicGet(); + pDest->nsec = now%1000000000ul; + pDest->secPastEpoch = now/1000000000ul; + return 0; +} + int epicsTimeGetCurrentInt(epicsTimeStamp *pDest) { gtProvider *ptp = gtPvt.lastTimeProvider; diff --git a/modules/libcom/src/osi/epicsMutex.cpp b/modules/libcom/src/osi/epicsMutex.cpp index 7c8d05056..035431145 100644 --- a/modules/libcom/src/osi/epicsMutex.cpp +++ b/modules/libcom/src/osi/epicsMutex.cpp @@ -247,6 +247,7 @@ void epicsShareAPI epicsMutexShowAll(int onlyLocked,unsigned int level) epicsMutexOsdUnlock(epicsMutexGlobalLock); } +#if !defined(__GNUC__) || __GNUC__<4 || (__GNUC__==4 && __GNUC_MINOR__<8) epicsMutex :: epicsMutex () : id ( epicsMutexCreate () ) { @@ -254,6 +255,7 @@ epicsMutex :: epicsMutex () : throw mutexCreateFailed (); } } +#endif epicsMutex :: epicsMutex ( const char *pFileName, int lineno ) : id ( epicsMutexOsiCreate (pFileName, lineno) ) diff --git a/modules/libcom/src/osi/epicsMutex.h b/modules/libcom/src/osi/epicsMutex.h index 6d74f9599..070efd0e4 100644 --- a/modules/libcom/src/osi/epicsMutex.h +++ b/modules/libcom/src/osi/epicsMutex.h @@ -32,8 +32,12 @@ public: typedef epicsGuard release_t; class mutexCreateFailed; /* exception payload */ class invalidMutex; /* exception payload */ +#if !defined(__GNUC__) || __GNUC__<4 || (__GNUC__==4 && __GNUC_MINOR__<8) epicsMutex (); epicsMutex ( const char *pFileName, int lineno ); +#else + epicsMutex ( const char *pFileName = __builtin_FILE(), int lineno = __builtin_LINE() ); +#endif ~epicsMutex (); void show ( unsigned level ) const; void lock (); /* blocks until success */ diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 892d73de0..813f2dfd9 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -31,6 +31,18 @@ using namespace std; +epicsThreadId epicsShareAPI epicsThreadCreate ( + const char * name, unsigned int priority, unsigned int stackSize, + EPICSTHREADFUNC funptr,void * parm ) +{ + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + opts.priority = priority; + opts.stackSize = stackSize; + opts.joinable = 0; + + return epicsThreadCreateOpt(name, funptr, parm, &opts); +} + epicsThreadRunable::~epicsThreadRunable () {} void epicsThreadRunable::run () {} void epicsThreadRunable::show ( unsigned int ) const {} @@ -141,9 +153,18 @@ bool epicsThread::exitWait ( const double delay ) throw () if ( this->pThreadDestroyed ) { *this->pThreadDestroyed = true; } + bool j; + { + epicsGuard < epicsMutex > guard ( this->mutex ); + j = joined; + joined = true; + } + if(!j) { + epicsThreadMustJoin(this->id); + } return true; } - epicsTime exitWaitBegin = epicsTime::getCurrent (); + epicsTime exitWaitBegin = epicsTime::getMonotonic (); double exitWaitElapsed = 0.0; epicsGuard < epicsMutex > guard ( this->mutex ); this->cancel = true; @@ -151,9 +172,15 @@ bool epicsThread::exitWait ( const double delay ) throw () epicsGuardRelease < epicsMutex > unguard ( guard ); this->event.signal (); this->exitEvent.wait ( delay - exitWaitElapsed ); - epicsTime current = epicsTime::getCurrent (); + epicsTime current = epicsTime::getMonotonic (); exitWaitElapsed = current - exitWaitBegin; } + if(this->terminated && !joined) { + joined = true; + + epicsGuardRelease < epicsMutex > unguard ( guard ); + epicsThreadMustJoin(this->id); + } } catch ( std :: exception & except ) { errlogPrintf ( @@ -177,11 +204,18 @@ epicsThread::epicsThread ( epicsThreadRunable & runableIn, const char * pName, unsigned stackSize, unsigned priority ) : runable ( runableIn ), id ( 0 ), pThreadDestroyed ( 0 ), - begin ( false ), cancel ( false ), terminated ( false ) + begin ( false ), cancel ( false ), terminated ( false ), + joined ( false ) { - this->id = epicsThreadCreate ( - pName, priority, stackSize, epicsThreadCallEntryPoint, - static_cast < void * > ( this ) ); + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + opts.stackSize = stackSize; + opts.priority = priority; + opts.joinable = 1; + + this->id = epicsThreadCreateOpt( + pName, epicsThreadCallEntryPoint, + static_cast < void * > ( this ), + &opts); if ( ! this->id ) { throw unableToCreateThread (); } @@ -193,9 +227,8 @@ epicsThread::~epicsThread () throw () char nameBuf [256]; this->getName ( nameBuf, sizeof ( nameBuf ) ); fprintf ( stderr, - "epicsThread::~epicsThread(): " - "blocking for thread \"%s\" to exit\n", - nameBuf ); + "epicsThread::~epicsThread(): \"%s\" blocking for thread \"%s\" to exit\n", + getNameSelf(), nameBuf ); fprintf ( stderr, "was epicsThread object destroyed before thread exit ?\n"); } diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index 84b2c4788..da16a0b25 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -45,6 +45,7 @@ typedef enum { epicsThreadBooleanStatusFail, epicsThreadBooleanStatusSuccess } epicsThreadBooleanStatus; +/** Lookup target specific default stack size */ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize( epicsThreadStackSizeClass size); @@ -54,6 +55,20 @@ typedef struct epicsThreadOSD *epicsThreadId; typedef epicsThreadId epicsThreadOnceId; #define EPICS_THREAD_ONCE_INIT 0 +/** Perform one-time initialization. + * + * Run the provided function if it has not run, and is not running. + * + * @post The provided function has been run. + * + * @code + * static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT; + * static void myInitFunc(void *arg) { ... } + * static void some Function(void) { + * epicsThreadOnce(&onceId, &myInitFunc, NULL); + * } + * @endcode + */ epicsShareFunc void epicsShareAPI epicsThreadOnce( epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg); @@ -65,46 +80,140 @@ epicsShareFunc void epicsThreadRealtimeLock(void); epicsShareFunc void epicsShareAPI epicsThreadExitMain(void); +/** For use with epicsThreadCreateOpt() */ +typedef struct epicsThreadOpts { + /** Thread priority in OSI range (cf. epicsThreadPriority*) */ + unsigned int priority; + /** Thread stack size, either in bytes for this architecture or + * an enum epicsThreadStackSizeClass value. + */ + unsigned int stackSize; + /** Should thread be joinable? (default (0) is not joinable). + * If joinable=1, then epicsThreadMustJoin() must be called for cleanup thread resources. + */ + unsigned int joinable; +} epicsThreadOpts; + +/** Default initial values for epicsThreadOpts + * Applications should always use this macro to initialize an epicsThreadOpts + * structure. Additional fields may be added in the future, and the order of + * the fields might also change, thus code that assumes the above definition + * might break if these rules are not followed. + */ +#define EPICS_THREAD_OPTS_INIT { \ + epicsThreadPriorityLow, epicsThreadStackMedium, 0} + +/** @brief Allocate and start a new OS thread. + * @param name A name describing this thread. Appears in various log and error message. + * @param funptr The thread main function. + * @param parm Passed to thread main function. + * @param opts Modifiers for the new thread, or NULL to use target specific defaults. + * @return NULL on error + */ +epicsShareFunc epicsThreadId epicsThreadCreateOpt ( + const char * name, + EPICSTHREADFUNC funptr, void * parm, + const epicsThreadOpts *opts ); +/** Short-hand for epicsThreadCreateOpt() to create an un-joinable thread. */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( const char * name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr,void * parm ); +/** Short-hand for epicsThreadCreateOpt() to create an un-joinable thread. + * On error calls cantProceed() + */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate ( const char * name, unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void * parm ); + EPICSTHREADFUNC funptr,void * parm ); + +/* This gets undefined in osdThread.h on VxWorks < 6.9 */ +#define EPICS_THREAD_CAN_JOIN +/** Wait for a joinable thread to exit (return from its main function) */ +epicsShareFunc void epicsThreadMustJoin(epicsThreadId id); +/** Block the current thread until epicsThreadResume(). */ epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void); +/** Resume a thread suspended with epicsThreadSuspendSelf() */ epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadId id); +/** Return thread OSI priority */ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority( epicsThreadId id); +/** Return thread OSI priority */ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPrioritySelf(void); +/** Change OSI priority of target thread. */ epicsShareFunc void epicsShareAPI epicsThreadSetPriority( epicsThreadId id,unsigned int priority); +/** Lookup the next usage OSI priority such that priority > *pPriorityJustBelow + * if this is possible with the current target configuration and privlages. + */ epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadHighestPriorityLevelBelow ( unsigned int priority, unsigned *pPriorityJustBelow); +/** Lookup the next usage OSI priority such that priority < *pPriorityJustBelow + * if this is possible with the current target configuration and privlages. + */ epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadLowestPriorityLevelAbove ( unsigned int priority, unsigned *pPriorityJustAbove); +/** Test if two thread IDs actually refer to the same OS thread */ epicsShareFunc int epicsShareAPI epicsThreadIsEqual( epicsThreadId id1, epicsThreadId id2); +/** Test if thread has been suspended with epicsThreadSuspendSelf() */ epicsShareFunc int epicsShareAPI epicsThreadIsSuspended(epicsThreadId id); +/** @brief Block the calling thread for at least the specified time. + * @param seconds Time to wait in seconds. Values <=0 blocks for the shortest possible time. + */ epicsShareFunc void epicsShareAPI epicsThreadSleep(double seconds); +/** @brief Query a value approximating the OS timer/scheduler resolution. + * @return A value in seconds >=0 + * + * @warning On targets other than vxWorks and RTEMS, the quantum value often isn't + * meaningful. Use of this function is discouraged in portable code. + */ epicsShareFunc double epicsShareAPI epicsThreadSleepQuantum(void); +/** Find an epicsThreadId associated with the current thread. + * For non-EPICS threads, a new epicsThreadId may be allocated. + */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf(void); +/** Attempt to find the first instance of a thread by name. + * @return An epicsThreadId, or NULL if no such thread is currently running. + * Note that a non-NULL ID may still be invalid if this call races + * with thread exit. + * + * @warning Safe use of this function requires external knowledge that this + * thread will not return. + */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId(const char *name); +/** Return a value approximating the number of threads which this target + * can run in parallel. This value is advisory. + * @return >=1 + */ epicsShareFunc int epicsThreadGetCPUs(void); +/** Return the name of the current thread. + * + * @return Never NULL. Storage lifetime tied to epicsThreadId. + * + * This is either a copy of the string passed to epicsThread*Create*(), + * or an arbitrary unique string for non-EPICS threads. + */ epicsShareFunc const char * epicsShareAPI epicsThreadGetNameSelf(void); -/* For epicsThreadGetName name is guaranteed to be null terminated */ -/* size is size of buffer to hold name (including terminator) */ -/* Failure results in an empty string stored in name */ +/** Copy out the thread name into the provided buffer. + * + * Guaranteed to be null terminated. + * size is number of bytes in buffer to hold name (including terminator). + * Failure results in an empty string stored in name. + */ epicsShareFunc void epicsShareAPI epicsThreadGetName( epicsThreadId id, char *name, size_t size); epicsShareFunc int epicsShareAPI epicsThreadIsOkToBlock(void); epicsShareFunc void epicsShareAPI epicsThreadSetOkToBlock(int isOkToBlock); +/** Print to stdout information about all running EPICS threads. + * @param level 0 prints minimal output. Higher values print more details. + */ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level); +/** Print info about a single EPICS thread. */ epicsShareFunc void epicsShareAPI epicsThreadShow( epicsThreadId id,unsigned int level); @@ -115,10 +224,17 @@ epicsShareFunc int epicsThreadHookDelete(EPICS_THREAD_HOOK_ROUTINE hook); epicsShareFunc void epicsThreadHooksShow(void); epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func); +/** Thread local storage */ typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId; +/** Allocate a new thread local variable. + * This variable will initially hold NULL for each thread. + */ epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void); +/** Free a thread local variable */ epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id); +/** Update thread local variable */ epicsShareFunc void epicsShareAPI epicsThreadPrivateSet(epicsThreadPrivateId,void *); +/** Fetch the current value of a thread local variable */ epicsShareFunc void * epicsShareAPI epicsThreadPrivateGet(epicsThreadPrivateId); #ifdef __cplusplus @@ -130,33 +246,64 @@ epicsShareFunc void * epicsShareAPI epicsThreadPrivateGet(epicsThreadPrivateId); #include "epicsEvent.h" #include "epicsMutex.h" +//! Interface used with class epicsThread class epicsShareClass epicsThreadRunable { public: virtual ~epicsThreadRunable () = 0; + //! Thread main function. + //! C++ exceptions which propagate from this method will be caught and a warning printed. + //! No other action is taken. virtual void run () = 0; + //! Optional. Called via epicsThread::show() virtual void show ( unsigned int level ) const; }; extern "C" void epicsThreadCallEntryPoint ( void * ); +/** @brief An OS thread + * + * A wrapper around the epicsThread* C API. + * + * @note Threads must be start() ed. + */ class epicsShareClass epicsThread { public: + /** Create a new thread with the provided information. + * + * cf. epicsThreadOpts + * @note Threads must be start() ed. + * @throws epicsThread::unableToCreateThread on error. + */ epicsThread ( epicsThreadRunable &,const char *name, unsigned int stackSize, unsigned int priority=epicsThreadPriorityLow ); ~epicsThread () throw (); + //! Actually start the thread. void start () throw (); + //! Wait for the thread epicsRunnable::run() to return. void exitWait () throw (); + //! Wait for the thread epicsRunnable::run() to return. + //! @param delay Wait up to this many seconds. + //! @returns true if run() returned. false on timeout. bool exitWait ( const double delay ) throw (); + //! @throws A special exitException which will be caught and ignored. + //! @note This exitException doesn't not derive from std::exception static void exit (); + //! cf. epicsThreadResume() void resume () throw (); + //! cf. epicsThreadGetName(); void getName ( char * name, size_t size ) const throw (); + //! cf. epicsThreadGetIdSelf()() epicsThreadId getId () const throw (); + //! cf. epicsThreadGetPriority() unsigned int getPriority () const throw (); + //! cf. epicsThreadSetPriority() void setPriority ( unsigned int ) throw (); bool priorityIsEqual ( const epicsThread & ) const throw (); bool isSuspended () const throw (); + //! @return true if call through this thread's epicsRunnable::run() bool isCurrentThread () const throw (); bool operator == ( const epicsThread & ) const throw (); + //! Say something interesting about this thread to stdout. void show ( unsigned level ) const throw (); /* these operate on the current thread */ @@ -178,6 +325,7 @@ private: bool begin; bool cancel; bool terminated; + bool joined; bool beginWait () throw (); epicsThread ( const epicsThread & ); diff --git a/modules/libcom/src/osi/epicsTime.cpp b/modules/libcom/src/osi/epicsTime.cpp index 6dd3efd4c..f80d1738b 100644 --- a/modules/libcom/src/osi/epicsTime.cpp +++ b/modules/libcom/src/osi/epicsTime.cpp @@ -38,7 +38,7 @@ #include "epicsStdio.h" static const char pEpicsTimeVersion[] = - "@(#) " EPICS_VERSION_STRING ", Common Utilities Library " __DATE__; + "@(#) " EPICS_VERSION_STRING ", Common Utilities Library"; // // useful public constants @@ -215,6 +215,13 @@ epicsTime epicsTime::getCurrent () return epicsTime ( current ); } +epicsTime epicsTime::getMonotonic() +{ + epicsTimeStamp current; + epicsTimeGetMonotonic (¤t); // can't fail + return epicsTime ( current ); +} + epicsTime epicsTime::getEvent (const epicsTimeEvent &event) { epicsTimeStamp current; @@ -952,7 +959,8 @@ extern "C" { try { local_tm_nano_sec tmns = epicsTime (*pSrc); *pDest = tmns.ansi_tm; - *pNSecDest = tmns.nSec; + if (pNSecDest) + *pNSecDest = tmns.nSec; } catch (...) { return S_time_conversion; @@ -964,7 +972,8 @@ extern "C" { try { gm_tm_nano_sec gmtmns = epicsTime (*pSrc); *pDest = gmtmns.ansi_tm; - *pNSecDest = gmtmns.nSec; + if (pNSecDest) + *pNSecDest = gmtmns.nSec; } catch (...) { return S_time_conversion; diff --git a/modules/libcom/src/osi/epicsTime.h b/modules/libcom/src/osi/epicsTime.h index bc86b737f..e9ec71aaf 100644 --- a/modules/libcom/src/osi/epicsTime.h +++ b/modules/libcom/src/osi/epicsTime.h @@ -85,6 +85,7 @@ public: static epicsTime getEvent ( const epicsTimeEvent & ); static epicsTime getCurrent (); + static epicsTime getMonotonic (); /* convert to and from EPICS epicsTimeStamp format */ operator epicsTimeStamp () const; @@ -191,6 +192,7 @@ extern "C" { epicsShareFunc int epicsShareAPI epicsTimeGetCurrent ( epicsTimeStamp * pDest ); epicsShareFunc int epicsShareAPI epicsTimeGetEvent ( epicsTimeStamp *pDest, int eventNumber); +epicsShareFunc int epicsTimeGetMonotonic ( epicsTimeStamp * pDest ); /* These are callable from an Interrupt Service Routine */ epicsShareFunc int epicsTimeGetCurrentInt(epicsTimeStamp *pDest); diff --git a/modules/libcom/src/osi/os/Darwin/osdSockAddrReuse.cpp b/modules/libcom/src/osi/os/Darwin/osdSockAddrReuse.cpp deleted file mode 100644 index 869514160..000000000 --- a/modules/libcom/src/osi/os/Darwin/osdSockAddrReuse.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author: Jeff Hill - */ - -#define epicsExportSharedSymbols -#include "osiSock.h" -#include "errlog.h" - -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressReuseDuringTimeWaitState ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEADDR, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEADDR?\n"); - } -} - -/* - * SO_REUSEPORT is not in POSIX - */ -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressUseForDatagramFanout ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEPORT, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEPORT?\n"); - } -} diff --git a/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c b/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c new file mode 100644 index 000000000..20bd82b14 --- /dev/null +++ b/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c @@ -0,0 +1,19 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#define EPICS_PRIVATE_API +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + * See https://www.unix.com/man-page/osx/2/setsockopt + */ +int epicsSocketUnsentCount(SOCKET sock) { + int unsent; + socklen_t len = sizeof(unsent); + if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0) + return unsent; + return -1; +} diff --git a/modules/libcom/src/osi/os/Darwin/osdgetexec.c b/modules/libcom/src/osi/os/Darwin/osdgetexec.c new file mode 100644 index 000000000..4e4961c59 --- /dev/null +++ b/modules/libcom/src/osi/os/Darwin/osdgetexec.c @@ -0,0 +1,50 @@ + +#include +#include + +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + uint32_t max = 64u; + char *ret = NULL; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + /* cf. "man 3 dyld" */ + if(_NSGetExecutablePath(ret, &max)==0) { + /* max left unchanged */ + ret[max-1] = '\0'; + break; + } + /* max has been updated with required size */ + } + + /* TODO: _NSGetExecutablePath() doesn't follow symlinks */ + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c b/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c new file mode 100644 index 000000000..3c0a8f915 --- /dev/null +++ b/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c @@ -0,0 +1,19 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#define EPICS_PRIVATE_API +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + * See https://linux.die.net/man/7/tcp + */ +int epicsSocketUnsentCount(SOCKET sock) { + int unsent; + if (ioctl(sock, SIOCOUTQ, &unsent) == 0) + return unsent; + return -1; +} diff --git a/modules/libcom/src/osi/os/Linux/osdThread.h b/modules/libcom/src/osi/os/Linux/osdThread.h index 7d2a4868d..bb1fdcb0a 100644 --- a/modules/libcom/src/osi/os/Linux/osdThread.h +++ b/modules/libcom/src/osi/os/Linux/osdThread.h @@ -22,6 +22,7 @@ extern "C" { typedef struct epicsThreadOSD { ELLNODE node; + int refcnt; pthread_t tid; pid_t lwpId; pthread_attr_t attr; @@ -35,6 +36,7 @@ typedef struct epicsThreadOSD { int isRealTimeScheduled; int isOnThreadList; unsigned int osiPriority; + int joinable; char name[1]; /* actually larger */ } epicsThreadOSD; diff --git a/modules/libcom/src/osi/os/Linux/osdgetexec.c b/modules/libcom/src/osi/os/Linux/osdgetexec.c new file mode 100644 index 000000000..f79906fb7 --- /dev/null +++ b/modules/libcom/src/osi/os/Linux/osdgetexec.c @@ -0,0 +1,58 @@ + +#include +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +#ifndef PATH_MAX +# define PATH_MAX 100 +#endif + +char *epicsGetExecName(void) +{ + size_t max = PATH_MAX; + char *ret = NULL; + ssize_t n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = readlink("/proc/self/exe", ret, max); + if(n == -1) { + free(ret); + ret = NULL; + break; + } else if(n < max) { + /* readlink() never adds a nil */ + ret[n] = '\0'; + break; + } + + max += 64; + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c b/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c index 0a96bad1a..b8f79e706 100644 --- a/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c +++ b/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c @@ -350,7 +350,12 @@ static void unsolicitedHandlerEPICS(int vectorNumber) ); } -#endif /* defined(__PPC__) && defined(mpc750) */ +#else /* !defined(__PPC__) && !defined(__mcf528x__) */ + +/* No known VME interface here, provide a dummy */ +devLibVME *pdevLibVME; + +#endif /* defined(__PPC__) || defined(__mcf528x__) */ /* * Some vxWorks convenience routines diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index 769e95820..bdcd8c17e 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -35,6 +35,7 @@ #include "osiUnistd.h" #include "osdInterrupt.h" #include "epicsExit.h" +#include "epicsAtomic.h" epicsShareFunc void osdThreadHooksRun(epicsThreadId id); epicsShareFunc void osdThreadHooksRunMain(epicsThreadId id); @@ -47,6 +48,9 @@ struct taskVar { struct taskVar *back; char *name; rtems_id id; + rtems_id join_barrier; /* only valid if joinable */ + int refcnt; + int joinable; EPICSTHREADFUNC funptr; void *parm; unsigned int threadVariableCapacity; @@ -163,6 +167,22 @@ taskVarUnlock (void) epicsMutexOsdUnlock (taskVarMutex); } +static +void taskUnref(struct taskVar *v) +{ + int ref = epicsAtomicDecrIntT(&v->refcnt); + assert(ref>=0); + if(ref>0) return; + + + if (v->joinable) { + rtems_barrier_delete(v->join_barrier); + } + free (v->threadVariables); + free (v->name); + free (v); +} + /* * EPICS threads destroy themselves by returning from the thread entry function. * This simple wrapper provides the same semantics on RTEMS. @@ -183,9 +203,12 @@ threadWrapper (rtems_task_argument arg) if (v->forw) v->forw->back = v->back; taskVarUnlock (); - free (v->threadVariables); - free (v->name); - free (v); + if(v->joinable) { + rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT); + if(sc!=RTEMS_SUCCESSFUL) + cantProceed("oops %s\n", rtems_status_text(sc)); + } + taskUnref(v); rtems_task_delete (RTEMS_SELF); } @@ -196,21 +219,34 @@ void epicsThreadExitMain (void) { } -static void +static rtems_status_code setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr, - void *parm) + void *parm, int joinable) { struct taskVar *v; uint32_t note; - rtems_status_code sc; + rtems_status_code sc = RTEMS_SUCCESSFUL; v = mallocMustSucceed (sizeof *v, "epicsThreadCreate_vars"); v->name = epicsStrDup(name); v->id = tid; v->funptr = funptr; v->parm = parm; + v->joinable = joinable; + v->refcnt = joinable ? 2 : 1; v->threadVariableCapacity = 0; v->threadVariables = NULL; + if (joinable) { + char c[3]; + strncpy(c, v->name, 3); + sc = rtems_barrier_create(rtems_build_name('~', c[0], c[1], c[2]), + RTEMS_BARRIER_AUTOMATIC_RELEASE | RTEMS_LOCAL, + 2, &v->join_barrier); + if (sc != RTEMS_SUCCESSFUL) { + free(v); + return sc; + } + } note = (uint32_t)v; rtems_task_set_note (tid, RTEMS_NOTEPAD_TASKVAR, note); taskVarLock (); @@ -222,10 +258,14 @@ setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr, taskVarUnlock (); if (funptr) { sc = rtems_task_start (tid, threadWrapper, (rtems_task_argument)v); - if (sc != RTEMS_SUCCESSFUL) - errlogPrintf ("setThreadInfo: Can't start %s: %s\n", - name, rtems_status_text(sc)); } + if (sc != RTEMS_SUCCESSFUL) { + if (joinable) { + rtems_barrier_delete(v->join_barrier); + } + free(v); + } + return sc; } /* @@ -247,7 +287,8 @@ epicsThreadInit (void) if (!onceMutex || !taskVarMutex) cantProceed("epicsThreadInit() can't create global mutexes\n"); rtems_task_ident (RTEMS_SELF, 0, &tid); - setThreadInfo (tid, "_main_", NULL, NULL); + if(setThreadInfo (tid, "_main_", NULL, NULL, 0) != RTEMS_SUCCESSFUL) + cantProceed("epicsThreadInit() unable to setup _main_"); osdThreadHooksRunMain((epicsThreadId)tid); initialized = 1; epicsThreadCreate ("ImsgDaemon", 99, @@ -263,15 +304,26 @@ void epicsThreadRealtimeLock(void) * Create and start a new thread */ epicsThreadId -epicsThreadCreate (const char *name, - unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void *parm) +epicsThreadCreateOpt ( + const char * name, + EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { + unsigned int stackSize; rtems_id tid; rtems_status_code sc; char c[4]; - if (!initialized) epicsThreadInit(); + if (!initialized) + epicsThreadInit(); + + if (!opts) { + static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT; + opts = &opts_default; + } + stackSize = opts->stackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); + if (stackSize < RTEMS_MINIMUM_STACK_SIZE) { errlogPrintf ("Warning: epicsThreadCreate %s illegal stackSize %d\n", name, stackSize); @@ -279,7 +331,7 @@ epicsThreadCreate (const char *name, } strncpy (c, name, sizeof c); sc = rtems_task_create (rtems_build_name (c[0], c[1], c[2], c[3]), - epicsThreadGetOssPriorityValue (priority), + epicsThreadGetOssPriorityValue (opts->priority), stackSize, RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), RTEMS_FLOATING_POINT|RTEMS_LOCAL, @@ -289,7 +341,13 @@ epicsThreadCreate (const char *name, name, rtems_status_text(sc)); return 0; } - setThreadInfo (tid, name, funptr,parm); + sc = setThreadInfo (tid, name, funptr, parm, opts->joinable); + if (sc != RTEMS_SUCCESSFUL) { + errlogPrintf ("epicsThreadCreate create failure during setup for %s: %s\n", + name, rtems_status_text(sc)); + rtems_task_delete(tid); + return 0; + } return (epicsThreadId)tid; } @@ -305,6 +363,51 @@ threadMustCreate (const char *name, return tid; } +void epicsThreadMustJoin(epicsThreadId id) +{ + rtems_id target_tid = (rtems_id)id, self_tid; + struct taskVar *v = 0; + + rtems_task_ident (RTEMS_SELF, 0, &self_tid); + + { + uint32_t note; + rtems_task_get_note (target_tid, RTEMS_NOTEPAD_TASKVAR, ¬e); + v = (void *)note; + } + /* 'v' may be NULL if 'id' represents a non-EPICS thread other than _main_. */ + + if(!v || !v->joinable) { + if(epicsThreadGetIdSelf()==id) { + errlogPrintf("Warning: %s thread self-join of unjoinable\n", v ? v->name : "non-EPICS thread"); + + } else { + /* try to error nicely, however in all likelyhood de-ref of + * 'id' has already caused SIGSEGV as we are racing thread exit, + * which free's 'id'. + */ + cantProceed("Error: %s thread not joinable.\n", v->name); + } + return; + + } else if(target_tid!=self_tid) { + /* wait for target to complete */ + rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT); + if(sc!=RTEMS_SUCCESSFUL) + cantProceed("oopsj %s\n", rtems_status_text(sc)); + + if(sc != RTEMS_SUCCESSFUL) { + errlogPrintf("epicsThreadMustJoin('%s') -> %s\n", v->name, rtems_status_text(sc)); + } + } + + v->joinable = 0; + taskUnref(v); + /* target task may be deleted. + * self task is not deleted, even for self join. + */ +} + void epicsThreadSuspendSelf (void) { diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.h b/modules/libcom/src/osi/os/RTEMS/osdThread.h index 4451f845a..4eef8c01f 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.h +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.h @@ -3,10 +3,21 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ +#ifndef INC_osdThread_H +#define INC_osdThread_H + +#ifdef __cplusplus +extern "C" { +#endif + int epicsThreadGetOssPriorityValue(unsigned int osiPriority); +#ifdef __cplusplus +} +#endif + +#endif /* INC_osdThread_H */ diff --git a/modules/libcom/src/osi/os/WIN32/osdFindAddr.c b/modules/libcom/src/osi/os/WIN32/osdFindAddr.c new file mode 100644 index 000000000..5172e2638 --- /dev/null +++ b/modules/libcom/src/osi/os/WIN32/osdFindAddr.c @@ -0,0 +1,108 @@ +/*************************************************************************\ +* Copyright (C) 2017 Freddie Akeroyd +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#include +#define epicsExportSharedSymbols +#include "epicsStackTracePvt.h" +#include "epicsStackTrace.h" +#include "epicsString.h" +#include "epicsStdio.h" +#include "gpHash.h" + +#define MAX_SYM_SIZE 255 + +/* + * we cache a list of previously located symbols, currently just to + * avoid a memory leak in allocating sym_p->s_nam and not + * to save on a SymFromAddr() call. This was done in case libraries + * were dynamically unloaded/reloaded and the cached answer might not + * then be correct, but this may be over cautious. + */ +static struct gphPvt* symbol_table; + +typedef struct +{ + char* name; + void* value; + char* file; + char* fileAndLine; + size_t line; +} SymbolData; + +int epicsFindAddr(void *addr, epicsSymbol *sym_p) +{ + static int first_call = 1; + static HANDLE process = NULL; + DWORD64 displacement64 = 0; + DWORD displacement = 0; + SYMBOL_INFO *symbol; + IMAGEHLP_LINE64 line; + GPHENTRY* symbol_entry; + SymbolData* symbol_data; + size_t len; + if (first_call) + { + SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS); + process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + gphInitPvt(&symbol_table, 256); /* table size must be a power of 2 in range 256 to 65536 */ + first_call = 0; + } + symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + (MAX_SYM_SIZE + 1) * sizeof(char), 1); + symbol->MaxNameLen = MAX_SYM_SIZE; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + if (!SymFromAddr(process, (DWORD64)addr, &displacement64, symbol)) + { + sym_p->s_nam = 0; + sym_p->s_val = 0; + sym_p->f_nam = 0; + free(symbol); + return -1; + } + if ( (symbol_entry = gphFind(symbol_table, symbol->Name, addr)) != NULL ) + { + symbol_data = (SymbolData*)symbol_entry->userPvt; + } + else + { + symbol_entry = gphAdd(symbol_table, symbol->Name, addr); + symbol_data = (SymbolData*)calloc(sizeof(SymbolData), 1); + symbol_data->name = strdup(symbol->Name); + symbol_data->value = (void*)symbol->Address; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + if (SymGetLineFromAddr64(process, (DWORD64)addr, &displacement, &line)) + { + symbol_data->file = strdup(line.FileName); + symbol_data->line = line.LineNumber; + len = strlen(line.FileName) + 32; /* add enough for [line %lu] */ + symbol_data->fileAndLine = calloc((len + 1) * sizeof(char), 1); + epicsSnprintf(symbol_data->fileAndLine, len, "%s[line %lu]", line.FileName, (unsigned long)line.LineNumber); + } + symbol_entry->userPvt = symbol_data; + } + sym_p->s_nam = symbol_data->name; + sym_p->s_val = symbol_data->value; + sym_p->f_nam = symbol_data->fileAndLine; + free(symbol); + return 0; +} + +int epicsFindAddrGetFeatures(void) +{ +#if defined(_MINGW) +/* 64bit MINGW can lookup DLL public symbols, 32bit cannot - but we need to be a dynamic build to have a DLL to lookup */ +# if defined(_WIN64) && defined(EPICS_CALL_DLL) + return EPICS_STACKTRACE_DYN_SYMBOLS; +# else + return 0; /* only able to print addresses */ +# endif /* _WIN64 && EPICS_CALL_DLL */ +#else + return EPICS_STACKTRACE_LCL_SYMBOLS + | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_DYN_SYMBOLS; +#endif /* _MINGW */ +} diff --git a/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c b/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c new file mode 100644 index 000000000..3f4ab3eee --- /dev/null +++ b/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c @@ -0,0 +1,26 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#define epicsExportSharedSymbols +#define EPICS_PRIVATE_API +#include "osiSock.h" +#include + +/* + * epicsSocketUnsentCount () + * See https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0 + */ +int epicsSocketUnsentCount(SOCKET sock) { +#ifdef SIO_TCP_INFO +/* Windows 10 Version 1703 / Server 2016 */ + DWORD infoVersion = 0, bytesReturned; + TCP_INFO_v0 tcpInfo; + int status; + if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion), + &tcpInfo, sizeof(tcpInfo), &bytesReturned, NULL, NULL)) == 0) + return tcpInfo.BytesInFlight; +#endif + return -1; +} diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 8cdb4a3f4..67a64bb9a 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -32,11 +32,11 @@ #include "epicsAssert.h" #include "ellLib.h" #include "epicsExit.h" +#include "epicsAtomic.h" epicsShareFunc void osdThreadHooksRun(epicsThreadId id); void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName ); -static void threadCleanupWIN32 ( void ); typedef struct win32ThreadGlobal { CRITICAL_SECTION mutex; @@ -46,6 +46,7 @@ typedef struct win32ThreadGlobal { typedef struct epicsThreadOSD { ELLNODE node; + int refcnt; HANDLE handle; EPICSTHREADFUNC funptr; void * parm; @@ -53,6 +54,7 @@ typedef struct epicsThreadOSD { DWORD id; unsigned epicsPriority; char isSuspended; + char joinable; } win32ThreadParam; typedef struct epicsThreadPrivateOSD { @@ -172,7 +174,6 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void ) static win32ThreadGlobal * pWin32ThreadGlobal = 0; static LONG initStarted = 0; static LONG initCompleted = 0; - int crtlStatus; LONG started; LONG done; @@ -215,15 +216,6 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void ) return 0; } - crtlStatus = atexit ( threadCleanupWIN32 ); - if ( crtlStatus ) { - TlsFree ( pWin32ThreadGlobal->tlsIndexThreadLibraryEPICS ); - DeleteCriticalSection ( & pWin32ThreadGlobal->mutex ); - free ( pWin32ThreadGlobal ); - pWin32ThreadGlobal = 0; - return 0; - } - InterlockedExchange ( & initCompleted, 1 ); return pWin32ThreadGlobal; @@ -238,6 +230,10 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm ) } if ( pParm ) { + int cnt = epicsAtomicDecrIntT(&pParm->refcnt); + if(cnt > 0) return; + assert(cnt==0); + /* fprintf ( stderr, "thread %s is exiting\n", pParm->pName ); */ EnterCriticalSection ( & pGbl->mutex ); ellDelete ( & pGbl->threadList, & pParm->node ); @@ -245,26 +241,6 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm ) CloseHandle ( pParm->handle ); free ( pParm ); - TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, 0 ); - } -} - -/* - * threadCleanupWIN32 () - */ -static void threadCleanupWIN32 ( void ) -{ - win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); - win32ThreadParam * pParm; - - if ( ! pGbl ) { - fprintf ( stderr, "threadCleanupWIN32: unable to find ctx\n" ); - return; - } - - while ( ( pParm = ( win32ThreadParam * ) - ellFirst ( & pGbl->threadList ) ) ) { - epicsParmCleanupWIN32 ( pParm ); } } @@ -464,21 +440,6 @@ epicsShareFunc unsigned int epicsShareAPI return stackSizeTable[stackSizeClass]; } -void epicsThreadCleanupWIN32 () -{ - win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); - win32ThreadParam * pParm; - - if ( ! pGbl ) { - fprintf ( stderr, "epicsThreadCleanupWIN32: unable to find ctx\n" ); - return; - } - - pParm = ( win32ThreadParam * ) - TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS ); - epicsParmCleanupWIN32 ( pParm ); -} - /* * epicsWin32ThreadEntry() */ @@ -512,6 +473,7 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) /* * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!! */ + TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, (void*)0xdeadbeef ); epicsParmCleanupWIN32 ( pParm ); return retStat; /* this indirectly closes the thread handle */ @@ -526,6 +488,7 @@ static win32ThreadParam * epicsThreadParmCreate ( const char *pName ) pParmWIN32->pName = (char *) ( pParmWIN32 + 1 ); strcpy ( pParmWIN32->pName, pName ); pParmWIN32->isSuspended = 0; + epicsAtomicIncrIntT(&pParmWIN32->refcnt); } return pParmWIN32; } @@ -579,11 +542,14 @@ static win32ThreadParam * epicsThreadImplicitCreate ( void ) /* * epicsThreadCreate () */ -epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName, - unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC pFunc,void *pParm) +epicsThreadId epicsThreadCreateOpt ( + const char * pName, + EPICSTHREADFUNC pFunc, void * pParm, + const epicsThreadOpts *opts ) { win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); win32ThreadParam * pParmWIN32; + unsigned int stackSize; int osdPriority; DWORD wstat; BOOL bstat; @@ -592,18 +558,26 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName, return NULL; } + if (!opts) { + static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT; + opts = &opts_default; + } + stackSize = opts->stackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); + pParmWIN32 = epicsThreadParmCreate ( pName ); if ( pParmWIN32 == 0 ) { return ( epicsThreadId ) pParmWIN32; } pParmWIN32->funptr = pFunc; pParmWIN32->parm = pParm; - pParmWIN32->epicsPriority = priority; + pParmWIN32->epicsPriority = opts->priority; { unsigned threadId; pParmWIN32->handle = (HANDLE) _beginthreadex ( - 0, stackSize, epicsWin32ThreadEntry, + 0, stackSize, epicsWin32ThreadEntry, pParmWIN32, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, & threadId ); @@ -615,7 +589,7 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName, pParmWIN32->id = ( DWORD ) threadId ; } - osdPriority = epicsThreadGetOsdPriorityValue (priority); + osdPriority = epicsThreadGetOsdPriorityValue (opts->priority); bstat = SetThreadPriority ( pParmWIN32->handle, osdPriority ); if (!bstat) { CloseHandle ( pParmWIN32->handle ); @@ -637,9 +611,48 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName, return NULL; } + if(opts->joinable) { + pParmWIN32->joinable = 1; + epicsAtomicIncrIntT(&pParmWIN32->refcnt); + } + return ( epicsThreadId ) pParmWIN32; } +void epicsThreadMustJoin(epicsThreadId id) +{ + win32ThreadParam * pParmWIN32 = id; + + if(!id) { + /* no-op */ + } else if(!pParmWIN32->joinable) { + if(epicsThreadGetIdSelf()==id) { + fprintf(stderr, "Warning: %s thread self-join of unjoinable\n", pParmWIN32->pName); + + } else { + /* try to error nicely, however in all likelyhood de-ref of + * 'id' has already caused SIGSEGV as we are racing thread exit, + * which free's 'id'. + */ + cantProceed("Error: %s thread not joinable.\n", pParmWIN32->pName); + } + return; + + } else if(epicsThreadGetIdSelf() != id) { + DWORD status = WaitForSingleObject(pParmWIN32->handle, INFINITE); + if(status != WAIT_OBJECT_0) { + /* TODO: signal error? */ + } + + pParmWIN32->joinable = 0; + epicsParmCleanupWIN32(pParmWIN32); + } else { + /* join self silently does nothing */ + pParmWIN32->joinable = 0; + epicsParmCleanupWIN32(pParmWIN32); + } +} + /* * epicsThreadSuspendSelf () */ diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.h b/modules/libcom/src/osi/os/WIN32/osdThread.h index 136e96bf4..69bc364f0 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.h +++ b/modules/libcom/src/osi/os/WIN32/osdThread.h @@ -3,13 +3,11 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ #ifndef osdThreadh #define osdThreadh - #endif /* osdThreadh */ diff --git a/modules/libcom/src/osi/os/WIN32/osdgetexec.c b/modules/libcom/src/osi/os/WIN32/osdgetexec.c new file mode 100644 index 000000000..a46ce50cd --- /dev/null +++ b/modules/libcom/src/osi/os/WIN32/osdgetexec.c @@ -0,0 +1,52 @@ + +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + size_t max = 128; + char *ret = NULL; + DWORD n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = GetModuleFileName(NULL, ret, max); + if(n == 0) { + free(ret); + ret = NULL; + break; + } else if(n < max) { + ret[n] = '\0'; + break; + } + + max += 64; + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '\\'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/WIN32/osiFileName.h b/modules/libcom/src/osi/os/WIN32/osiFileName.h index 6ff0308b2..ced745f71 100644 --- a/modules/libcom/src/osi/os/WIN32/osiFileName.h +++ b/modules/libcom/src/osi/os/WIN32/osiFileName.h @@ -15,7 +15,29 @@ #ifndef osiFileNameH #define osiFileNameH +#include + +#ifdef __cplusplus +extern "C" { +#endif + #define OSI_PATH_LIST_SEPARATOR ";" #define OSI_PATH_SEPARATOR "\\" +/** Return the absolute path of the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecName(void); + +/** Return the absolute path of the directory containing the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecDir(void); + +#ifdef __cplusplus +} +#endif + #endif /* osiFileNameH */ diff --git a/modules/libcom/src/osi/os/cygwin32/osiFileName.h b/modules/libcom/src/osi/os/cygwin32/osiFileName.h index 6d7fd6eb9..1e7799098 100644 --- a/modules/libcom/src/osi/os/cygwin32/osiFileName.h +++ b/modules/libcom/src/osi/os/cygwin32/osiFileName.h @@ -14,7 +14,29 @@ #ifndef osiFileNameH #define osiFileNameH +#include + +#ifdef __cplusplus +extern "C" { +#endif + #define OSI_PATH_LIST_SEPARATOR ";" #define OSI_PATH_SEPARATOR "\\" +/** Return the absolute path of the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecName(void); + +/** Return the absolute path of the directory containing the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecDir(void); + +#ifdef __cplusplus +} +#endif + #endif /* osiFileNameH */ diff --git a/modules/libcom/src/osi/os/default/osdSockUnsentCount.c b/modules/libcom/src/osi/os/default/osdSockUnsentCount.c new file mode 100644 index 000000000..ef01e9b24 --- /dev/null +++ b/modules/libcom/src/osi/os/default/osdSockUnsentCount.c @@ -0,0 +1,15 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#define EPICS_PRIVATE_API +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + */ +int epicsSocketUnsentCount(SOCKET sock) { + /* not implemented */ + return -1; +} diff --git a/modules/libcom/src/osi/os/default/osdgetexec.c b/modules/libcom/src/osi/os/default/osdgetexec.c new file mode 100644 index 000000000..0bec9ead9 --- /dev/null +++ b/modules/libcom/src/osi/os/default/osdgetexec.c @@ -0,0 +1,14 @@ +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + return NULL; +} + +char *epicsGetExecDir(void) +{ + return NULL; +} diff --git a/modules/libcom/src/osi/os/freebsd/osdgetexec.c b/modules/libcom/src/osi/os/freebsd/osdgetexec.c new file mode 100644 index 000000000..39c0a163d --- /dev/null +++ b/modules/libcom/src/osi/os/freebsd/osdgetexec.c @@ -0,0 +1,68 @@ + +#include +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + size_t max = PATH_MAX; + char *ret = NULL; + ssize_t n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = readlink("/proc/curproc/file", ret, max); + if(n == -1) { + free(ret); + ret = NULL; + break; + } else if(n < max) { + /* readlink() never adds a nil */ + ret[n] = '\0'; + break; + } + + max += 64; + } + + if(!ret) { + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + ret = malloc(max); + if(ret) { + sysctl(mib, 4, ret, &cb, NULL, 0); + /* TODO: error check */ + } + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/iOS/osdSockAddrReuse.cpp b/modules/libcom/src/osi/os/iOS/osdSockAddrReuse.cpp deleted file mode 100644 index 9f64e331a..000000000 --- a/modules/libcom/src/osi/os/iOS/osdSockAddrReuse.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author: Jeff Hill - */ - -#define epicsExportSharedSymbols -#include "osiSock.h" -#include "errlog.h" - -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressReuseDuringTimeWaitState ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEADDR, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEADDR?\n"); - } -} - -/* - * SO_REUSEPORT is not in POSIX - */ -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressUseForDatagramFanout ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEPORT, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEPORT?\n"); - } -} diff --git a/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c b/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c new file mode 100644 index 000000000..20bd82b14 --- /dev/null +++ b/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c @@ -0,0 +1,19 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#define EPICS_PRIVATE_API +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + * See https://www.unix.com/man-page/osx/2/setsockopt + */ +int epicsSocketUnsentCount(SOCKET sock) { + int unsent; + socklen_t len = sizeof(unsent); + if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0) + return unsent; + return -1; +} diff --git a/modules/libcom/src/osi/os/posix/epicsMath.h b/modules/libcom/src/osi/os/posix/epicsMath.h index 4e558676c..6a76f0afb 100644 --- a/modules/libcom/src/osi/os/posix/epicsMath.h +++ b/modules/libcom/src/osi/os/posix/epicsMath.h @@ -14,6 +14,18 @@ #include #ifdef __cplusplus + +#if __cplusplus>=201103L +#include + +#if __GLIBCXX__>20160427 +using std::isfinite; +using std::isinf; +using std::isnan; +using std::isnormal; +#endif +#endif /* c++11 */ + extern "C" { #endif diff --git a/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp b/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp index 3a3f78ebd..bac6a587e 100644 --- a/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp +++ b/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp @@ -12,6 +12,9 @@ /* * Author: Jeff Hill */ +#if defined(__rtems__) +# define __BSD_VISIBLE 1 +#endif #define epicsExportSharedSymbols #include "osiSock.h" @@ -31,19 +34,23 @@ epicsShareFunc void epicsShareAPI } } -/* - * SO_REUSEPORT is not in POSIX - */ +#ifdef SO_REUSEPORT +# define X_REUSEUDP SO_REUSEPORT +#else +# define X_REUSEUDP SO_REUSEADDR +#endif + epicsShareFunc void epicsShareAPI epicsSocketEnableAddressUseForDatagramFanout ( SOCKET s ) { int yes = true; int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEADDR, + status = setsockopt ( s, SOL_SOCKET, X_REUSEUDP, (char *) & yes, sizeof ( yes ) ); if ( status < 0 ) { errlogPrintf ( "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEADDR?\n"); + "unable to set %s?\n", + (X_REUSEUDP==SO_REUSEADDR)?"SO_REUSEADDR":"SO_REUSEPORT"); } } diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index 7b75bdd0f..9068d0b5c 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -38,6 +38,7 @@ #include "errlog.h" #include "epicsAssert.h" #include "epicsExit.h" +#include "epicsAtomic.h" epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level); epicsShareFunc void osdThreadHooksRun(epicsThreadId id); @@ -167,12 +168,14 @@ static epicsThreadOSD * create_threadInfo(const char *name) return NULL; } strcpy(pthreadInfo->name, name); + epicsAtomicIncrIntT(&pthreadInfo->refcnt); /* initial ref for the thread itself */ return pthreadInfo; } static epicsThreadOSD * init_threadInfo(const char *name, unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void *parm) + EPICSTHREADFUNC funptr,void *parm, + unsigned joinable) { epicsThreadOSD *pthreadInfo; int status; @@ -182,12 +185,15 @@ static epicsThreadOSD * init_threadInfo(const char *name, return NULL; pthreadInfo->createFunc = funptr; pthreadInfo->createArg = parm; + pthreadInfo->joinable = joinable; status = pthread_attr_init(&pthreadInfo->attr); checkStatusOnce(status,"pthread_attr_init"); if(status) return 0; - status = pthread_attr_setdetachstate( - &pthreadInfo->attr, PTHREAD_CREATE_DETACHED); - checkStatusOnce(status,"pthread_attr_setdetachstate"); + if(!joinable){ + status = pthread_attr_setdetachstate( + &pthreadInfo->attr, PTHREAD_CREATE_DETACHED); + checkStatusOnce(status,"pthread_attr_setdetachstate"); + } #if defined (_POSIX_THREAD_ATTR_STACKSIZE) #if ! defined (OSITHREAD_USE_DEFAULT_STACK) status = pthread_attr_setstacksize( &pthreadInfo->attr,(size_t)stackSize); @@ -204,6 +210,8 @@ static void free_threadInfo(epicsThreadOSD *pthreadInfo) { int status; + if(epicsAtomicDecrIntT(&pthreadInfo->refcnt) > 0) return; + status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo"); if(pthreadInfo->isOnThreadList) ellDelete(&pthreadList,&pthreadInfo->node); @@ -366,7 +374,7 @@ static void once(void) if(errVerbose) fprintf(stderr,"task priorities are not implemented\n"); #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ - pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0); + pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0,0); assert(pthreadInfo!=NULL); status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo); checkStatusOnceQuit(status,"pthread_setspecific","epicsThreadInit"); @@ -445,15 +453,22 @@ void epicsThreadRealtimeLock(void) #endif } -epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) -{ #if defined (OSITHREAD_USE_DEFAULT_STACK) - return 0; +#define STACK_SIZE(f) (0) #elif defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE > 0 #define STACK_SIZE(f) (f * 0x10000 * sizeof(void *)) static const unsigned stackSizeTable[epicsThreadStackBig+1] = { STACK_SIZE(1), STACK_SIZE(2), STACK_SIZE(4) }; +#else +#define STACK_SIZE(f) (0) +#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/ + +epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) +{ +#if defined (OSITHREAD_USE_DEFAULT_STACK) + return 0; +#elif defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE > 0 if (stackSizeClassstackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); + sigfillset(&blockAllSig); - pthread_sigmask(SIG_SETMASK,&blockAllSig,&oldSig); - pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm); - if(pthreadInfo==0) return 0; + pthread_sigmask(SIG_SETMASK, &blockAllSig, &oldSig); + + pthreadInfo = init_threadInfo(name, opts->priority, stackSize, funptr, + parm, opts->joinable); + if (pthreadInfo==0) + return 0; + pthreadInfo->isEpicsThread = 1; - setSchedulingPolicy(pthreadInfo,SCHED_FIFO); + setSchedulingPolicy(pthreadInfo, SCHED_FIFO); pthreadInfo->isRealTimeScheduled = 1; - status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr, - start_routine,pthreadInfo); - if(status==EPERM){ + + status = pthread_create(&pthreadInfo->tid, &pthreadInfo->attr, + start_routine, pthreadInfo); + if (status==EPERM) { /* Try again without SCHED_FIFO*/ free_threadInfo(pthreadInfo); - pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm); - if(pthreadInfo==0) return 0; + + pthreadInfo = init_threadInfo(name, opts->priority, stackSize, + funptr, parm, opts->joinable); + if (pthreadInfo==0) + return 0; + pthreadInfo->isEpicsThread = 1; - status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr, - start_routine,pthreadInfo); + status = pthread_create(&pthreadInfo->tid, &pthreadInfo->attr, + start_routine, pthreadInfo); } - checkStatusOnce(status,"pthread_create"); - if(status) { + checkStatusOnce(status, "pthread_create"); + if (status) { free_threadInfo(pthreadInfo); return 0; } - status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL); - checkStatusOnce(status,"pthread_sigmask"); - return(pthreadInfo); + + status = pthread_sigmask(SIG_SETMASK, &oldSig, NULL); + checkStatusOnce(status, "pthread_sigmask"); + if (pthreadInfo->joinable) { + /* extra ref for epicsThreadMustJoin() */ + epicsAtomicIncrIntT(&pthreadInfo->refcnt); + } + return pthreadInfo; } /* @@ -584,7 +623,40 @@ static epicsThreadOSD *createImplicit(void) } return pthreadInfo; } - + +void epicsThreadMustJoin(epicsThreadId id) +{ + void *ret = NULL; + int status; + + if(!id) { + return; + } else if(!id->joinable) { + if(epicsThreadGetIdSelf()==id) { + errlogPrintf("Warning: %s thread self-join of unjoinable\n", id->name); + + } else { + /* try to error nicely, however in all likelyhood de-ref of + * 'id' has already caused SIGSEGV as we are racing thread exit, + * which free's 'id'. + */ + cantProceed("Error: %s thread not joinable.\n", id->name); + } + return; + } + + status = pthread_join(id->tid, &ret); + if(status == EDEADLK) { + /* Thread can't join itself (directly or indirectly) + * so we detach instead. + */ + status = pthread_detach(id->tid); + checkStatusOnce(status, "pthread_detach"); + } else checkStatusOnce(status, "pthread_join"); + id->joinable = 0; + free_threadInfo(id); +} + epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void) { epicsThreadOSD *pthreadInfo; diff --git a/modules/libcom/src/osi/os/posix/osdThread.h b/modules/libcom/src/osi/os/posix/osdThread.h index 3a80b537c..8fe8f14eb 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.h +++ b/modules/libcom/src/osi/os/posix/osdThread.h @@ -3,9 +3,8 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ #ifndef osdThreadh #define osdThreadh @@ -22,6 +21,7 @@ extern "C" { typedef struct epicsThreadOSD { ELLNODE node; + int refcnt; pthread_t tid; pthread_attr_t attr; struct sched_param schedParam; @@ -34,6 +34,7 @@ typedef struct epicsThreadOSD { int isRealTimeScheduled; int isOnThreadList; unsigned int osiPriority; + int joinable; char name[1]; /* actually larger */ } epicsThreadOSD; diff --git a/modules/libcom/src/osi/os/solaris/osdgetexec.c b/modules/libcom/src/osi/os/solaris/osdgetexec.c new file mode 100644 index 000000000..ff9739ca9 --- /dev/null +++ b/modules/libcom/src/osi/os/solaris/osdgetexec.c @@ -0,0 +1,30 @@ + +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + const char *raw = getexecname(); + char *ret = NULL; + /* manpage says getexecname() might return a relative path. we treat this as an error */ + if(raw[0]=='/') { + ret = strdup(raw); + } + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c b/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c index 82bec603d..93d30fc38 100644 --- a/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c +++ b/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c @@ -110,7 +110,21 @@ static long vxDevWriteProbe (unsigned wordSize, volatile void *ptr, const void * static void *devA24Malloc(size_t size); static void devA24Free(void *pBlock); -static long devInit(void) { return 0;} + +/* We don't know which functions are implemented in the BSP */ +static int (*sysIntEnableFunc)(int) = NULL; +static int (*sysIntDisableFunc)(int) = NULL; +static int (*sysIntEnablePICFunc)(int) = NULL; +static int (*sysIntDisablePICFunc)(int) = NULL; + +static long devInit(void) +{ + sysIntEnableFunc = epicsFindSymbol ("sysIntEnable"); + sysIntDisableFunc = epicsFindSymbol ("sysIntDisable"); + sysIntDisablePICFunc = epicsFindSymbol ("sysIntDisablePIC"); + sysIntEnablePICFunc = epicsFindSymbol ("sysIntEnablePIC"); + return 0; +} static long vxDevConnectInterruptVME ( unsigned vectorNumber, @@ -214,16 +228,16 @@ static long vxDevDisconnectInterruptVME ( */ static long vxDevEnableInterruptLevelVME (unsigned level) { -# if CPU_FAMILY != I80X86 + if (sysIntEnableFunc) { int s; - s = sysIntEnable (level); + s = sysIntEnableFunc (level); if (s!=OK) { return S_dev_intEnFail; } return 0; -# else + } else { return S_dev_intEnFail; -# endif + } } /* @@ -231,16 +245,16 @@ static long vxDevEnableInterruptLevelVME (unsigned level) */ long devEnableInterruptLevelISA (unsigned level) { -# if CPU_FAMILY == I80X86 + if (sysIntEnablePICFunc) { int s; - s = sysIntEnablePIC (level); + s = sysIntEnablePICFunc (level); if (s!=OK) { return S_dev_intEnFail; } return 0; -# else + } else { return S_dev_intEnFail; -# endif + } } /* @@ -248,15 +262,15 @@ long devEnableInterruptLevelISA (unsigned level) */ long devDisableInterruptLevelISA (unsigned level) { -# if CPU_FAMILY == I80X86 + if (sysIntDisablePICFunc) { int s; - s = sysIntDisablePIC (level); + s = sysIntDisablePICFunc (level); if (s!=OK) { return S_dev_intEnFail; } -# else + } else { return S_dev_intEnFail; -# endif + } return 0; } @@ -266,16 +280,16 @@ long devDisableInterruptLevelISA (unsigned level) */ static long vxDevDisableInterruptLevelVME (unsigned level) { -# if CPU_FAMILY != I80X86 + if (sysIntDisableFunc) { int s; - s = sysIntDisable (level); + s = sysIntDisableFunc (level); if (s!=OK) { return S_dev_intDissFail; } return 0; -# else + } else { return S_dev_intEnFail; -# endif + } } /* diff --git a/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c b/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c index e0c6b2278..1e6b0a8ad 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c +++ b/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c @@ -9,10 +9,13 @@ #include #include +#include +#include #define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE #include "epicsTypes.h" #include "epicsTime.h" +#include "cantProceed.h" #define NS_PER_SEC 1000000000 @@ -23,6 +26,7 @@ union timebase { UINT64 u64; /* epicsMonotonicGet() */ }; +static void measureTickRate(void); #if CPU_FAMILY == PPC #include @@ -46,12 +50,15 @@ void osdMonotonicInit(void) if (sysTimeBaseFreq) { ticksPerSec = sysTimeBaseFreq(); - if (!ticksPerSec) - printf("Warning: Failed to set up monotonic time source.\n"); - /* Warn here only if the BSP routine exists but returned 0 */ + if (ticksPerSec) + return; + + /* This should never happen */ + printf("Warning: sysTimeBaseFreq() present but returned zero.\n"); } - else - ticksPerSec = 0; /* Warn on first use */ + + /* Fall back to measuring */ + measureTickRate(); } @@ -73,8 +80,14 @@ void osdMonotonicInit(void) { ticksPerSec = vxCpuIdGetFreq(); - if (!ticksPerSec) - printf("Warning: Failed to set up monotonic time source.\n"); + if (ticksPerSec) + return; + + /* This should never happen */ + printf("Warning: vxCpuIdGetFreq() returned zero.\n"); + + /* Fall back to measuring */ + measureTickRate(); } @@ -96,13 +109,7 @@ epicsUInt64 epicsMonotonicGet(void) union timebase tbNow; if (!ticksPerSec) { - static int warned = 0; - - if (!warned) { - printf("Warning: Monotonic time source is not available.\n"); - warned = 1; - } - return 0; + cantProceed("Monotonic time source not available.\n"); } TIMEBASEGET(tbNow); @@ -111,3 +118,20 @@ epicsUInt64 epicsMonotonicGet(void) */ return ((long double) tbNow.u64) * NS_PER_SEC / ticksPerSec; } + +static void measureTickRate(void) +{ + union timebase start, end; + int sysTicks = sysClkRateGet(); /* 1 second */ + + printf("osdMonotonicInit: Measuring CPU time-base frequency ..."); + fflush(stdout); + + taskDelay(1); + TIMEBASEGET(start); + taskDelay(sysTicks); + TIMEBASEGET(end); + ticksPerSec = end.u64 - start.u64; + + printf(" %llu ticks/sec.\n", (unsigned long long) ticksPerSec); +} diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index ce01ea609..babdf11cf 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -34,6 +34,22 @@ #include "vxLib.h" #include "epicsExit.h" +#ifdef EPICS_THREAD_CAN_JOIN + /* The implementation of epicsThreadMustJoin() here uses 2 features + * of VxWorks that were first introduced in VxWorks 6.9: taskWait(), + * and the taskSpareFieldGet/Set routines in taskUtilLib. + */ + #include + + #define JOIN_WARNING_TIMEOUT (60 * sysClkRateGet()) + + static SPARE_NUM joinField; + #define ALLOT_JOIN(tid) taskSpareNumAllot(tid, &joinField) +#else + #define ALLOT_JOIN(tid) +#endif + + epicsShareFunc void osdThreadHooksRun(epicsThreadId id); #if CPU_FAMILY == MC680X0 @@ -109,6 +125,7 @@ static void epicsThreadInit(void) assert(taskIdList); taskIdListSize = ID_LIST_CHUNK; atRebootRegister(); + ALLOT_JOIN(0); done = 1; } lock = 0; @@ -170,19 +187,62 @@ void epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg) } semGive(epicsThreadOnceMutex); } - -static void createFunction(EPICSTHREADFUNC func, void *parm) + +#ifdef EPICS_THREAD_CAN_JOIN + +/* The next 2 routines are not static so they appear in the back-trace + * of the epicsThreads that have called them. + */ +void epicsThreadAwaitingJoin(int tid) +{ + SEM_ID joinSem = (SEM_ID) taskSpareFieldGet(tid, joinField); + STATUS status; + + if (!joinSem || (int) joinSem == ERROR) + return; + + /* Wait for our supervisor */ + status = semTake(joinSem, JOIN_WARNING_TIMEOUT); + if (status && errno == S_objLib_OBJ_TIMEOUT) { + errlogPrintf("Warning: epicsThread '%s' still awaiting join\n", + epicsThreadGetNameSelf()); + status = semTake(joinSem, WAIT_FOREVER); + } + if (status) + perror("epicsThreadAwaitingJoin"); + + taskSpareFieldSet(tid, joinField, 0); + semDelete(joinSem); +} + #define PREPARE_JOIN(tid, joinable) \ + taskSpareFieldSet(tid, joinField, \ + joinable ? (int) semBCreate(SEM_Q_FIFO, SEM_EMPTY) : 0) + #define AWAIT_JOIN(tid) \ + epicsThreadAwaitingJoin(tid) + +#else + + #define PREPARE_JOIN(tid, joinable) + #define AWAIT_JOIN(tid) + +#endif + +void epicsThreadEntry(EPICSTHREADFUNC func, void *parm) { int tid = taskIdSelf(); taskVarAdd(tid,(int *)(char *)&papTSD); - /*Make sure that papTSD is still 0 after that call to taskVarAdd*/ - papTSD = 0; + papTSD = NULL; /* Initialize for this thread */ + osdThreadHooksRun((epicsThreadId)tid); + (*func)(parm); + epicsExitCallAtThreadExits (); free(papTSD); taskVarDelete(tid,(int *)(char *)&papTSD); + + AWAIT_JOIN(tid); } #ifdef ALTIVEC @@ -190,27 +250,87 @@ static void createFunction(EPICSTHREADFUNC func, void *parm) #else #define TASK_FLAGS (VX_FP_TASK) #endif -epicsThreadId epicsThreadCreate(const char *name, - unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void *parm) +epicsThreadId epicsThreadCreateOpt(const char * name, + EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { + unsigned int stackSize; int tid; epicsThreadInit(); - if(stackSize<100) { - errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,stackSize); - return(0); + + if (!opts) { + static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT; + opts = &opts_default; } - tid = taskSpawn((char *)name,getOssPriorityValue(priority), + stackSize = opts->stackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); + + if (stackSize < 100) { + errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n", + name, stackSize); + return 0; + } + + tid = taskCreate((char *)name,getOssPriorityValue(opts->priority), TASK_FLAGS, stackSize, - (FUNCPTR)createFunction,(int)funptr,(int)parm, + (FUNCPTR)epicsThreadEntry, (int)funptr, (int)parm, 0,0,0,0,0,0,0,0); - if(tid==ERROR) { + if (tid == ERROR) { errlogPrintf("epicsThreadCreate %s failure %s\n", - name,strerror(errno)); - return(0); + name, strerror(errno)); + return 0; } - return((epicsThreadId)tid); + + PREPARE_JOIN(tid, opts->joinable); + taskActivate(tid); + + return (epicsThreadId)tid; +} + +void epicsThreadMustJoin(epicsThreadId id) +{ +#ifdef EPICS_THREAD_CAN_JOIN + const char *fn = "epicsThreadMustJoin"; + int tid = (int) id; + SEM_ID joinSem; + STATUS status; + + if (!tid) + return; + + joinSem = (SEM_ID) taskSpareFieldGet(tid, joinField); + if ((int) joinSem == ERROR) { + errlogPrintf("%s: Thread %#x no longer exists.\n", fn, tid); + return; + } + + if (tid == taskIdSelf()) { + if (joinSem) { + taskSpareFieldSet(tid, joinField, 0); + semDelete(joinSem); + } + else { + errlogPrintf("%s: Thread '%s' (%#x) can't self-join.\n", + fn, epicsThreadGetNameSelf(), tid); + } + return; + } + + if (!joinSem) { + cantProceed("%s: Thread '%s' (%#x) is not joinable.\n", + fn, taskName(tid), tid); + return; + } + + semGive(joinSem); /* Rendezvous with thread */ + + status = taskWait(tid, WAIT_FOREVER); + if (status && errno != S_objLib_OBJ_ID_ERROR) { + perror(fn); + cantProceed("%s: ", fn); + } +#endif } void epicsThreadSuspendSelf() diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.h b/modules/libcom/src/osi/os/vxWorks/osdThread.h index 2ee9f2d46..15145663b 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.h +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.h @@ -3,11 +3,17 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ + #ifndef osdThreadh #define osdThreadh +/* VxWorks 6.9 and later can support joining threads */ + +#if (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR < 9) +#undef EPICS_THREAD_CAN_JOIN +#endif + #endif /* osdThreadh */ diff --git a/modules/libcom/src/osi/os/vxWorks/osdTime.cpp b/modules/libcom/src/osi/os/vxWorks/osdTime.cpp index fdfefb704..27f50eb4e 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdTime.cpp +++ b/modules/libcom/src/osi/os/vxWorks/osdTime.cpp @@ -25,22 +25,38 @@ #define NTP_REQUEST_TIMEOUT 4 /* seconds */ +extern "C" { + int tz2timezone(void); +} + static char sntp_sync_task[] = "ipsntps"; static char ntp_daemon[] = "ipntpd"; static const char *pserverAddr = NULL; +static CLOCKTIME_SYNCHOOK prevHook; + extern char* sysBootLine; +static void timeSync(int synchronized) { + if (!tz2timezone()) + ClockTime_syncHook = prevHook; /* Don't call me again */ +} + static int timeRegister(void) { - /* If TIMEZONE not defined, set it from EPICS_TIMEZONE */ - if (getenv("TIMEZONE") == NULL) { - const char *timezone = envGetConfigParamPtr(&EPICS_TIMEZONE); - if (timezone == NULL) { - printf("timeRegister: No Time Zone Information\n"); - } else { - epicsEnvSet("TIMEZONE", timezone); + /* If TZ not defined, set it from EPICS_TZ */ + if (getenv("TZ") == NULL) { + const char *tz = envGetConfigParamPtr(&EPICS_TZ); + + if (tz && *tz) { + epicsEnvSet("TZ", tz); + + /* Call tz2timezone() once we know what year it is */ + prevHook = ClockTime_syncHook; + ClockTime_syncHook = timeSync; } + else if (getenv("TIMEZONE") == NULL) + printf("timeRegister: No Time Zone Information available\n"); } // Define EPICS_TS_FORCE_NTPTIME to force use of NTPTime provider @@ -58,7 +74,7 @@ static int timeRegister(void) } if (useNTP) { - // Start NTP first so it can be used to sync SysTime + // Start NTP first so it can be used to sync ClockTime NTPTime_Init(100); ClockTime_Init(CLOCKTIME_SYNC); } else { diff --git a/modules/libcom/src/osi/os/vxWorks/tz2timezone.c b/modules/libcom/src/osi/os/vxWorks/tz2timezone.c new file mode 100644 index 000000000..df8db8514 --- /dev/null +++ b/modules/libcom/src/osi/os/vxWorks/tz2timezone.c @@ -0,0 +1,278 @@ +/*************************************************************************\ +* Copyright (c) 2009 Brookhaven Science Associates, as Operator of +* Brookhaven National Laboratory. +* Copyright (c) 2019 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. +\*************************************************************************/ +/* + * Authors: Larry Hoff, Andrew Johnson + */ + +/* + * This file exports a single function "int tz2timezone(void)" which reads + * the TZ environment variable (defined by POSIX) and converts it to the + * TIMEZONE environment variable defined by ANSI. The latter is used by + * VxWorks "time" functions, is largely deprecated in other computing + * environments, has limitations, and is difficult to maintain. This holds + * out the possibility of "pretending" that VxWorks supports "TZ" - until + * such time as it actually does. + * + * For simplicity, only the "POSIX standard form" of TZ will be supported. + * Even that is complicated enough (see following spec). Furthermore, + * only the "M" form of DST start and stop dates are supported. + * + * TZ = zone[-]offset[dst[offset],start[/time],end[/time]] + * + * zone + * A three or more letter name for the timezone in normal (winter) time. + * + * [-]offset + * A signed time giving the offset of the time zone westwards from + * Greenwich. The time has the form hh[:mm[:ss]] with a one of two + * digit hour, and optional two digit minutes and seconds. + * + * dst + * The name of the time zone when daylight saving is in effect. It may + * be followed by an offset giving how big the adjustment is, required + * if different than the default of 1 hour. + * + * start/time,end/time + * Specify the start and end of the daylight saving period. The start + * and end fields indicate on what day the changeover occurs, and must + * be in this format: + * + * Mm.n.d + * This indicates month m, the n-th occurrence of day d, where + * 1 <= m <= 12, 1 <= n <= 5, 0 <= d <= 6, 0=Sunday + * The 5th occurrence means the last occurrence of that day in a + * month. So M4.1.0 is the first Sunday in April, M9.5.0 is the + * last Sunday in September. + * + * The time field indicates what hour the changeover occurs on the given + * day (TIMEZONE only supports switching on the hour). + * + */ + +#include +#include /* getenv() */ +#include /* printf() */ +#include /* strchr() */ +#include /* isalpha() */ + +#include + +/* for reference: TZ syntax, example, and TIMEZONE example + * std offset dst [offset],start[/time],end[/time] + * CST6CDT5,M3.2.0,M11.1.0 + * EST+5EDT,M4.1.0/2,M10.5.0/2 + * + * std offset start stop + * TIMEZONE=EST::300:030802:110102 + */ + +static int extractDate(const char *tz, struct tm *current, char *s) +{ + static const int startdays[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 + }; + static const int molengths[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + + int month, week, weekday, hour=2; /* default=2AM */ + int jan1wday, wday, mday; + + /* Require 'M' format */ + if (*++tz != 'M') { + printf("tz2timezone: Unsupported date type, need 'M' format\n"); + return ERROR; + } + tz++; + + if (sscanf(tz, "%d.%d.%d/%d", &month, &week, &weekday, &hour) < 3) + return ERROR; /* something important missing */ + + if (month == 0 || month>12 || + week < 1 || week > 5 || + weekday < 0 || weekday > 6 || + hour < 0 || hour > 23) + return ERROR; + + /* Now for some brute-force calendar calculations... */ + /* start month is in "month", and the day is "weekday", but + we need to know when that weekday first occurs in that month */ + /* Let's start with weekday on Jan. 1 */ + jan1wday = (7 + current->tm_wday - (current->tm_yday % 7)) % 7; + + /* We need to know if it is a leap year (and if it matters) */ + /* Let's assume that we're working with a date between 1901 and 2099, + that way we don't have to think about the "century exception". + If this code is still running (unchanged) in 2100, I'll be stunned + (and 139 years old) */ + wday = (jan1wday + startdays[month-1] + + ((month > 2 && (current->tm_year % 4 == 0)) ? 1 : 0)) % 7; + + /* Let's see on what day-of-the-month the first target weekday occurs + (counting from 1). The result is a number between 1 and 7, inclusive. */ + mday = 1 + ((7 + weekday - wday) % 7); + + /* Next, we add the week offset. If we overflow the month, we subtract + one week */ + mday += 7 * (week - 1); + if (mday > molengths[month-1]) + mday -= 7; + + /* Should I handle Feb 29? I'm willing to gamble that no one in their right + mind would schedule a time change to occur on Feb. 29. If so, we'll be a + week early */ + sprintf(s, "%02d%02d%02d", month, mday, hour); + + return OK; +} + + +static const char *getTime(const char *s, int *time) +{ + /* Time format is [+/-]hh[:mm][:ss] followed by the next zone name */ + + *time = 0; + + if (!isdigit((int) s[0])) + return s; /* no number here... */ + + if (!isdigit((int) s[1])) { /* single digit form */ + *time = s[0] - '0'; + return s + 1; + } + + if (isdigit((int) s[1])) { /* two digit form */ + *time = 10 * (s[0] - '0') + (s[1] - '0'); + return s + 2; + } + + return s; /* does not follow supported form */ +} + +int tz2timezone(void) +{ + const char *tz = getenv("TZ"); + /* Spec. says that zone names must be at least 3 chars. + * I've never seen a longer zone name, but I'll allocate + * 40 chars. If you live in a zone with a longer name, + * you may want to think about the benefits of relocation. + */ + char zone[40]; + char start[10], stop[10]; /* only really need 7 bytes now */ + int hours = 0, minutes = 0, sign = 1; + /* This is more than enough, even with a 40-char zone + * name, and 4-char offset. + */ + char timezone[100]; + int i = 0; /* You *always need an "i" :-) */ + epicsTimeStamp now; + struct tm current; + + /* First let's get the current time. We need the year to + * compute the start/stop dates for DST. + */ + if (epicsTimeGetCurrent(&now) || + epicsTimeToTM(¤t, NULL, &now)) + return ERROR; + + /* Make sure TZ exists. + * Spec. says that ZONE must be at least 3 chars. + */ + if ((!tz) || (strlen(tz) < 3)) + return ERROR; + + /* OK, now a bunch of brute-force parsing. My brain hurts if + * I try to think of an elegant regular expression for the + * string. + */ + + /* Start extracting zone name, must be alpha */ + while ((i < sizeof(zone) - 1) && isalpha((int) *tz)) { + zone[i++] = *tz++; + } + if (i < 3) + return ERROR; /* Too short, not a real zone name? */ + + zone[i] = 0; /* Nil-terminate (for now) */ + + /* Now extract offset time. The format is [+/-]hh[:mm[:ss]] + * Recall that TIMEZONE doesn't support seconds.... + */ + if (*tz == '-') { + sign = -1; + tz++; + } + else if (*tz == '+') { + tz++; + } + + /* Need a digit now */ + if (!isdigit((int) *tz)) + return ERROR; + + /* First get the hours */ + tz = getTime(tz, &hours); + if (hours > 24) + return ERROR; + + if (*tz == ':') { /* There is a minutes part */ + /* Need another digit now */ + if (!isdigit((int) *++tz)) + return ERROR; + + /* Extract the minutes */ + tz = getTime(tz, &minutes); + if (minutes > 60) + return ERROR; + + /* Skip any seconds part */ + if (*tz == ':') { + int seconds; + tz = getTime(tz + 1, &seconds); + } + } + + /* Extract any DST zone name, must be alpha */ + if (isalpha((int) *tz)) { + zone[i++] = '/'; /* Separate the names */ + + while ((i < sizeof(zone) - 1) && isalpha((int) *tz)) { + zone[i++] = *tz++; + } + zone[i] = 0; /* Nil-terminate */ + } + + minutes += hours * 60; + minutes *= sign; + + /* Look for start/stop dates - require neither or both */ + tz = strchr(tz, ','); + if (!tz) { /* No daylight savings time here */ + /* Format the env. variable */ + sprintf(timezone, "TIMEZONE=%s::%d", zone, minutes); + } + else { + if (extractDate(tz, ¤t, start) != OK) + return ERROR; + + tz = strchr(tz + 1, ','); + if (!tz) + return ERROR; + if (extractDate(tz, ¤t, stop) != OK) + return ERROR; + + /* Format the env. variable */ + sprintf(timezone, "TIMEZONE=%s::%d:%s:%s", zone, minutes, start, stop); + } + + /* Make it live! */ + putenv(timezone); + + return OK; +} diff --git a/modules/libcom/src/osi/osiClockTime.c b/modules/libcom/src/osi/osiClockTime.c index 091a95715..c591d3839 100644 --- a/modules/libcom/src/osi/osiClockTime.c +++ b/modules/libcom/src/osi/osiClockTime.c @@ -23,7 +23,8 @@ #include "taskwd.h" #define NSEC_PER_SEC 1000000000 -#define ClockTimeSyncInterval_value 60.0 +#define ClockTimeSyncInterval_initial 1.0 +#define ClockTimeSyncInterval_normal 60.0 static struct { @@ -79,7 +80,7 @@ static void ClockTime_InitOnce(void *pfirst) ClockTimePvt.loopEvent = epicsEventMustCreate(epicsEventEmpty); ClockTimePvt.lock = epicsMutexCreate(); - ClockTimePvt.ClockTimeSyncInterval = 1.0; /* First sync */ + ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_initial; epicsAtExit(ClockTime_Shutdown, NULL); @@ -148,6 +149,8 @@ void ClockTime_GetProgramStart(epicsTimeStamp *pDest) /* Synchronization thread */ #if defined(vxWorks) || defined(__rtems__) +CLOCKTIME_SYNCHOOK ClockTime_syncHook = NULL; + static void ClockTimeSync(void *dummy) { taskwdInsert(0, NULL, NULL); @@ -179,11 +182,16 @@ static void ClockTimeSync(void *dummy) ClockTimePvt.syncTime = timeNow; epicsMutexUnlock(ClockTimePvt.lock); - ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_value; + if (ClockTime_syncHook) + ClockTime_syncHook(1); + + ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_normal; } } ClockTimePvt.synchronized = 0; + if (ClockTime_syncHook) + ClockTime_syncHook(0); taskwdRemove(0); } #endif diff --git a/modules/libcom/src/osi/osiClockTime.h b/modules/libcom/src/osi/osiClockTime.h index 17eacab3e..23598886d 100644 --- a/modules/libcom/src/osi/osiClockTime.h +++ b/modules/libcom/src/osi/osiClockTime.h @@ -19,6 +19,12 @@ void ClockTime_Init(int synchronize); void ClockTime_Shutdown(void *dummy); int ClockTime_Report(int level); +#if defined(vxWorks) || defined(__rtems__) +typedef void (* CLOCKTIME_SYNCHOOK)(int synchronized); + +extern CLOCKTIME_SYNCHOOK ClockTime_syncHook; +#endif + #ifdef __cplusplus } #endif diff --git a/modules/libcom/src/osi/osiSock.h b/modules/libcom/src/osi/osiSock.h index 061619e89..6e3b053c5 100644 --- a/modules/libcom/src/osi/osiSock.h +++ b/modules/libcom/src/osi/osiSock.h @@ -52,6 +52,14 @@ enum epicsSocketSystemCallInterruptMechanismQueryInfo { epicsShareFunc enum epicsSocketSystemCallInterruptMechanismQueryInfo epicsSocketSystemCallInterruptMechanismQuery (); +#ifdef EPICS_PRIVATE_API +/* + * Some systems (e.g Linux and Windows 10) allow to check the amount + * of unsent data in the output queue. + * Returns -1 if the information is not available. + */ +epicsShareFunc int epicsSocketUnsentCount(SOCKET sock); +#endif /* * convert socket address to ASCII in this order diff --git a/modules/libcom/src/taskwd/taskwd.c b/modules/libcom/src/taskwd/taskwd.c index 44ddc779c..4f30a5a5d 100644 --- a/modules/libcom/src/taskwd/taskwd.c +++ b/modules/libcom/src/taskwd/taskwd.c @@ -376,7 +376,7 @@ epicsShareFunc void taskwdShow(int level) mCount, tCount, fCount); if (level) { printf("%16.16s %9s %12s %12s %12s\n", - "THREAD NAME", "STATE", "EPICS TID", "CALLBACK", "USR ARG"); + "THREAD NAME", "STATE", "EPICS TID", "epicsCallback", "USR ARG"); pt = (struct tNode *)ellFirst(&tList); while (pt != NULL) { epicsThreadGetName(pt->tid, tName, sizeof(tName)); diff --git a/modules/libcom/src/timer/epicsTimer.cpp b/modules/libcom/src/timer/epicsTimer.cpp index e55280e7e..15bebef7f 100644 --- a/modules/libcom/src/timer/epicsTimer.cpp +++ b/modules/libcom/src/timer/epicsTimer.cpp @@ -173,7 +173,7 @@ extern "C" double epicsShareAPI epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId pQueue ) { try { - return pQueue->process ( epicsTime::getCurrent() ); + return pQueue->process ( epicsTime::getMonotonic() ); } catch ( ... ) { return 1.0; diff --git a/modules/libcom/src/timer/epicsTimer.h b/modules/libcom/src/timer/epicsTimer.h index 72270f273..6e054ed4f 100644 --- a/modules/libcom/src/timer/epicsTimer.h +++ b/modules/libcom/src/timer/epicsTimer.h @@ -118,7 +118,7 @@ inline double epicsTimer::getExpireDelay () { epicsTimer::expireInfo info = this->getExpireInfo (); if ( info.active ) { - double delay = info.expireTime - epicsTime::getCurrent (); + double delay = info.expireTime - epicsTime::getMonotonic (); if ( delay < 0.0 ) { delay = 0.0; } diff --git a/modules/libcom/src/timer/timer.cpp b/modules/libcom/src/timer/timer.cpp index 35d6e47bf..6f0c7ea4a 100644 --- a/modules/libcom/src/timer/timer.cpp +++ b/modules/libcom/src/timer/timer.cpp @@ -54,7 +54,7 @@ void timer::destroy () void timer::start ( epicsTimerNotify & notify, double delaySeconds ) { - this->start ( notify, epicsTime::getCurrent () + delaySeconds ); + this->start ( notify, epicsTime::getMonotonic () + delaySeconds ); } void timer::start ( epicsTimerNotify & notify, const epicsTime & expire ) @@ -129,7 +129,7 @@ void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire ) debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n", typeid ( this->notify ).name (), - expire - epicsTime::getCurrent (), + expire - epicsTime::getMonotonic (), this, preemptCount ) ); } @@ -190,7 +190,7 @@ void timer::show ( unsigned int level ) const double delay; if ( this->curState == statePending || this->curState == stateActive ) { try { - delay = this->exp - epicsTime::getCurrent(); + delay = this->exp - epicsTime::getMonotonic(); } catch ( ... ) { delay = - DBL_MAX; diff --git a/modules/libcom/src/timer/timerQueue.cpp b/modules/libcom/src/timer/timerQueue.cpp index 8f7f98e12..a62eab96e 100644 --- a/modules/libcom/src/timer/timerQueue.cpp +++ b/modules/libcom/src/timer/timerQueue.cpp @@ -30,7 +30,7 @@ timerQueue::timerQueue ( epicsTimerQueueNotify & notifyIn ) : pExpireTmr ( 0 ), processThread ( 0 ), exceptMsgTimeStamp ( - epicsTime :: getCurrent () - exceptMsgMinPeriod ), + epicsTime :: getMonotonic () - exceptMsgMinPeriod ), cancelPending ( false ) { } @@ -49,7 +49,7 @@ void timerQueue :: char date[64]; double delay; try { - epicsTime cur = epicsTime :: getCurrent (); + epicsTime cur = epicsTime :: getMonotonic (); delay = cur - this->exceptMsgTimeStamp; cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f" ); diff --git a/modules/libcom/src/timer/timerQueueActive.cpp b/modules/libcom/src/timer/timerQueueActive.cpp index 4db68c00c..5751b2428 100644 --- a/modules/libcom/src/timer/timerQueueActive.cpp +++ b/modules/libcom/src/timer/timerQueueActive.cpp @@ -73,7 +73,7 @@ void timerQueueActive :: _printLastChanceExceptionMessage ( { char date[64]; try { - epicsTime cur = epicsTime :: getCurrent (); + epicsTime cur = epicsTime :: getMonotonic (); cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f"); } catch ( ... ) { @@ -91,7 +91,7 @@ void timerQueueActive :: run () epics::atomic::set(this->exitFlag, 0); while ( ! this->terminateFlag ) { try { - double delay = this->queue.process ( epicsTime::getCurrent() ); + double delay = this->queue.process ( epicsTime::getMonotonic() ); debugPrintf ( ( "timer thread sleeping for %g sec (max)\n", delay ) ); this->rescheduleEvent.wait ( delay ); } diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index a76d3f1d8..0710e8103 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG PROD_LIBS += Com @@ -217,8 +217,17 @@ epicsMessageQueueTest_SRCS += epicsMessageQueueTest.cpp testHarness_SRCS += epicsMessageQueueTest.cpp TESTS += epicsMessageQueueTest +# we need to build this with debug symbols in all configurations +# otherwise the test will not be able to lookup names and so fail TESTPROD_HOST += epicsStackTraceTest epicsStackTraceTest_SRCS += epicsStackTraceTest.c +ifneq ($(findstring mingw,$(T_A)),) +epicsStackTraceTest_CFLAGS_WIN32 += -g -O0 +epicsStackTraceTest_LDFLAGS_WIN32 += -g +else +epicsStackTraceTest_CFLAGS_WIN32 += -Zi +epicsStackTraceTest_LDFLAGS_WIN32 += -DEBUG +endif testHarness_SRCS += epicsStackTraceTest.c TESTS += epicsStackTraceTest @@ -232,6 +241,11 @@ osiSockTest_SRCS += osiSockTest.c testHarness_SRCS += osiSockTest.c TESTS += osiSockTest +TESTPROD_HOST += testexecname +testexecname_SRCS += testexecname.c +# no point in including in testHarness. Not implemented for RTEMS/vxWorks. +TESTS += testexecname + ifeq ($(BUILD_CLASS),HOST) ifneq ($(OS_CLASS),WIN32) # This test can only be run on a build host, and is broken on Windows @@ -241,6 +255,11 @@ TESTS += yajlTest endif endif +TESTPROD_HOST += iocshTest +iocshTest_SRCS += iocshTest.cpp +TESTS += iocshTest +TESTFILES += $(wildcard ../iocshTest*.cmd) + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunLibComTests.c @@ -300,3 +319,6 @@ endif endif include $(TOP)/configure/RULES + +rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl + $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES) diff --git a/modules/libcom/test/aslibtest.c b/modules/libcom/test/aslibtest.c index 875aa56fd..4237fafb1 100644 --- a/modules/libcom/test/aslibtest.c +++ b/modules/libcom/test/aslibtest.c @@ -81,8 +81,8 @@ static const char hostname_config[] = "" static void testHostNames(void) { - testDiag("testHostNames()"); + asCheckClientIP = 0; testOk1(asInitMem(hostname_config, NULL)==0); @@ -102,18 +102,53 @@ static void testHostNames(void) testAccess("ro", 0); testAccess("rw", 0); - setHost("nosuchhost"); + setHost("guaranteed.invalid."); testAccess("invalid", 0); testAccess("DEFAULT", 0); testAccess("ro", 0); testAccess("rw", 0); } + +static void testUseIP(void) +{ + testDiag("testUseIP()"); + asCheckClientIP = 1; + + /* still host names in .acf */ + testOk1(asInitMem(hostname_config, NULL)==0); + /* now resolved to IPs */ + + setUser("testing"); + setHost("localhost"); /* will not match against resolved IP */ + asAsl = 0; + + testAccess("invalid", 0); + testAccess("DEFAULT", 0); + testAccess("ro", 0); + testAccess("rw", 0); + + setHost("127.0.0.1"); + + testAccess("invalid", 0); + testAccess("DEFAULT", 0); + testAccess("ro", 1); + testAccess("rw", 3); + + setHost("guaranteed.invalid."); + + testAccess("invalid", 0); + testAccess("DEFAULT", 0); + testAccess("ro", 0); + testAccess("rw", 0); +} + MAIN(aslibtest) { - testPlan(14); + testPlan(27); testSyntaxErrors(); testHostNames(); + testUseIP(); errlogFlush(); return testDone(); } diff --git a/modules/libcom/test/cvtFastPerform.cpp b/modules/libcom/test/cvtFastPerform.cpp index c3f99dc61..28c831349 100644 --- a/modules/libcom/test/cvtFastPerform.cpp +++ b/modules/libcom/test/cvtFastPerform.cpp @@ -147,11 +147,11 @@ void Perf :: measure (double srcD, float srcF, int prec) std::memset(buf, 0, sizeof(buf)); - epicsTime beg = epicsTime :: getCurrent (); + epicsTime beg = epicsTime :: getMonotonic (); for ( unsigned i = 0; i < nIterations; i++ ) { c->target (srcD, srcF, buf, sizeof(buf) - 1, prec); } - epicsTime end = epicsTime :: getCurrent (); + epicsTime end = epicsTime :: getMonotonic (); double elapsed = end - beg; elapsed /= nIterations * nUnrolled; diff --git a/modules/libcom/test/epicsAtomicPerform.cpp b/modules/libcom/test/epicsAtomicPerform.cpp index 2ef005efe..98eaf1778 100644 --- a/modules/libcom/test/epicsAtomicPerform.cpp +++ b/modules/libcom/test/epicsAtomicPerform.cpp @@ -394,12 +394,12 @@ static const unsigned N = 10000; void recursiveOwnershipRetPerformance () { RefCtr refCtr; - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); for ( size_t i = 0; i < N; i++ ) { Ownership ownership ( refCtr ); recurRetOwner1000 ( ownership ); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= N * 1000u; // convert to delay per call delay *= 1e6; // convert to micro seconds testDiag ( "retOwnership() takes %f microseconds", delay ); @@ -408,13 +408,13 @@ void recursiveOwnershipRetPerformance () void ownershipPassRefPerformance () { RefCtr refCtr; - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); for ( size_t i = 0; i < N; i++ ) { Ownership ownershipSrc ( refCtr ); Ownership ownershipDest; passRefOwnership1000 ( ownershipSrc, ownershipDest ); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= N * 1000u; // convert to delay per call delay *= 1e6; // convert to micro seconds testDiag ( "passRefOwnership() takes %f microseconds", delay ); @@ -456,7 +456,7 @@ void Ten < T > :: diagnostic ( double delay ) template < class T > void measurePerformance () { - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); T target; for ( size_t i = 0; i < N; i++ ) { target.run (); @@ -470,7 +470,7 @@ void measurePerformance () target.run (); target.run (); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= ( N * 10u ); // convert to delay per call target.diagnostic ( delay ); } diff --git a/modules/libcom/test/epicsCalcTest.cpp b/modules/libcom/test/epicsCalcTest.cpp index 2492c95ba..25701b153 100644 --- a/modules/libcom/test/epicsCalcTest.cpp +++ b/modules/libcom/test/epicsCalcTest.cpp @@ -612,18 +612,12 @@ MAIN(epicsCalcTest) testExpr(0.0 + NaN); testExpr(Inf + 0.0); testExpr(Inf + Inf); -#if defined(_WIN64) && defined(_MSC_VER) + // only test CALC as MSVC seems to incorrectly evaluate this expression at compile time. + // see note in epicsMathTest testCalc("Inf + -Inf", NaN); -#else - testExpr(Inf + -Inf); -#endif testExpr(Inf + NaN); testExpr(-Inf + 0.0); -#if defined(_WIN64) && defined(_MSC_VER) testCalc("-Inf + Inf", NaN); -#else - testExpr(-Inf + Inf); -#endif testExpr(-Inf + -Inf); testExpr(-Inf + NaN); testExpr(NaN + 0.0); diff --git a/modules/libcom/test/epicsEventTest.cpp b/modules/libcom/test/epicsEventTest.cpp index 7c1a24141..b3e48f8f2 100644 --- a/modules/libcom/test/epicsEventTest.cpp +++ b/modules/libcom/test/epicsEventTest.cpp @@ -156,9 +156,9 @@ static void eventWakeupTest(void) static double eventWaitMeasureDelayError( const epicsEventId &id, const double & delay ) { - epicsTime beg = epicsTime::getCurrent(); + epicsTime beg = epicsTime::getMonotonic(); epicsEventWaitWithTimeout ( id, delay ); - epicsTime end = epicsTime::getCurrent(); + epicsTime end = epicsTime::getMonotonic(); double meas = end - beg; double error = fabs ( delay - meas ); testDiag("epicsEventWaitWithTimeout(%.6f) delay error %.6f sec", diff --git a/modules/libcom/test/epicsMathTest.c b/modules/libcom/test/epicsMathTest.c index 8ea763cf0..6d1fb85e8 100644 --- a/modules/libcom/test/epicsMathTest.c +++ b/modules/libcom/test/epicsMathTest.c @@ -32,23 +32,23 @@ MAIN(epicsMathTest) testOk1(epicsINF > 0.0); testOk1(epicsINF - epicsINF != 0.0); -#if defined(_WIN64) && defined(_MSC_VER) - testTodoBegin("Known failure on windows-x64"); +#if defined(_MSC_VER) + testTodoBegin("Known failure on windows (MSVC optimizer bug?)"); #endif testOk1(epicsINF + -epicsINF != 0.0); testOk1(-epicsINF + epicsINF != 0.0); -#if defined(_WIN64) && defined(_MSC_VER) +#if defined(_MSC_VER) testTodoEnd(); #endif testOk1(isnan(epicsINF - epicsINF)); -#if defined(_WIN64) && defined(_MSC_VER) - testTodoBegin("Known failure on windows-x64"); +#if defined(_MSC_VER) + testTodoBegin("Known failure on windows (MSVC optimizer bug?)"); #endif testOk1(isnan(epicsINF + -epicsINF)); testOk1(isnan(-epicsINF + epicsINF)); -#if defined(_WIN64) && defined(_MSC_VER) +#if defined(_MSC_VER) testTodoEnd(); #endif @@ -62,12 +62,12 @@ MAIN(epicsMathTest) testOk1(!(epicsNAN > epicsNAN)); testOk1(isnan(epicsNAN - epicsNAN)); -#if defined(_WIN64) && defined(_MSC_VER) - testTodoBegin("Known failure on windows-x64"); +#if defined(_MSC_VER) + testTodoBegin("Known failure on windows (MSVC optimizer bug?)"); #endif testOk1(isnan(epicsNAN + -epicsNAN)); testOk1(isnan(-epicsNAN + epicsNAN)); -#if defined(_WIN64) && defined(_MSC_VER) +#if defined(_MSC_VER) testTodoEnd(); #endif diff --git a/modules/libcom/test/epicsMutexTest.cpp b/modules/libcom/test/epicsMutexTest.cpp index d44e5c0f1..e3ad5868f 100644 --- a/modules/libcom/test/epicsMutexTest.cpp +++ b/modules/libcom/test/epicsMutexTest.cpp @@ -168,32 +168,32 @@ void epicsMutexPerformance () unsigned i; // test a single lock pair - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); static const unsigned N = 1000; for ( i = 0; i < N; i++ ) { tenLockPairsSquared ( mutex ); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= N * 100u; // convert to delay per lock pair delay *= 1e6; // convert to micro seconds testDiag("lock()*1/unlock()*1 takes %f microseconds", delay); // test a two times recursive lock pair - begin = epicsTime::getCurrent (); + begin = epicsTime::getMonotonic (); for ( i = 0; i < N; i++ ) { tenDoubleRecursiveLockPairsSquared ( mutex ); } - delay = epicsTime::getCurrent () - begin; + delay = epicsTime::getMonotonic () - begin; delay /= N * 100u; // convert to delay per lock pair delay *= 1e6; // convert to micro seconds testDiag("lock()*2/unlock()*2 takes %f microseconds", delay); // test a four times recursive lock pair - begin = epicsTime::getCurrent (); + begin = epicsTime::getMonotonic (); for ( i = 0; i < N; i++ ) { tenQuadRecursiveLockPairsSquared ( mutex ); } - delay = epicsTime::getCurrent () - begin; + delay = epicsTime::getMonotonic () - begin; delay /= N * 100u; // convert to delay per lock pair delay *= 1e6; // convert to micro seconds testDiag("lock()*4/unlock()*4 takes %f microseconds", delay); diff --git a/modules/libcom/test/epicsSockResolveTest.c b/modules/libcom/test/epicsSockResolveTest.c index 8131d9dbf..04b2973fa 100644 --- a/modules/libcom/test/epicsSockResolveTest.c +++ b/modules/libcom/test/epicsSockResolveTest.c @@ -75,8 +75,11 @@ MAIN(epicsSockResolveTest) testSkip(2, " aToIPAddr() failed"); } else { - testOk(addr.sin_addr.s_addr == htonl(okdata[i].IP), " IP correct"); - testOk(addr.sin_port == htons(okdata[i].port), " Port correct"); + testOk(addr.sin_addr.s_addr == htonl(okdata[i].IP), + " IP correct 0x%08x == 0x%08x", (unsigned)ntohl(addr.sin_addr.s_addr), + (unsigned)okdata[i].IP); + testOk(addr.sin_port == htons(okdata[i].port), " Port correct %u == %u", + ntohs(addr.sin_port), okdata[i].port); } } diff --git a/modules/libcom/test/epicsStackTraceTest.c b/modules/libcom/test/epicsStackTraceTest.c index b89fc7836..f6c81a8f2 100644 --- a/modules/libcom/test/epicsStackTraceTest.c +++ b/modules/libcom/test/epicsStackTraceTest.c @@ -106,7 +106,7 @@ findStringOcc(const char *buf, const char *what) while ( (buf = strstr(buf, what)) ) { /* Is it just a prefix? */ ch = buf[l]; - if ( ! isalnum(ch) && '_' != ch ) { + if ( ! isalnum(ch) && '_' != ch && '.' != ch ) { rval++; } buf += l; diff --git a/modules/libcom/test/epicsThreadPerform.cpp b/modules/libcom/test/epicsThreadPerform.cpp index c8fd34515..b73d90c9e 100644 --- a/modules/libcom/test/epicsThreadPerform.cpp +++ b/modules/libcom/test/epicsThreadPerform.cpp @@ -55,9 +55,9 @@ static void epicsThreadPriorityTest() static double threadSleepMeasureDelayError ( const double & delay ) { - epicsTime beg = epicsTime::getCurrent(); + epicsTime beg = epicsTime::getMonotonic(); epicsThreadSleep ( delay ); - epicsTime end = epicsTime::getCurrent(); + epicsTime end = epicsTime::getMonotonic(); double meas = end - beg; double error = fabs ( delay - meas ); return error; @@ -76,10 +76,10 @@ static double measureSleepQuantum ( double interval = rand (); interval /= RAND_MAX; interval *= testInterval; - epicsTime start = epicsTime::getCurrent (); + epicsTime start = epicsTime::getMonotonic (); epicsTime current = start; while ( current - start < interval ) { - current = epicsTime::getCurrent (); + current = epicsTime::getMonotonic (); } errorSum += threadSleepMeasureDelayError ( testInterval ); if ( i % ( iterations / 10 ) == 0 ) { @@ -150,7 +150,7 @@ static void epicsThreadGetIdSelfPerfTest () { static const unsigned N = 10000; static const double microSecPerSec = 1e6; - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); for ( unsigned i = 0u; i < N; i++ ) { epicsThreadGetIdSelf (); epicsThreadGetIdSelf (); @@ -164,7 +164,7 @@ static void epicsThreadGetIdSelfPerfTest () epicsThreadGetIdSelf (); epicsThreadGetIdSelf (); }; - epicsTime end = epicsTime::getCurrent (); + epicsTime end = epicsTime::getMonotonic (); printf ( "It takes %f micro sec to call epicsThreadGetIdSelf ()\n", microSecPerSec * ( end - begin ) / (10 * N) ); } @@ -204,12 +204,12 @@ static void timeEpicsThreadPrivateGet () { priv.set ( 0 ); - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); static const unsigned N = 1000u; for ( unsigned i = 0u; i < N; i++ ) { callItTenTimesSquared (); } - double delay = epicsTime::getCurrent() - begin; + double delay = epicsTime::getMonotonic() - begin; delay /= N * 100u; // convert to sec per call delay *= 1e6; // convert to micro sec printf("epicsThreadPrivateGet() takes %f microseconds\n", delay); diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index eb26cc8bf..46f116f9c 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -18,11 +18,14 @@ #include #include "epicsThread.h" +#include "epicsEvent.h" #include "epicsTime.h" #include "errlog.h" #include "epicsUnitTest.h" #include "testMain.h" +namespace { + static epicsThreadPrivate privateKey; class myThread: public epicsThreadRunable { @@ -37,7 +40,7 @@ private: }; myThread::myThread(int arg,const char *name) : - thread(*this,name,epicsThreadGetStackSize(epicsThreadStackSmall),50+arg), + thread(*this,name,epicsThreadStackSmall,50+arg), argvalue(0) { argvalue = new int; @@ -52,7 +55,7 @@ void myThread::run() startEvt.signal(); int *pset = argvalue; privateKey.set(argvalue); - epicsThreadSleep(2.0); + int *pget = privateKey.get(); testOk1(pget == pset); @@ -60,34 +63,8 @@ void myThread::run() testOk1(thread.getPriority() == epicsThreadGetPriority(self)); } - -typedef struct info { - int isOkToBlock; -} info; - -extern "C" { -static void thread(void *arg) +void testMyThread() { - info *pinfo = (info *)arg; - - epicsThreadSetOkToBlock(pinfo->isOkToBlock); - epicsThreadSleep(1.0); - - testOk(epicsThreadIsOkToBlock() == pinfo->isOkToBlock, - "%s epicsThreadIsOkToBlock() = %d", - epicsThreadGetNameSelf(), pinfo->isOkToBlock); - epicsThreadSleep(0.1); -} -} - - -MAIN(epicsThreadTest) -{ - testPlan(9); - - unsigned int ncpus = epicsThreadGetCPUs(); - testDiag("System has %u CPUs", ncpus); - testOk1(ncpus > 0); const int ntasks = 3; myThread *myThreads[ntasks]; @@ -107,16 +84,157 @@ MAIN(epicsThreadTest) myThreads[i]->thread.exitWait(); delete myThreads[i]; } +} - unsigned int stackSize = epicsThreadGetStackSize(epicsThreadStackSmall); +struct joinStuff { + epicsThreadOpts *opts; + epicsEvent *trigger; + epicsEvent *finished; +}; - info infoA = {0}; - epicsThreadCreate("threadA", 50, stackSize, thread, &infoA); +void donothing(void *arg) +{} - info infoB = {1}; - epicsThreadCreate("threadB", 50, stackSize, thread, &infoB); +void dowait(void *arg) +{ + epicsEvent *trigger = (epicsEvent *) arg; + trigger->wait(); + epicsThreadSleep(0.1); +} +void dodelay(void *arg) +{ epicsThreadSleep(2.0); +} + +void joinTests(void *arg) +{ + struct joinStuff *stuff = (struct joinStuff *) arg; + + // Task finishes before parent joins + epicsThreadId tid = epicsThreadCreateOpt("nothing", + &donothing, 0, stuff->opts); + epicsThreadSleep(0.1); + epicsThreadMustJoin(tid); + + // Parent joins before task finishes + tid = epicsThreadCreateOpt("await", + &dowait, stuff->trigger, stuff->opts); + stuff->trigger->signal(); + epicsThreadMustJoin(tid); + + // Parent gets delayed until task finishes + epicsTime start, end; + start = epicsTime::getCurrent(); + tid = epicsThreadCreateOpt("delay", + &dodelay, 0, stuff->opts); + epicsThreadMustJoin(tid); + end = epicsTime::getCurrent(); + double duration = end - start; +#ifndef EPICS_THREAD_CAN_JOIN + testTodoBegin("Thread join doesn't work"); +#endif + testOk(duration > 1.0, "Join delayed parent (%g seconds)", duration); + testTodoEnd(); + + // This is a no-op + epicsThreadId self = epicsThreadGetIdSelf(); + epicsThreadMustJoin(self); + + // This is a no-op as well, except for a warning. + eltc(0); + epicsThreadMustJoin(self); + eltc(1); + + stuff->finished->signal(); +} + +void testJoining() +{ + epicsThreadOpts opts1 = EPICS_THREAD_OPTS_INIT; + epicsThreadOpts opts2 = EPICS_THREAD_OPTS_INIT; + epicsEvent finished, trigger; + struct joinStuff stuff = { + &opts1, &trigger, &finished + }; + + opts1.priority = 50; + opts2.priority = 40; + opts1.joinable = 1; + opts2.joinable = 1; + epicsThreadCreateOpt("parent", &joinTests, &stuff, &opts2); + + // Thread 'parent' joins itself, so we can't. + testOk(finished.wait(10.0), "Join tests #1 completed"); + + // Repeat with opposite thread priorities + stuff.opts = &opts2; + epicsThreadCreateOpt("parent", &joinTests, &stuff, &opts1); + testOk(finished.wait(10.0), "Join tests #2 completed"); +} + +} // namespace + +typedef struct info { + int isOkToBlock; + int didSomething; +} info; + +extern "C" { +static void thread(void *arg) +{ + info *pinfo = (info *)arg; + + epicsThreadSetOkToBlock(pinfo->isOkToBlock); + + testOk(epicsThreadIsOkToBlock() == pinfo->isOkToBlock, + "%s epicsThreadIsOkToBlock() = %d", + epicsThreadGetNameSelf(), pinfo->isOkToBlock); + + pinfo->didSomething = 1; +} +} + +static void testOkToBlock() +{ + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + + opts.priority = 50; + opts.joinable = 1; + + info infoA = {0, 0}; + epicsThreadId threadA = epicsThreadCreateOpt("threadA", thread, &infoA, &opts); + + info infoB = {1, 0}; + epicsThreadId threadB = epicsThreadCreateOpt("threadB", thread, &infoB, &opts); + + // join B first to better our chance of detecting if it never runs. + epicsThreadMustJoin(threadB); + testOk1(infoB.didSomething); + + epicsThreadMustJoin(threadA); + testOk1(infoA.didSomething); +} + + +MAIN(epicsThreadTest) +{ + testPlan(15); + + unsigned int ncpus = epicsThreadGetCPUs(); + testDiag("System has %u CPUs", ncpus); + testOk1(ncpus > 0); + testDiag("main() thread %p", epicsThreadGetIdSelf()); + + testJoining(); // Do this first, ~epicsThread() uses it... + testMyThread(); + testOkToBlock(); + + // attempt to self-join from a non-EPICS thread + // to make sure it does nothing as expected + eltc(0); + epicsThreadMustJoin(epicsThreadGetIdSelf()); + eltc(1); return testDone(); } diff --git a/modules/libcom/test/epicsTimerTest.cpp b/modules/libcom/test/epicsTimerTest.cpp index aebf3f066..12e5eaeb2 100644 --- a/modules/libcom/test/epicsTimerTest.cpp +++ b/modules/libcom/test/epicsTimerTest.cpp @@ -112,10 +112,9 @@ double delayVerify::checkError () const double actualDelay = this->expireStamp - this->beginStamp; double measuredError = actualDelay - this->expectedDelay; double percentError = 100.0 * fabs ( measuredError ) / this->expectedDelay; - if ( ! testOk ( percentError < messageThresh, "%f < %f", percentError, messageThresh ) ) { - testDiag ( "delay = %f s, error = %f s (%.1f %%)", - this->expectedDelay, measuredError, percentError ); - } + testOk ( percentError < messageThresh, "%f < %f, delay = %f s, error = %f s (%.1f %%)", + percentError, messageThresh, + this->expectedDelay, measuredError, percentError ); return measuredError; } @@ -156,7 +155,7 @@ void testAccuracy () expireCount = nTimers; for ( i = 0u; i < nTimers; i++ ) { - epicsTime cur = epicsTime::getCurrent (); + epicsTime cur = epicsTime::getMonotonic (); pTimers[i]->setBegin ( cur ); pTimers[i]->start ( cur + pTimers[i]->delay () ); } @@ -253,7 +252,7 @@ void testCancel () testDiag ( "cancelCount = %u", cancelVerify::cancelCount ); testDiag ( "starting %d timers", nTimers ); - epicsTime exp = epicsTime::getCurrent () + 4.0; + epicsTime exp = epicsTime::getMonotonic () + 4.0; for ( i = 0u; i < nTimers; i++ ) { pTimers[i]->start ( exp ); } @@ -339,7 +338,7 @@ void testExpireDestroy () testOk1 ( expireDestroyVerify::destroyCount == 0 ); testDiag ( "starting %d timers", nTimers ); - epicsTime cur = epicsTime::getCurrent (); + epicsTime cur = epicsTime::getMonotonic (); for ( i = 0u; i < nTimers; i++ ) { pTimers[i]->start ( cur ); } @@ -432,7 +431,7 @@ void testPeriodic () testOk1 ( timerCount == nTimers ); testDiag ( "starting %d timers", nTimers ); - epicsTime cur = epicsTime::getCurrent (); + epicsTime cur = epicsTime::getMonotonic (); for ( i = 0u; i < nTimers; i++ ) { pTimers[i]->start ( cur ); } diff --git a/modules/libcom/test/iocshTest.cpp b/modules/libcom/test/iocshTest.cpp new file mode 100644 index 000000000..1216ed579 --- /dev/null +++ b/modules/libcom/test/iocshTest.cpp @@ -0,0 +1,131 @@ +/*************************************************************************\ +* Copyright (c) 2019 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace { +void findTestData() +{ + const char *locations[] = { + ".", + "..", + ".." OSI_PATH_LIST_SEPARATOR "O.Common", + "O.Common", + }; + + for(size_t i=0; i %d", expect ? "ran" : "expected error from", fname, err); +} + +void testCmd(const char *cmd, bool expect=true) +{ + testDiag("eval \"%s\"", cmd); + int err = iocshCmd(cmd); + testOk((err==0) ^ (!expect), "%s \"%s\" -> %d", expect ? "eval'd" : "expected error from", cmd, err); +} + +std::set reached; +const iocshArg positionArg0 = {"position", iocshArgString}; +const iocshArg * const positionArgs[1] = { &positionArg0 }; +const iocshFuncDef positionFuncDef = {"position",1,positionArgs}; +void positionCallFunc(const iocshArgBuf *args) +{ + testDiag("Reaching \"%s\"", args[0].sval); + reached.insert(args[0].sval); +} + +void testPosition(const std::string& pos, bool expect=true) +{ + testOk((reached.find(pos)!=reached.end()) ^ !expect, + "%sreached position %s", expect ? "" : "not ", pos.c_str()); +} + +const iocshArg assertArg0 = {"condition", iocshArgInt}; +const iocshArg * const assertArgs[1] = {&assertArg0}; +const iocshFuncDef assertFuncDef = {"assert",1,assertArgs}; +void assertCallFunc(const iocshArgBuf *args) +{ + iocshSetError(args[0].ival); +} + +} // namespace + +MAIN(iocshTest) +{ + testPlan(19); + libComRegister(); + iocshRegister(&positionFuncDef, &positionCallFunc); + iocshRegister(&assertFuncDef, &assertCallFunc); + findTestData(); + + testFile("iocshTestSuccess.cmd"); + testPosition("success"); + reached.clear(); + testPosition("success", false); + + testCmd(" + +#include +#include + +#include + +MAIN(testexecname) +{ + testPlan(1); + + { + char *buf = epicsGetExecName(); + if(!buf) { + testSkip(1, "epicsGetExecName() not available for this target"); + } else { + char *loc = strstr(buf, "testexecname"); + testOk(!!loc, "Find \"testexecname\" in \"%s\"", buf); + } + } + + return testDone(); +} diff --git a/modules/libcom/vxWorks/Makefile b/modules/libcom/vxWorks/Makefile index e2c0b5d2d..3eced3b08 100644 --- a/modules/libcom/vxWorks/Makefile +++ b/modules/libcom/vxWorks/Makefile @@ -5,7 +5,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG # Install Boost smart_ptr headers needed by VxWorks 6.x diff --git a/modules/normativeTypes b/modules/normativeTypes index c6168a747..6d41566b4 160000 --- a/modules/normativeTypes +++ b/modules/normativeTypes @@ -1 +1 @@ -Subproject commit c6168a74772a93f18facc83631c13db381ff15bb +Subproject commit 6d41566b40a3f20582f1b37dbf4557bfdf5da674 diff --git a/modules/pvAccess b/modules/pvAccess index 60fefdb2c..c8c3cf4fd 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 60fefdb2c10389e14828c48a332eef74bdd4c8e5 +Subproject commit c8c3cf4fd8b3490221c1e231c354e73735ee3813 diff --git a/modules/pvData b/modules/pvData index cdd698011..b903df5d0 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit cdd6980117cffb96708a1876d512579d6a692e03 +Subproject commit b903df5d0daf08592368be2978efb2d828617a8c diff --git a/modules/pvDatabase b/modules/pvDatabase index 428f78482..d7bd5628d 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit 428f7848262deab47f10bcebd145dd0453579ef0 +Subproject commit d7bd5628d47f82b2ad2cab2ea97dade98c2ee128 diff --git a/modules/pvaClient b/modules/pvaClient index aba40922e..9add9daf8 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit aba40922e6a96519c214c7644bfdf49a8bd0d7f6 +Subproject commit 9add9daf85bc5cc970bf43be798f013d64263332 diff --git a/src/template/base/makeBaseApp.pl b/src/template/base/makeBaseApp.pl index d6da8adf8..0421f004b 100644 --- a/src/template/base/makeBaseApp.pl +++ b/src/template/base/makeBaseApp.pl @@ -3,7 +3,7 @@ # Authors: Ralph Lange, Marty Kraimer, Andrew Johnson and Janet Anderson use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use Cwd; use Getopt::Std; diff --git a/src/tools/Makefile b/src/tools/Makefile index 0df179781..c58c923b9 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -25,6 +25,7 @@ PERL_SCRIPTS += convertRelease.pl PERL_SCRIPTS += cvsclean.pl PERL_SCRIPTS += depclean.pl PERL_SCRIPTS += dos2unix.pl +PERL_SCRIPTS += epicsProve.pl PERL_SCRIPTS += expandVars.pl PERL_SCRIPTS += fullPathName.pl PERL_SCRIPTS += installEpics.pl @@ -39,6 +40,8 @@ PERL_SCRIPTS += tap-to-junit-xml.pl PERL_SCRIPTS += useManifestTool.pl PERL_SCRIPTS += genVersionHeader.pl +PERL_SCRIPTS += makeRPath.py + HTMLS = style.css HTMLS += EPICS/Getopts.html HTMLS += EPICS/Path.html diff --git a/src/tools/convertRelease.pl b/src/tools/convertRelease.pl index a5a1a77d8..9ccb6f55d 100644 --- a/src/tools/convertRelease.pl +++ b/src/tools/convertRelease.pl @@ -19,7 +19,7 @@ use Getopt::Std; $Getopt::Std::STANDARD_HELP_VERSION = 1; use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use EPICS::Path; use EPICS::Release; @@ -259,24 +259,26 @@ sub checkRelease { my $latest = AbsPath($macros{$app}); my %paths = ($latest => $app); foreach $app (@modules) { - my $path = AbsPath($macros{$app}); + my $val = $macros{$app}; + next if $val eq ''; + my $path = AbsPath($val); if ($path ne $latest && exists $paths{$path}) { my $prev = $paths{$path}; print "\n" unless ($status); print "This application's RELEASE file(s) define\n"; - print "\t$app = $macros{$app}\n"; - print "after but not adjacent to\n\t$prev = $macros{$prev}\n"; + print "\t$app = $val\n"; + print "and\n\t$prev = $macros{$prev}\n"; print "both of which resolve to $path\n" - if $path ne $macros{$app} || $path ne $macros{$prev}; + if $path ne $val || $path ne $macros{$prev}; $status = 2; } $paths{$path} = $app; $latest = $path; } if ($status == 2) { - print "Module definitions that share paths must be grouped together.\n"; - print "Either remove a definition, or move it to a line immediately\n"; - print "above or below the other(s).\n"; + print "Module definitions that share the same path must have their\n"; + print "first definitions grouped together. Either remove a module,\n"; + print "or arrange them so all those with that path are adjacent.\n"; print "Any non-module definitions belong in configure/CONFIG_SITE.\n"; $status = 1; } diff --git a/src/tools/epicsProve.pl b/src/tools/epicsProve.pl new file mode 100644 index 000000000..a1b0c14d4 --- /dev/null +++ b/src/tools/epicsProve.pl @@ -0,0 +1,10 @@ +#!/usr/bin/env perl + +# Some Windows Perl installations provide a prove.bat file which +# doesn't work properly. + +use App::Prove; + +my $app = App::Prove->new; +$app->process_args(@ARGV); +exit( $app->run ? 0 : 1 ); diff --git a/src/tools/expandVars.pl b/src/tools/expandVars.pl index 01e65fb3a..855aca329 100644 --- a/src/tools/expandVars.pl +++ b/src/tools/expandVars.pl @@ -10,7 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use EPICS::Getopts; use EPICS::Path; diff --git a/src/tools/fullPathName.pl b/src/tools/fullPathName.pl index c8ac49a12..20ef6d231 100644 --- a/src/tools/fullPathName.pl +++ b/src/tools/fullPathName.pl @@ -17,7 +17,7 @@ use Getopt::Std; $Getopt::Std::STANDARD_HELP_VERSION = 1; use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use EPICS::Path; diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py new file mode 100644 index 000000000..89590e8df --- /dev/null +++ b/src/tools/makeRPath.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import sys +import os +from collections import OrderedDict # used as OrderedSet + +from argparse import ArgumentParser + +if os.environ.get('EPICS_DEBUG_RPATH','')=='YES': + sys.stderr.write('%s'%sys.argv) + +P = ArgumentParser(description='''Compute and output -rpath entries for each of the given paths. + Paths under --root will be computed as relative to --final .''', +epilog=''' +eg. A library to be placed in /build/lib and linked against libraries in +'/build/lib', '/build/module/lib', and '/other/lib' would pass: + + "makeRPath.py -F /build/lib -R /build /build/lib /build/module/lib /other/lib" +which prints "-Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib" +''') +P.add_argument('-F','--final',default=os.getcwd(), help='Final install location for ELF file') +P.add_argument('-R','--root',default='', help='Root(s) of relocatable tree. Separate with :') +P.add_argument('-O', '--origin', default='$ORIGIN') +P.add_argument('path', nargs='*') +args = P.parse_args() + +# eg. +# target to be installed as: /build/bin/blah +# +# post-install will copy as: /install/bin/blah +# +# Need to link against: +# /install/lib/libA.so +# /build/lib/libB.so +# /other/lib/libC.so +# +# Want final result to be: +# -rpath $ORIGIN/../lib -rpath /other/lib \ +# -rpath-link /build/lib -rpath-link /install/lib + +fdir = os.path.abspath(args.final) +roots = [os.path.abspath(root) for root in args.root.split(':') if len(root)] + +# find the root which contains the final location +froot = None +for root in roots: + frel = os.path.relpath(fdir, root) + if not frel.startswith('..'): + # final dir is under this root + froot = root + break + +if froot is None: + sys.stderr.write("makeRPath: Final location %s\nNot under any of: %s\n"%(fdir, roots)) + # skip $ORIGIN handling below... + roots = [] + +output = OrderedDict() +for path in args.path: + path = os.path.abspath(path) + + for root in roots: + rrel = os.path.relpath(path, root) + if not rrel.startswith('..'): + # path is under this root + + # some older binutils don't seem to handle $ORIGIN correctly + # when locating dependencies of libraries. So also provide + # the absolute path for internal use by 'ld' only. + output['-Wl,-rpath-link,'+path] = True + + # frel is final location relative to enclosing root + # rrel is target location relative to enclosing root + path = os.path.relpath(rrel, frel) + break + + output['-Wl,-rpath,'+os.path.join(args.origin, path)] = True + +print(' '.join(output))