Merge branch '7.0' into PSI-7.0
This commit is contained in:
@@ -25,14 +25,19 @@ init:
|
||||
# Set clone depth (do not fetch complete history)
|
||||
clone_depth: 5
|
||||
|
||||
# Skipping commits affecting only specific files
|
||||
# Skip commits affecting only specific files
|
||||
skip_commits:
|
||||
files:
|
||||
- 'documentation/*'
|
||||
# Removed - 'documentation/*'
|
||||
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
|
||||
# the last commit pushed to a PR only updates the Release Notes the whole
|
||||
# PR build gets skipped. GitHub Actions looks at the complete list
|
||||
# of files changed since its last build, which is much more useful.
|
||||
- 'startup/*'
|
||||
- '.github/*'
|
||||
- '.tools/*'
|
||||
- '.gitattributes'
|
||||
- '.lgtm.yml'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
@@ -67,6 +72,8 @@ environment:
|
||||
- CMP: vs2010
|
||||
- CMP: gcc
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
# TODO: static linking w/ readline isn't working. Bypass auto-detect
|
||||
COMMANDLINE_LIBRARY: EPICS
|
||||
|
||||
# Platform: processor architecture
|
||||
platform:
|
||||
|
||||
@@ -32,13 +32,18 @@ init:
|
||||
# Set clone depth (do not fetch complete history)
|
||||
clone_depth: 5
|
||||
|
||||
# Skipping commits affecting only specific files
|
||||
# Skip commits affecting only specific files
|
||||
skip_commits:
|
||||
files:
|
||||
- 'documentation/*'
|
||||
# Removed - 'documentation/*'
|
||||
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
|
||||
# the last commit pushed to a PR only updates the Release Notes the whole
|
||||
# PR build gets skipped. GitHub Actions looks at the complete list
|
||||
# of files changed since its last build, which is much more useful.
|
||||
- 'startup/*'
|
||||
- '.github/*'
|
||||
- '.tools/*'
|
||||
- '.lgtm.yml'
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
@@ -73,6 +78,9 @@ environment:
|
||||
- CMP: vs2012
|
||||
- CMP: vs2010
|
||||
- CMP: gcc
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
# TODO: static linking w/ readline isn't working. Bypass auto-detect
|
||||
COMMANDLINE_LIBRARY: EPICS
|
||||
|
||||
# Platform: processor architecture
|
||||
platform:
|
||||
|
||||
2
.ci
2
.ci
Submodule .ci updated: d675de24e6...aea7906839
137
.github/workflows/ci-scripts-build.yml
vendored
137
.github/workflows/ci-scripts-build.yml
vendored
@@ -15,6 +15,7 @@ on:
|
||||
- 'startup/*'
|
||||
- '.appveyor/*'
|
||||
- '.tools/*'
|
||||
- '.lgtm.yml'
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
@@ -24,6 +25,7 @@ on:
|
||||
- 'startup/*'
|
||||
- '.appveyor/*'
|
||||
- '.tools/*'
|
||||
- '.lgtm.yml'
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
@@ -34,7 +36,7 @@ env:
|
||||
EPICS_TEST_IMPRECISE_TIMING: YES
|
||||
|
||||
jobs:
|
||||
build-base:
|
||||
native:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
# Set environment variables from matrix parameters
|
||||
@@ -45,6 +47,7 @@ jobs:
|
||||
RTEMS: ${{ matrix.rtems }}
|
||||
RTEMS_TARGET: ${{ matrix.rtems_target }}
|
||||
EXTRA: ${{ matrix.extra }}
|
||||
EXTRA1: ${{ matrix.extra1 }}
|
||||
TEST: ${{ matrix.test }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -69,10 +72,17 @@ jobs:
|
||||
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||
name: "Ub-20 gcc-9 C++11, static"
|
||||
|
||||
- os: ubuntu-16.04
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: static
|
||||
extra: "CMD_CFLAGS=-funsigned-char"
|
||||
extra1: "CMD_CXXFLAGS=-funsigned-char"
|
||||
name: "Ub-20 gcc-9 unsigned char"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
name: "Ub-16 clang-9"
|
||||
name: "Ub-20 clang-10"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: clang
|
||||
@@ -85,7 +95,6 @@ jobs:
|
||||
configuration: default
|
||||
rtems: "5"
|
||||
rtems_target: RTEMS-pc686-qemu
|
||||
test: NO
|
||||
name: "Ub-20 gcc-9 + RT-5.1 pc686"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
@@ -137,6 +146,7 @@ jobs:
|
||||
rtems: "4.10"
|
||||
name: "Ub-20 gcc-9 + RT-4.10"
|
||||
rtems_target: RTEMS-pc386-qemu
|
||||
test: NO
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
@@ -145,35 +155,6 @@ jobs:
|
||||
name: "Ub-20 gcc-9 + RT-4.9"
|
||||
rtems_target: RTEMS-pc386-qemu
|
||||
|
||||
- os: ubuntu-16.04
|
||||
cmp: gcc-4.8
|
||||
utoolchain: "4.8"
|
||||
configuration: default
|
||||
name: "Ub-16 gcc-4.8"
|
||||
|
||||
- os: ubuntu-16.04
|
||||
cmp: gcc-4.9
|
||||
utoolchain: "4.9"
|
||||
configuration: default
|
||||
name: "Ub-16 gcc-4.9"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc-8
|
||||
utoolchain: "8"
|
||||
configuration: default
|
||||
name: "Ub-20 gcc-8"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc-9
|
||||
utoolchain: "9"
|
||||
configuration: default
|
||||
name: "Ub-20 gcc-9"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
name: "Ub-20 clang-10"
|
||||
|
||||
- os: macos-latest
|
||||
cmp: clang
|
||||
configuration: default
|
||||
@@ -200,7 +181,7 @@ jobs:
|
||||
name: "Win2019 mingw"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Automatic core dumper analysis
|
||||
@@ -210,14 +191,86 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
|
||||
if: runner.os == 'Linux'
|
||||
- name: "apt-get install ${{ matrix.cmp }}"
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
- name: Build main module
|
||||
run: python .ci/cue.py build
|
||||
- name: Run main module tests
|
||||
run: python .ci/cue.py -T 60M test
|
||||
- name: Upload tapfiles Artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tapfiles ${{ matrix.name }}
|
||||
path: '**/O.*/*.tap'
|
||||
if-no-files-found: ignore
|
||||
- name: Collect and show test results
|
||||
if: ${{ always() }}
|
||||
run: python .ci/cue.py -T 5M test-results
|
||||
|
||||
docker:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ matrix.image }}
|
||||
# Set environment variables from matrix parameters
|
||||
env:
|
||||
CMP: ${{ matrix.cmp }}
|
||||
BCFG: ${{ matrix.configuration }}
|
||||
EXTRA: ${{ matrix.extra }}
|
||||
TEST: ${{ matrix.test }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Job names also name artifacts, character limitations apply
|
||||
include:
|
||||
- name: "CentOS-7"
|
||||
image: centos:7
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
|
||||
- name: "Fedora-33"
|
||||
image: fedora:33
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
|
||||
- name: "Fedora-latest"
|
||||
image: fedora:latest
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
|
||||
steps:
|
||||
- name: "Build newer Git"
|
||||
# actions/checkout@v2 wants git >=2.18
|
||||
# centos:7 has 1.8
|
||||
if: matrix.image=='centos:7'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install software-properties-common
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install g++-${{ matrix.utoolchain }}
|
||||
if: matrix.utoolchain
|
||||
yum -y install curl make gcc curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker
|
||||
curl https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.29.0.tar.gz | tar -xz
|
||||
cd git-*
|
||||
make -j2 prefix=/usr/local all
|
||||
make prefix=/usr/local install
|
||||
cd ..
|
||||
rm -rf git-*
|
||||
type -a git
|
||||
git --version
|
||||
- name: "Redhat setup"
|
||||
run: |
|
||||
dnfyum() {
|
||||
dnf -y "$@" || yum -y "$@"
|
||||
return $?
|
||||
}
|
||||
dnfyum install python3 gdb make perl gcc-c++ glibc-devel readline-devel ncurses-devel perl-devel perl-Test-Simple
|
||||
git --version || dnfyum install git
|
||||
# rather than just bite the bullet and link python3 -> python,
|
||||
# people would rather just break all existing scripts...
|
||||
[ -e /usr/bin/python ] || ln -sf python3 /usr/bin/python
|
||||
python --version
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@master
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
- name: Build main module
|
||||
@@ -226,7 +279,7 @@ jobs:
|
||||
run: python .ci/cue.py -T 20M test
|
||||
- name: Upload tapfiles Artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tapfiles ${{ matrix.name }}
|
||||
path: '**/O.*/*.tap'
|
||||
|
||||
50
.lgtm.yml
Normal file
50
.lgtm.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
# Configuration for lgtm.com
|
||||
#
|
||||
|
||||
path_classifiers:
|
||||
test:
|
||||
- exclude: /
|
||||
- test
|
||||
- "modules/*/test*"
|
||||
library:
|
||||
- modules/libcom/src/yacc
|
||||
- modules/libcom/src/flex
|
||||
template:
|
||||
- src/template
|
||||
- modules/ca/src/template
|
||||
- modules/database/src/template
|
||||
|
||||
extraction:
|
||||
cpp:
|
||||
prepare:
|
||||
packages:
|
||||
- "libreadline-dev"
|
||||
index:
|
||||
build_command:
|
||||
- "g++ --version"
|
||||
- "make --version"
|
||||
- "perl --version"
|
||||
- "make -sj2 || echo '*** Build failed, ignored for lgtm ***'"
|
||||
|
||||
python:
|
||||
index:
|
||||
include:
|
||||
- src/tools
|
||||
|
||||
# Interpreted languages to be excluded
|
||||
javascript:
|
||||
index:
|
||||
exclude:
|
||||
- "*"
|
||||
|
||||
# Compiled languages to be excluded
|
||||
java:
|
||||
index:
|
||||
build_command: "echo No Java code in this project"
|
||||
csharp:
|
||||
index:
|
||||
build_command: "echo No C# code in this project"
|
||||
go:
|
||||
index:
|
||||
build_command: "echo No Go code in this project"
|
||||
|
||||
@@ -140,10 +140,12 @@ sed \
|
||||
-e '/\/\.ci-local\//d' \
|
||||
-e '/\/\.tools\//d' \
|
||||
-e '/\/jenkins\//d' \
|
||||
-e '/\/\.git/d' \
|
||||
-e '/\/\.github\//d' \
|
||||
-e '/\/\.gitmodules$/d' \
|
||||
-e '/\/\.hgtags$/d' \
|
||||
-e '/\/\.cproject$/d' \
|
||||
-e '/\/\.project$/d' \
|
||||
-e '/\/\.lgtm\.yml$/d' \
|
||||
-e '/\/\.travis\.yml$/d' \
|
||||
-e '/\/\.appveyor\.yml$/d' \
|
||||
-e '/\/\.readthedocs\.yml$/d' \
|
||||
|
||||
@@ -34,6 +34,11 @@ ifeq ($(origin EPICS_HOST_ARCH), undefined)
|
||||
EHA :=
|
||||
endif
|
||||
|
||||
# Make Perl hash iteration reproducible.
|
||||
# See: https://reproducible-builds.org/docs/stable-outputs/
|
||||
#
|
||||
export PERL_HASH_SEED = 0
|
||||
|
||||
-include $(CONFIG)/RELEASE
|
||||
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH)
|
||||
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
|
||||
@@ -51,6 +51,7 @@ OPT_CXXFLAGS_NO = -g
|
||||
|
||||
CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
|
||||
CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))
|
||||
OPT_LDFLAGS_NO = -g
|
||||
|
||||
PIPE_CFLAGS_YES_YES = -pipe
|
||||
PIPE_CFLAGS = $(PIPE_CFLAGS_$(GCC_PIPE)_$(GNU))
|
||||
|
||||
@@ -38,10 +38,16 @@ TOOLS = $(abspath $(EPICS_BASE_HOST_BIN))
|
||||
FIND_TOOL = $(firstword $(wildcard $(TOOLS)/$(1) \
|
||||
$(TOP)/src/tools/$(1)) $(EPICS_BASE)/src/tools/$(1))
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Find Perl modules for dependencies
|
||||
FIND_PM = $(wildcard $(EPICS_BASE)/lib/perl/$(1))
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# EPICS Base build tools and tool flags
|
||||
|
||||
PODTOHTML = $(PERL) $(TOOLS)/podToHtml.pl
|
||||
PODTOHTML_pl = $(TOOLS)/podToHtml.pl
|
||||
PODTOHTML_dep = $(PODTOHTML_pl) $(call FIND_PM,EPICS/PodHtml.pm)
|
||||
PODTOHTML = $(PERL) $(PODTOHTML_pl)
|
||||
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
|
||||
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
|
||||
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG)
|
||||
|
||||
@@ -48,15 +48,15 @@ EPICS_VERSION = 7
|
||||
EPICS_REVISION = 0
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 6
|
||||
EPICS_MODIFICATION = 7
|
||||
|
||||
# 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 = 1
|
||||
|
||||
# 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
|
||||
|
||||
# No changes should be needed below here
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
EPICS_CA_MAJOR_VERSION = 4
|
||||
EPICS_CA_MINOR_VERSION = 14
|
||||
EPICS_CA_MAINTENANCE_VERSION = 0
|
||||
EPICS_CA_MAINTENANCE_VERSION = 3
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 0
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 1
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -56,6 +56,7 @@ GNU_DIR = /usr
|
||||
# Directories
|
||||
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
INSTALL_ABSOLUTE = $(abspath $(INSTALL_LOCATION))
|
||||
|
||||
INSTALL_LOCATION_LIB = $(INSTALL_LOCATION)/lib
|
||||
INSTALL_LOCATION_BIN = $(INSTALL_LOCATION)/bin
|
||||
@@ -71,23 +72,30 @@ INSTALL_DBD = $(INSTALL_LOCATION)/dbd
|
||||
INSTALL_DB = $(INSTALL_LOCATION)/db
|
||||
INSTALL_CONFIG = $(INSTALL_LOCATION)/configure
|
||||
|
||||
FINAL_LOCATION = $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
|
||||
#-------------------------------------------------------
|
||||
# These are default settings that may be overridden later
|
||||
|
||||
# Directory for OS independant build created files
|
||||
COMMON_DIR = ../O.Common
|
||||
# Eventual install path (to be compiled into binaries)
|
||||
FINAL_LOCATION = $(INSTALL_ABSOLUTE)
|
||||
|
||||
# IOC's absolute path to $(TOP), may be overridden inside the application
|
||||
IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
|
||||
# IOC's view of install path
|
||||
IOCS_APPL_TOP = $(INSTALL_ABSOLUTE)
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Silencing the build - suppress messages during 'make -s'
|
||||
# How to portably check the flags to make
|
||||
define checkflags
|
||||
make-$1 = $(findstring $1,$(filter-out --%,$(MAKEFLAGS)))
|
||||
endef
|
||||
# This is extensible to most single letter flags:
|
||||
$(foreach flag,s q, $(eval $(call checkflags,$(flag))))
|
||||
|
||||
# Silent builds - suppress messages during 'make -s'
|
||||
NOP = :
|
||||
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(filter -s,$(MFLAGS)),-q,)
|
||||
ECHO = @$(if $(make-s),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(make-s),-q,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
|
||||
QUESTION_FLAG := $(if $(filter -q,$(MFLAGS)),-i,)
|
||||
QUESTION_FLAG := $(if $(make-q),-i,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
ifdef T_A
|
||||
@@ -133,6 +141,8 @@ LIB_SUFFIX =
|
||||
SHRLIB_PREFIX = $(LIB_PREFIX)
|
||||
DLLSTUB_PREFIX = $(LIB_PREFIX)
|
||||
DLLSTUB_SUFFIX = $(LIB_SUFFIX)
|
||||
LOADABLE_SHRLIB_PREFIX = $(SHRLIB_PREFIX)
|
||||
LOADABLE_SHRLIB_SUFFIX = $(SHRLIB_SUFFIX)
|
||||
|
||||
BUILDLIB_PREFIX_YES = $(DLLSTUB_PREFIX)
|
||||
BUILDLIB_PREFIX_NO = $(LIB_PREFIX)
|
||||
@@ -153,12 +163,14 @@ CMPLR_SRC_DIRS += . $(foreach dir, .. $(SRC_DIRS), \
|
||||
ALL_SRC_DIRS = $(CMPLR_SRC_DIRS) $(OS_SRC_DIRS) $(GENERIC_SRC_DIRS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Directory for OS independant build created files
|
||||
COMMON_DIR = ../O.Common
|
||||
|
||||
# compile line include directories
|
||||
INSTALL_INCLUDES += \
|
||||
-I$(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) \
|
||||
-I$(INSTALL_INCLUDE)/os/$(OS_CLASS) \
|
||||
-I$(INSTALL_INCLUDE)
|
||||
SRC_INCLUDES = -I$(COMMON_DIR) $(addprefix -I, $(wildcard $(ALL_SRC_DIRS)))
|
||||
INSTALL_INCLUDE_DIRS = $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) \
|
||||
$(INSTALL_INCLUDE)/os/$(OS_CLASS) $(INSTALL_INCLUDE)
|
||||
INSTALL_INCLUDES += $(addprefix -I, $(INSTALL_INCLUDE_DIRS))
|
||||
SRC_INCLUDES = $(addprefix -I, $(COMMON_DIR) $(wildcard $(ALL_SRC_DIRS)))
|
||||
|
||||
#--------------------------------------------------
|
||||
# Target filename definitions
|
||||
@@ -172,23 +184,27 @@ TESTSHRLIBNAME = $(TESTSHRLIBNAME_$(SHARED_LIBRARIES))
|
||||
#--------------------------------------------------
|
||||
# obj files
|
||||
|
||||
TARGET_OBJS = $($*_LDOBJS) $(addsuffix $(OBJ),$(basename $($*_OBJS) $($*_SRCS)))
|
||||
TARGET_OBJS = $($*_LDOBJS) $(addsuffix $(OBJ), \
|
||||
$(basename $($*_OBJS) $($*_SRCS)))
|
||||
|
||||
PRODUCT_OBJS = $(addsuffix $(OBJ),$(basename $(SRCS) $(USR_SRCS) $(PROD_SRCS) $(USR_OBJS) $(PROD_OBJS)))
|
||||
PRODUCT_OBJS = $(addsuffix $(OBJ), \
|
||||
$(basename $(SRCS) $(USR_SRCS) $(PROD_SRCS) $(USR_OBJS) $(PROD_OBJS)))
|
||||
PROD_LD_OBJS = $(TARGET_OBJS) $(PRODUCT_OBJS)
|
||||
|
||||
LIBRARY_OBJS = $(addsuffix $(OBJ),$(basename $(SRCS) $(USR_SRCS) $(LIB_SRCS) $(LIBSRCS) $(USR_OBJS) $(LIB_OBJS)))
|
||||
LIBRARY_OBJS = $(addsuffix $(OBJ), \
|
||||
$(basename $(SRCS) $(USR_SRCS) $(LIB_SRCS) $(LIBSRCS) $(USR_OBJS) $(LIB_OBJS)))
|
||||
LIBRARY_LD_OBJS = $(TARGET_OBJS) $(LIBRARY_OBJS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Windows resource files
|
||||
|
||||
TARGET_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $($*_RCS))),)
|
||||
TARGET_RESS = $(if $(RES), $(addsuffix $(RES), $(basename $($*_RCS))))
|
||||
|
||||
PROD_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $(RCS) $(PROD_RCS))),)
|
||||
PROD_RESS = $(if $(RES), $(addsuffix $(RES), $(basename $(RCS) $(PROD_RCS))))
|
||||
PROD_LD_RESS = $(TARGET_RESS) $(PROD_RESS)
|
||||
|
||||
LIBRARY_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $(RCS) $(LIB_RCS) $(LIBRARY_RCS))),)
|
||||
LIBRARY_RESS = $(if $(RES), $(addsuffix $(RES), \
|
||||
$(basename $(RCS) $(LIB_RCS) $(LIBRARY_RCS))))
|
||||
LIBRARY_LD_RESS = $(TARGET_RESS) $(LIBRARY_RESS)
|
||||
|
||||
#--------------------------------------------------
|
||||
@@ -257,6 +273,7 @@ WARN_CXXFLAGS = $(WARN_CXXFLAGS_$($(BUILD_CLASS)_WARN))
|
||||
OPT_CPPFLAGS = $(OPT_CPPFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
OPT_CFLAGS = $(OPT_CFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
OPT_CXXFLAGS = $(OPT_CXXFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
OPT_LDFLAGS = $(OPT_LDFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
|
||||
# Static build flags
|
||||
STATIC_CFLAGS = $(STATIC_CFLAGS_$(STATIC_BUILD))
|
||||
@@ -265,19 +282,19 @@ STATIC_LDFLAGS = $(STATIC_LDFLAGS_$(STATIC_BUILD))
|
||||
STATIC_LDLIBS = $(STATIC_LDLIBS_$(STATIC_BUILD))
|
||||
|
||||
#--------------------------------------------------
|
||||
# cflags for shared library src files (from SHRLIB_CFLAGS)
|
||||
LIBRARY_SRCS=$(basename $(foreach lib,$(LIBRARY) $(TESTLIBRARY) $(LOADABLE_LIBRARY),$($(lib)_OBJSNAME) $(LIBRARY_OBJS)))
|
||||
LIBRARY_SRC_CFLAGS=$($(patsubst $*,SHRLIB,$(findstring $*,$(LIBRARY_SRCS)))_CFLAGS)
|
||||
# cflags for shared library src files
|
||||
LIBRARY_SRCS = $(basename $(foreach lib, \
|
||||
$(LIBRARY) $(TESTLIBRARY) $(LOADABLE_LIBRARY), \
|
||||
$($(lib)_OBJSNAME) $(LIBRARY_OBJS)))
|
||||
LIBRARY_SRC_CFLAGS = $(if $(findstring $*, $(LIBRARY_SRCS)), $(SHRLIB_CFLAGS))
|
||||
|
||||
#--------------------------------------------------
|
||||
# prefix, suffix, and ldflags for loadable shared libraries
|
||||
TARGET_LIB_LDFLAGS=$($(patsubst $*,LOADABLE_,$(findstring $*,$(LOADABLE_LIBRARY)))SHRLIB_LDFLAGS)
|
||||
LOADABLE_SHRLIB_PREFIX=$(SHRLIB_PREFIX)
|
||||
LOADABLE_SHRLIB_SUFFIX=$(SHRLIB_SUFFIX)
|
||||
# ldflags for loadable and shared libraries
|
||||
TARGET_LIB_LDFLAGS = $(if $(findstring $*, $(LOADABLE_LIBRARY)), \
|
||||
$(LOADABLE_SHRLIB_LDFLAGS), $(SHRLIB_LDFLAGS))
|
||||
|
||||
#--------------------------------------------------
|
||||
# Command-line input support default
|
||||
COMMANDLINE_LIBRARY = EPICS
|
||||
OP_SYS_LDLIBS += $(LDLIBS_$(COMMANDLINE_LIBRARY))
|
||||
OP_SYS_LDFLAGS += $(LDFLAGS_$(COMMANDLINE_LIBRARY))
|
||||
RUNTIME_LDFLAGS += $(RUNTIME_LDFLAGS_$(COMMANDLINE_LIBRARY))
|
||||
@@ -285,31 +302,31 @@ RUNTIME_LDFLAGS += $(RUNTIME_LDFLAGS_$(COMMANDLINE_LIBRARY))
|
||||
#--------------------------------------------------
|
||||
# Flags
|
||||
|
||||
INCLUDES = -I. $(SRC_INCLUDES) $(INSTALL_INCLUDES) $(RELEASE_INCLUDES)\
|
||||
$(TARGET_INCLUDES) $(USR_INCLUDES) $(CMD_INCLUDES) $(OP_SYS_INCLUDES)\
|
||||
$($(BUILD_CLASS)_INCLUDES)
|
||||
INCLUDES = -I. $(SRC_INCLUDES) $(INSTALL_INCLUDES) $(RELEASE_INCLUDES) \
|
||||
$(TARGET_INCLUDES) $(USR_INCLUDES) $(CMD_INCLUDES) $(OP_SYS_INCLUDES) \
|
||||
$($(BUILD_CLASS)_INCLUDES)
|
||||
|
||||
CFLAGS = $($(BUILD_CLASS)_CFLAGS) $(POSIX_CFLAGS) $(OPT_CFLAGS)\
|
||||
$(DEBUG_CFLAGS) $(PIPE_CFLAGS) $(WARN_CFLAGS) $(TARGET_CFLAGS)\
|
||||
$(USR_CFLAGS) $(CMD_CFLAGS) $(ARCH_DEP_CFLAGS) $(CODE_CFLAGS)\
|
||||
$(STATIC_CFLAGS) $(OP_SYS_CFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
CFLAGS = $($(BUILD_CLASS)_CFLAGS) $(POSIX_CFLAGS) $(OPT_CFLAGS) \
|
||||
$(DEBUG_CFLAGS) $(PIPE_CFLAGS) $(WARN_CFLAGS) $(TARGET_CFLAGS) \
|
||||
$(USR_CFLAGS) $(CMD_CFLAGS) $(ARCH_DEP_CFLAGS) $(CODE_CFLAGS) \
|
||||
$(STATIC_CFLAGS) $(OP_SYS_CFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
|
||||
CXXFLAGS = $($(BUILD_CLASS)_CXXFLAGS) $(POSIX_CXXFLAGS) $(OPT_CXXFLAGS)\
|
||||
$(DEBUG_CXXFLAGS) $(PIPE_CFLAGS) $(WARN_CXXFLAGS) $(TARGET_CXXFLAGS)\
|
||||
$(USR_CXXFLAGS) $(CMD_CXXFLAGS) $(ARCH_DEP_CXXFLAGS) $(CODE_CXXFLAGS)\
|
||||
$(STATIC_CXXFLAGS) $(OP_SYS_CXXFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
CXXFLAGS = $($(BUILD_CLASS)_CXXFLAGS) $(POSIX_CXXFLAGS) $(OPT_CXXFLAGS) \
|
||||
$(DEBUG_CXXFLAGS) $(PIPE_CFLAGS) $(WARN_CXXFLAGS) $(TARGET_CXXFLAGS) \
|
||||
$(USR_CXXFLAGS) $(CMD_CXXFLAGS) $(ARCH_DEP_CXXFLAGS) $(CODE_CXXFLAGS) \
|
||||
$(STATIC_CXXFLAGS) $(OP_SYS_CXXFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
|
||||
LDFLAGS = $(OPT_LDFLAGS) $(TARGET_LDFLAGS) $(USR_LDFLAGS) $(CMD_LDFLAGS)\
|
||||
$(POSIX_LDFLAGS) $(ARCH_DEP_LDFLAGS) $(DEBUG_LDFLAGS) $(OP_SYS_LDFLAGS)\
|
||||
$($(BUILD_CLASS)_LDFLAGS) $(RUNTIME_LDFLAGS) $(CODE_LDFLAGS)
|
||||
LDFLAGS = $(OPT_LDFLAGS) $(TARGET_LDFLAGS) $(USR_LDFLAGS) $(CMD_LDFLAGS) \
|
||||
$(POSIX_LDFLAGS) $(ARCH_DEP_LDFLAGS) $(DEBUG_LDFLAGS) $(OP_SYS_LDFLAGS) \
|
||||
$($(BUILD_CLASS)_LDFLAGS) $(RUNTIME_LDFLAGS) $(CODE_LDFLAGS)
|
||||
|
||||
LDLIBS = $(POSIX_LDLIBS) $(ARCH_DEP_LDLIBS) $(DEBUG_LDLIBS) $(OP_SYS_LDLIBS)\
|
||||
$(GNU_LDLIBS_$(GNU))
|
||||
LDLIBS = $(POSIX_LDLIBS) $(ARCH_DEP_LDLIBS) $(DEBUG_LDLIBS) $(OP_SYS_LDLIBS) \
|
||||
$(GNU_LDLIBS_$(GNU))
|
||||
|
||||
CPPFLAGS = $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
|
||||
$(DEBUG_CPPFLAGS) $(WARN_CPPFLAGS) $(BASE_CPPFLAGS) $(TARGET_CPPFLAGS)\
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS) $(API_CPPFLAGS)
|
||||
CPPFLAGS = $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS) \
|
||||
$(DEBUG_CPPFLAGS) $(WARN_CPPFLAGS) $(BASE_CPPFLAGS) $(TARGET_CPPFLAGS) \
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS) \
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS) $(API_CPPFLAGS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# ar definition default
|
||||
@@ -396,7 +413,7 @@ INSTALL_DOCS = $(DOCS:%= $(INSTALL_DOC)/%)
|
||||
INSTALL_HTMLS = $(HTMLS:%= $(INSTALL_HTML)/$(HTMLS_DIR)/%)
|
||||
|
||||
INSTALL_TEMPLATE = $(addprefix $(INSTALL_TEMPLATES_SUBDIR)/, \
|
||||
$(subst $(CONFIG),top/configure,$(TEMPLATES)))
|
||||
$(subst $(CONFIG),top/configure,$(TEMPLATES)))
|
||||
INSTALL_CONFIGS = $(CONFIGS:%= $(INSTALL_CONFIG)/%)
|
||||
|
||||
INSTALL_BIN_INSTALLS = $(addprefix $(INSTALL_BIN)/,$(notdir $(BIN_INSTALLS)))
|
||||
@@ -431,42 +448,41 @@ INSTALL_INC += $(foreach inc, $(INC), \
|
||||
$(CMPLR_INSTALL_INC) \
|
||||
$(OS_INSTALL_INC) \
|
||||
$(GENERIC_INSTALL_INC) \
|
||||
$(GENERATED_INSTALL_INC) ) )
|
||||
INSTALL_INC += $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INC_$(OS_CLASS)) )
|
||||
$(GENERATED_INSTALL_INC)))
|
||||
INSTALL_INC += $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INC_$(OS_CLASS)))
|
||||
|
||||
#
|
||||
# Rule 0
|
||||
#
|
||||
CMPLR_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/, $(INSTALL_INC_jjj) )
|
||||
INSTALL_INC_jjj = $(foreach dir, $(CMPLR_SRC_DIRS), $(INSTALL_INC_iii) )
|
||||
INSTALL_INC_iii = $(subst $(dir)/, , $(INSTALL_INC_hhh) )
|
||||
INSTALL_INC_hhh = $(wildcard $(addsuffix /$(inc), $(dir)) )
|
||||
CMPLR_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/, \
|
||||
$(foreach dir, $(CMPLR_SRC_DIRS), \
|
||||
$(subst $(dir)/,, $(wildcard $(addsuffix /$(inc), $(dir))))))
|
||||
|
||||
#
|
||||
# Rule 1
|
||||
#
|
||||
OS_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INSTALL_INC_ggg) )
|
||||
INSTALL_INC_ggg = $(foreach dir, $(OS_SRC_DIRS), $(INSTALL_INC_fff) )
|
||||
INSTALL_INC_fff = $(subst $(dir)/, , $(INSTALL_INC_eee) )
|
||||
INSTALL_INC_eee = $(wildcard $(addsuffix /$(inc), $(dir)) )
|
||||
OS_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, \
|
||||
$(foreach dir, $(OS_SRC_DIRS), \
|
||||
$(subst $(dir)/,, $(wildcard $(addsuffix /$(inc), $(dir))))))
|
||||
|
||||
#
|
||||
# Rule 2
|
||||
#
|
||||
GENERIC_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/, $(INSTALL_INC_ccc) )
|
||||
INSTALL_INC_ccc = $(foreach dir, .. $(SRC_DIRS), $(INSTALL_INC_bbb) )
|
||||
INSTALL_INC_bbb = $(subst $(dir)/, , $(INSTALL_INC_aaa) )
|
||||
INSTALL_INC_aaa = $(wildcard $(addsuffix /$(inc), $(dir)) )
|
||||
GENERIC_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/, \
|
||||
$(foreach dir, .. $(SRC_DIRS), \
|
||||
$(subst $(dir)/,, $(wildcard $(addsuffix /$(inc), $(dir))))))
|
||||
|
||||
#
|
||||
# Rule 3
|
||||
#
|
||||
GENERATED_INSTALL_INC = $(INSTALL_INCLUDE)/$(inc)
|
||||
|
||||
COMMON_INC += $(filter $(COMMON_DIR)/%, $(foreach file, $(INC), \
|
||||
$(firstword $(SOURCE_INC) $(COMMON_DIR)/$(file) ) ) )
|
||||
SOURCE_INC = $(wildcard $(file) $(SOURCE_INC_bbb) )
|
||||
SOURCE_INC_bbb = $(foreach dir, $(ALL_SRC_DIRS), $(SOURCE_INC_aaa) )
|
||||
SOURCE_INC_aaa = $(addsuffix /$(file), $(dir) )
|
||||
#---------------------------------------------------------------
|
||||
# Files listed in INC that must first be created in O.Common
|
||||
COMMON_INC += $(filter $(COMMON_DIR)/%, \
|
||||
$(foreach file, $(INC), \
|
||||
$(firstword $(wildcard $(file) \
|
||||
$(foreach dir, $(ALL_SRC_DIRS), \
|
||||
$(addsuffix /$(file), $(dir)))) $(COMMON_DIR)/$(file))))
|
||||
|
||||
endif
|
||||
|
||||
@@ -5,22 +5,28 @@
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# Set EPICS_DATABASE if necessary
|
||||
ifndef EPICS_DATABASE
|
||||
EPICS_DATABASE = $(if $(BUILDING_DATABASE),$(INSTALL_LOCATION),$(EPICS_BASE))
|
||||
# Installed perl scripts and dependent modules that have
|
||||
# a significant effect on the script's output
|
||||
DBDEXPAND_pl = $(EPICS_BASE_HOST_BIN)/dbdExpand.pl
|
||||
DBDTORECTYPEH_pl = $(EPICS_BASE_HOST_BIN)/dbdToRecordtypeH.pl
|
||||
DBDTORECTYPEH_dep = $(DBDTORECTYPEH_pl) $(call FIND_PM,DBD/Rec*.pm)
|
||||
DBDTOMENUH_pl = $(EPICS_BASE_HOST_BIN)/dbdToMenuH.pl
|
||||
DBDTOMENUH_dep = $(DBDTOMENUH_pl) $(call FIND_PM,DBD/Menu.pm)
|
||||
DBDTOHTML_pl = $(EPICS_BASE_HOST_BIN)/dbdToHtml.pl
|
||||
DBDTOHTML_dep = $(DBDTOHTML_pl) $(call FIND_PM,EPICS/Pod*Html.pm)
|
||||
REGRECDEVDRV_pl = $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
REGRECDEVDRV_dep = $(REGRECDEVDRV_pl)
|
||||
|
||||
# Paths to tools built here
|
||||
EPICS_DATABASE_HOST_BIN = $(EPICS_DATABASE)/bin/$(EPICS_HOST_ARCH)
|
||||
endif
|
||||
# Commands for running scripts in recipes
|
||||
DBEXPAND = $(PERL) $(DBDEXPAND_pl)
|
||||
DBTORECORDTYPEH = $(PERL) $(DBDTORECTYPEH_pl)
|
||||
DBTOMENUH = $(PERL) $(DBDTOMENUH_pl)
|
||||
DBDTOHTML = $(PERL) $(DBDTOHTML_pl)
|
||||
REGISTERRECORDDEVICEDRIVER = $(PERL) $(REGRECDEVDRV_pl)
|
||||
|
||||
# Set location of locally-built tools
|
||||
MAKEBPT = $(EPICS_DATABASE_HOST_BIN)/makeBpt$(HOSTEXE)
|
||||
DBEXPAND = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdExpand.pl
|
||||
DBTORECORDTYPEH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToRecordtypeH.pl
|
||||
DBTOMENUH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToMenuH.pl
|
||||
DBDTOHTML = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToHtml.pl
|
||||
REGISTERRECORDDEVICEDRIVER = $(PERL) $(EPICS_DATABASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
MSI3_15 = $(EPICS_DATABASE_HOST_BIN)/msi$(HOSTEXE)
|
||||
# Installed binary executables, quoted for running on Windows
|
||||
MAKEBPT = "$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)"
|
||||
MSI3_15 = "$(EPICS_BASE_HOST_BIN)/msi$(HOSTEXE)"
|
||||
|
||||
# Libraries needed to link a basic IOC
|
||||
EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Version number for the database APIs and shared library
|
||||
|
||||
EPICS_DATABASE_MAJOR_VERSION = 3
|
||||
EPICS_DATABASE_MINOR_VERSION = 20
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 0
|
||||
EPICS_DATABASE_MINOR_VERSION = 22
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 1
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# Set location of locally generated tools
|
||||
YACC = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/antelope$(HOSTEXE)
|
||||
LEX = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/e_flex$(HOSTEXE) \
|
||||
# Our locally-built tools
|
||||
# Windows can need these paths to be quoted
|
||||
YACC = "$(EPICS_BASE_HOST_BIN)/antelope$(HOSTEXE)"
|
||||
LEX = "$(EPICS_BASE_HOST_BIN)/e_flex$(HOSTEXE)" \
|
||||
-S$(EPICS_BASE)/include/flex.skel.static
|
||||
|
||||
# Default stack size for osiThread
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Version number for the libcom APIs and shared library
|
||||
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 20
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 0
|
||||
EPICS_LIBCOM_MINOR_VERSION = 22
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -17,7 +17,7 @@ TEMPL_SUFFIX ?= .template
|
||||
# vpath
|
||||
|
||||
vpath %.pm $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
|
||||
vpath %.pod $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
|
||||
vpath %.pod $(USR_VPATH) $(SRC_DIRS) .. $(dir $(DBD))
|
||||
vpath %.dbd $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
|
||||
vpath %.db $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
|
||||
vpath %.vdb $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
|
||||
@@ -217,32 +217,32 @@ realclean: clean
|
||||
#---------------------------------------------------------------
|
||||
# Dependency files
|
||||
|
||||
%Record.h$(DEP): $(COMMON_DIR)/%Record.dbd
|
||||
%Record.h$(DEP): $(COMMON_DIR)/%Record.dbd $(DBDTORECTYPEH_dep)
|
||||
@$(RM) $@
|
||||
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
%Record.h$(DEP): %Record.dbd
|
||||
%Record.h$(DEP): %Record.dbd $(DBDTORECTYPEH_dep)
|
||||
@$(RM) $@
|
||||
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
%Record.h$(DEP): ../%Record.dbd
|
||||
%Record.h$(DEP): ../%Record.dbd $(DBDTORECTYPEH_dep)
|
||||
@$(RM) $@
|
||||
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
menu%.h$(DEP): $(COMMON_DIR)/menu%.dbd
|
||||
menu%.h$(DEP): $(COMMON_DIR)/menu%.dbd $(DBDTOMENUH_dep)
|
||||
@$(RM) $@
|
||||
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
menu%.h$(DEP): menu%.dbd
|
||||
menu%.h$(DEP): menu%.dbd $(DBDTOMENUH_dep)
|
||||
@$(RM) $@
|
||||
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
menu%.h$(DEP): ../menu%.dbd
|
||||
menu%.h$(DEP): ../menu%.dbd $(DBDTOMENUH_dep)
|
||||
@$(RM) $@
|
||||
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
@@ -261,7 +261,7 @@ menu%.h$(DEP): ../menu%.dbd
|
||||
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
%.dbd$(DEP):
|
||||
%.dbd$(DEP): $($*_DBD)
|
||||
@$(RM) $@
|
||||
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $($*_DBD) > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
@@ -330,32 +330,32 @@ $(INSTALL_DB)/%$(TEMPL_SUFFIX): ../%$(TEMPL_SUFFIX)
|
||||
#---------------------------------------------------------------
|
||||
# INC files
|
||||
|
||||
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd
|
||||
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd $(DBDTORECTYPEH_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%Record.h: %Record.dbd
|
||||
$(COMMON_DIR)/%Record.h: %Record.dbd $(DBDTORECTYPEH_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%Record.h: ../%Record.dbd
|
||||
$(COMMON_DIR)/%Record.h: ../%Record.dbd $(DBDTORECTYPEH_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd
|
||||
$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd $(DBDTOMENUH_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/menu%.h: menu%.dbd
|
||||
$(COMMON_DIR)/menu%.h: menu%.dbd $(DBDTOMENUH_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/menu%.h: ../menu%.dbd
|
||||
$(COMMON_DIR)/menu%.h: ../menu%.dbd $(DBDTOMENUH_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
@@ -366,6 +366,7 @@ $(COMMON_DIR)/menu%.h: ../menu%.dbd
|
||||
# DBD files
|
||||
|
||||
$(COMMON_DIR)/bpt%.dbd: bpt%.data
|
||||
$(ECHO) "Converting data from $<"
|
||||
@$(RM) $(notdir $@)
|
||||
$(MAKEBPT) $< $(notdir $@)
|
||||
@$(MV) $(notdir $@) $@
|
||||
@@ -399,7 +400,7 @@ $(COMMON_DBDCATS):$(COMMON_DIR)/%.dbd:
|
||||
$(DBDCAT_COMMAND)
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.dbd:
|
||||
$(COMMON_DIR)/%.dbd: $($*_DBD)
|
||||
$(ECHO) "Creating dbd file $(notdir $@)"
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBEXPAND) $(DBDFLAGS) -o $(notdir $@) $($*_DBD)
|
||||
@@ -429,33 +430,33 @@ $(foreach file, $(DBD_INSTALLS), $(eval $(call DBD_INSTALLS_template, $(file))))
|
||||
#---------------------------------------------------------------
|
||||
# HTML files
|
||||
|
||||
$(COMMON_DIR)/%.html: %.dbd.pod
|
||||
$(COMMON_DIR)/%.html: %.dbd.pod $(DBDTOHTML_pl)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBDTOHTML) $(DBDFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.html: %.pod
|
||||
$(COMMON_DIR)/%.html: %.pod $(PODTOHTML_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(PODTOHTML) -s -s -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.html: %.pm
|
||||
$(COMMON_DIR)/%.html: %.pm $(PODTOHTML_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(PODTOHTML) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.html: ../%.pm
|
||||
$(COMMON_DIR)/%.html: ../%.pm $(PODTOHTML_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(PODTOHTML) -s -o $(notdir $@) $<
|
||||
@$(MKDIR) $(dir $@)
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.html: ../%.pl
|
||||
$(COMMON_DIR)/%.html: ../%.pl $(PODTOHTML_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(PODTOHTML) -s -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%.html %.html
|
||||
.PRECIOUS: $(COMMON_DIR)/%.html
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# DB files
|
||||
@@ -526,16 +527,19 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file))))
|
||||
#---------------------------------------------------------------
|
||||
# register record,device,driver support
|
||||
|
||||
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
|
||||
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd $(REGRECDEVDRV_dep)
|
||||
@$(RM) $@
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
|
||||
$< $(basename $@) $(IOCS_APPL_TOP)
|
||||
|
||||
%_registerRecordDeviceDriver.cpp: %.dbd
|
||||
%_registerRecordDeviceDriver.cpp: %.dbd $(REGRECDEVDRV_dep)
|
||||
@$(RM) $@
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
|
||||
$< $(basename $@) $(IOCS_APPL_TOP)
|
||||
|
||||
%_registerRecordDeviceDriver.cpp: ../%.dbd
|
||||
%_registerRecordDeviceDriver.cpp: ../%.dbd $(REGRECDEVDRV_dep)
|
||||
@$(RM) $@
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
|
||||
$< $(basename $@) $(IOCS_APPL_TOP)
|
||||
|
||||
.PRECIOUS: %_registerRecordDeviceDriver.cpp
|
||||
|
||||
@@ -224,7 +224,7 @@ 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)
|
||||
@@ -386,23 +386,25 @@ $(MODNAME): %$(MODEXT): %$(EXE)
|
||||
# Automated testing
|
||||
|
||||
runtests: run-tap-tests
|
||||
run-tap-tests: $(TESTSCRIPTS.t)
|
||||
run-tap-tests: | build
|
||||
ifneq ($(TESTSCRIPTS.t),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(ECHO) "$(PROVE) $^"
|
||||
@$(PROVE) $^ || $(PROVE_FAILURE)
|
||||
$(ECHO) "$(PROVE) $(TESTSCRIPTS.t)"
|
||||
@$(PROVE) $(TESTSCRIPTS.t) || $(PROVE_FAILURE)
|
||||
endif
|
||||
endif
|
||||
|
||||
tapfiles: $(TAPFILES)
|
||||
junitfiles: $(JUNITFILES)
|
||||
# prevent deletion of partial output from failing tests
|
||||
.PRECIOUS: $(TAPFILES) $(JUNITFILES)
|
||||
|
||||
test-results: tap-results
|
||||
tap-results: $(TAPFILES)
|
||||
ifneq ($(strip $(TAPFILES)),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(ECHO) "$(PROVE.tap) $^"
|
||||
@$(PROVE.tap) $^ || $(PROVE_FAILURE)
|
||||
$(ECHO) "$(PROVE.tap) $(TAPFILES)"
|
||||
@$(PROVE.tap) $(TAPFILES) || $(PROVE_FAILURE)
|
||||
endif
|
||||
|
||||
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
|
||||
@@ -418,7 +420,7 @@ ifneq ($(CURRENT_JUNITFILES),)
|
||||
endif
|
||||
|
||||
# A .tap file is the output from running the associated test script
|
||||
$(TAPFILES.t): %.tap: %.t
|
||||
$(TAPFILES.t): %.tap: %.t | build
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(ECHO) "$(PERL) $< -tap > $@"
|
||||
@$(PERL) $< -tap > $@ || $(TAPFILE_FAILURE)
|
||||
@@ -574,6 +576,10 @@ $(INSTALL_DOC)/%: ../%
|
||||
$(ECHO) "Installing doc $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(INSTALL_DOC)
|
||||
|
||||
$(INSTALL_HTML)/$(HTMLS_DIR)/%: $(COMMON_DIR)/%
|
||||
$(ECHO) "Installing generated html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
$(INSTALL_HTML)/$(HTMLS_DIR)/%: %
|
||||
$(ECHO) "Installing html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
@@ -582,10 +588,6 @@ $(INSTALL_HTML)/$(HTMLS_DIR)/%: ../%
|
||||
$(ECHO) "Installing html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
$(INSTALL_HTML)/$(HTMLS_DIR)/%: $(COMMON_DIR)/%
|
||||
$(ECHO) "Installing generated html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
$(INSTALL_TEMPLATES_SUBDIR)/%: ../%
|
||||
$(ECHO) "Installing $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
@@ -27,7 +27,7 @@ $(foreach file,$(MAKEFILE_LIST), \
|
||||
|
||||
PRINT_Var = $(@:PRINT.%=%)
|
||||
PRINT.%:
|
||||
@echo $(PRINT_Var) = '$($(PRINT_Var))'
|
||||
@+echo $(PRINT_Var) = '$($(PRINT_Var))'
|
||||
|
||||
.PHONY: PRINT PRINT.%
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
# INC += myVersion.h
|
||||
|
||||
# Default settings
|
||||
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl
|
||||
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl $(QUIET_FLAG)
|
||||
|
||||
EXPANDARCH = -a $(T_A)
|
||||
EXPANDFLAGS += -t $(INSTALL_LOCATION)
|
||||
@@ -55,22 +55,17 @@ EXPANDFLAGS += $(addprefix -D ,$(EXPAND_VARS) $($@_EXPAND_VARS))
|
||||
EXPANDFLAGS += $(foreach var, $(EXPAND_ME) $($@_EXPAND_ME), \
|
||||
-D$(var)="$(strip $($(var)))")
|
||||
|
||||
# The names of files to be expanded must end with '@'
|
||||
# Output files
|
||||
EXPANDED = $(EXPAND:%@=%)
|
||||
EXPANDED_COM = $(EXPAND_COMMON:%@=%)
|
||||
EXPANDED_COMMON = $(EXPANDED_COM:%=$(COMMON_DIR)/%)
|
||||
EXPANDED_COMMON = $(EXPAND_COMMON:%@=$(COMMON_DIR)/%)
|
||||
|
||||
$(EXPANDED): %: %@
|
||||
$(ECHO) "Expanding $< to $@"
|
||||
@$(RM) $@
|
||||
$(EXPAND_TOOL) $(EXPANDARCH) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
|
||||
|
||||
$(EXPANDED_COM): %: %@
|
||||
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %@
|
||||
$(ECHO) "Expanding $< to $(COMMON_DIR)/$@"
|
||||
@$(RM) $@
|
||||
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
|
||||
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %
|
||||
@$(MV) $< $@
|
||||
|
||||
clean: expand_clean
|
||||
|
||||
|
||||
@@ -22,13 +22,14 @@
|
||||
# 7. Submodules must have a configure/CONFIG_SITE file that contains
|
||||
# -include $(TOP)/../CONFIG_SITE.local
|
||||
|
||||
# Add checked-out submodules to DIRS
|
||||
LIVE_SUBMODULES = $(subst /Makefile,,$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
|
||||
DIRS += $(LIVE_SUBMODULES)
|
||||
# Add checked-out submodules to DIRS, unless INSTALL_LOCATION is empty
|
||||
LIVE_SUBMODULES = $(subst /Makefile,, \
|
||||
$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
|
||||
live = $(if $(wildcard $(INSTALL_CONFIG)/RULES_TOP),LIVE,DEAD)
|
||||
DIRS += $($(live)_SUBMODULES)
|
||||
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
|
||||
INSTALL_LOCATION_ABS := $(abspath $(INSTALL_LOCATION))
|
||||
RELEASE_LOCAL := RELEASE.$(EPICS_HOST_ARCH).local
|
||||
|
||||
# Ensure that RELEASE.<host>.local exists before doing anything else
|
||||
@@ -38,14 +39,13 @@ all host $(DIRS) $(ARCHS) $(ACTIONS) $(dirActionTargets) $(dirArchTargets) \
|
||||
# Convenience target
|
||||
RELEASE.host: $(RELEASE_LOCAL)
|
||||
|
||||
$(RELEASE_LOCAL): Makefile CONFIG_SITE.local
|
||||
$(RELEASE_LOCAL): Makefile $(CONFIG)/CONFIG_SITE \
|
||||
$(wildcard $(CONFIG)/CONFIG_SITE.local)
|
||||
$(ECHO) Creating $@ with
|
||||
$(ECHO) " $(PARENT_MODULE) = $(INSTALL_LOCATION_ABS)"
|
||||
@echo $(PARENT_MODULE) = $(INSTALL_LOCATION_ABS)> $@
|
||||
realclean:
|
||||
$(RM) $(wildcard RELEASE.*.local)
|
||||
$(ECHO) " $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)"
|
||||
@echo $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)> $@
|
||||
|
||||
.PHONY: RELEASE.host realclean
|
||||
.PHONY: RELEASE.host
|
||||
|
||||
# Testing: Combine test failure logs from the live submodules
|
||||
TESTS_FAILED_LOGS = $(wildcard $(addsuffix /$(TESTS_FAILED_LOG), \
|
||||
|
||||
@@ -23,35 +23,42 @@ ifndef DISABLE_TOP_RULES
|
||||
# Rules for a regular application top directory
|
||||
#
|
||||
|
||||
distclean: realclean cvsclean realuninstall
|
||||
# When run by 'make distclean' the realuninstall target also
|
||||
# removes any modules/RELEASE.<host>.local files
|
||||
distclean: realclean cvsclean realuninstall
|
||||
|
||||
realuninstall: uninstallDirs
|
||||
realuninstall: uninstallDirs
|
||||
$(RMDIR) $(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB)
|
||||
ifeq (modules,$(filter modules,$(DIRS)))
|
||||
ifeq (distclean,$(filter distclean,$(MAKECMDGOALS)))
|
||||
$(RM) $(wildcard modules/RELEASE.*.local)
|
||||
endif
|
||||
endif
|
||||
|
||||
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
|
||||
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
|
||||
ifneq ($(INSTALL_LOCATION),$(TOP))
|
||||
UNINSTALL_DIRS += $(INSTALL_CONFIG)
|
||||
endif
|
||||
uninstallDirs: | clean
|
||||
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
|
||||
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
|
||||
ifneq ($(INSTALL_LOCATION),$(TOP))
|
||||
UNINSTALL_DIRS += $(INSTALL_CONFIG)
|
||||
endif
|
||||
uninstallDirs:
|
||||
$(RMDIR) $(UNINSTALL_DIRS)
|
||||
|
||||
# Remove the bin and lib directories if they have no sub-directories
|
||||
#
|
||||
EMPTY_INSTALL_DIRS = \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
|
||||
uninstall: archuninstall uninstallDirs | clean
|
||||
EMPTY_INSTALL_DIRS = \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
|
||||
uninstall: archuninstall uninstallDirs
|
||||
$(RMDIR) $(EMPTY_INSTALL_DIRS)
|
||||
|
||||
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
|
||||
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
|
||||
|
||||
uninstall$(DIVIDER)%: | clean
|
||||
uninstall$(DIVIDER)%:
|
||||
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
|
||||
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))
|
||||
|
||||
# Only run this at the top of the parent
|
||||
runtests test-results:
|
||||
# Only run this at the top of the parent
|
||||
runtests test-results:
|
||||
@$(SHOWTESTFAILURES)
|
||||
|
||||
else
|
||||
@@ -76,7 +83,6 @@ help:
|
||||
@echo " inc - Installs header, dbd and html files"
|
||||
@echo " build - Builds and installs all targets"
|
||||
@echo " install - Builds and installs all targets"
|
||||
@echo " buildInstall - Same as install (deprecated)"
|
||||
@echo " clean - Removes the O.<arch> dirs created by running make"
|
||||
@echo " In O.<arch> dir, clean removes build created files"
|
||||
@echo " realclean - Removes ALL O.<arch> dirs"
|
||||
@@ -101,7 +107,8 @@ ifndef DISABLE_TOP_RULES
|
||||
@echo " uninstall$(DIVIDER)<arch> - Remove bin & lib directories for <arch> only."
|
||||
@echo " uninstall - Remove install directories created by this hostarch."
|
||||
@echo " realuninstall - Removes ALL install dirs"
|
||||
@echo " distclean - Same as realclean cvsclean realuninstall."
|
||||
@echo " distclean - Does realclean cvsclean realuninstall and deletes any"
|
||||
@echo " generated modules/RELEASE.<host>.local files"
|
||||
endif
|
||||
@echo " help - Prints this list of valid make targets "
|
||||
@echo "Object targets are supported by the O.<arch> level Makefile .e.g"
|
||||
|
||||
@@ -77,7 +77,10 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
|
||||
|
||||
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
|
||||
ECHO = @$(if $(make-s),$(NOP),echo)
|
||||
|
||||
# Originally set in os/CONFIG.UnixCommon.Common
|
||||
MKDIR = mkdir -p
|
||||
|
||||
#--------------------------------------------------
|
||||
# Although RTEMS uses gcc, it wants to use gcc its own way
|
||||
|
||||
@@ -11,14 +11,15 @@ MUNCH_SUFFIX = .boot
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
||||
gzip -f9 rtems
|
||||
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@ \
|
||||
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@.elf \
|
||||
$(PROJECT_RELEASE)/lib/bootloader.o \
|
||||
--just-symbols=$< \
|
||||
-b binary rtems.gz \
|
||||
--no-warn-mismatch \
|
||||
--no-warn-mismatch \
|
||||
-T $(PROJECT_RELEASE)/lib/ppcboot.lds \
|
||||
-Map $<.map
|
||||
rm -f rtems.gz
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $@.elf $@
|
||||
rm -f rtems.gz $@.elf
|
||||
endef
|
||||
|
||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||
|
||||
@@ -56,7 +56,7 @@ SHRLIB_LDLIBS = $(addprefix -l, $($*_LDLIBS) $(LIB_LIBS) $(USR_LIBS)) \
|
||||
|
||||
SHRLIB_DEPLIB_DIRS = $(foreach word, \
|
||||
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(SHRLIB_DEPLIBS))), \
|
||||
$(shell $(FULLPATHNAME) $(word)))
|
||||
$(abspath $(word)))
|
||||
|
||||
SHRLIBDIR_LDFLAGS += $(SHRLIB_DEPLIB_DIRS:%=-L%)
|
||||
|
||||
@@ -85,7 +85,7 @@ PROD_LDLIBS += $($(firstword $(LDLIBS_STATIC_$(STATIC_BUILD)) \
|
||||
|
||||
PROD_DEPLIB_DIRS = $(foreach word, \
|
||||
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(PROD_DEPLIBS))), \
|
||||
$(shell $(FULLPATHNAME) $(word)))
|
||||
$(abspath $(word)))
|
||||
|
||||
PRODDIR_LDFLAGS += $(PROD_DEPLIB_DIRS:%=-L%)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ OP_SYS_LDFLAGS += -dynamic -Z -L$(SDK_DIR)/usr/lib -L$(SDK_DIR)/usr/lib/system
|
||||
# Shared libraries
|
||||
SHRLIB_VERSION = $(EPICS_VERSION).$(EPICS_REVISION).$(EPICS_MODIFICATION)
|
||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined suppress \
|
||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||
-install_name $(abspath $(INSTALL_LIB))/$@ \
|
||||
-compatibility_version $(EPICS_VERSION).$(EPICS_REVISION) \
|
||||
-current_version $(SHRLIB_VERSION)
|
||||
SHRLIB_SUFFIX_BASE = .dylib
|
||||
|
||||
21
configure/os/CONFIG.Common.vxWorks-e500v2
Normal file
21
configure/os/CONFIG.Common.vxWorks-e500v2
Normal file
@@ -0,0 +1,21 @@
|
||||
# CONFIG.Common.vxWorks-e500v2
|
||||
#
|
||||
# Definitions for vxWorks-e500v2 target archs (MVME2500)
|
||||
# Sites may override these definitions in CONFIG_SITE.Common.vxWorks-e500v2
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Include definitions common to all vxWorks target archs
|
||||
include $(CONFIG)/os/CONFIG.Common.vxWorksCommon
|
||||
|
||||
# Vx GNU cross compiler suffix
|
||||
CMPLR_SUFFIX = ppc
|
||||
|
||||
ARCH_CLASS = ppc
|
||||
|
||||
# Architecture specific build flags
|
||||
ARCH_DEP_CFLAGS += -te500v2 -mhard-float
|
||||
ARCH_DEP_CPPFLAGS += -DCPU=PPC85XX
|
||||
ARCH_DEP_CFLAGS += -DCPU_VARIANT=_ppc85XX_e500v2
|
||||
ARCH_DEP_CFLAGS += -mlongcall
|
||||
|
||||
GNU_TARGET = powerpc-wrs-vxworks
|
||||
@@ -12,7 +12,7 @@ ARCH_CLASS = x86
|
||||
POSIX = NO
|
||||
|
||||
# Definitions used when COMMANDLINE_LIBRARY is READLINE
|
||||
LDLIBS_READLINE = -lreadline -lcurses
|
||||
LDLIBS_READLINE = -lreadline -ltermcap
|
||||
|
||||
ARCH_DEP_CFLAGS += -m32
|
||||
ARCH_DEP_LDFLAGS += -m32
|
||||
|
||||
@@ -66,8 +66,8 @@ GNU = NO
|
||||
#
|
||||
# Darwin shared libraries
|
||||
#
|
||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined dynamic_lookup \
|
||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace \
|
||||
-install_name $(abspath $(INSTALL_LIB))/$@ \
|
||||
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
|
||||
$(addprefix -current_version , $(SHRLIB_VERSION))
|
||||
SHRLIB_SUFFIX_BASE = .dylib
|
||||
|
||||
@@ -6,3 +6,8 @@
|
||||
|
||||
# Include common gnu compiler definitions
|
||||
include $(CONFIG)/CONFIG.gnuCommon
|
||||
|
||||
STATIC_LDFLAGS_YES= -Wl,-Bstatic
|
||||
STATIC_LDFLAGS_NO=
|
||||
STATIC_LDLIBS_YES= -Wl,-Bdynamic
|
||||
STATIC_LDLIBS_NO=
|
||||
|
||||
@@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
|
||||
GNU_LDLIBS_YES =
|
||||
|
||||
# Link with system libraries
|
||||
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
|
||||
@@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
|
||||
GNU_LDLIBS_YES =
|
||||
|
||||
# Link with system libraries
|
||||
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
|
||||
@@ -34,5 +34,6 @@
|
||||
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
|
||||
# overridden in this file for native builds, e.g. variables such as
|
||||
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
|
||||
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 instead.
|
||||
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 or for
|
||||
# cross-builds in CONFIG_SITE.<host-arch>.linux-aarch64 instead.
|
||||
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
# to inform the system of the shared library location.
|
||||
|
||||
|
||||
# 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'
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
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'
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
# to inform the system of the shared library location.
|
||||
|
||||
|
||||
# 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'
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
# to inform the system of the shared library location.
|
||||
|
||||
|
||||
# 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'
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
# 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'
|
||||
|
||||
@@ -3,21 +3,24 @@
|
||||
# Site specific definitions for darwin builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Note the dir/firstword/wildcard functions below are used
|
||||
# to avoid warnings about missing directories.
|
||||
# These settings are designed for users of Homebrew.
|
||||
# Users of other third-party package managers are welcome to
|
||||
# provide patches appropriate for their manager.
|
||||
ifneq (,$(wildcard /opt/homebrew))
|
||||
# Default location on aarch64
|
||||
HOMEBREW_DIR = /opt/homebrew
|
||||
else ifneq (,$(wildcard /usr/local/Homebrew))
|
||||
# Default location on x86_64
|
||||
HOMEBREW_DIR = /usr/local
|
||||
endif
|
||||
|
||||
# Mix-and-match of different package systems is probably not advisable,
|
||||
# but you can try that if you like...
|
||||
|
||||
# Uncomment these definitions when using Homebrew packages:
|
||||
#OP_SYS_INCLUDES += -I/usr/local/include
|
||||
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /usr/local/lib/*))))
|
||||
|
||||
# Uncomment these definitions when using DarwinPorts packages:
|
||||
#OP_SYS_INCLUDES += -I/opt/local/include
|
||||
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /opt/local/lib/*))))
|
||||
|
||||
# Uncomment these definitions when using Fink packages:
|
||||
#OP_SYS_INCLUDES += -I/sw/include
|
||||
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /sw/lib/*))))
|
||||
# Look for Homebrew's readline
|
||||
ifneq (,$(wildcard $(HOMEBREW_DIR)/opt/readline))
|
||||
READLINE_DIR = $(HOMEBREW_DIR)/opt/readline
|
||||
endif
|
||||
|
||||
# Use GNU readline if it's avaiilable
|
||||
ifneq (,$(wildcard $(READLINE_DIR)/include/readline/readline.h))
|
||||
INCLUDES_READLINE = -I$(READLINE_DIR)/include
|
||||
LDFLAGS_READLINE = -L$(READLINE_DIR)/lib
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CONFIG_SITE.linux-x86.linux-aarch64
|
||||
# CONFIG_SITE.linux-x86_64.linux-aarch64
|
||||
#
|
||||
# Site specific definitions for linux-x86 host - linux-aarch64 target builds
|
||||
# Site specific definitions for linux-x86_64 host - linux-aarch64 target builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Set GNU crosscompiler target name
|
||||
|
||||
@@ -35,3 +35,15 @@ OS_API = posix
|
||||
OS_API = score
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
# if defined(__rtems__) && __RTEMS_MAJOR__<5 && __has_include(<libtecla.h>)
|
||||
COMMANDLINE_LIBRARY ?= LIBTECLA
|
||||
# elif __has_include(<readline/readline.h>)
|
||||
COMMANDLINE_LIBRARY ?= READLINE
|
||||
# else
|
||||
COMMANDLINE_LIBRARY ?= EPICS
|
||||
# endif
|
||||
#else
|
||||
COMMANDLINE_LIBRARY ?= EPICS
|
||||
#endif
|
||||
|
||||
170
documentation/ComponentReference.pod
Normal file
170
documentation/ComponentReference.pod
Normal file
@@ -0,0 +1,170 @@
|
||||
=head1 EPICS Component Reference Manual
|
||||
|
||||
This document provides reference information about the record types,
|
||||
menus, link types and channel filters included with EPICS Base.
|
||||
|
||||
Many details about the record and menu definitions are derived automatically
|
||||
from the source code at build time.
|
||||
|
||||
|
||||
=head2 Introduction and IOC Concepts
|
||||
|
||||
These links point to an external website where introductory and overview
|
||||
documentation is now being published.
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Introduction to EPICS|https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html>
|
||||
|
||||
=item * L<Process Database Concepts|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Record Type Definitions
|
||||
|
||||
These sections describe common aspects of the record types:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Fields Common to All Record Types|dbCommonRecord>
|
||||
|
||||
=item * L<Fields Common to Input Record Types|dbCommonInput>
|
||||
|
||||
=item * L<Fields Common to Output Record Types|dbCommonOutput>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
These are the record types supplied with EPICS Base:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Analog Array Input Record (aai)|aaiRecord>
|
||||
|
||||
=item * L<Analog Array Output Record (aao)|aaoRecord>
|
||||
|
||||
=item * L<Analog Input Record (ai)|aiRecord>
|
||||
|
||||
=item * L<Analog Output Record (ao)|aoRecord>
|
||||
|
||||
=item * L<Array Subroutine Record (aSub)|aSubRecord>
|
||||
|
||||
=item * L<Binary Input Record (bi)|biRecord>
|
||||
|
||||
=item * L<Binary Output Record (bo)|boRecord>
|
||||
|
||||
=item * L<Calculation Output Record (calcout)|calcoutRecord>
|
||||
|
||||
=item * L<Calculation Record (calc)|calcRecord>
|
||||
|
||||
=item * L<Compression Record (compress)|compressRecord>
|
||||
|
||||
=item * L<Data Fanout Record (dfanout)|dfanoutRecord>
|
||||
|
||||
=item * L<Event Record (event)|eventRecord>
|
||||
|
||||
=item * L<Fanout Record (fanout)|fanoutRecord>
|
||||
|
||||
=item * L<Histogram Record (histogram)|histogramRecord>
|
||||
|
||||
=item * L<64-bit Integer Input Record (int64in)|int64inRecord>
|
||||
|
||||
=item * L<64-bit Integer Output Record (int64out)|int64outRecord>
|
||||
|
||||
=item * L<Long Input Record (longin)|longinRecord>
|
||||
|
||||
=item * L<Long Output Record (longout)|longoutRecord>
|
||||
|
||||
=item * L<Long String Input Record (lsi)|lsiRecord>
|
||||
|
||||
=item * L<Long String Output Record (lso)|lsoRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Input Direct Record (mbbiDirect)|mbbiDirectRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Input Record (mbbi)|mbbiRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Output Direct Record (mbboDirect)|mbboDirectRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Output Record (mbbo)|mbboRecord>
|
||||
|
||||
=item * L<Permissive Record (permissive)|permissiveRecord>
|
||||
|
||||
=item * L<Printf Record (printf)|printfRecord>
|
||||
|
||||
=item * L<Select Record (sel)|selRecord>
|
||||
|
||||
=item * L<Sequence Record (seq)|seqRecord>
|
||||
|
||||
=item * L<State Record (state)|stateRecord>
|
||||
|
||||
=item * L<String Input Record (stringin)|stringinRecord>
|
||||
|
||||
=item * L<String Output Record (stringout)|stringoutRecord>
|
||||
|
||||
=item * L<Sub-Array Record (subArray)|subArrayRecord>
|
||||
|
||||
=item * L<Subroutine Record (sub)|subRecord>
|
||||
|
||||
=item * L<Waveform Record (waveform)|waveformRecord>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Menu Definitions
|
||||
|
||||
Menu field choices are documented with the record type that defines them, or
|
||||
here for the global menus that are used by multiple record types:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Alarm Severity Menu|menuAlarmSevr>
|
||||
|
||||
=item * L<Alarm Status Menu|menuAlarmStat>
|
||||
|
||||
=item * L<Analog Conversions Menu|menuConvert>
|
||||
|
||||
=item * L<Field Type Menu|menuFtype>
|
||||
|
||||
=item * L<Invalid Value Output Action Menu|menuIvoa>
|
||||
|
||||
=item * L<Output Mode Select Menu|menuOmsl>
|
||||
|
||||
=item * L<Process at iocInit Menu|menuPini>
|
||||
|
||||
=item * L<Post Monitors Menu|menuPost>
|
||||
|
||||
=item * L<Priority Menu|menuPriority>
|
||||
|
||||
=item * L<Scan Menu|menuScan>
|
||||
|
||||
=item * L<Simulation Mode Menu|menuSimm>
|
||||
|
||||
=item * L<YesE<sol>No Menu|menuYesNo>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Other Components
|
||||
|
||||
EPICS Base also comes with extensible sets of server Channel Filters and IOC
|
||||
Database Link types, which are documented here:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Channel Filters|filters>
|
||||
|
||||
=item * L<IOC Database Link Types|links>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Corrections and Updates
|
||||
|
||||
Corrections to these documents can be submitted as patch files to the EPICS
|
||||
core developers, or as GitHub pull requests to the 7.0 branch of Base.
|
||||
These document sources can be found under `modules/database/src` tree, mostly
|
||||
in the `std/rec` and `ioc/db` directories in files with extension `.dbd.pod`.
|
||||
The documentation source format is a combination of the EPICS DBD file format
|
||||
with an extended version of Perl's POD (plain old documentation); run `perldoc
|
||||
pod` for details of POD.
|
||||
@@ -762,7 +762,6 @@ WARN_LOGFILE =
|
||||
INPUT = ../mainpage.dox \
|
||||
../RELEASE_NOTES.md \
|
||||
../README.md \
|
||||
../RecordReference.md \
|
||||
@TOP@/include
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
@@ -2300,7 +2299,7 @@ PLANTUML_JAR_PATH =
|
||||
# Minimum value: 0, maximum value: 10000, default value: 50.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
DOT_GRAPH_MAX_NODES = 100
|
||||
|
||||
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
|
||||
# generated by dot. A depth value of 3 means that only nodes reachable from the
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
ifeq ($(T_A),$(EPICS_HOST_ARCH))
|
||||
|
||||
DOXYGEN=doxygen
|
||||
|
||||
EXPAND = Doxyfile@
|
||||
|
||||
EXPAND_ME += EPICS_VERSION
|
||||
EXPAND_ME += EPICS_REVISION
|
||||
EXPAND_ME += EPICS_MODIFICATION
|
||||
EXPAND_ME += EPICS_PATCH_LEVEL
|
||||
EXPAND_ME += OS_CLASS CMPLR_CLASS
|
||||
|
||||
HTMLS += ComponentReference.html
|
||||
|
||||
TARGETS += doxygen
|
||||
|
||||
DOXYGEN = doxygen
|
||||
ME = documentation/O.$(T_A)/html
|
||||
GH_FILES = $(ME)/ $(ME)/.nojekyll $(ME)/*.* $(ME)/*/*.*
|
||||
|
||||
install: doxygen
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
doxygen: Doxyfile ../mainpage.dox
|
||||
doxygen: Doxyfile ../mainpage.dox $(INSTALL_HTMLS)
|
||||
$(DOXYGEN)
|
||||
rsync -av $(TOP)/html/ html/
|
||||
|
||||
@@ -29,7 +29,3 @@ commit: doxygen
|
||||
(cd $(TOP) && $(CURDIR)/../commit-gh.sh $(GH_FILES))
|
||||
|
||||
.PHONY: commit
|
||||
|
||||
endif # EPICS_HOST_ARCH
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Installation Instructions {#install}
|
||||
|
||||
## EPICS Base Release 7.0.5
|
||||
## EPICS Base Release 7.0.x
|
||||
|
||||
-----
|
||||
|
||||
@@ -74,7 +74,7 @@ is older but does still work.
|
||||
|
||||
#### Perl
|
||||
|
||||
You must have Perl version 5.10 or later installed. The EPICS
|
||||
You must have Perl version 5.10.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.
|
||||
|
||||
@@ -387,7 +387,7 @@ 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
|
||||
into `$(INSTALL_LOCATION)/lib/<arch>`. The default definition for
|
||||
`$(INSTALL_LOCATION)` is `$(TOP)` which is the root directory in the
|
||||
distribution directory structure, `base`. Intermediate object files
|
||||
are stored in `O.<arch>` source subdirectories during the build
|
||||
|
||||
@@ -2,14 +2,350 @@
|
||||
|
||||
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 the 3.15 branch are not described at the top of this file but
|
||||
lower down, under the 3.15 release 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.
|
||||
from commits to the 3.15 branch are described
|
||||
[further down this file](#changes-incorporated-from-the-315-branch)
|
||||
under the 3.15 release 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 PVA submodules each have their own individual sets of release notes which
|
||||
should also be read to understand what has changed since earlier releases.
|
||||
|
||||
**This version of EPICS has not been released yet.**
|
||||
|
||||
## Changes made on the 7.0 branch since 7.0.7
|
||||
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
### Add conditional output (OOPT) to the longout record
|
||||
|
||||
The longout record can now be configured using its new OOPT and OOCH fields
|
||||
to (not) write to its output link depending on the contents of VAL, in a
|
||||
similar manner to the calcout record. More information can be found on the
|
||||
reference page for the longout record type that accompanies this release.
|
||||
|
||||
This functionality was suggested in
|
||||
[lp# 1398215](https://bugs.launchpad.net/epics-base/+bug/1398215) and may
|
||||
be added to other output record types if the community finds it useful,
|
||||
please send feedback about the feature to tech-talk.
|
||||
|
||||
### Tab completion for IOC shell
|
||||
|
||||
When built with optional GNU libreadline support, the interactive IOC shell
|
||||
will perform tab completion for command names as well as for some arguments
|
||||
of the built-in commands. For example, the record name argument of `dbpr`,
|
||||
and the path name argument of `cd`.
|
||||
|
||||
Externally defined commands have a limited ability to opt into completion by
|
||||
using the new `iocshArgStringRecord` and `iocshArgStringPath` argument types.
|
||||
Both function identically to `iocshArgString` but indicate how to suggest
|
||||
completion strings.
|
||||
|
||||
Builds on macOS (darwin-x86 or darwin-aarch64 targets) normally use Apple's
|
||||
libedit library in readline compatibility mode, which doesn't support the tab
|
||||
completion API that GNU readline provides. You can use Homebrew or some other
|
||||
third-party package manager to install the GNU readline package, then edit the
|
||||
configure/os/CONFIG_SITE.darwinCommon.darwinCommon file to have EPICS use the
|
||||
real thing to get tab completion in the IOC shell. The default settings in that
|
||||
file currently look for and use a Homebrew-installed readline if present.
|
||||
|
||||
### Add FMOD as CALC Expression
|
||||
|
||||
The floating point modulo function `FMOD(NUM,DEN)` has been added to the CALC
|
||||
expression engine and is available to all software using that (calc and calcout
|
||||
record types, access security library and some extensions).
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.7
|
||||
|
||||
### Doxygen Annotations
|
||||
|
||||
Thanks to several attendees at the 2022 EPICS Codeathon the number of header
|
||||
files with Doxygen annotations in the EPICS Core has again increased.
|
||||
|
||||
### Build System updates
|
||||
|
||||
The top-level make targets `uninstall`, `archuninstall` and similar no
|
||||
longer trigger the `clean` target which empties build directories, this
|
||||
was a bug introduced in 7.0.5.
|
||||
|
||||
The `make distclean` target now properly deletes the generated file(s)
|
||||
`modules/RELEASE.<host>.local` which are essential to build the external
|
||||
submodules under the `modules` directory, and should not crash if the
|
||||
build is configured with `INSTALL_LOCATION` pointing to an empty external directory (i.e. if you run `make distclean` twice in succession). When
|
||||
`INSTALL_LOCATION` is set in the files `configure/CONFIG_SITE` or
|
||||
`configure/CONFIG_SITE.local` the `modules/RELEASE.<host>.local` file
|
||||
will now be regenerated in case the install path has been modified.
|
||||
|
||||
Note that passing `INSTALL_LOCATION=<path>` on the make command-line will
|
||||
only work if you have run `make distclean` immediately beforehand, as the
|
||||
`modules/RELEASE.<host>.local` file must be recreated using the new path.
|
||||
|
||||
### Enhancements to `capr.pl`
|
||||
|
||||
The `capr.pl` script can now display records from older Base versions to
|
||||
which fields have since been added, and shows long strings and array data
|
||||
up to 10 elements, use the new `-n` option to increase that number.
|
||||
The script is fully event-driven and prints all the field data received by
|
||||
the end of the CA wait time (`-w` option which defaults to 2 seconds).
|
||||
The interest level can now be specified using the `-l` option before the
|
||||
PV name, and the new `-D` flag outputs debugging information.
|
||||
|
||||
### Time Synchronization on VxWorks
|
||||
|
||||
VxWorks 6.9 can do its own OS clock time synchronization, if it has been
|
||||
configured by setting `SNTPC_PRIMARY_IPV4_ADDR`. Since EPICS 3.15.3 the
|
||||
IOC time support code has checked for the existence of the VxWorks time
|
||||
synchronization task and avoided starting the EPICS one if the OS task
|
||||
exists and the OS clock gives a "recent" time (i.e. after when EPICS was
|
||||
compiled), unless the environment variable `EPICS_TS_FORCE_NTPTIME` is
|
||||
also set. However a logic error in that code required the environment
|
||||
variable to be set in more cases than it should have.
|
||||
|
||||
This error has been fixed and the IOC should work normally if the VxWorks
|
||||
task is configured and running. The `TIMEZONE` value for the year is also
|
||||
now calculated at initialization in this configuration, previously it was
|
||||
only done when the IOC synchronzation task was used. Setting the above
|
||||
environment variable will now cause the IOC support code to shut down the
|
||||
VxWorks synchronization thread (if running) before starting the EPICS one.
|
||||
|
||||
Running the iocsh command `ClockTime_Report` now shows whether the VxWorks
|
||||
task is running as well as giving the state of the IOC synchronization task.
|
||||
The `ClockTime_Init` command can also be used to stop or restart the IOC
|
||||
time synchronization task while the IOC is running, depending on the `0` or
|
||||
`1` parameter passed to it. This last change also applies to RTEMS IOCs.
|
||||
|
||||
### Incompatible change to `struct db_field_log`
|
||||
|
||||
This change may cause channel filters which manipulate array updates
|
||||
to fail to compile.
|
||||
|
||||
To avoid potential speculation issues arising from overlapping code pointers
|
||||
with data values, `union dbfl_ref` is modified to remove the `dtor` member.
|
||||
`dtor` is moved out into the enclosing `struct db_field_log`.
|
||||
|
||||
So eg. using a `db_field_log* p`, the expression `p->u.r.dtor` must be
|
||||
changed to `(p)->dtor`.
|
||||
|
||||
### Fix undef ts on first camonitor update of NORD from waveformRecord
|
||||
|
||||
The order over operations when processing a waveformRecord is adjusted
|
||||
so that updates to NORD is posted with the correct timestamp.
|
||||
|
||||
### Automatic COMMANDLINE_LIBRARY w/ newer compilers
|
||||
|
||||
When built with a compiler supporting `__has_include<>`, the presence
|
||||
of the `<readline/readline.h>` will be used to automatically determine
|
||||
a default value for `COMMANDLINE_LIBRARY`.
|
||||
|
||||
Mingw builds with readline support now link `-ltermcap` instead of `-lcurses`.
|
||||
|
||||
This should not effect sites which set explicitly set `COMMANDLINE_LIBRARY`
|
||||
as the only definition in Base now has the form `COMMANDLINE_LIBRARY ?= ...`.
|
||||
|
||||
### Perl CA support for empty long strings
|
||||
|
||||
The Perl CA bindings have been fixed to handle zero-length long string data
|
||||
properly.
|
||||
|
||||
### `aao` gains `OMSL` and `DOL`
|
||||
|
||||
The `aao` record types gains the same `DOL` functionality found
|
||||
in other output record types (`ao`, `longout`, etc.)
|
||||
|
||||
### Server exports `RSRV_SERVER_PORT`
|
||||
|
||||
During `iocInit()`, the environment variable `RSRV_SERVER_PORT` is set
|
||||
with the TCP port number selected.
|
||||
|
||||
### `dbdExpand.pl` sorts all items by name
|
||||
|
||||
DBD files generated by the `dbdExpand.pl` script are now sorted within each
|
||||
item type by the primary name of the item. The result should resolve any
|
||||
issues with reproducable builds. No option is provided to prevent the sorting,
|
||||
previously the order was essentially random and varied each time.
|
||||
|
||||
### `dbExpand.pl` sorts records by name
|
||||
|
||||
Records are now output by this program in order, sorted by name. The new flag
|
||||
`-s` can be given to output the records in the same order they were read in,
|
||||
instead of sorting them.
|
||||
|
||||
Note that there are currently no build rules provided with Base which make use
|
||||
of this program.
|
||||
|
||||
### Simulation Mode RAW Support for Output Record Types
|
||||
|
||||
SIMM=RAW support has been added for the relevant output record types
|
||||
(ao, bo, mbbo, mbboDirect).
|
||||
RAW simulation mode will have those records do the appropriate conversion
|
||||
and write RVAL to the location pointed to by SIOL.
|
||||
|
||||
### Fixed leak from a non-EPICS thread
|
||||
|
||||
On some targets, if a thread not created by `epicsThreadCreate*()` directly
|
||||
or indirectly calls an `epicsThread*()` function, a specific tracking struct
|
||||
is allocated.
|
||||
|
||||
Prior to this release, on POSIX and WIN32 targets, this
|
||||
struct would not be `free()`d, resulting in a memory leak.
|
||||
|
||||
This release fixed the leak on POSIX targets.
|
||||
|
||||
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
|
||||
for WIN32 status.
|
||||
|
||||
### Fix `CHECK_RELEASE = WARN`
|
||||
|
||||
This now works again, it was broken in 2019 (7.0.3.1) by an errant commit.
|
||||
|
||||
### Document `DISP` as design-time field
|
||||
|
||||
The DISP field can be set to a non-zero value to prevent records being changed
|
||||
from outside the IOC (this is ancient behavior), but has never been documented
|
||||
as being usable at design-time (DCT=Yes in the Record Reference tables). This
|
||||
has now been changed.
|
||||
|
||||
### Make `epicsInt8` signed on all architectures
|
||||
|
||||
The `epicsInt8` and thus `DBF_CHAR` types have always been unsigned on
|
||||
architectures where `char` is unsigned, for example on many PowerPC CPU
|
||||
architectures. This was counter-intuitive, and resulted in IOC behavior
|
||||
differing between architectures when converting `DBF_CHAR` values into a
|
||||
signed integer or floating point type.
|
||||
|
||||
**WARNING**: This fix may change behavior of existing databases on target
|
||||
architectures with unsigned `char` (mainly PowerPC) when using input links to
|
||||
read from `CHAR` arrays. Architectures with signed `char` (usually x86) should
|
||||
be unaffected, although some compilers might generate new warnings.
|
||||
|
||||
### Allow hexadecimal and octal numbers in hardware links
|
||||
|
||||
[GH:213](https://github.com/epics-base/epics-base/pull/213)
|
||||
|
||||
Several types of hardware links (`VME_IO`, `CAMAC_IO`, etc) now accept
|
||||
hexadecimal and octal numbers. (Hexadecimal numbers had already been valid
|
||||
up to EPICS R3.15.) This change may introduce incompatibilities when using
|
||||
numbers with leading `0` as they will now be parsed as octal.
|
||||
|
||||
### Fix embedded implementations of `epicsEvent`
|
||||
|
||||
[GH:202](https://github.com/epics-base/epics-base/issues/202) and
|
||||
[GH:206](https://github.com/epics-base/epics-base/pull/206)
|
||||
|
||||
Heinz Junkes provided a new implementation of the `epicsEvent` API suitable for
|
||||
RTEMS Posix targets (RTEMS 5.1 and later). In review a few issues related to
|
||||
overflow of timeout values surfaced in this and other embedded implementations,
|
||||
and these were also been fixed in this Pull Request. The API documentation for
|
||||
this and some other routines has also been updated.
|
||||
|
||||
### Breakpoint Table Names
|
||||
|
||||
The names of breakpoint tables were made unnecessarily strict when DBD file
|
||||
processing was moved to Perl for the 3.15 release series. Table names may now
|
||||
contain the special characters `_` `-` `:` `;` `.` `[` `]` `<` `>` in addition
|
||||
to letters and digits.
|
||||
|
||||
### Fix for `undefined` in configure/RELEASE files
|
||||
|
||||
Prevents `Use of uninitialized value` warnings from convertRelease.pl.
|
||||
|
||||
### Colorized Messages for errlog
|
||||
|
||||
Many internal error messages now emit ANSI escape sequences to highlight the
|
||||
words "ERROR" and "WARNING" in an attempt to make occurrences more noticeable
|
||||
during IOC startup.
|
||||
|
||||
The macros `ERL_ERROR` and `ERL_WARNING` are defined for external usage,
|
||||
and expand as string constants. eg.
|
||||
|
||||
```c
|
||||
#include <errlog.h>
|
||||
#ifndef ERL_ERROR
|
||||
# define ERL_ERROR "ERROR"
|
||||
#endif
|
||||
void fn() {
|
||||
...
|
||||
errlogPrintf(ERL_ERROR ": something bad happens :(\n");
|
||||
```
|
||||
|
||||
ANSI escapes are automatically removed from errlog output not destined
|
||||
for a terminal. For example, for logClient, if stderr is redirected,
|
||||
or if unsupported (`$TERM` not set, or Windows < 10).
|
||||
|
||||
### `dbnd` filter pass through `DBE_ALARM|DBE_PROPERTY`
|
||||
|
||||
The `dbnd` server side filter now passes through alarm and property
|
||||
change events, even when not exceeding the deadband.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.6.1
|
||||
|
||||
### `mbboDirectRecord` enhancements
|
||||
|
||||
The bit fields `B0` - `B1F` of this record are now always updated and have a
|
||||
monitor posted when the `VAL` field is set and the record processed. It is now
|
||||
possible to initialize the record's value by setting the bit fields inside a
|
||||
database file as long as no other method was used to initialize it (suc as
|
||||
setting `VAL` directly, using `DOL`, or by an initial readback from device
|
||||
support). A new internal field `OBIT` was added to store information about
|
||||
monitors posted on the bit fields.
|
||||
|
||||
### Minimum Perl Version is now 5.10.1
|
||||
|
||||
Some scripts now make use of features that were introduced to this Perl version
|
||||
that was released in 2009.
|
||||
|
||||
### DB Links to `DBF_MENU` fields fixed
|
||||
|
||||
[GH:183](https://github.com/epics-base/epics-base/issues/183)
|
||||
These were broken in a previous release, but now work again.
|
||||
|
||||
### Long String access to CALC fields fixed
|
||||
|
||||
[GH:194](https://github.com/epics-base/epics-base/issues/194)
|
||||
This was broken in a previous release, but now works again.
|
||||
|
||||
### Minor Changes
|
||||
|
||||
+ Many code comments have been spell-checked and corrected.
|
||||
+ Passing a `-DDEBUG` compiler flag no longer breaks the build.
|
||||
+ Parallel builds of RTEMS-mvme2100 and RTEMS-mvme2700 targets now work.
|
||||
+ Illegal characters seen in JSON strings in a database file should now get a
|
||||
better error message.
|
||||
|
||||
### Other Launchpad Bugs and GitHub Issues Fixed
|
||||
|
||||
+ [lp:1938459](https://bugs.launchpad.net/epics-base/+bug/1938459)
|
||||
[GH:191](https://github.com/epics-base/epics-base/pull/191) int64in only
|
||||
checks lower 32 bits for change
|
||||
+ [lp:1941875](https://bugs.launchpad.net/epics-base/+bug/1941875) Buggy
|
||||
warning message "Record/Alias name '...' should not contain non-printable ...
|
||||
+ [GH:187](https://github.com/epics-base/epics-base/issues/187) waveformRecord
|
||||
missing PACT=true?
|
||||
+ [GH:189](https://github.com/epics-base/epics-base/pull/189) Fix a couple
|
||||
memory leaks and a segfault
|
||||
+ [GH:200](https://github.com/epics-base/epics-base/pull/200) and
|
||||
[GH:201](https://github.com/epics-base/epics-base/pull/201) Fix timers on MS
|
||||
Windows for non-EPICS threads
|
||||
|
||||
### Compiler interface for epicsAtomic tidied up
|
||||
|
||||
[GH:192](https://github.com/epics-base/epics-base/pull/192)
|
||||
Both GCC and CLANG compiler intrisics used for the epicsAtomic APIs have been revised; implementations using CLANG should now run faster as they now use the compiler's built-in atomic functions instead of taking a mutex.
|
||||
|
||||
### The epicsTime code has been reimplemented
|
||||
|
||||
[GH:185](https://github.com/epics-base/epics-base/pull/185)
|
||||
This was done to simplify the code and may have improved performance slightly for some uses. Support for the old NTP-specific `struct l_fp` has been dropped but all other routines and methods of the `class epicsTime` function as before.
|
||||
|
||||
### Updates to Record Reference documentation
|
||||
|
||||
Many of the built-in record types have had improvements to their documentation with additional fields added to the tables, rewrites of descriptions and links to other documents added or fixed.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.6
|
||||
|
||||
@@ -358,10 +694,10 @@ broken.
|
||||
|
||||
This fixes [lauchpad bug #1896295](https://bugs.launchpad.net/bugs/1896295).
|
||||
|
||||
### Support for Apple M1 (arm64) Processors
|
||||
### Support for Apple M1/M2 (arm64) Processors
|
||||
|
||||
Thanks to Jeong Han Lee this release comes with build support for Apple's new
|
||||
M1 CPUs running macOS, using the target name `darwin-aarch64`.
|
||||
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
|
||||
|
||||
It should also be possible to build universal binaries containing code for
|
||||
both the Intel and arm64 processors under either target name: In the
|
||||
@@ -1377,7 +1713,7 @@ editing and history. This functionality has now been restored, see Launchpad
|
||||
### 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
|
||||
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
|
||||
@@ -1975,6 +2311,24 @@ header and removed the need for dbScan.c to reach into the internals of its
|
||||
|
||||
## Changes from the 3.15 branch since 3.15.9
|
||||
|
||||
### Support for Apple M1/M2 (arm64) Processors
|
||||
|
||||
Thanks to Jeong Han Lee this release comes with build support for Apple's new
|
||||
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
|
||||
|
||||
### Set thread names on Windows
|
||||
|
||||
On MS Windows, epicsThread names are made available to the OS and debugger
|
||||
using `SetThreadDescription()` if available as well as using the older
|
||||
exception mechanism.
|
||||
|
||||
### Fix timers on MS Windows for non-EPICS threads
|
||||
|
||||
The waitable timer changes in 3.15.9 broke calls to `epicsThreadSleep()` and
|
||||
similar routines that used timers (including `ca_pend_event()`) when made from
|
||||
threads that were not started using the epicsThread APIs.
|
||||
[This problem](https://github.com/epics-base/epics-base/pull/200)
|
||||
[has now been fixed](https://github.com/epics-base/epics-base/pull/201).
|
||||
|
||||
## Changes made between 3.15.8 and 3.15.9
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# Record Reference Documentation {#recordrefmanual}
|
||||
|
||||
The documentation below for the record types and menus included with Base was
|
||||
converted from the old EPICS Wiki pages and updated. This list only includes the
|
||||
record types supplied with Base. The first two links below are to an external
|
||||
website where these original reference chapters are now being published.
|
||||
|
||||
* [Introduction to EPICS](https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html)
|
||||
* [Process Database Concepts](https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html)
|
||||
* [Fields Common to All Record Types](dbCommonRecord.html)
|
||||
* [Fields Common to Input Record Types](dbCommonInput.html)
|
||||
* [Fields Common to Output Record Types](dbCommonOutput.html)
|
||||
|
||||
## Record Types
|
||||
|
||||
* [Analog Array Input Record (aai)](aaiRecord.html)
|
||||
* [Analog Array Output Record (aao)](aaoRecord.html)
|
||||
* [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)
|
||||
* [Histogram Record (histogram)](histogramRecord.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)
|
||||
* [Long String Input Record (lsi)](lsiRecord.html)
|
||||
* [Long String Output Record (lso)](lsoRecord.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)
|
||||
* [Printf Record (printf)](printfRecord.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)
|
||||
* [Process at iocInit Menu](menuPini.html)
|
||||
* [Post Monitors Menu](menuPost.html)
|
||||
* [Priority Menu](menuPriority.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 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 source format is a combination of the EPICS DBD file format
|
||||
with an extended version of Perl's POD (plain old documentation); run `perldoc
|
||||
pod` for details of POD.
|
||||
@@ -37,26 +37,11 @@ that should be performed when creating production releases of EPICS Base.</p>
|
||||
|
||||
<h3>The Release Process</h3>
|
||||
|
||||
<h4>Full Process</h4>
|
||||
|
||||
<p>The version released on the Feature Freeze date is designated the first
|
||||
pre-release, <tt>-pre1</tt>. The first release candidate <tt>-rc1</tt> is the
|
||||
first version that has undergone testing by the developers and has shown no
|
||||
problems that must be fixed before release. New versions should be made at about
|
||||
2-weekly intervals after the <tt>-pre1</tt> release, and designated as either
|
||||
pre-release or release candidate versions by the Release Manager. Release
|
||||
candidates are announced to the whole community via the tech-talk mailing list,
|
||||
pre-releases are announced to to the developers via the core-talk list. After a
|
||||
release candidate has been available for 2 weeks without any new problems being
|
||||
reported or major changes having to be committed, the final release can be
|
||||
made.</p>
|
||||
|
||||
<h4>Short Process for Patch Releases</h4>
|
||||
|
||||
<p>The Patch Release date and its scope are agreed upon a few weeks ahead of the
|
||||
release. If no blocking issues are raised, the release is made by the Release
|
||||
Manager on or as soon as possible after that date, following the steps below
|
||||
starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<p>We used to have one written down here, but we weren't following it very
|
||||
closely so now the decision to make a new release is taken during the Core
|
||||
Developers bi-weekly meetings in an informal manner. The steps detailed below
|
||||
were written to remind Andrew (or anyone else who does the release) about
|
||||
everything that has to be done since it's so easy to miss steps.</p>
|
||||
|
||||
<h3>Roles</h3>
|
||||
|
||||
@@ -65,12 +50,12 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<dl>
|
||||
<dt><strong>Release Manager</strong> ()</dt>
|
||||
<dd>Responsible for managing and tagging the release</dd>
|
||||
<dt><strong>Platform Developers</strong> (optional)</dt>
|
||||
<dt><strong>Platform Developers</strong> (informal)</dt>
|
||||
<dd>Responsible for individual operating system platforms</dd>
|
||||
<dt><strong>Application Developers</strong></dt>
|
||||
<dd>Responsible for support modules that depend on EPICS Base.</dd>
|
||||
<dt><strong>Website Manager</strong> (Andrew Johnson)</dt>
|
||||
<dd>Responsible for the EPICS website</dd>
|
||||
<dt><strong>APS Website Editor</strong> (Andrew Johnson)</dt>
|
||||
<dd>Responsible for the APS EPICS website</dd>
|
||||
</dl>
|
||||
|
||||
<form>
|
||||
@@ -111,9 +96,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
& all developers</td>
|
||||
<td>Ensure that documentation will be updated before the release date:
|
||||
<ul>
|
||||
<li>Application Developers Guide</li>
|
||||
<li>Release Notes</li>
|
||||
<li>Known Problems</li>
|
||||
<li>Other documents</li>
|
||||
</ul>
|
||||
</td>
|
||||
@@ -125,87 +108,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Website Manager</td>
|
||||
<td>Release Manager</td>
|
||||
<td>Create a release milestone on Launchpad. If a target release date is
|
||||
known set "Date Targeted" to the expected release date. Note that
|
||||
pre-release and release-candidate versions should not get Launchpad
|
||||
milestones, only the final release.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Creating pre-release and release-candidate versions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<!-- Submodules... -->
|
||||
<td>Edit and commit changes to the EPICS version number file
|
||||
configure/CONFIG_BASE_VERSION.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Tag the module in Git, using these tag conventions:
|
||||
<ul>
|
||||
<li>
|
||||
<tt>R7.0.5-pre<i>n</i></tt>
|
||||
— pre-release tag
|
||||
</li>
|
||||
<li>
|
||||
<tt>R7.0.5-rc<i>n</i></tt>
|
||||
— release candidate tag
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for 7.0.5-rc1' R7.0.5-rc1
|
||||
</tt></blockquote>
|
||||
Note that submodules must <em>not</em> be tagged with the version used
|
||||
for the top-level, they each have their own separate version numbers
|
||||
that are only tagged at the final release.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Export the tagged version into a tarfile. The <tt>make-tar.sh</tt>
|
||||
script generates a gzipped tarfile directly from the tag, excluding the
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.5-rc1 base-7.0.5-rc1.tar.gz base-7.0.5-rc1/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-7.0.5-rc1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Test the tarfile by extracting its contents and building it on at
|
||||
least one supported platform.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Copy the tarfile and its signature to the Base download area of the
|
||||
website and add the new files to the website Base download index
|
||||
page.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Create or update a website subdirectory to hold the release
|
||||
documentation, and copy in selected files from the base/documentation
|
||||
and base/html directories of the tarfile.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Create or modify the webpage for the new release with links to the
|
||||
release documents and tar file. Pre-release and release-candidate
|
||||
versions should use the page and URL for the final release version
|
||||
number.</td>
|
||||
known set "Date Targeted" to the expected release date.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Testing</th>
|
||||
@@ -250,11 +155,8 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Release Manager</td>
|
||||
<td>Check that documentation has been updated:
|
||||
<ul>
|
||||
<li><a href="https://launchpad.net/epics-appdev">Application
|
||||
Developers Guide</a></li>
|
||||
<li>Release Notes</li>
|
||||
<li>Known Problems (hopefully empty)</li>
|
||||
<li>Other documents (converting...)</li>
|
||||
<li>Other documents</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -266,9 +168,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Obtain a positive <q>Ok to release</q> from all platform developers
|
||||
once a release candidate version has gone for 2 weeks without any major
|
||||
new issues being reported.</td>
|
||||
<td>Obtain a positive <q>Ok to release</q> from developers.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Creating the final release version</th>
|
||||
@@ -277,9 +177,12 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>
|
||||
<p>For each external submodule in turn (assuming it has not been tagged
|
||||
yet):</p>
|
||||
<p><b>For each external submodule</b> in turn (assuming it has not been
|
||||
tagged yet):</p>
|
||||
<ol>
|
||||
<li><tt>git grep UNRELEASED</tt> and insert the module version to any
|
||||
doxygen annotations that have a <tt>@since UNRELEASED</tt> comment.
|
||||
Commit (don't push yet).</li>
|
||||
<li>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
|
||||
@@ -288,7 +191,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
cd base-7.0/modules/<module>/documentation<br />
|
||||
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
|
||||
</tt></blockquote>
|
||||
Commit changes (don't push yet).</li>
|
||||
Commit changes (don't push).</li>
|
||||
|
||||
<li>Edit the module's release version file
|
||||
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and its top-level
|
||||
@@ -298,7 +201,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
|
||||
<li>Tag the module:
|
||||
<blockquote><tt>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.5' <module-version>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.7' <module-version>
|
||||
</tt></blockquote>
|
||||
</li>
|
||||
|
||||
@@ -326,15 +229,24 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
<p>Commit all the submodule updates to the 7.0 branch.</p>
|
||||
<p><b>After all submodules complete</b> commit the submodule updates
|
||||
which were added for each submodule in step 4 above to the 7.0 branch
|
||||
(don't push). After committing, make sure that the output from
|
||||
<tt>git submodule status --cached</tt> only shows the appropriate
|
||||
version tags in the right-most parenthesized column with no
|
||||
<tt>-<i>n</t>-g<i>xxxxxxx</i></tt> suffix.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
|
||||
<td>Edit the main EPICS Base version file and the built-in module version
|
||||
files:
|
||||
<td>
|
||||
<p><tt>git grep UNRELEASED</tt> and insert the release version to any
|
||||
doxygen annotations that have a <tt>@since UNRELEASED</tt> comment.
|
||||
Commit (don't push).</p>
|
||||
<p>Edit the main EPICS Base version file and the built-in module version
|
||||
files:</p>
|
||||
<ul>
|
||||
<li><tt>configure/CONFIG_BASE_VERSION</tt></li>
|
||||
<li><tt>configure/CONFIG_LIBCOM_VERSION</tt></li>
|
||||
@@ -346,6 +258,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<tt>PATCH_LEVEL</tt> value should have been incremented after the
|
||||
previous release tag was applied. Set all <tt>DEVELOPMENT_FLAG</tt>
|
||||
values to 0 and <tt>EPICS_DEV_SNAPSHOT</tt> to the empty string.</p>
|
||||
<p>Edit the headings in the Release Notes to show the appropriate
|
||||
version number and remove the warning about this being an unreleased
|
||||
version of EPICS.</p>
|
||||
<p>Commit these changes (don't push).</p>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -355,9 +270,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Tag the epics-base module in Git:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.5
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.7
|
||||
</tt></blockquote>
|
||||
<p>Don't push these commits or the new tag to the Launchpad repository
|
||||
<p>Don't push anything to the Launchpad repository
|
||||
yet.</p>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -376,6 +291,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
release by incrementing the MAINTENANCE_VERSION or PATCH_LEVEL value
|
||||
in each file. Set all <tt>DEVELOPMENT_FLAG</tt> values to 1 and
|
||||
<tt>EPICS_DEV_SNAPSHOT</tt> to "-DEV".</p>
|
||||
<p>Set up the headings in the Release Notes for the next release
|
||||
version number and restore the warning about this being an unreleased
|
||||
version of EPICS.</p>
|
||||
<p>Commit these changes (don't push).</p>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -387,12 +305,12 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.5 ../base-7.0.5.tar.gz base-7.0.5/
|
||||
./.tools/make-tar.sh R7.0.7 ../base-7.0.7.tar.gz base-7.0.7/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
cd ..<br />
|
||||
gpg --armor --sign --detach-sig base-7.0.5.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.7.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -412,38 +330,38 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Copy the tarfile and its signature to the Base download area of the
|
||||
website.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Update the website subdirectory that holds the release
|
||||
documentation, and copy in the files from the base/documentation
|
||||
directory of the tarfile.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Update the webpage for the new release with links to the release
|
||||
documents and tar file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Add the new release tar file to the website Base download index
|
||||
page.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Link to the release webpage from other relevent areas of the
|
||||
website - update front page and sidebars.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Add an entry to the website News page, linking to the new version
|
||||
webpage.</td>
|
||||
</tr>
|
||||
@@ -453,17 +371,17 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
|
||||
epics-controls web-server.
|
||||
<blockquote><tt>
|
||||
scp base-7.0.5.tar.gz base-7.0.5.tar.gz.asc epics-controls:download/base<br />
|
||||
scp base-7.0.7.tar.gz base-7.0.7.tar.gz.asc epics-controls:download/base<br />
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Follow instructions on
|
||||
<a href="https://epics-controls.org/resources-and-support/documents/epics-website-documentation/adding-a-page-for-a-new-release/">
|
||||
Add a page for a new release</a> to create a new release webpage (not
|
||||
@@ -478,7 +396,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Release Manager</td>
|
||||
<td>Go to the Launchpad milestone for this release. Click the Create
|
||||
release button and add the release date. Put a URL for the release page
|
||||
in the Release notes box, and click the Create release button. Upload
|
||||
|
||||
@@ -5,11 +5,11 @@ Documentation index
|
||||
|
||||
@li @ref releasenotes
|
||||
@li @ref install
|
||||
@li @ref recordrefmanual
|
||||
@li <a href="ComponentReference.html">EPICS Component Reference Manual</a>
|
||||
@li <a href="filters.html">Field Modifiers and Channel Filters</a>
|
||||
@li <a href="links.html">Extensible IOC Database Links</a>
|
||||
@li <a href="CAref.html">Channel Access Reference Manual</a>
|
||||
@li <a href="filters.html">Server Side Filters Reference</a>
|
||||
@li <a href="msi.html">msi: Macro Substitution and Include Tool</a>
|
||||
@li <a href="links.html">JSON Link Types</a>
|
||||
@li <a href="CA.html">Perl 5 Interface to Channel Access</a>
|
||||
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
# modules/CONFIG_SITE.local
|
||||
#
|
||||
# Despite the .local in its name, this file *is* included in EPICS Base
|
||||
# sources and should *not* be modified by sites. This trick is necessary
|
||||
# to allow external submodules to be placed inside the modules directory
|
||||
# without having to modify them, as long as their configure/CONFIG_SITE
|
||||
# file includes the standard line
|
||||
# -include $(TOP)/../CONFIG_SITE.local
|
||||
# that causes this file to be read in during submodule builds.
|
||||
|
||||
# The name our submodules know us by:
|
||||
PARENT_MODULE = EPICS_BASE
|
||||
|
||||
@@ -88,7 +88,7 @@ const char * ca_message_text []
|
||||
"Bad event subscription (monitor) identifier",
|
||||
"Remote channel has new network address",
|
||||
"New or resumed network connection",
|
||||
"Specified task isnt a member of a CA context",
|
||||
"Specified task isn't a member of a CA context",
|
||||
"Attempt to use defunct CA feature failed",
|
||||
|
||||
"The supplied string is empty",
|
||||
@@ -324,7 +324,7 @@ int epicsStdCall ca_create_channel (
|
||||
*chanptr = pChanNotify;
|
||||
pChanNotify->initiateConnect ( guard );
|
||||
// no need to worry about a connect preempting here because
|
||||
// the connect sequence will not start untill initiateConnect()
|
||||
// the connect sequence will not start until initiateConnect()
|
||||
// is called
|
||||
}
|
||||
catch ( cacChannel::badString & ) {
|
||||
@@ -384,9 +384,9 @@ int epicsStdCall ca_clear_channel ( chid pChan )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( cac.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
@@ -720,7 +720,7 @@ int epicsStdCall ca_context_status ( ca_client_context * pcac, unsigned level )
|
||||
/*
|
||||
* ca_current_context ()
|
||||
*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* used when an auxiliary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
// extern "C"
|
||||
@@ -740,7 +740,7 @@ struct ca_client_context * epicsStdCall ca_current_context ()
|
||||
/*
|
||||
* ca_attach_context ()
|
||||
*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* used when an auxiliary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
// extern "C"
|
||||
|
||||
@@ -494,7 +494,7 @@ void verifyConnectionHandlerConnect ( appChan *pChans, unsigned chanCount,
|
||||
/*
|
||||
* verifyBlockingConnect ()
|
||||
*
|
||||
* 1) verify that we dont print a disconnect message when
|
||||
* 1) verify that we don't print a disconnect message when
|
||||
* we delete the last channel
|
||||
*
|
||||
* 2) verify that we delete the connection to the IOC
|
||||
@@ -645,7 +645,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
status = ca_pend_io ( 1e-16 );
|
||||
if ( status == ECA_TIMEOUT ) {
|
||||
/*
|
||||
* we end up here if the channel isnt on the same host
|
||||
* we end up here if the channel isn't on the same host
|
||||
*/
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll ();
|
||||
@@ -1112,7 +1112,7 @@ void verifyHighThroughputRead ( chid chan, unsigned interestLevel )
|
||||
unsigned i;
|
||||
|
||||
/*
|
||||
* verify we dont jam up on many uninterrupted
|
||||
* verify we don't jam up on many uninterrupted
|
||||
* solicitations
|
||||
*/
|
||||
if ( ca_read_access (chan) ) {
|
||||
@@ -1152,7 +1152,7 @@ void verifyHighThroughputWrite ( chid chan, unsigned interestLevel )
|
||||
}
|
||||
|
||||
/*
|
||||
* verify we dont jam up on many uninterrupted
|
||||
* verify we don't jam up on many uninterrupted
|
||||
* get callback requests
|
||||
*/
|
||||
void verifyHighThroughputReadCallback ( chid chan, unsigned interestLevel )
|
||||
@@ -1181,7 +1181,7 @@ void verifyHighThroughputReadCallback ( chid chan, unsigned interestLevel )
|
||||
}
|
||||
|
||||
/*
|
||||
* verify we dont jam up on many uninterrupted
|
||||
* verify we don't jam up on many uninterrupted
|
||||
* put callback request
|
||||
*/
|
||||
void verifyHighThroughputWriteCallback ( chid chan, unsigned interestLevel )
|
||||
@@ -1239,7 +1239,7 @@ void verifyBadString ( chid chan, unsigned interestLevel )
|
||||
verify ( status == ECA_NORMAL );
|
||||
if ( strcmp ( stimStr, respStr ) ) {
|
||||
printf (
|
||||
"Test fails if stim \"%s\" isnt roughly equiv to resp \"%s\"\n",
|
||||
"Test fails if stim \"%s\" isn't roughly equiv to resp \"%s\"\n",
|
||||
stimStr, respStr);
|
||||
}
|
||||
showProgressEnd ( interestLevel );
|
||||
@@ -1395,7 +1395,7 @@ static void multiSubscrDestroyNoLateCallbackThread ( void * pParm )
|
||||
|
||||
/*
|
||||
* raise the priority of the current thread hoping to improve our
|
||||
* likelyhood of detecting a bug
|
||||
* likelihood of detecting a bug
|
||||
*/
|
||||
priorityOfTestThread = epicsThreadGetPrioritySelf ();
|
||||
epicsThreadSetPriority ( epicsThreadGetIdSelf(), epicsThreadPriorityHigh );
|
||||
@@ -1445,7 +1445,7 @@ static void multiSubscrDestroyNoLateCallbackThread ( void * pParm )
|
||||
}
|
||||
|
||||
/*
|
||||
* verify that, in a preemtive callback mode client, a subscription callback never
|
||||
* verify that, in a preemptive callback mode client, a subscription callback never
|
||||
* comes after the subscription is destroyed
|
||||
*/
|
||||
static void multiSubscrDestroyNoLateCallbackTest ( const char *pName, unsigned interestLevel )
|
||||
@@ -1563,7 +1563,7 @@ void multiSubscriptionDeleteTest ( chid chan, unsigned interestLevel )
|
||||
/*
|
||||
* singleSubscriptionDeleteTest
|
||||
*
|
||||
* verify that we dont fail when we repeatedly create
|
||||
* verify that we don't fail when we repeatedly create
|
||||
* and delete only one subscription with a high level of
|
||||
* traffic on it
|
||||
*/
|
||||
@@ -1617,7 +1617,7 @@ void singleSubscriptionDeleteTest ( chid chan, unsigned interestLevel )
|
||||
/*
|
||||
* channelClearWithEventTrafficTest
|
||||
*
|
||||
* verify that we can delete a channel that has subcriptions
|
||||
* verify that we can delete a channel that has subscriptions
|
||||
* attached with heavy update traffic
|
||||
*/
|
||||
void channelClearWithEventTrafficTest ( const char *pName, unsigned interestLevel )
|
||||
@@ -2481,7 +2481,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
showProgress ( interestLevel );
|
||||
|
||||
/*
|
||||
* attempt to uncover problems where the last event isnt sent
|
||||
* attempt to uncover problems where the last event isn't sent
|
||||
* and hopefully get into a flow control situation
|
||||
*/
|
||||
prevPassCount = 0u;
|
||||
@@ -2522,7 +2522,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
for ( j = 0; j < NELEMENTS ( test ); j++ ) {
|
||||
/*
|
||||
* we shouldnt see old monitors because
|
||||
* we shouldn't see old monitors because
|
||||
* we resubscribed
|
||||
*/
|
||||
verify ( test[j].count <= i + 2 );
|
||||
@@ -3016,7 +3016,7 @@ void testMultithreadSubscr ( void * pParm )
|
||||
}
|
||||
|
||||
/*
|
||||
* test installation of subscriptions similar to usage paterns
|
||||
* test installation of subscriptions similar to usage patterns
|
||||
* employed by modern versions of the sequencer
|
||||
*/
|
||||
void verifyMultithreadSubscr ( const char * pName, unsigned interestLevel )
|
||||
@@ -3111,7 +3111,7 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
|
||||
status = ca_flush_io ();
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
/* look for infinite loop in fd manager schedualing */
|
||||
/* look for infinite loop in fd manager scheduling */
|
||||
epicsTimeGetCurrent ( & begin );
|
||||
eventCount = 0u;
|
||||
while ( 1 ) {
|
||||
@@ -3175,7 +3175,7 @@ void verifyConnectWithDisconnectedChannels (
|
||||
* we should be able to connect to a valid
|
||||
* channel within a reasonable delay even
|
||||
* though there is one permanently
|
||||
* diasconnected channel
|
||||
* disconnected channel
|
||||
*/
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
verify ( status == ECA_NORMAL );
|
||||
@@ -3491,7 +3491,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
|
||||
|
||||
/*
|
||||
* CA pend event delay accuracy test
|
||||
* (CA asssumes that search requests can be sent
|
||||
* (CA assumes that search requests can be sent
|
||||
* at least every 25 mS on all supported os)
|
||||
*/
|
||||
printf ( "\n" );
|
||||
|
||||
@@ -32,7 +32,13 @@ static const iocshArg *acctstArgs[] =
|
||||
&acctstArg3,
|
||||
&acctstArg4
|
||||
};
|
||||
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
|
||||
static const iocshFuncDef acctstFuncDef = {
|
||||
"acctst",
|
||||
5,
|
||||
acctstArgs,
|
||||
"Execute a Channel Access regression test.\n\n"
|
||||
"For more information, see the 'acctst' documentation in the Channel Access reference.\n",
|
||||
};
|
||||
|
||||
|
||||
/* Wrapper called by iocsh, selects the argument types that print needs */
|
||||
|
||||
@@ -130,8 +130,8 @@ bool bhe::updatePeriod (
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
|
||||
//
|
||||
// this block is enetered if the beacon was created as a side effect of
|
||||
// creating a connection and so we dont yet know the first beacon time
|
||||
// this block is entered if the beacon was created as a side effect of
|
||||
// creating a connection and so we don't yet know the first beacon time
|
||||
// and sequence number
|
||||
//
|
||||
if ( this->timeStamp == epicsTime () ) {
|
||||
@@ -154,7 +154,7 @@ bool bhe::updatePeriod (
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1) detect beacon duplications due to redundant routes
|
||||
// 1) detect beacon duplication due to redundant routes
|
||||
// 2) detect lost beacons due to input queue overrun or damage
|
||||
if ( CA_V410 ( protocolRevision ) ) {
|
||||
unsigned beaconSeqAdvance;
|
||||
@@ -175,7 +175,7 @@ bool bhe::updatePeriod (
|
||||
|
||||
// throw out sequence numbers that jump forward by only a few numbers
|
||||
// (this situation is probably caused by a duplicate route
|
||||
// or a beacon due to input queue overun)
|
||||
// or a beacon due to input queue overrun)
|
||||
if ( beaconSeqAdvance > 1 && beaconSeqAdvance < 4 ) {
|
||||
logBeaconDiscard ( beaconSeqAdvance, currentTime );
|
||||
return false;
|
||||
@@ -244,8 +244,8 @@ bool bhe::updatePeriod (
|
||||
/*
|
||||
* Is this an IOC seen because of an IOC reboot
|
||||
* (beacon come at a higher rate just after the
|
||||
* IOC reboots). Lower tolarance here because we
|
||||
* dont have to worry about lost beacons.
|
||||
* IOC reboots). Lower tolerance here because we
|
||||
* don't have to worry about lost beacons.
|
||||
*
|
||||
* It may be possible to get false triggers here
|
||||
* if the client is busy, but this does not cause
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u+1u)
|
||||
|
||||
/*
|
||||
* 1500 (max of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
|
||||
* (the MTU of Ethernet is currently independent of its speed varient)
|
||||
* 1500 (max of Ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
|
||||
* (the MTU of Ethernet is currently independent of its speed variant)
|
||||
*/
|
||||
#define ETHERNET_MAX_UDP ( 1500u - 20u - 8u )
|
||||
#define MAX_UDP_RECV ( 0xffff + 16u ) /* allow large frames to be received in the future */
|
||||
@@ -117,7 +117,7 @@ typedef ca_uint32_t caResId;
|
||||
|
||||
/*
|
||||
* for use with search and not_found (if search fails and
|
||||
* its not a broadcast tell the client to look elesewhere)
|
||||
* its not a broadcast tell the client to look elsewhere)
|
||||
*/
|
||||
#define DOREPLY 10u
|
||||
#define DONTREPLY 5u
|
||||
@@ -176,7 +176,7 @@ typedef struct ca_hdr {
|
||||
struct mon_info {
|
||||
ca_float32_t m_lval; /* low delta */
|
||||
ca_float32_t m_hval; /* high delta */
|
||||
ca_float32_t m_toval; /* period btween samples */
|
||||
ca_float32_t m_toval; /* period between samples */
|
||||
ca_uint16_t m_mask; /* event select mask */
|
||||
ca_uint16_t m_pad; /* extend to 32 bits */
|
||||
};
|
||||
|
||||
@@ -224,7 +224,7 @@ void ca_client_context::changeExceptionEvent (
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->ca_exception_func = pfunc;
|
||||
this->ca_exception_arg = arg;
|
||||
// should block here until releated callback in progress completes
|
||||
// should block here until related callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::replaceErrLogHandler (
|
||||
@@ -237,7 +237,7 @@ void ca_client_context::replaceErrLogHandler (
|
||||
else {
|
||||
this->pVPrintfFunc = epicsVprintf;
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
// should block here until related callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::registerForFileDescriptorCallBack (
|
||||
@@ -252,7 +252,7 @@ void ca_client_context::registerForFileDescriptorCallBack (
|
||||
// w/o having sent the wakeup message
|
||||
this->_sendWakeupMsg ();
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
// should block here until related callback in progress completes
|
||||
}
|
||||
|
||||
int ca_client_context :: printFormated (
|
||||
@@ -392,9 +392,19 @@ void ca_client_context :: vSignal (
|
||||
}
|
||||
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
char date[64];
|
||||
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
|
||||
this->printFormated ( " Current Time: %s\n", date );
|
||||
try {
|
||||
char date[64];
|
||||
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
|
||||
this->printFormated ( " Current Time: %s\n", date );
|
||||
}
|
||||
catch ( std::exception & except ) {
|
||||
errlogPrintf (
|
||||
"CA client library thread \"%s\" caught C++ exception \"%s\"\n",
|
||||
epicsThreadGetNameSelf (), except.what () );
|
||||
epicsTimeStamp now = current;
|
||||
this->printFormated ( " Current Time: %u.%u\n",
|
||||
now.secPastEpoch, now.nsec );
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate execution if unsuccessful
|
||||
@@ -768,9 +778,9 @@ LIBCA_API int epicsStdCall ca_clear_subscription ( evid pMon )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( cac.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
|
||||
@@ -285,7 +285,7 @@ cac::~cac ()
|
||||
// this blocks until the UDP thread exits so that
|
||||
// it will not sneak in any new clients
|
||||
//
|
||||
// lock intentionally not held here so that we dont deadlock
|
||||
// lock intentionally not held here so that we don't deadlock
|
||||
// waiting for the UDP thread to exit while it is waiting to
|
||||
// get the lock.
|
||||
{
|
||||
@@ -312,7 +312,7 @@ cac::~cac ()
|
||||
//
|
||||
// wait for all tcp threads to exit
|
||||
//
|
||||
// this will block for oustanding sends to go out so dont
|
||||
// this will block for outstanding sends to go out so don't
|
||||
// hold a lock while waiting
|
||||
//
|
||||
{
|
||||
@@ -411,7 +411,7 @@ void cac::show (
|
||||
|
||||
::printf ( "Channel Access Client Context at %p for user %s\n",
|
||||
static_cast <const void *> ( this ), this->pUserName );
|
||||
// this also supresses the "defined, but not used"
|
||||
// this also suppresses the "defined, but not used"
|
||||
// warning message
|
||||
::printf ( "\trevision \"%s\"\n", pVersionCAC );
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ typedef unsigned CA_SYNC_GID;
|
||||
#define CA_OP_CONN_UP 6
|
||||
#define CA_OP_CONN_DOWN 7
|
||||
|
||||
/* depricated */
|
||||
/* deprecated */
|
||||
#define CA_OP_SEARCH 2
|
||||
|
||||
/*
|
||||
@@ -464,7 +464,7 @@ LIBCA_API int epicsStdCall ca_array_get_callback
|
||||
/* Specify a function to be executed whenever significant changes */
|
||||
/* occur to a channel. */
|
||||
/* NOTES: */
|
||||
/* 1) Evid may be omited by passing a NULL pointer */
|
||||
/* 1) Evid may be omitted by passing a NULL pointer */
|
||||
/* */
|
||||
/* 2) An array count of zero specifies the native db count */
|
||||
/* */
|
||||
@@ -559,19 +559,19 @@ LIBCA_API chid epicsStdCall ca_evid_to_chid ( evid id );
|
||||
/*
|
||||
* ca_pend_event()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds
|
||||
* timeout R wait for this delay in seconds
|
||||
*/
|
||||
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeOut);
|
||||
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeout);
|
||||
#define ca_poll() ca_pend_event(1e-12)
|
||||
|
||||
/*
|
||||
* ca_pend_io()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds but return early
|
||||
* timeout R wait for this delay in seconds but return early
|
||||
* if all get requests (or search requests with null
|
||||
* connection handler pointer have completed)
|
||||
*/
|
||||
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeOut);
|
||||
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeout);
|
||||
|
||||
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
|
||||
LIBCA_API int epicsStdCall ca_pend (ca_real timeout, int early);
|
||||
@@ -837,7 +837,7 @@ LIBCA_API double epicsStdCall ca_beacon_period (chid chan);
|
||||
LIBCA_API double epicsStdCall ca_receive_watchdog_delay (chid chan);
|
||||
|
||||
/*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* used when an auxiliary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
LIBCA_API struct ca_client_context * epicsStdCall ca_current_context ();
|
||||
|
||||
@@ -188,7 +188,7 @@ int main ( int argc, char ** argv )
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ("casw: error from recv was = \"%s\"\n",
|
||||
errlogPrintf ("casw: " ERL_ERROR " from recv was = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
@@ -224,7 +224,7 @@ int main ( int argc, char ** argv )
|
||||
* always set this field to INADDR_ANY
|
||||
*
|
||||
* clients always assume that if this
|
||||
* field is set to something that isnt INADDR_ANY
|
||||
* field is set to something that isn't INADDR_ANY
|
||||
* then it is the overriding IP address of the server.
|
||||
*/
|
||||
ina.sin_family = AF_INET;
|
||||
@@ -235,7 +235,7 @@ int main ( int argc, char ** argv )
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* old servers dont supply this and the
|
||||
* old servers don't supply this and the
|
||||
* default port must be assumed
|
||||
*/
|
||||
ina.sin_port = htons ( serverPort );
|
||||
|
||||
@@ -45,7 +45,7 @@ bool comBuf::flushToWire ( wireSendAdapter & wire, const epicsTime & currentTime
|
||||
return true;
|
||||
}
|
||||
|
||||
// throwing the exception from a function that isnt inline
|
||||
// throwing the exception from a function that isn't inline
|
||||
// shrinks the GNU compiled object code
|
||||
void comBuf::throwInsufficentBytesException ()
|
||||
{
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
bool push ( const T & value );
|
||||
template < class T >
|
||||
unsigned push ( const T * pValue, unsigned nElem );
|
||||
unsigned push ( const char * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsOldString * pValue, unsigned nElem );
|
||||
@@ -208,6 +209,11 @@ inline unsigned comBuf :: push ( const epicsUInt8 *pValue, unsigned nElem )
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const char *pValue, unsigned nElem )
|
||||
{
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsOldString * pValue, unsigned nElem )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
|
||||
@@ -46,7 +46,7 @@ void comQueRecv::clear ()
|
||||
this->nBytesPending = 0u;
|
||||
}
|
||||
|
||||
unsigned comQueRecv::copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes )
|
||||
unsigned comQueRecv::copyOutBytes ( char *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned totalBytes = 0u;
|
||||
do {
|
||||
@@ -196,7 +196,7 @@ epicsUInt16 comQueRecv::popUInt16 ()
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
// try first for all in one buffer efficient version
|
||||
epicsUInt16 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
@@ -215,7 +215,7 @@ epicsUInt32 comQueRecv::popUInt32 ()
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
// try first for all in one buffer efficient version
|
||||
epicsUInt32 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
@@ -230,7 +230,7 @@ epicsUInt32 comQueRecv::popUInt32 ()
|
||||
|
||||
bool comQueRecv::popOldMsgHeader ( caHdrLargeArray & msg )
|
||||
{
|
||||
// try first for all in one buffer efficent version
|
||||
// try first for all in one buffer efficient version
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
return false;
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
comQueRecv ( comBufMemoryManager & );
|
||||
~comQueRecv ();
|
||||
unsigned occupiedBytes () const;
|
||||
unsigned copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes );
|
||||
unsigned copyOutBytes ( char *pBuf, unsigned nBytes );
|
||||
unsigned removeBytes ( unsigned nBytes );
|
||||
void pushLastComBufReceived ( comBuf & );
|
||||
void clear ();
|
||||
|
||||
@@ -27,17 +27,17 @@
|
||||
// 1) Allow sufficent headroom so that users will be able to perform
|
||||
// a reasonable amount of IO within CA callbacks without experiencing
|
||||
// a push/pull deadlock. If a potential push/pull deadlock situation
|
||||
// occurs then detect and avoid it and provide diagnotic to the user
|
||||
// occurs then detect and avoid it and provide diagnostic to the user
|
||||
// via special status.
|
||||
// 2) Return status to the user when there is insufficent memory to
|
||||
// 2) Return status to the user when there is insufficient memory to
|
||||
// queue a complete message.
|
||||
// 3) return status to the user when a message cant be flushed because
|
||||
// a connection dropped.
|
||||
// 4) Do not allocate too much memory in exception situatons (such as
|
||||
// 4) Do not allocate too much memory in exception situations (such as
|
||||
// after a circuit disconnect).
|
||||
// 5) Avoid allocating more memory than is absolutely necessary to meet
|
||||
// the above requirements.
|
||||
// 6) Message fragments must never be sent to the IOC when there isnt
|
||||
// 6) Message fragments must never be sent to the IOC when there isn't
|
||||
// enough memory to queue part of a message (we also must not force
|
||||
// a disconnect because the client is starved for memory).
|
||||
// 7) avoid the need to check status for each byte pushed into the
|
||||
@@ -45,7 +45,7 @@
|
||||
//
|
||||
// Implementation:
|
||||
// 1) When queuing a complete message, first test to see if a flush is
|
||||
// required. If it is a receive thread scheduals the flush with the
|
||||
// required. If it is a receive thread schedules the flush with the
|
||||
// send thread, and otherwise directly execute the system call. The
|
||||
// send thread must run at a higher priority than the receive thread
|
||||
// if we are to minimize memory consumption.
|
||||
@@ -58,9 +58,9 @@
|
||||
// a) A user is queuing more requests that demand a response from a
|
||||
// callback than are removed by the response that initiated the
|
||||
// callback, and this situation persists for many callbacks until
|
||||
// all buffering in the system is exausted.
|
||||
// all buffering in the system is exhausted.
|
||||
// b) A user is queuing many requests that demand a response from one
|
||||
// callback until all buffering in the system is exausted.
|
||||
// callback until all buffering in the system is exhausted.
|
||||
// c) Some combination of both (a) nad (b).
|
||||
//
|
||||
//
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "caerr.h"
|
||||
|
||||
/*
|
||||
* NOOP if this isnt required
|
||||
* NOOP if this isn't required
|
||||
*/
|
||||
#ifdef EPICS_CONVERSION_REQUIRED
|
||||
|
||||
@@ -326,7 +326,7 @@ arrayElementCount num /* number of values */
|
||||
** int encode; boolean, if true vax to ieee
|
||||
** else ieee to vax
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1022,7 +1022,7 @@ arrayElementCount num /* number of values */
|
||||
** int encode; boolean, if true vax to ieee
|
||||
** else ieee to vax
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1056,7 +1056,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_sts_long(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1118,7 +1118,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_time_short(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1239,7 +1239,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_sts_char(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1274,7 +1274,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_time_long(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1325,7 +1325,7 @@ arrayElementCount num /* number of values */
|
||||
for(i=0; i<num; i++){
|
||||
*pDest = dbr_ntohs( *pSrc );
|
||||
/*
|
||||
* dont increment these inside the MACRO
|
||||
* don't increment these inside the MACRO
|
||||
*/
|
||||
pDest++;
|
||||
pSrc++;
|
||||
|
||||
@@ -123,7 +123,7 @@ typedef epicsOldString dbr_class_name_t;
|
||||
LIBCA_API extern const int epicsTypeToDBR_XXXX [lastEpicsType+1];
|
||||
|
||||
/*
|
||||
* The DBR_XXXX types are indicies into this array
|
||||
* The DBR_XXXX types are indices into this array
|
||||
*/
|
||||
LIBCA_API extern const epicsType DBR_XXXXToEpicsType [LAST_BUFFER_TYPE+1];
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ void hostNameCache::transactionComplete ( const char * pHostNameIn )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
// a few legacy clients have a direct pointer to this buffer so we
|
||||
// set the entrire string to nill terminators before we start copying
|
||||
// set the entire string to nill terminators before we start copying
|
||||
// in the name (this reduces the chance that another thread will see
|
||||
// garbage characters).
|
||||
size_t newNameLen = strlen ( pHostNameIn );
|
||||
|
||||
@@ -79,7 +79,7 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
|
||||
const char *pStr;
|
||||
const char *pToken;
|
||||
struct sockaddr_in addr;
|
||||
char buf[32u]; /* large enough to hold an IP address */
|
||||
char buf[256u]; /* large enough to hold an IP address or hostname */
|
||||
int status, ret = -1;
|
||||
|
||||
pStr = envGetConfigParamPtr (pEnv);
|
||||
@@ -189,7 +189,7 @@ extern "C" void epicsStdCall configureChannelAccessAddressList
|
||||
int yes;
|
||||
|
||||
/*
|
||||
* dont load the list twice
|
||||
* don't load the list twice
|
||||
*/
|
||||
assert ( ellCount (pList) == 0 );
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request
|
||||
* monitor flow control
|
||||
*
|
||||
* turning this down effects maximum throughput
|
||||
* because we dont get an optimal number of bytes
|
||||
* because we don't get an optimal number of bytes
|
||||
* per network frame
|
||||
*/
|
||||
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
|
||||
|
||||
@@ -57,7 +57,7 @@ void msgForMultiplyDefinedPV::transactionComplete ( const char * pHostNameRej )
|
||||
// calls into cac for the notification
|
||||
// the msg object (= this) is being deleted as part of the notification
|
||||
this->cb.pvMultiplyDefinedNotify ( *this, this->channel, this->acc, pHostNameRej );
|
||||
// !! dont touch 'this' pointer after this point because object has been deleted !!
|
||||
// !! don't touch 'this' pointer after this point because object has been deleted !!
|
||||
}
|
||||
|
||||
void * msgForMultiplyDefinedPV::operator new ( size_t size,
|
||||
|
||||
@@ -147,14 +147,14 @@ void nciu::connect ( unsigned nativeType,
|
||||
guard, this->accessRightState );
|
||||
}
|
||||
|
||||
// channel uninstal routine grabs the callback lock so
|
||||
// channel uninstall routine grabs the callback lock so
|
||||
// a channel will not be deleted while a call back is
|
||||
// in progress
|
||||
//
|
||||
// the callback lock is also taken when a channel
|
||||
// disconnects to prevent a race condition with the
|
||||
// code below - ie we hold the callback lock here
|
||||
// so a chanel cant be destroyed out from under us.
|
||||
// so a channel cant be destroyed out from under us.
|
||||
this->notify().connectNotify ( guard );
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
// destructor is virtual (therefore it is protected).
|
||||
// I assume that SUNPRO will fix this in future versions.
|
||||
// With other compilers we get warnings (and
|
||||
// potential problems) if we dont make the baseNMIU
|
||||
// potential problems) if we don't make the baseNMIU
|
||||
// destructor virtual.
|
||||
#if defined ( __SUNPRO_CC ) && ( __SUNPRO_CC <= 0x540 )
|
||||
# define NETIO_VIRTUAL_DESTRUCTOR
|
||||
|
||||
@@ -591,16 +591,16 @@ void ca_client_context :: whenThereIsAnExceptionDestroySyncGroupIO (
|
||||
io.destroy ( *this->pCallbackGuard.get(), guard );
|
||||
}
|
||||
else {
|
||||
// dont reverse the lock hierarchy
|
||||
// don't reverse the lock hierarchy
|
||||
epicsGuardRelease < epicsMutex > guardRelease ( guard );
|
||||
{
|
||||
//
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( this->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
@@ -571,7 +571,7 @@ int epicsStdCall ca_create_subscription (
|
||||
oldSubscription (
|
||||
guard, *pChan, pChan->io, tmpType, count, mask,
|
||||
pCallBack, pCallBackArg, monixptr );
|
||||
// dont touch object created after above new because
|
||||
// don't touch object created after above new because
|
||||
// the first callback might have canceled, and therefore
|
||||
// destroyed, it
|
||||
return ECA_NORMAL;
|
||||
|
||||
@@ -41,7 +41,7 @@ oldSubscription::oldSubscription (
|
||||
*pEventId = this;
|
||||
}
|
||||
io.subscribe ( guard, type, nElem, mask, *this, &this->id );
|
||||
// Dont touch this pointer after this point because the
|
||||
// Don't touch this pointer after this point because the
|
||||
// 1st update callback might cancel the subscription and
|
||||
// thereby destroy this object.
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
/*
|
||||
* these can be external since there is only one instance
|
||||
* per machine so we dont care about reentrancy
|
||||
* per machine so we don't care about reentrancy
|
||||
*/
|
||||
static tsDLList < repeaterClient > client_list;
|
||||
|
||||
@@ -335,7 +335,7 @@ static void fanOut ( const osiSockAddr & from, const void * pMsg,
|
||||
|
||||
while ( ( pclient = client_list.get () ) ) {
|
||||
theClients.add ( *pclient );
|
||||
/* Dont reflect back to sender */
|
||||
/* Don't reflect back to sender */
|
||||
if ( pclient->identicalAddress ( from ) ) {
|
||||
continue;
|
||||
}
|
||||
@@ -392,7 +392,7 @@ static void register_new_client ( osiSockAddr & from,
|
||||
* repeater would not always allow the loopback address
|
||||
* as a local client address so current clients alternate
|
||||
* between the address of the first non-loopback interface
|
||||
* found and the loopback addresss when subscribing with
|
||||
* found and the loopback address when subscribing with
|
||||
* the CA repeater until all CA repeaters have been updated
|
||||
* to current code.
|
||||
*/
|
||||
@@ -452,7 +452,7 @@ static void register_new_client ( osiSockAddr & from,
|
||||
}
|
||||
|
||||
/*
|
||||
* send a noop message to all other clients so that we dont
|
||||
* send a noop message to all other clients so that we don't
|
||||
* accumulate sockets when there are no beacons
|
||||
*/
|
||||
caHdr noop;
|
||||
|
||||
@@ -279,8 +279,8 @@ epicsTimerNotify::expireStatus searchTimer::expire (
|
||||
if ( this->searchAttempts ) {
|
||||
char buf[64];
|
||||
currentTime.strftime ( buf, sizeof(buf), "%M:%S.%09f");
|
||||
debugPrintf ( ("sent %u delay sec=%f Rts=%s\n",
|
||||
nFrameSent, this->period(), buf ) );
|
||||
debugPrintf ( ("sent %u delay Rts=%s\n",
|
||||
nFrameSent, buf ) );
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -317,7 +317,7 @@ void searchTimer :: show ( unsigned level ) const
|
||||
|
||||
//
|
||||
// Reset the delay to the next search request if we get
|
||||
// at least one response. However, dont reset this delay if we
|
||||
// at least one response. However, don't reset this delay if we
|
||||
// get a delayed response to an old search request.
|
||||
//
|
||||
void searchTimer::uninstallChanDueToSuccessfulSearchResponse (
|
||||
|
||||
@@ -82,8 +82,8 @@ private:
|
||||
double framesPerTry; /* # of UDP frames per search try */
|
||||
double framesPerTryCongestThresh; /* one half N tries w congest */
|
||||
unsigned retry;
|
||||
unsigned searchAttempts; /* num search tries after last timer experation */
|
||||
unsigned searchResponses; /* num search resp after last timer experation */
|
||||
unsigned searchAttempts; /* num search tries after last timer expiration */
|
||||
unsigned searchResponses; /* num search resp after last timer expiration */
|
||||
const unsigned index;
|
||||
ca_uint32_t dgSeqNoAtTimerExpireBegin;
|
||||
ca_uint32_t dgSeqNoAtTimerExpireEnd;
|
||||
|
||||
@@ -82,9 +82,9 @@ extern "C" int epicsStdCall ca_sg_delete ( const CA_SYNC_GID gid )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( pcac->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( pcac->mutex );
|
||||
@@ -106,9 +106,9 @@ void sync_group_reset ( ca_client_context & client, CASG & sg )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( client.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( client.mutex );
|
||||
@@ -219,9 +219,9 @@ extern "C" int epicsStdCall ca_sg_test ( const CA_SYNC_GID gid )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( pcac->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( pcac->mutex );
|
||||
|
||||
@@ -176,7 +176,7 @@ void tcpRecvWatchdog::sendBacklogProgressNotify (
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
|
||||
// We dont set "beaconAnomaly" to be false here because, after we see a
|
||||
// We don't set "beaconAnomaly" to be false here because, after we see a
|
||||
// beacon anomaly (which could be transiently detecting a reboot) we will
|
||||
// not trust the beacon as an indicator of a healthy server until we
|
||||
// receive at least one message from the server.
|
||||
|
||||
@@ -81,7 +81,7 @@ void tcpSendThread::run ()
|
||||
|
||||
while ( true ) {
|
||||
|
||||
// dont wait if there is still labor to be done below
|
||||
// don't wait if there is still labor to be done below
|
||||
if ( ! laborPending ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->iiu.sendThreadFlushEvent.wait ();
|
||||
@@ -124,7 +124,7 @@ void tcpSendThread::run ()
|
||||
}
|
||||
else {
|
||||
// This wakes up the resp thread so that it can call
|
||||
// the connect callback. This isnt maximally efficent
|
||||
// the connect callback. This isn't maximally efficient
|
||||
// but it has the excellent side effect of not requiring
|
||||
// that the UDP thread take the callback lock. There are
|
||||
// almost no V42 servers left at this point.
|
||||
@@ -178,7 +178,7 @@ void tcpSendThread::run ()
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAC TCP clean socket shutdown error was %s\n",
|
||||
errlogPrintf ("CAC TCP clean socket shutdown " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ void tcpSendThread::run ()
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAC TCP clean socket shutdown error was %s\n",
|
||||
errlogPrintf ("CAC TCP clean socket shutdown " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ void tcpSendThread::run ()
|
||||
|
||||
while ( ! this->iiu.recvThread.exitWait ( 30.0 ) ) {
|
||||
// it is possible to get stuck here if the user calls
|
||||
// ca_context_destroy() when a circuit isnt known to
|
||||
// ca_context_destroy() when a circuit isn't known to
|
||||
// be unresponsive, but is. That situation is probably
|
||||
// rare, and the IP kernel might have a timeout for
|
||||
// such situations, nevertheless we will attempt to deal
|
||||
@@ -283,7 +283,7 @@ unsigned tcpiiu::sendBytes ( const void *pBuf,
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAC: unexpected TCP send error: %s\n",
|
||||
errlogPrintf ( "CAC: unexpected TCP send " ERL_ERROR ": %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ void tcpiiu::recvBytes (
|
||||
return;
|
||||
}
|
||||
|
||||
// if the circuit was locally aborted then supress
|
||||
// if the circuit was locally aborted then suppress
|
||||
// warning messages about bad file descriptor etc
|
||||
if ( this->state != iiucs_connected &&
|
||||
this->state != iiucs_clean_shutdown ) {
|
||||
@@ -358,9 +358,9 @@ void tcpiiu::recvBytes (
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
|
||||
// the replacable printf handler isnt called here
|
||||
// because it reqires a callback lock which probably
|
||||
// isnt appropriate here
|
||||
// the replaceable printf handler isn't called here
|
||||
// because it requires a callback lock which probably
|
||||
// isn't appropriate here
|
||||
char name[64];
|
||||
this->hostNameCacheInstance.getName (
|
||||
name, sizeof ( name ) );
|
||||
@@ -535,11 +535,11 @@ void tcpRecvThread::run ()
|
||||
}
|
||||
|
||||
//
|
||||
// we dont feel comfortable calling this with a lock applied
|
||||
// we don't feel comfortable calling this with a lock applied
|
||||
// (it might block for longer than we like)
|
||||
//
|
||||
// we would prefer to improve efficency by trying, first, a
|
||||
// recv with the new MSG_DONTWAIT flag set, but there isnt
|
||||
// we would prefer to improve efficiency by trying, first, a
|
||||
// recv with the new MSG_DONTWAIT flag set, but there isn't
|
||||
// universal support
|
||||
//
|
||||
bool bytesArePending = this->iiu.bytesArePendingInOS ();
|
||||
@@ -957,7 +957,7 @@ void tcpiiu::initiateAbortShutdown (
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAC TCP socket linger set error was %s\n",
|
||||
errlogPrintf ( "CAC TCP socket linger set " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
this->discardingPendingData = true;
|
||||
@@ -988,7 +988,7 @@ void tcpiiu::initiateAbortShutdown (
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAC TCP socket shutdown error was %s\n",
|
||||
errlogPrintf ("CAC TCP socket shutdown " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -1002,7 +1002,7 @@ void tcpiiu::initiateAbortShutdown (
|
||||
};
|
||||
|
||||
//
|
||||
// wake up the send thread if it isnt blocking in send()
|
||||
// wake up the send thread if it isn't blocking in send()
|
||||
//
|
||||
this->sendThreadFlushEvent.signal ();
|
||||
this->flushBlockEvent.signal ();
|
||||
@@ -1058,7 +1058,7 @@ void tcpiiu::show ( unsigned level ) const
|
||||
this->_receiveThreadIsBusy );
|
||||
}
|
||||
if ( level > 2u ) {
|
||||
::printf ( "\tvirtual circuit socket identifier %d\n", this->sock );
|
||||
::printf ( "\tvirtual circuit socket identifier %d\n", (int)this->sock );
|
||||
::printf ( "\tsend thread flush signal:\n" );
|
||||
this->sendThreadFlushEvent.show ( level-2u );
|
||||
::printf ( "\tsend thread:\n" );
|
||||
@@ -1580,7 +1580,7 @@ void tcpiiu::subscriptionRequest (
|
||||
maxBytes = MAX_TCP;
|
||||
}
|
||||
unsigned dataType = subscr.getType ( guard );
|
||||
// data type bounds checked when sunscription created
|
||||
// data type bounds checked when subscription created
|
||||
arrayElementCount maxElem = ( maxBytes - dbr_size[dataType] ) / dbr_value_size[dataType];
|
||||
if ( nElem > maxElem ) {
|
||||
throw cacChannel::msgBodyCacheTooSmall ();
|
||||
@@ -1633,7 +1633,7 @@ void tcpiiu::subscriptionUpdateRequest (
|
||||
throw cacChannel::msgBodyCacheTooSmall ();
|
||||
}
|
||||
comQueSendMsgMinder minder ( this->sendQue, guard );
|
||||
// nElem boounds checked above
|
||||
// nElem bounds checked above
|
||||
this->sendQue.insertRequestHeader (
|
||||
CA_PROTO_READ_NOTIFY, 0u,
|
||||
static_cast < ca_uint16_t > ( dataType ),
|
||||
@@ -1712,7 +1712,7 @@ void tcpiiu :: flush ( epicsGuard < epicsMutex > & guard )
|
||||
this->flushRequest ( guard );
|
||||
// the process thread is not permitted to flush as this
|
||||
// can result in a push / pull deadlock on the TCP pipe.
|
||||
// Instead, the process thread scheduals the flush with the
|
||||
// Instead, the process thread schedules the flush with the
|
||||
// send thread which runs at a higher priority than the
|
||||
// receive thread. The same applies to the UDP thread for
|
||||
// locking hierarchy reasons.
|
||||
@@ -1817,7 +1817,7 @@ void tcpiiu::disconnectAllChannels (
|
||||
}
|
||||
|
||||
while ( nciu * pChan = this->createRespPend.get () ) {
|
||||
// we dont yet know the server's id so we cant
|
||||
// we don't yet know the server's id so we cant
|
||||
// send a channel delete request and will instead
|
||||
// trust that the server can do the proper cleanup
|
||||
// when the circuit disconnects
|
||||
@@ -1848,7 +1848,7 @@ void tcpiiu::disconnectAllChannels (
|
||||
|
||||
while ( nciu * pChan = this->unrespCircuit.get () ) {
|
||||
// if we know that the circuit is unresponsive
|
||||
// then we dont send a channel delete request and
|
||||
// then we don't send a channel delete request and
|
||||
// will instead trust that the server can do the
|
||||
// proper cleanup when the circuit disconnects
|
||||
pChan->disconnectAllIO ( cbGuard, guard );
|
||||
@@ -1883,7 +1883,7 @@ void tcpiiu::unlinkAllChannels (
|
||||
while ( nciu * pChan = this->createRespPend.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
// we dont yet know the server's id so we cant
|
||||
// we don't yet know the server's id so we cant
|
||||
// send a channel delete request and will instead
|
||||
// trust that the server can do the proper cleanup
|
||||
// when the circuit disconnects
|
||||
@@ -1921,7 +1921,7 @@ void tcpiiu::unlinkAllChannels (
|
||||
channelNode::cs_none;
|
||||
pChan->disconnectAllIO ( cbGuard, guard );
|
||||
// if we know that the circuit is unresponsive
|
||||
// then we dont send a channel delete request and
|
||||
// then we don't send a channel delete request and
|
||||
// will instead trust that the server can do the
|
||||
// proper cleanup when the circuit disconnects
|
||||
pChan->serviceShutdownNotify ( cbGuard, guard );
|
||||
@@ -1951,7 +1951,7 @@ void tcpiiu::installChannel (
|
||||
this->channelCountTot++;
|
||||
chan.channelNode::listMember = channelNode::cs_createReqPend;
|
||||
chan.searchReplySetUp ( *this, sidIn, typeIn, countIn, guard );
|
||||
// The tcp send thread runs at apriority below the udp thread
|
||||
// The tcp send thread runs at a priority below the udp thread
|
||||
// so that this will not send small packets
|
||||
this->sendThreadFlushEvent.signal ();
|
||||
}
|
||||
@@ -2060,7 +2060,7 @@ bool tcpiiu::bytesArePendingInOS () const
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
osiSockIoctl_t bytesPending = 0; /* shut up purifys yapping */
|
||||
osiSockIoctl_t bytesPending = 0; /* shut up Purify's yapping */
|
||||
int status = socket_ioctl ( this->sock,
|
||||
FIONREAD, & bytesPending );
|
||||
if ( status >= 0 ) {
|
||||
|
||||
@@ -279,7 +279,7 @@ skip_rest:
|
||||
|
||||
/*
|
||||
* wait for the operation to complete
|
||||
* (outstabnding decrements to zero)
|
||||
* (outstanding decrements to zero)
|
||||
*/
|
||||
while(ntries){
|
||||
ca_pend_event(1.0);
|
||||
|
||||
@@ -202,7 +202,7 @@ udpiiu::udpiiu (
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf("CAC: failed to set mcast ttl %d\n", ttl);
|
||||
errlogPrintf("CAC: failed to set mcast ttl %d\n", (int)ttl);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -266,7 +266,7 @@ udpiiu::udpiiu (
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( this->sock );
|
||||
errlogPrintf ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf );
|
||||
errlogPrintf ( "CAC: getsockname () " ERL_ERROR " was \"%s\"\n", sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
if ( tmpAddr.sa.sa_family != AF_INET) {
|
||||
@@ -428,7 +428,7 @@ void udpRecvThread::run ()
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAC: UDP recv error was \"%s\"\n",
|
||||
errlogPrintf ( "CAC: UDP recv " ERL_ERROR " was \"%s\"\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -536,9 +536,9 @@ void epicsStdCall caRepeaterRegistrationMessage (
|
||||
if ( status < 0 ) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
/*
|
||||
* Different OS return different codes when the repeater isnt running.
|
||||
* Its ok to supress these messages because I print another warning message
|
||||
* if we time out registerring with the repeater.
|
||||
* Different OS return different codes when the repeater isn't running.
|
||||
* Its ok to suppress these messages because I print another warning message
|
||||
* if we time out registering with the repeater.
|
||||
*
|
||||
* Linux returns SOCK_ECONNREFUSED
|
||||
* Windows 2000 returns SOCK_ECONNRESET
|
||||
@@ -673,7 +673,7 @@ bool udpiiu :: searchRespAction (
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
/*
|
||||
* we dont currently know what to do with channel's
|
||||
* we don't currently know what to do with channel's
|
||||
* found to be at non-IP type addresses
|
||||
*/
|
||||
if ( addr.sa.sa_family != AF_INET ) {
|
||||
@@ -762,7 +762,7 @@ bool udpiiu::beaconAction (
|
||||
* always set this field to INADDR_ANY
|
||||
*
|
||||
* clients always assume that if this
|
||||
* field is set to something that isnt INADDR_ANY
|
||||
* field is set to something that isn't INADDR_ANY
|
||||
* then it is the overriding IP address of the server.
|
||||
*/
|
||||
ina.sin_family = AF_INET;
|
||||
@@ -772,7 +772,7 @@ bool udpiiu::beaconAction (
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* old servers dont supply this and the
|
||||
* old servers don't supply this and the
|
||||
* default port must be assumed
|
||||
*/
|
||||
ina.sin_port = htons ( this->serverPort );
|
||||
@@ -874,7 +874,7 @@ void udpiiu::postMsg (
|
||||
size = pCurMsg->m_postsize + sizeof ( *pCurMsg );
|
||||
|
||||
/*
|
||||
* dont allow msg body extending beyond frame boundary
|
||||
* don't allow msg body extending beyond frame boundary
|
||||
*/
|
||||
if ( size > blockSize ) {
|
||||
char buf[64];
|
||||
@@ -1044,7 +1044,7 @@ void udpiiu :: SearchRespCallback :: notify (
|
||||
const osiSockAddr & addr, const epicsTime & currentTime )
|
||||
{
|
||||
/*
|
||||
* we dont currently know what to do with channel's
|
||||
* we don't currently know what to do with channel's
|
||||
* found to be at non-IP type addresses
|
||||
*/
|
||||
if ( addr.sa.sa_family != AF_INET ) {
|
||||
@@ -1119,7 +1119,7 @@ bool udpiiu :: datagramFlush (
|
||||
{
|
||||
guard.assertIdenticalMutex ( cacMutex );
|
||||
|
||||
// dont send the version header by itself
|
||||
// don't send the version header by itself
|
||||
if ( this->nBytesInXmitBuf <= sizeof ( caHdr ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
* here and just generates unnecessary compiler warnings. */
|
||||
#define REENTRINC
|
||||
|
||||
/* Clang-12 and later generates many warnings about compound token */
|
||||
#ifdef __has_warning
|
||||
# if __has_warning("-Wcompound-token-split-by-macro")
|
||||
# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "EXTERN.h"
|
||||
#include "perl.h"
|
||||
#include "XSUB.h"
|
||||
@@ -201,6 +208,8 @@ SV * newSVdbr(struct event_handler_args *peha) {
|
||||
if (is_primitive) {
|
||||
if (value_type == DBR_CHAR) {
|
||||
/* Long string => Perl scalar */
|
||||
if (peha->count == 0)
|
||||
return newSVpvn(peha->dbr, 0);
|
||||
((char *)peha->dbr) [peha->count - 1] = 0;
|
||||
return newSVpv(peha->dbr, 0);
|
||||
}
|
||||
@@ -271,8 +280,12 @@ SV * newSVdbr(struct event_handler_args *peha) {
|
||||
char *str = dbr_value_ptr(peha->dbr, peha->type);
|
||||
|
||||
/* Long string => Perl scalar */
|
||||
str[peha->count - 1] = 0;
|
||||
val = newSVpv(str, 0);
|
||||
if (peha->count == 0)
|
||||
val = newSVpvn(str, 0);
|
||||
else {
|
||||
str[peha->count - 1] = 0;
|
||||
val = newSVpv(str, 0);
|
||||
}
|
||||
} else if (peha->count == 1) {
|
||||
/* Single value => Perl scalar */
|
||||
val = newSVdbf(value_type,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env perl
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2005 UChicago Argonne LLC, as Operator of Argonne
|
||||
# Copyright (c) 2022 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# SPDX-License-Identifier: EPICS
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
@@ -14,26 +14,24 @@
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
use 5.10.1;
|
||||
use strict;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib ("$Bin/../../lib/perl");
|
||||
use FindBin qw($RealBin);
|
||||
use lib ("$RealBin/../../lib/perl");
|
||||
|
||||
use Getopt::Std;
|
||||
use EPICS::Path;
|
||||
use Cwd 'abs_path';
|
||||
use CA;
|
||||
|
||||
######### Globals ##########
|
||||
|
||||
our ($opt_h, $opt_f, $opt_r);
|
||||
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} || "$Bin/../../dbd/softIoc.dbd";
|
||||
our $opt_w = 1;
|
||||
our ($opt_h, $opt_f, $opt_l, $opt_r, $opt_D);
|
||||
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} // abs_path("$RealBin/../../dbd/softIoc.dbd");
|
||||
our $opt_w = 2;
|
||||
our $opt_n = 10;
|
||||
|
||||
my %record = (); # Empty hash to put dbd data in
|
||||
my $iIdx = 0; # Array indexes for interest, data type and base
|
||||
my $tIdx = 1;
|
||||
my $bIdx = 2;
|
||||
my %device = (); # Empty hash to record which rec types have device support
|
||||
|
||||
# EPICS field types
|
||||
my %fieldType = (
|
||||
@@ -58,13 +56,14 @@ my %fieldType = (
|
||||
);
|
||||
|
||||
# globals for sub caget
|
||||
my %connected;
|
||||
my $unconnected_count;
|
||||
my %callback_data;
|
||||
my %timed_out;
|
||||
my $callback_incomplete;
|
||||
|
||||
######### Main program ############
|
||||
|
||||
HELP_MESSAGE() unless getopts('hd:f:rw:');
|
||||
HELP_MESSAGE() unless getopts('hDd:f:l:n:rw:');
|
||||
HELP_MESSAGE() if $opt_h;
|
||||
|
||||
die "File $opt_d not found. (\"capr.pl -h\" gives help)\n"
|
||||
@@ -76,7 +75,7 @@ print "Using $opt_d\n\n";
|
||||
# Print a list of record types
|
||||
if ($opt_r) {
|
||||
print ("Record types found:\n");
|
||||
printList(0);
|
||||
printList($opt_l);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -100,7 +99,7 @@ if (@ARGV) {
|
||||
} else {
|
||||
# Drop any ".FIELD" part
|
||||
s/\. \w+ $//x;
|
||||
printRecord($_, 0);
|
||||
printRecord($_, $opt_l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,9 +129,11 @@ sub parseDbd {
|
||||
my $thisRecord;
|
||||
my $thisField;
|
||||
my $thisType;
|
||||
my $thisSize = 0;
|
||||
my $field = {};
|
||||
my $interest = 0;
|
||||
my $thisBase = 'DECIMAL';
|
||||
my $special = '';
|
||||
|
||||
while (@dbd) {
|
||||
$_ = shift @dbd;
|
||||
@@ -149,35 +150,47 @@ sub parseDbd {
|
||||
$thisField = $1;
|
||||
$thisType = $2;
|
||||
$isAfield = 1;
|
||||
$thisSize = 1024 if $thisType =~ m/^ DBF_(IN|OUT|FWD)LINK $/x;
|
||||
}
|
||||
elsif ( m/interest \s* \( \s* (\w+) \s* \)/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 2 && $isAfield;
|
||||
$interest = $1;
|
||||
}
|
||||
elsif ( m/size \s* \( \s* ([0-9]+) \s* \)/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 2 && $isAfield;
|
||||
$thisSize = $1;
|
||||
}
|
||||
elsif ( m/special \s* \( \s* (\w+) \s* \)/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 2 && $isAfield;
|
||||
$special = $1;
|
||||
}
|
||||
elsif ( m/base \s* \( \s* (\w+) \s* \)/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 2 && $isAfield;
|
||||
$thisBase = $1;
|
||||
}
|
||||
elsif ( m/device \s* \( (\w+) \s* ,/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 0;
|
||||
$device{$1}++;
|
||||
}
|
||||
if ( m/\{/ ) {
|
||||
$level++;
|
||||
}
|
||||
if ( m/\}/ ) {
|
||||
if ($level == 2 && $isAfield) {
|
||||
my $params = [];
|
||||
$params->[$iIdx] = $interest;
|
||||
$params->[$tIdx] = $thisType;
|
||||
$params->[$bIdx] = $thisBase;
|
||||
my $params = {};
|
||||
$params->{interest} = $interest;
|
||||
$params->{dbfType} = $thisType;
|
||||
$params->{base} = $thisBase;
|
||||
$params->{special} = $special;
|
||||
$params->{size} = $thisSize;
|
||||
$field->{$thisField} = $params;
|
||||
|
||||
# Reset default values
|
||||
$isAfield = 0;
|
||||
$interest = 0; # reset default
|
||||
$thisBase = 'DECIMAL'; # reset default
|
||||
$interest = 0;
|
||||
$thisBase = 'DECIMAL';
|
||||
$special = '';
|
||||
$thisSize = 0;
|
||||
}
|
||||
elsif ($level == 1 && $isArecord) {
|
||||
$isArecord = 0;
|
||||
@@ -207,21 +220,23 @@ sub getRecType {
|
||||
|
||||
# Given the record type and field, returns the interest level, data type
|
||||
# and number base for the field
|
||||
# Usage: ($dataType, $interest, $base) = getFieldParams($recType, $field);
|
||||
# Usage: ($dataType, $interest, $base, $special, $size) = getFieldParams($recType, $field);
|
||||
sub getFieldParams {
|
||||
my ($recType, $field) = @_;
|
||||
|
||||
my $params = $record{$recType}{$field} or
|
||||
die "Can't find params for $recType.$field";
|
||||
exists($fieldType{$params->[$tIdx]}) ||
|
||||
exists($fieldType{$params->{dbfType}}) ||
|
||||
die "Field data type $field for $recType not found in dbd file --";
|
||||
exists($params->[$iIdx]) ||
|
||||
exists($params->{interest}) ||
|
||||
die "Interest level for $field in $recType not found in dbd file --";
|
||||
|
||||
my $fType = $fieldType{$params->[$tIdx]};
|
||||
my $fInterest = $params->[$iIdx];
|
||||
my $fBase = $params->[$bIdx];
|
||||
return ($fType, $fInterest, $fBase);
|
||||
my $fType = $fieldType{$params->{dbfType}};
|
||||
my $fInterest = $params->{interest};
|
||||
my $fBase = $params->{base};
|
||||
my $fSpecial = $params->{special};
|
||||
my $fSize = $params->{size};
|
||||
return ($fType, $fInterest, $fBase, $fSpecial, $fSize);
|
||||
}
|
||||
|
||||
# Prints field name and data for given field. Formats output so
|
||||
@@ -233,27 +248,37 @@ sub printField {
|
||||
my $screenWidth = 80;
|
||||
my ($outStr, $wide);
|
||||
|
||||
my $field = "$fieldName:";
|
||||
|
||||
if ( $dataType eq 'DBF_STRING' ) {
|
||||
$outStr = sprintf('%-5s %s', $field, $fieldData);
|
||||
} elsif ( $base eq 'HEX' ) {
|
||||
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
|
||||
$outStr = sprintf('%-5s 0x%x', $field, $val);
|
||||
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
|
||||
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
|
||||
} elsif ( $dataType eq 'DBF_CHAR' ) {
|
||||
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
|
||||
} else {
|
||||
# DBF_INT64, DBF_LONG, DBF_SHORT,
|
||||
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
|
||||
$outStr = sprintf('%-5s %d', $field, $fieldData);
|
||||
if (ref $fieldData eq 'ARRAY') {
|
||||
my $elems = scalar @{$fieldData};
|
||||
my $field = "$fieldName\[$elems\]:";
|
||||
my $count = $elems > $opt_n ? $opt_n : $elems;
|
||||
my @show = @{$fieldData}[0 .. $count - 1];
|
||||
$outStr = sprintf('%-5s %s', $field, join(', ', @show));
|
||||
$outStr .= ", ..." if $elems > $count;
|
||||
}
|
||||
else {
|
||||
my $field = "$fieldName:";
|
||||
if ( $dataType eq 'DBF_STRING' ) {
|
||||
$outStr = sprintf('%-5s %s', $field, $fieldData);
|
||||
} elsif ( $base eq 'HEX' ) {
|
||||
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
|
||||
$outStr = sprintf('%-5s 0x%x', $field, $val);
|
||||
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
|
||||
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
|
||||
} elsif ( $dataType eq 'DBF_UCHAR' ) {
|
||||
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
|
||||
} else {
|
||||
# DBF_INT64, DBF_LONG, DBF_SHORT,
|
||||
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
|
||||
$outStr = sprintf('%-5s %d', $field, $fieldData);
|
||||
}
|
||||
}
|
||||
|
||||
my $len = length($outStr);
|
||||
if ($len <= 20) { $wide = 20; }
|
||||
elsif ( $len <= 40 ) { $wide = 40; }
|
||||
elsif ( $len <= 60 ) { $wide = 60; }
|
||||
if ($len < 20) { $wide = 20; }
|
||||
elsif ( $len < 40 ) { $wide = 40; }
|
||||
elsif ( $len < 60 ) { $wide = 60; }
|
||||
else { $wide = 80;}
|
||||
|
||||
my $pad = $wide - $len;
|
||||
@@ -269,49 +294,64 @@ sub printField {
|
||||
return $col;
|
||||
}
|
||||
|
||||
# Query for a list of fields simultaneously.
|
||||
# The results are filled in the the %callback_data global hash
|
||||
# and the result of the operation is the number of read pvs
|
||||
# Query the native values of a list of PVs simultaneously.
|
||||
# The data is returned in the the %callback_data global hash.
|
||||
# The return value is the number of read pvs
|
||||
#
|
||||
# NOTE: Not re-entrant because results are written to global hash
|
||||
# %callback_data
|
||||
#
|
||||
# Usage: $fields_read = caget( @pvlist )
|
||||
sub caget {
|
||||
my @chans = map { CA->new($_); } @_;
|
||||
|
||||
#clear any previous results;
|
||||
%connected = ();
|
||||
$unconnected_count = scalar @_;
|
||||
%callback_data = ();
|
||||
%timed_out = ();
|
||||
$callback_incomplete = 0;
|
||||
|
||||
eval { CA->pend_io($opt_w); };
|
||||
if ($@) {
|
||||
if ($@ =~ m/^ECA_TIMEOUT/) {
|
||||
my $name = $chans[0]->name;
|
||||
my $err = (@chans > 1) ? 'some fields' : "'$name'";
|
||||
print "Channel connect timed out: $err not found.\n";
|
||||
foreach my $chan (@chans) {
|
||||
$timed_out{$chan->name} = !$chan->is_connected;
|
||||
}
|
||||
@chans = grep { $_->is_connected } @chans;
|
||||
} else {
|
||||
die $@;
|
||||
}
|
||||
}
|
||||
my @chans = map {
|
||||
print " Creating channel for $_\n" if $opt_D;
|
||||
CA->new($_, \&canew_callback);
|
||||
} @_;
|
||||
my $channel_count = scalar @chans;
|
||||
return 0 unless $channel_count gt 0;
|
||||
|
||||
map {
|
||||
$_->get_callback(\&caget_callback, $_->field_type);
|
||||
} @chans;
|
||||
print " $channel_count channels created.\n" if $opt_D;
|
||||
|
||||
my $fields_read = $callback_incomplete = @chans;
|
||||
CA->pend_event(0.1)
|
||||
while $callback_incomplete;
|
||||
return $fields_read;
|
||||
my $elapsed = 0;
|
||||
do {
|
||||
print " Waiting for $unconnected_count channels to connect\n"
|
||||
if $unconnected_count && $opt_D;
|
||||
print " Waiting for data from $callback_incomplete channels\n"
|
||||
if $callback_incomplete && $opt_D;
|
||||
CA->pend_event(0.1);
|
||||
$elapsed += 0.1;
|
||||
} until (($elapsed > $opt_w) or
|
||||
(scalar %connected && $callback_incomplete == 0));
|
||||
my $data_count = scalar keys %callback_data;
|
||||
printf " Got data from %d of %d channels\n", $data_count, $channel_count
|
||||
if $opt_D;
|
||||
return $data_count;
|
||||
}
|
||||
|
||||
sub canew_callback {
|
||||
my ($chan, $up) = @_;
|
||||
return unless $up;
|
||||
$connected{$chan->name} = $chan;
|
||||
$unconnected_count--;
|
||||
my $ftype = $chan->field_type;
|
||||
my $count = $chan->element_count;
|
||||
$ftype = 'DBR_LONG' if $ftype eq 'DBR_CHAR' && $count == 1;
|
||||
print " Getting ${\$chan->name} as $ftype\n" if $opt_D;
|
||||
# We have to fetch all elements so we can show how many there are
|
||||
$chan->get_callback(\&caget_callback, $ftype);
|
||||
$callback_incomplete++;
|
||||
}
|
||||
|
||||
sub caget_callback {
|
||||
my ($chan, $status, $data) = @_;
|
||||
die $status if $status;
|
||||
print " Got ${\$chan->name} = '$data'\n" if $opt_D;
|
||||
$callback_data{$chan->name} = $data;
|
||||
$callback_incomplete--;
|
||||
}
|
||||
@@ -333,69 +373,83 @@ sub printRecord {
|
||||
my @ftypes = (); #types, from parser
|
||||
my @bases = (); #bases, from parser
|
||||
foreach my $field (sort keys %{$record{$recType}}) {
|
||||
# Skip DTYP field if this rec type doesn't have device support defined
|
||||
next if $field eq 'DTYP' && !exists($device{$recType});
|
||||
|
||||
my ($fType, $fInterest, $base) = getFieldParams($recType, $field);
|
||||
# FIXME: Support waveform.VAL fields etc.
|
||||
unless( $fType eq 'DBF_NOACCESS' ) {
|
||||
if ($interest >= $fInterest ) {
|
||||
my $fToGet = "$name.$field";
|
||||
push @fields_pr, $field;
|
||||
push @readlist, $fToGet;
|
||||
push @ftypes, $fType;
|
||||
push @bases, $base;
|
||||
}
|
||||
my ($fType, $fInterest, $base, $special, $size) =
|
||||
getFieldParams($recType, $field);
|
||||
next if $fInterest > $interest;
|
||||
my $fToGet = "$name.$field";
|
||||
if ($fType eq 'DBF_NOACCESS') {
|
||||
next unless $special eq 'SPC_DBADDR';
|
||||
$fType = 'DBF_STRING';
|
||||
}
|
||||
elsif ($fType eq 'DBF_STRING' && $size >= 40) {
|
||||
$fToGet .= '$';
|
||||
}
|
||||
push @fields_pr, $field;
|
||||
push @readlist, $fToGet;
|
||||
push @ftypes, $fType;
|
||||
push @bases, $base;
|
||||
}
|
||||
my $fields_read = caget( @readlist );
|
||||
|
||||
my @missing;
|
||||
|
||||
# print while iterating over lists gathered
|
||||
my $col = 0;
|
||||
for (my $i=0; $i < scalar @readlist; $i++) {
|
||||
my $field = $fields_pr[$i];
|
||||
my $fToGet = $readlist[$i];
|
||||
my ($fType, $data, $base);
|
||||
next if $timed_out{$fToGet};
|
||||
push @missing, $field unless exists $callback_data{$fToGet};
|
||||
next unless exists $callback_data{$fToGet};
|
||||
$fType = $ftypes[$i];
|
||||
$base = $bases[$i];
|
||||
$data = $callback_data{$fToGet};
|
||||
$col = printField($field, $data, $fType, $base, $col);
|
||||
}
|
||||
print("\n"); # Final newline
|
||||
|
||||
printf "\nUnreadable fields: %s\n", join(', ', @missing) if @missing && $opt_D;
|
||||
}
|
||||
|
||||
# Prints list of record types found in dbd file. If level > 0
|
||||
# then the fields of that record type, their interest levels and types are
|
||||
# also printed.
|
||||
# Diagnostic routine, usage: void printList(level);
|
||||
# then uses printRecordList to display all fields in each record type.
|
||||
sub printList {
|
||||
my $level = shift;
|
||||
|
||||
foreach my $rkey (sort keys(%record)) {
|
||||
print(" $rkey\n");
|
||||
if ($level > 0) {
|
||||
foreach my $fkey (keys %{$record{$rkey}}) {
|
||||
print("\tField $fkey - interest $record{$rkey}{$fkey}[$iIdx] ");
|
||||
print("- type $record{$rkey}{$fkey}[$tIdx] ");
|
||||
print("- base $record{$rkey}{$fkey}[$bIdx]\n");
|
||||
}
|
||||
printRecordList($rkey);
|
||||
}
|
||||
else {
|
||||
print(" $rkey\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Prints list of fields with interest levels for given record type
|
||||
# Diagnostic routine, usage: void printRecordList("recordType");
|
||||
# Prints list of fields and metadata for given record type
|
||||
sub printRecordList {
|
||||
my $type = shift;
|
||||
|
||||
if (exists($record{$type}) ) {
|
||||
print("Record type - $type\n");
|
||||
foreach my $fkey (sort keys %{$record{$type}}) {
|
||||
printf('%-8s', $fkey);
|
||||
printf(" interest = $record{$type}{$fkey}[$iIdx]");
|
||||
printf(" type = %-12s ",$record{$type}{$fkey}[$tIdx]);
|
||||
print (" base = $record{$type}{$fkey}[$bIdx]\n");
|
||||
my $param = $record{$type}{$fkey};
|
||||
my $dbfType = $param->{dbfType};
|
||||
printf " %-8s", $fkey;
|
||||
printf " interest = %d", $param->{interest};
|
||||
printf " type = %-12s", $dbfType;
|
||||
if ($dbfType eq 'DBF_STRING') {
|
||||
printf " size = %s\n", $param->{size};
|
||||
}
|
||||
elsif ($dbfType =~ m/DBF_U?(CHAR|SHORT|INT|LONG|INT64)/) {
|
||||
printf " base = %s\n", $param->{base};
|
||||
}
|
||||
elsif ($dbfType eq 'DBF_NOACCESS') {
|
||||
printf " special = %s\n", $param->{special};
|
||||
}
|
||||
else {
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -411,16 +465,20 @@ sub HELP_MESSAGE {
|
||||
" capr.pl [options] <record name> [<interest>]\n",
|
||||
"\n",
|
||||
" -h Print this help message.\n",
|
||||
" -D Print debug messages.\n",
|
||||
"Channel Access options:\n",
|
||||
" -w <sec>: Wait time, specifies CA timeout, default is $opt_w second\n",
|
||||
"Database Definitions:\n",
|
||||
" -d <file.dbd>: The file containing record type definitions.\n",
|
||||
" This can be set using the EPICS_CAPR_DBD_FILE environment variable.\n",
|
||||
" Default: ", AbsPath($opt_d), "\n",
|
||||
" Default: ", abs_path($opt_d), "\n",
|
||||
"Output Options:\n",
|
||||
" -r Lists all record types in the selected dbd file.\n",
|
||||
" -f <record type>: Lists all fields with their interest level, data type\n",
|
||||
" and number base for the given record_type.\n",
|
||||
" -f <record type>: Lists all fields with interest level, data type\n",
|
||||
" and other information for the given record_type.\n",
|
||||
" -l <interest>: interest level\n",
|
||||
" -n <elems>: Maximum number of array elements to display\n",
|
||||
" Default: $opt_n\n",
|
||||
"\n",
|
||||
"Base version: ", CA->version, "\n";
|
||||
exit 1;
|
||||
|
||||
@@ -256,7 +256,7 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
|
||||
for (n = 0; n < nPvs; n++) {
|
||||
|
||||
switch (format) {
|
||||
case plain: /* Emulate old caget behaviour */
|
||||
case plain: /* Emulate old caget behavior */
|
||||
if (pvs[n].nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
|
||||
else printf("%s", pvs[n].name);
|
||||
printf("%c", fieldSeparator);
|
||||
|
||||
@@ -192,7 +192,7 @@ int caget (pv *pvs, int nPvs, OutputT format,
|
||||
for (n = 0; n < nPvs; n++) {
|
||||
|
||||
switch (format) {
|
||||
case plain: /* Emulate old caput behaviour */
|
||||
case plain: /* Emulate old caput behavior */
|
||||
if (pvs[n].reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
|
||||
else printf("%s", pvs[n].name);
|
||||
printf("%c", fieldSeparator);
|
||||
|
||||
@@ -241,7 +241,7 @@ void asCaStart(void)
|
||||
epicsThreadGetStackSize(epicsThreadStackBig),
|
||||
(EPICSTHREADFUNC)asCaTask,0);
|
||||
if(threadid==0) {
|
||||
errMessage(0,"asCaStart: taskSpawn Failure\n");
|
||||
errMessage(0,"asCaStart: taskSpawn Failure");
|
||||
}
|
||||
}
|
||||
epicsMutexMustLock(asCaTaskLock);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "asIocRegister.h"
|
||||
|
||||
/* asSetFilename */
|
||||
static const iocshArg asSetFilenameArg0 = { "ascf",iocshArgString};
|
||||
static const iocshArg asSetFilenameArg0 = { "ascf",iocshArgStringPath};
|
||||
static const iocshArg * const asSetFilenameArgs[] = {&asSetFilenameArg0};
|
||||
static const iocshFuncDef asSetFilenameFuncDef =
|
||||
{"asSetFilename",1,asSetFilenameArgs,
|
||||
@@ -97,7 +97,7 @@ static void aspmemCallFunc(const iocshArgBuf *args)
|
||||
}
|
||||
|
||||
/* astac */
|
||||
static const iocshArg astacArg0 = { "recordname",iocshArgString};
|
||||
static const iocshArg astacArg0 = { "recordname",iocshArgStringRecord};
|
||||
static const iocshArg astacArg1 = { "user",iocshArgString};
|
||||
static const iocshArg astacArg2 = { "host",iocshArgString};
|
||||
static const iocshArg * const astacArgs[] = {&astacArg0,&astacArg1,&astacArg2};
|
||||
|
||||
@@ -11,5 +11,6 @@
|
||||
|
||||
# This is a Makefile fragment, see src/ioc/Makefile.
|
||||
|
||||
$(patsubst %,$(COMMON_DIR)/%,$(BPT_DBD)) : \
|
||||
$(COMMON_DIR)/bpt%.dbd : $(MAKEBPT)
|
||||
$(addprefix $(COMMON_DIR)/,$(BPT_DBD)) : $(COMMON_DIR)/bpt%.dbd : \
|
||||
$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)
|
||||
# Don't try to use $(MAKEBPT) above
|
||||
|
||||
@@ -13,13 +13,15 @@
|
||||
|
||||
THESE_RULES := $(IOCDIR)/db/RULES
|
||||
|
||||
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
|
||||
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES) \
|
||||
$(DBDTORECTYPEH_dep)
|
||||
@$(RM) $@
|
||||
@$(DBTORECORDTYPEH) -D -I ../db -I $(COMMON_DIR) -o $(COMMONDEP_TARGET) $< > $@
|
||||
|
||||
$(COMMON_DIR)/dbCommonRecord.html: ../db/dbCommon.dbd.pod
|
||||
|
||||
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
|
||||
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES) \
|
||||
$(DBDTORECTYPEH_dep)
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTORECORDTYPEH) -I ../db -I $(COMMON_DIR) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
@@ -85,7 +85,7 @@ static epicsEventId startStopEvent;
|
||||
static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = {
|
||||
"cbLow", "cbMedium", "cbHigh"
|
||||
};
|
||||
#define FULL_MSG(name) "callbackRequest: " name " ring buffer full\n"
|
||||
#define FULL_MSG(name) "callbackRequest: " ERL_ERROR " " name " ring buffer full\n"
|
||||
static char *fullMessage[NUM_CALLBACK_PRIORITIES] = {
|
||||
FULL_MSG("cbLow"), FULL_MSG("cbMedium"), FULL_MSG("cbHigh")
|
||||
};
|
||||
@@ -326,17 +326,17 @@ int callbackRequest(epicsCallback *pcallback)
|
||||
cbQueueSet *mySet;
|
||||
|
||||
if (!pcallback) {
|
||||
epicsInterruptContextMessage("callbackRequest: pcallback was NULL\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback was NULL\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
priority = pcallback->priority;
|
||||
if (priority < 0 || priority >= NUM_CALLBACK_PRIORITIES) {
|
||||
epicsInterruptContextMessage("callbackRequest: Bad priority\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Bad priority\n");
|
||||
return S_db_badChoice;
|
||||
}
|
||||
mySet = &callbackQueue[priority];
|
||||
if (!mySet->queue) {
|
||||
epicsInterruptContextMessage("callbackRequest: Callbacks not initialized\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Callbacks not initialized\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
if (mySet->queueOverflow) return S_db_bufFull;
|
||||
|
||||
@@ -529,7 +529,7 @@ long dbProcess(dbCommon *precord)
|
||||
}
|
||||
}
|
||||
|
||||
/* If already active dont process */
|
||||
/* If already active don't process */
|
||||
if (precord->pact) {
|
||||
unsigned short monitor_mask;
|
||||
|
||||
@@ -931,7 +931,7 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
no_elements = capacity = pfl->no_elements;
|
||||
}
|
||||
|
||||
/* Update field info from record (if neccessary);
|
||||
/* Update field info from record (if necessary);
|
||||
* may modify paddr->pfield.
|
||||
*/
|
||||
if (!dbfl_has_copy(pfl) &&
|
||||
@@ -1104,9 +1104,9 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
if (link_info.ltype == PV_LINK &&
|
||||
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
|
||||
chan = dbChannelCreate(link_info.target);
|
||||
if (chan && dbChannelOpen(chan) != 0) {
|
||||
errlogPrintf("ERROR: dbPutFieldLink %s.%s=%s: dbChannelOpen() failed\n",
|
||||
precord->name, pfldDes->name, link_info.target);
|
||||
if (chan && (status = dbChannelOpen(chan)) != 0) {
|
||||
errlogPrintf(ERL_ERROR ": dbPutFieldLink %s.%s=%s: dbChannelOpen() failed w/ 0x%lx\n",
|
||||
precord->name, pfldDes->name, link_info.target, status);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@@ -1325,7 +1325,6 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
void *pfieldsave = paddr->pfield;
|
||||
rset *prset = dbGetRset(paddr);
|
||||
long status = 0;
|
||||
long offset;
|
||||
dbFldDes *pfldDes;
|
||||
int isValueField;
|
||||
|
||||
@@ -1349,20 +1348,25 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
if (status) return status;
|
||||
}
|
||||
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
if (nRequest>1 || paddr->pfldDes->special == SPC_DBADDR) {
|
||||
long offset = 0;
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
}
|
||||
if (no_elements < nRequest)
|
||||
nRequest = no_elements;
|
||||
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
|
||||
nRequest, no_elements, offset);
|
||||
/* update array info */
|
||||
if (!status && prset->put_array_info)
|
||||
if (!status && paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->put_array_info) {
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
}
|
||||
} else {
|
||||
if (nRequest < 1) {
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
|
||||
@@ -73,7 +73,7 @@ DBCORE_API extern int dbAccessDebugPUTF;
|
||||
* options has a bit set for each option that was accepted
|
||||
* number_elements is actual number of elements obtained
|
||||
*
|
||||
* The individual items can be refered to by the expressions::
|
||||
* The individual items can be referred to by the expressions::
|
||||
*
|
||||
* buffer.status
|
||||
* buffer.severity
|
||||
@@ -220,6 +220,8 @@ DBCORE_API long dbNameToAddr(const char *pname, struct dbAddr *paddr);
|
||||
/** Initialize DBADDR from a dbEntry
|
||||
* Also handles SPC_DBADDR processing. This is really an internal
|
||||
* routine for use by dbNameToAddr() and dbChannelCreate().
|
||||
*
|
||||
* \since 7.0.2.1
|
||||
*/
|
||||
DBCORE_API long dbEntryToAddr(const struct dbEntry *pdbentry,
|
||||
struct dbAddr *paddr);
|
||||
@@ -227,6 +229,8 @@ DBCORE_API long dbEntryToAddr(const struct dbEntry *pdbentry,
|
||||
/** Initialize DBENTRY from a valid dbAddr*
|
||||
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
|
||||
* and finally dbFollowAlias().
|
||||
*
|
||||
* \since 3.16.1
|
||||
*/
|
||||
DBCORE_API void dbInitEntryFromAddr(struct dbAddr *paddr,
|
||||
struct dbEntry *pdbentry);
|
||||
@@ -234,6 +238,8 @@ DBCORE_API void dbInitEntryFromAddr(struct dbAddr *paddr,
|
||||
/** Initialize DBENTRY from a valid record (dbCommon*)
|
||||
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
|
||||
* and finally dbFollowAlias() when no field is specified.
|
||||
*
|
||||
* \since 3.16.1
|
||||
*/
|
||||
DBCORE_API void dbInitEntryFromRecord(struct dbCommon *prec,
|
||||
struct dbEntry *pdbentry);
|
||||
|
||||
@@ -97,7 +97,7 @@ static long FIND_CONT_NODE(
|
||||
* processing in that lockset to this task. The separate task is
|
||||
* used so that locksets that do not have breakpoints are isolated
|
||||
* from locksets that do. This allows the processing of other
|
||||
* locksets to continue uninterupted, even if they exist on the same
|
||||
* locksets to continue uninterrupted, even if they exist on the same
|
||||
* scan list as a lockset containing a breakpoint.
|
||||
*
|
||||
* An entrypoint is the first record that gets processed in a lockset.
|
||||
@@ -250,7 +250,7 @@ static long FIND_CONT_NODE(
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the breakpoint stack
|
||||
* Initialize the breakpoint stack
|
||||
*/
|
||||
void dbBkptInit(void)
|
||||
{
|
||||
|
||||
@@ -196,6 +196,73 @@ static void caLinkDec(caLink *pca)
|
||||
if (callback) callback(userPvt);
|
||||
}
|
||||
|
||||
struct waitPvt {
|
||||
caLink *pca;
|
||||
epicsEventId evt;
|
||||
};
|
||||
enum testEvent {
|
||||
testEventConnect,
|
||||
testEventCount,
|
||||
};
|
||||
|
||||
static
|
||||
void testdbCaWaitForEventCB(void *raw)
|
||||
{
|
||||
struct waitPvt *pvt = raw;
|
||||
|
||||
epicsMutexMustLock(pvt->pca->lock);
|
||||
epicsEventMustTrigger(pvt->evt);
|
||||
epicsMutexUnlock(pvt->pca->lock);
|
||||
}
|
||||
|
||||
static
|
||||
void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event)
|
||||
{
|
||||
caLink *pca;
|
||||
epicsEventId evt = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
dbScanLock(plink->precord);
|
||||
|
||||
assert(plink->type==CA_LINK);
|
||||
pca = (caLink *)plink->value.pv_link.pvt;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
assert(!pca->monitor && !pca->connect && !pca->userPvt);
|
||||
|
||||
while(!pca->isConnected || (event==testEventCount && pca->nUpdate < cnt)) {
|
||||
struct waitPvt pvt = {pca, evt};
|
||||
pca->connect = &testdbCaWaitForEventCB;
|
||||
pca->monitor = &testdbCaWaitForEventCB;
|
||||
pca->userPvt = &pvt;
|
||||
|
||||
epicsMutexUnlock(pca->lock);
|
||||
dbScanUnlock(plink->precord);
|
||||
|
||||
epicsEventMustWait(evt);
|
||||
|
||||
dbScanLock(plink->precord);
|
||||
epicsMutexMustLock(pca->lock);
|
||||
|
||||
pca->connect = NULL;
|
||||
pca->monitor = NULL;
|
||||
pca->userPvt = NULL;
|
||||
}
|
||||
|
||||
epicsEventDestroy(evt);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
dbScanUnlock(plink->precord);
|
||||
}
|
||||
|
||||
void testdbCaWaitForConnect(DBLINK *plink)
|
||||
{
|
||||
testdbCaWaitForEvent(plink, 0, testEventConnect);
|
||||
}
|
||||
|
||||
void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt)
|
||||
{
|
||||
testdbCaWaitForEvent(plink, cnt, testEventCount);
|
||||
}
|
||||
|
||||
/* Block until worker thread has processed all previously queued actions.
|
||||
* Does not prevent additional actions from being queued.
|
||||
*/
|
||||
@@ -232,22 +299,6 @@ void dbCaSync(void)
|
||||
epicsEventDestroy(wake);
|
||||
}
|
||||
|
||||
DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink)
|
||||
{
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
unsigned long ret;
|
||||
|
||||
if (!pca) return (unsigned long)-1;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
|
||||
ret = pca->nUpdate;
|
||||
|
||||
epicsMutexUnlock(pca->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dbCaCallbackProcess(void *userPvt)
|
||||
{
|
||||
struct link *plink = (struct link *)userPvt;
|
||||
@@ -785,6 +836,8 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
caLink *pca;
|
||||
short link_action = 0;
|
||||
struct link *plink;
|
||||
dbCaCallback connect = 0;
|
||||
void *userPvt = 0;
|
||||
|
||||
pca = ca_puser(arg.chid);
|
||||
assert(pca);
|
||||
@@ -851,11 +904,16 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
}
|
||||
pca->gotAttributes = 0;
|
||||
if (pca->dbrType != DBR_STRING) {
|
||||
/* will run connect() callback later */
|
||||
link_action |= CA_GET_ATTRIBUTES;
|
||||
} else {
|
||||
connect = pca->connect;
|
||||
userPvt = pca->userPvt;
|
||||
}
|
||||
done:
|
||||
if (link_action) addAction(pca, link_action);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
if (connect) connect(userPvt);
|
||||
}
|
||||
|
||||
static void eventCallback(struct event_handler_args arg)
|
||||
@@ -881,10 +939,10 @@ static void eventCallback(struct event_handler_args arg)
|
||||
if (precord) {
|
||||
if (arg.status != ECA_NORDACCESS &&
|
||||
arg.status != ECA_GETFAIL)
|
||||
errlogPrintf("dbCa: eventCallback record %s error %s\n",
|
||||
errlogPrintf("dbCa: eventCallback record %s " ERL_ERROR " %s\n",
|
||||
precord->name, ca_message(arg.status));
|
||||
} else {
|
||||
errlogPrintf("dbCa: eventCallback error %s\n",
|
||||
errlogPrintf("dbCa: eventCallback " ERL_ERROR " %s\n",
|
||||
ca_message(arg.status));
|
||||
}
|
||||
goto done;
|
||||
@@ -1029,10 +1087,10 @@ static void getAttribEventCallback(struct event_handler_args arg)
|
||||
if (arg.status != ECA_NORMAL) {
|
||||
dbCommon *precord = plink->precord;
|
||||
if (precord) {
|
||||
errlogPrintf("dbCa: getAttribEventCallback record %s error %s\n",
|
||||
errlogPrintf("dbCa: getAttribEventCallback record %s " ERL_ERROR " %s\n",
|
||||
precord->name, ca_message(arg.status));
|
||||
} else {
|
||||
errlogPrintf("dbCa: getAttribEventCallback error %s\n",
|
||||
errlogPrintf("dbCa: getAttribEventCallback " ERL_ERROR " %s\n",
|
||||
ca_message(arg.status));
|
||||
}
|
||||
epicsMutexUnlock(pca->lock);
|
||||
@@ -1058,6 +1116,7 @@ static void getAttribEventCallback(struct event_handler_args arg)
|
||||
|
||||
static void dbCaTask(void *arg)
|
||||
{
|
||||
epicsEventId requestSync = NULL;
|
||||
taskwdInsert(0, NULL, NULL);
|
||||
SEVCHK(ca_context_create(ca_enable_preemptive_callback),
|
||||
"dbCaTask calling ca_context_create");
|
||||
@@ -1078,13 +1137,20 @@ static void dbCaTask(void *arg)
|
||||
|
||||
epicsMutexMustLock(workListLock);
|
||||
if (!(pca = (caLink *)ellGet(&workList))){ /* Take off list head */
|
||||
if(requestSync) {
|
||||
/* dbCaSync() requires workListLock to be held here */
|
||||
epicsEventMustTrigger(requestSync);
|
||||
requestSync = NULL;
|
||||
}
|
||||
epicsMutexUnlock(workListLock);
|
||||
if (dbCaCtl == ctlExit) goto shutdown;
|
||||
break; /* workList is empty */
|
||||
}
|
||||
link_action = pca->link_action;
|
||||
if (link_action&CA_SYNC)
|
||||
epicsEventMustTrigger((epicsEventId)pca->userPvt); /* dbCaSync() requires workListLock to be held here */
|
||||
if (link_action&CA_SYNC) {
|
||||
assert(!requestSync);
|
||||
requestSync = pca->userPvt;
|
||||
}
|
||||
pca->link_action = 0;
|
||||
if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
|
||||
epicsMutexUnlock(workListLock); /* Give back immediately */
|
||||
|
||||
@@ -48,8 +48,12 @@ DBCORE_API long dbCaPutLink(struct link *plink,short dbrType,
|
||||
extern struct ca_client_context * dbCaClientContext;
|
||||
|
||||
#ifdef EPICS_DBCA_PRIVATE_API
|
||||
/* Wait CA link work queue to become empty. eg. after from dbPut() to OUT */
|
||||
DBCORE_API void dbCaSync(void);
|
||||
DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink);
|
||||
/* Wait for the data update counter to reach the specified value. */
|
||||
DBCORE_API void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt);
|
||||
/* Wait for CA link to become connected */
|
||||
DBCORE_API void testdbCaWaitForConnect(DBLINK *plink);
|
||||
#endif
|
||||
|
||||
/* These macros are for backwards compatibility */
|
||||
|
||||
@@ -9,14 +9,22 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Andrew Johnson <anj@aps.anl.gov>
|
||||
* Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#ifndef INC_dbChannel_H
|
||||
#define INC_dbChannel_H
|
||||
|
||||
/** \file dbChannel.h
|
||||
*
|
||||
* \author Andrew Johnson (ANL)
|
||||
* \author Ralph Lange (BESSY)
|
||||
*
|
||||
* \brief The dbChannel API gives access to record fields.
|
||||
*
|
||||
* The dbChannel API is used internally by the IOC and by link types, device
|
||||
* support and IOC servers (RSRV and QSRV) to access record fields, either
|
||||
* directly or through one or more server-side filters as specified in the
|
||||
* channel name used when creating the channel.
|
||||
*/
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "dbAddr.h"
|
||||
#include "ellLib.h"
|
||||
@@ -30,200 +38,531 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
/**
|
||||
* event subscription
|
||||
*/
|
||||
typedef struct evSubscrip {
|
||||
ELLNODE node;
|
||||
struct dbChannel *chan;
|
||||
EVENTFUNC *user_sub;
|
||||
void *user_arg;
|
||||
struct event_que *ev_que;
|
||||
db_field_log **pLastLog;
|
||||
unsigned long npend; /* n times this event is on the queue */
|
||||
unsigned long nreplace; /* n times replacing event on the queue */
|
||||
unsigned char select;
|
||||
char useValque;
|
||||
char callBackInProgress;
|
||||
char enabled;
|
||||
ELLNODE node;
|
||||
struct dbChannel * chan;
|
||||
EVENTFUNC * user_sub;
|
||||
void * user_arg;
|
||||
struct event_que * ev_que;
|
||||
db_field_log ** pLastLog;
|
||||
unsigned long npend; /**< n times this event is on the queue */
|
||||
unsigned long nreplace; /**< n times replacing event on the queue */
|
||||
unsigned char select;
|
||||
char useValque;
|
||||
char callBackInProgress;
|
||||
char enabled;
|
||||
} evSubscrip;
|
||||
|
||||
typedef struct chFilter chFilter;
|
||||
|
||||
/* A dbChannel points to a record field, and can have multiple filters */
|
||||
/** \brief A Database Channel object
|
||||
*
|
||||
* A dbChannel is created from a user-supplied channel name, and holds
|
||||
* pointers to the record & field and information about any filters that
|
||||
* were specified with it. The dbChannel macros defined in this header
|
||||
* file should always be used to read data from a dbChannel object, the
|
||||
* internal implementation may change without notice.
|
||||
*/
|
||||
typedef struct dbChannel {
|
||||
const char *name;
|
||||
dbAddr addr; /* address structure for record/field */
|
||||
long final_no_elements; /* final number of elements (arrays) */
|
||||
short final_field_size; /* final size of element */
|
||||
short final_type; /* final type of database field */
|
||||
ELLLIST filters; /* list of filters as created from JSON */
|
||||
ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
|
||||
ELLLIST post_chain; /* list of filters to be called post-event-queue */
|
||||
const char *name; /**< Channel name */
|
||||
dbAddr addr; /**< Pointers to record & field */
|
||||
long final_no_elements; /**< Final number of array elements */
|
||||
short final_field_size; /**< Final size of each element */
|
||||
short final_type; /**< Final type of database field */
|
||||
ELLLIST filters; /**< Filters used by dbChannel */
|
||||
ELLLIST pre_chain; /**< Filters on pre-event-queue chain */
|
||||
ELLLIST post_chain; /**< Filters on post-event-queue chain */
|
||||
} dbChannel;
|
||||
|
||||
/* Prototype for the channel event function that is called in filter stacks
|
||||
/** \brief Event filter function type
|
||||
*
|
||||
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
|
||||
* Unless dbfl_has_copy(pLog), it must call dbScanLock before accessing the data,
|
||||
* as this indicates the data is still owned by the record.
|
||||
* Prototype for channel event filter functions.
|
||||
*
|
||||
* This function has ownership of the field log pLog, if it wishes to discard
|
||||
* this update it should free the field log with db_delete_field_log() and
|
||||
* then return NULL.
|
||||
* When these functions are called the scan lock for the record associated
|
||||
* with \p chan _may_ already be locked, but they must use dbfl_has_copy()
|
||||
* to determine whether the data in \p pLog belongs to the record. If that
|
||||
* returns 0 the function must call dbScanLock() before accessing the data.
|
||||
*
|
||||
* A filter function owns the field log \p pLog when called. To discard an
|
||||
* update it should free the field log using db_delete_field_log() and
|
||||
* return NULL.
|
||||
*/
|
||||
typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
|
||||
|
||||
/* Return values from chFilterIf->parse_* routines: */
|
||||
/** \brief Result returned by chFilterIf parse routines.
|
||||
*
|
||||
* The parsing functions from a chFilterIf must return either \p parse_stop
|
||||
* (in event of an error) or \p parse_continue.
|
||||
*/
|
||||
typedef enum {
|
||||
parse_stop, parse_continue
|
||||
} parse_result;
|
||||
|
||||
/* These routines must be implemented by each filter plug-in */
|
||||
/** \brief Channel Filter Interface
|
||||
*
|
||||
* Routines to be implemented by each Channel Filter.
|
||||
*/
|
||||
typedef struct chFilterIf {
|
||||
/* cleanup pointer passed to dbRegisterFilter().
|
||||
* Called during DB shutdown
|
||||
/** \brief Release private filter data.
|
||||
*
|
||||
* Called during database shutdown to release resources allocated by
|
||||
* the filter.
|
||||
* \param puser The user-pointer passed into dbRegisterFilter().
|
||||
*/
|
||||
void (* priv_free)(void *puser);
|
||||
/* Parsing event handlers: */
|
||||
parse_result (* parse_start)(chFilter *filter);
|
||||
/* If parse_start() returns parse_continue for a filter, one of
|
||||
|
||||
/** \name Parsing event handlers
|
||||
*
|
||||
* A filter that doesn't accept a particular JSON value type may use a
|
||||
* \p NULL pointer to the parsing handler for that value type, which is
|
||||
* equivalent to a routine that always returns \p parse_stop.
|
||||
*/
|
||||
|
||||
/** \brief Create new filter instance.
|
||||
*
|
||||
* Called when a new filter instance is requested. Filter may allocate
|
||||
* resources for this instance and store in \p filter->puser.
|
||||
* If parse_start() returns \p parse_continue for a filter, one of
|
||||
* parse_abort() or parse_end() will later be called for that same
|
||||
* filter.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_start)(chFilter *filter);
|
||||
|
||||
/** \brief Parsing of filter instance is being cancelled.
|
||||
*
|
||||
* This function should release any memory allocated for the given
|
||||
* \p filter instance; no further parsing handlers will be called for it.
|
||||
* \param filter Pointer to instance data.
|
||||
*/
|
||||
void (* parse_abort)(chFilter *filter);
|
||||
/* If parse_abort() is called it should release any memory allocated
|
||||
* for this filter; no further parse_...() calls will be made;
|
||||
|
||||
/** \brief Parsing of filter instance has completed successfully.
|
||||
*
|
||||
* The parser has reached the end of this instance and no further parsing
|
||||
* handlers will be called for it. The filter must check the instance
|
||||
* data and indicate whether it was complete or not.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_end)(chFilter *filter);
|
||||
/* If parse_end() returns parse_stop it should have released any
|
||||
* memory allocated for this filter; no further parse_...() calls will
|
||||
* be made in this case.
|
||||
|
||||
/** \brief Parser saw \p null value.
|
||||
*
|
||||
* Optional.
|
||||
* Null values are rarely accepted by channel filters.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
|
||||
parse_result (* parse_null)(chFilter *filter);
|
||||
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
|
||||
parse_result (* parse_integer)(chFilter *filter, long integerVal);
|
||||
parse_result (* parse_double)(chFilter *filter, double doubleVal);
|
||||
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
|
||||
size_t stringLen); /* NB: stringVal is not zero-terminated: */
|
||||
|
||||
/** \brief Parser saw boolean value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param boolVal true/false Value.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
|
||||
|
||||
/** \brief Parser saw integer value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param integerVal Value.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_integer)(chFilter *filter, long integerVal);
|
||||
|
||||
/** \brief Parser saw double value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param doubleVal Value.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_double)(chFilter *filter, double doubleVal);
|
||||
|
||||
/** \brief Parser saw string value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param stringVal Value, not zero-terminated.
|
||||
* \param stringLen Number of chars in \p stringVal.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
|
||||
size_t stringLen);
|
||||
|
||||
/** \brief Parser saw start of a JSON map value.
|
||||
*
|
||||
* Optional.
|
||||
* Inside a JSON map all data consists of key/value pairs.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_start_map)(chFilter *filter);
|
||||
|
||||
/** \brief Parser saw a JSON map key.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param key Value not zero-terminated.
|
||||
* \param stringLen Number of chars in \p key
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_map_key)(chFilter *filter, const char *key,
|
||||
size_t stringLen); /* NB: key is not zero-terminated: */
|
||||
size_t stringLen);
|
||||
|
||||
/** \brief Parser saw end of a JSON map value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_end_map)(chFilter *filter);
|
||||
|
||||
/** \brief Parser saw start of a JSON array value.
|
||||
*
|
||||
* Optional.
|
||||
* Data inside a JSON array doesn't have to be all of the same type.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_start_array)(chFilter *filter);
|
||||
|
||||
/** \brief Parser saw end of a JSON array value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_end_array)(chFilter *filter);
|
||||
|
||||
/* Channel operations: */
|
||||
/** \name Channel operations */
|
||||
|
||||
/** \brief Open filter on channel.
|
||||
*
|
||||
* Optional, initialize instance.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
long (* channel_open)(chFilter *filter);
|
||||
void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
void (* channel_report)(chFilter *filter, int level, const unsigned short indent);
|
||||
|
||||
/** \brief Get pre-chain filter function.
|
||||
*
|
||||
* Optional.
|
||||
* Returns pre-chain filter function and context.
|
||||
* \param[in] filter Pointer to instance data.
|
||||
* \param[out] cb_out Write filter function pointer here.
|
||||
* \param[out] arg_out Write private data pointer here.
|
||||
* \param[in,out] probe db_field_log with metadata for adjusting.
|
||||
*/
|
||||
void (* channel_register_pre) (chFilter *filter,
|
||||
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
|
||||
/** \brief Get post-chain filter function.
|
||||
*
|
||||
* Optional, return post-chain filter function and context.
|
||||
* \param[in] filter Pointer to instance data.
|
||||
* \param[out] cb_out Write filter function pointer here.
|
||||
* \param[out] arg_out Write private data pointer here.
|
||||
* \param[in,out] probe db_field_log with metadata for adjusting.
|
||||
*/
|
||||
void (* channel_register_post)(chFilter *filter,
|
||||
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
|
||||
/** \brief Print information about filter to stdout.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param level Higher levels may provide more detail.
|
||||
* \param indent Indent all lines by this many spaces.
|
||||
*/
|
||||
void (* channel_report)(chFilter *filter,
|
||||
int level, const unsigned short indent);
|
||||
|
||||
/** \brief Close filter.
|
||||
*
|
||||
* Optional, releases resources allocated for this instance.
|
||||
* \param filter Pointer to instance data.
|
||||
*/
|
||||
void (* channel_close)(chFilter *filter);
|
||||
} chFilterIf;
|
||||
|
||||
/* A chFilterPlugin holds data for a filter plugin */
|
||||
/** \brief Filter plugin data
|
||||
*
|
||||
* A chFilterPlugin object holds data about a filter plugin.
|
||||
*/
|
||||
typedef struct chFilterPlugin {
|
||||
ELLNODE node;
|
||||
const char *name;
|
||||
const chFilterIf *fif;
|
||||
void *puser;
|
||||
ELLNODE node; /**< \brief List node (dbBase->filterList) */
|
||||
const char *name; /**< \brief Filter name */
|
||||
const chFilterIf *fif; /**< \brief Filter interface routines */
|
||||
void *puser; /**< \brief For use by the plugin */
|
||||
} chFilterPlugin;
|
||||
|
||||
/* A chFilter holds data for a single filter instance */
|
||||
/** \brief Filter instance data
|
||||
*
|
||||
* A chFilter holds data about a single filter instance.
|
||||
*/
|
||||
struct chFilter {
|
||||
ELLNODE list_node;
|
||||
ELLNODE pre_node;
|
||||
ELLNODE post_node;
|
||||
dbChannel *chan;
|
||||
const chFilterPlugin *plug;
|
||||
chPostEventFunc *pre_func;
|
||||
void *pre_arg;
|
||||
chPostEventFunc *post_func;
|
||||
void *post_arg;
|
||||
void *puser;
|
||||
ELLNODE list_node; /**< \brief List node (dbChannel->filters) */
|
||||
ELLNODE pre_node; /**< \brief List node (dbChannel->pre_chain) */
|
||||
ELLNODE post_node; /**< \brief List node (dbChannel->post_chain) */
|
||||
dbChannel *chan; /**< \brief The dbChannel we belong to */
|
||||
const chFilterPlugin *plug; /**< \brief The plugin that created us */
|
||||
chPostEventFunc *pre_func; /**< \brief pre-chain filter function */
|
||||
void *pre_arg; /**< \brief pre-chain context pointer */
|
||||
chPostEventFunc *post_func; /**< \brief post-chain filter function */
|
||||
void *post_arg; /**< \brief post-chain context pointer */
|
||||
void *puser; /**< \brief For use by the plugin */
|
||||
};
|
||||
|
||||
struct dbCommon;
|
||||
struct dbFldDes;
|
||||
|
||||
DBCORE_API void dbChannelInit (void);
|
||||
/** \brief Initialize the dbChannel subsystem. */
|
||||
DBCORE_API void dbChannelInit(void);
|
||||
|
||||
/** \brief Cleanup the dbChannel subsystem. */
|
||||
DBCORE_API void dbChannelExit(void);
|
||||
|
||||
/** \brief Test the given PV name for existance.
|
||||
*
|
||||
* This routine looks up the given record and field name, but does not check
|
||||
* whether any field modifiers given after the field name are correct.
|
||||
* This is sufficient for the correct server to quickly direct searches to the
|
||||
* IOC that owns that PV name. Field modifiers will be checked when
|
||||
* dbChannelCreate() is later called with the same name.
|
||||
* \param name Channel name.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelTest(const char *name);
|
||||
|
||||
/** \brief Create a dbChannel object for the given PV name.
|
||||
*
|
||||
* \param name Channel name.
|
||||
* \return Pointer to dbChannel object, or NULL if invalid.
|
||||
*/
|
||||
DBCORE_API dbChannel * dbChannelCreate(const char *name);
|
||||
|
||||
/** \brief Open a dbChannel for doing I/O.
|
||||
*
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelOpen(dbChannel *chan);
|
||||
|
||||
/*Following is also defined in db_convert.h*/
|
||||
/** \brief Request (DBR) type conversion array.
|
||||
*
|
||||
* This converter array is declared in db_convert.h but redeclared
|
||||
* here as it is needed by the dbChannel...CAType macros defined here.
|
||||
*/
|
||||
DBCORE_API extern unsigned short dbDBRnewToDBRold[];
|
||||
|
||||
/* In the following macros pChan is dbChannel* */
|
||||
/** \name dbChannel Inspection Macros */
|
||||
|
||||
/* evaluates to const char* */
|
||||
/** \brief Name that defined the channel.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns const char*
|
||||
*/
|
||||
#define dbChannelName(pChan) ((pChan)->name)
|
||||
|
||||
/* evaluates to struct dbCommon* */
|
||||
/** \brief Record the channel connects to.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns struct dbCommon*
|
||||
*/
|
||||
#define dbChannelRecord(pChan) ((pChan)->addr.precord)
|
||||
|
||||
/* evaluates to struct dbFldDes* */
|
||||
/** \brief Field descriptor for the field pointed to.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns struct dbFldDes*
|
||||
*/
|
||||
#define dbChannelFldDes(pChan) ((pChan)->addr.pfldDes)
|
||||
|
||||
/* evaluates to long */
|
||||
/** \brief Number of array elements in the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns long
|
||||
*/
|
||||
#define dbChannelElements(pChan) ((pChan)->addr.no_elements)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Data type (DBF type) of the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFieldType(pChan) ((pChan)->addr.field_type)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Request type (DBR type) of the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelExportType(pChan) ((pChan)->addr.dbr_field_type)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief CA data type of the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelExportCAType(pChan) (dbDBRnewToDBRold[dbChannelExportType(pChan)])
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Field (element if array) size in bytes.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFieldSize(pChan) ((pChan)->addr.field_size)
|
||||
|
||||
/* evaluates to long */
|
||||
/** \brief Array length after filtering.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns long
|
||||
*/
|
||||
#define dbChannelFinalElements(pChan) ((pChan)->final_no_elements)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Data type after filtering.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFinalFieldType(pChan) ((pChan)->final_type)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Channel CA data type after filtering.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFinalCAType(pChan) (dbDBRnewToDBRold[(pChan)->final_type])
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Field/element size after filtering, in bytes.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short */
|
||||
#define dbChannelFinalFieldSize(pChan) ((pChan)->final_field_size)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Field special attribute.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelSpecial(pChan) ((pChan)->addr.special)
|
||||
|
||||
/* Channel filters do not get to interpose here since there are many
|
||||
/** \brief Pointer to the record field.
|
||||
*
|
||||
* Channel filters do not get to interpose here since there are many
|
||||
* places where the field pointer is compared with the address of a
|
||||
* specific record field, so they can't modify the pointer value.
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns void *
|
||||
*/
|
||||
/* evaluates to void* */
|
||||
#define dbChannelField(pChan) ((pChan)->addr.pfield)
|
||||
|
||||
|
||||
/** \name dbChannel Operation Functions */
|
||||
|
||||
/** \brief dbGet() through a dbChannel.
|
||||
*
|
||||
* Calls dbGet() for the field that \p chan refers to.
|
||||
* Only call this routine if the record is already locked.
|
||||
* \param[in] chan Pointer to the dbChannel object.
|
||||
* \param[in] type Request type from dbFldTypes.h.
|
||||
* \param[out] pbuffer Pointer to data buffer.
|
||||
* \param[in,out] options Request options from dbAccessDefs.h.
|
||||
* \param[in,out] nRequest Pointer to the element count.
|
||||
* \param[in] pfl Pointer to a db_field_log or NULL.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelGet(dbChannel *chan, short type,
|
||||
void *pbuffer, long *options, long *nRequest, void *pfl);
|
||||
|
||||
/** \brief dbGetField() through a dbChannel.
|
||||
*
|
||||
* Get values from a PV through a channel.
|
||||
* This routine locks the record, calls
|
||||
* dbChannelGet(), then unlocks the record again.
|
||||
* \param[in] chan Pointer to the dbChannel object.
|
||||
* \param[in] type Request type from dbFldTypes.h.
|
||||
* \param[out] pbuffer Pointer to data buffer.
|
||||
* \param[in,out] options Request options from dbAccessDefs.h.
|
||||
* \param[in,out] nRequest Pointer to the element count.
|
||||
* \param[in] pfl Pointer to a db_field_log or NULL.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelGetField(dbChannel *chan, short type,
|
||||
void *pbuffer, long *options, long *nRequest, void *pfl);
|
||||
|
||||
/** \brief dbPut() through a dbChannel.
|
||||
*
|
||||
* Put values to a PV through a channel. Only call this routine if the
|
||||
* record is already locked.
|
||||
* Calls dbPut() for the field that \p chan refers to.
|
||||
* \param chan[in] Pointer to the dbChannel object.
|
||||
* \param type[in] Request type from dbFldTypes.h.
|
||||
* \param pbuffer[in] Pointer to data buffer.
|
||||
* \param nRequest[in] Number of elements in pbuffer.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelPut(dbChannel *chan, short type,
|
||||
const void *pbuffer, long nRequest);
|
||||
|
||||
/** \brief dbPutField() through a dbChannel.
|
||||
*
|
||||
* Put values to a PV through a channel.
|
||||
* This routine calls dbPutField() for the field that \p chan refers to.
|
||||
* \param chan[in] Pointer to the dbChannel object.
|
||||
* \param type[in] Request type from dbFldTypes.h.
|
||||
* \param pbuffer[in] Pointer to data buffer.
|
||||
* \param nRequest[in] Number of elements in pbuffer.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelPutField(dbChannel *chan, short type,
|
||||
const void *pbuffer, long nRequest);
|
||||
|
||||
/** \brief Print report on a channel.
|
||||
*
|
||||
* Print information about the channel to stdout.
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
* \param level Higher levels may provide more detail.
|
||||
* \param indent Indent all lines by this many spaces.
|
||||
*/
|
||||
DBCORE_API void dbChannelShow(dbChannel *chan, int level,
|
||||
const unsigned short indent);
|
||||
|
||||
/** \brief Print report on a channel's filters.
|
||||
*
|
||||
* Print information about the channel's filters to stdout.
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
* \param level Higher levels may provide more detail.
|
||||
* \param indent Indent all lines by this many spaces.
|
||||
*/
|
||||
DBCORE_API void dbChannelFilterShow(dbChannel *chan, int level,
|
||||
const unsigned short indent);
|
||||
|
||||
/** \brief Delete a channel.
|
||||
*
|
||||
* Releases resources owned by this channel and its filters.
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
*/
|
||||
DBCORE_API void dbChannelDelete(dbChannel *chan);
|
||||
|
||||
DBCORE_API void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
|
||||
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
|
||||
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
|
||||
|
||||
/** \name Other routines */
|
||||
|
||||
DBCORE_API void dbRegisterFilter(const char *key,
|
||||
const chFilterIf *fif, void *puser);
|
||||
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan,
|
||||
db_field_log *pLogIn);
|
||||
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan,
|
||||
db_field_log *pLogIn);
|
||||
DBCORE_API const chFilterPlugin * dbFindFilter(const char *key, size_t len);
|
||||
DBCORE_API void dbChannelGetArrayInfo(dbChannel *chan,
|
||||
void **pfield, long *no_elements, long *offset);
|
||||
|
||||
@@ -77,12 +77,12 @@ A set of periodic scan intervals
|
||||
=back
|
||||
|
||||
Additional periodic scan rates may be defined for individual IOCs by making a
|
||||
local copy of menuScan.dbd and adding more choices as required. Scan rates
|
||||
should normally be defined in order, with the fastest rates appearing first.
|
||||
Scan periods may now be specified in seconds, minutes, hours or Hertz/Hz, and
|
||||
plural time units will also be accepted (seconds are used if no unit is
|
||||
mentioned in the choice string). For example the rates given below are all
|
||||
valid:
|
||||
local copy of menuScan.dbd and adding more choices as required. Periodic scan
|
||||
rates should normally be defined in order following the other scan types, with
|
||||
the longest periods appearing first. Scan periods can be specified with a unit
|
||||
string of C<second>/C<seconds>, C<minute>/C<minutes>, C<hour>/C<hours> or
|
||||
C<Hertz>/C<Hz>. Seconds are used if no unit is included in the choice string.
|
||||
For example these rates are all valid:
|
||||
|
||||
1 hour
|
||||
0.5 hours
|
||||
@@ -97,7 +97,7 @@ initialization (before the normal scan tasks are started).
|
||||
|
||||
The B<PHAS> field orders the records within a specific SCAN group. This is not
|
||||
meaningful for passive records. All records of a specified phase are processed
|
||||
before those with higher phase number. Whenever possible it is better to use
|
||||
before those with higher phase number. It is generally better practice to use
|
||||
linked passive records to enforce the order of processing rather than a phase
|
||||
number.
|
||||
|
||||
@@ -109,23 +109,23 @@ The call to post_event is: post_event(short event_number).
|
||||
The B<PRIO> field specifies the scheduling priority for processing records
|
||||
with SCAN=C<I/O Event> and asynchronous record completion tasks.
|
||||
|
||||
The B<DISV> field specifies a "disable value". Record processing is
|
||||
immediately terminated if the value of this field is equal to the value of the
|
||||
DISA field, i.e. the record is disabled. Note that field values of a record
|
||||
can be changed by database put or Channel Access, even if a record is
|
||||
The B<DISV> field specifies a "disable value". Record processing cannot
|
||||
begin when the value of this field is equal to the value of the DISA
|
||||
field, meaning the record is disabled. Note that field values of a record
|
||||
can be changed by database or Channel Access puts, even if the record is
|
||||
disabled.
|
||||
|
||||
The B<DISA> field contains the value that is compared with DISV to determine
|
||||
if the record is disabled. The value of the DISA field is obtained via SDIS if
|
||||
SDIS is a database or channel access link. If SDIS is not a database or
|
||||
channel access link, then DISA can be set via dbPutField or dbPutLink.
|
||||
|
||||
If the B<PROC> field of a record is written to, the record is processed.
|
||||
The B<DISA> field contains the value that is compared with DISV to determine if
|
||||
the record is disabled. A value is obtained for the DISA field from the B<SDIS>
|
||||
link field before the IOC tries to process the record. If SDIS is not set, DISA
|
||||
may be set by some other method to enable and disable the record.
|
||||
|
||||
The B<DISS> field defines the record's "disable severity". If this field is
|
||||
not NO_ALARM and the record is disabled, the record will be put into alarm
|
||||
with this severity and a status of DISABLE_ALARM.
|
||||
|
||||
If the B<PROC> field of a record is written to, the record is processed.
|
||||
|
||||
The B<LSET> field contains the lock set to which this record belongs. All
|
||||
records linked in any way via input, output, or forward database links belong
|
||||
to the same lock set. Lock sets are determined at IOC initialization time, and
|
||||
@@ -135,15 +135,18 @@ The B<LCNT> field counts the number of times dbProcess finds the record active
|
||||
during successive scans, i.e. PACT is TRUE. If dbProcess finds the record
|
||||
active MAX_LOCK times (currently set to 10) it raises a SCAN_ALARM.
|
||||
|
||||
The B<PACT> field is TRUE while the record is being processed. For
|
||||
The B<PACT> field is TRUE while the record is active (being processed). For
|
||||
asynchronous records PACT can be TRUE from the time record processing is
|
||||
started until the asynchronous completion occurs. As long as PACT is TRUE,
|
||||
dbProcess will not call the record processing routine. See Application
|
||||
Developers Guide for details on usage of PACT.
|
||||
|
||||
The B<FLNK> field is a database link to another record (the "target" record).
|
||||
Processing a record with a specified FLNK field will force processing of the
|
||||
target record, provided the target record's SCAN field is set to C<Passive>.
|
||||
The B<FLNK> field is a link pointing to another record (the "target" record).
|
||||
Processing a record with the FLNK field set will trigger processing of the
|
||||
target record towards the end of processing the first record (but before PACT is
|
||||
cleared), provided the target record's SCAN field is set to C<Passive>. If the
|
||||
FLNK field is a Channel Access link it must point to the PROC field of the
|
||||
target record.
|
||||
|
||||
The B<SPVT> field is for internal use by the scanning system.
|
||||
|
||||
@@ -227,6 +230,8 @@ The B<SPVT> field is for internal use by the scanning system.
|
||||
}
|
||||
field(DISP,DBF_UCHAR) {
|
||||
prompt("Disable putField")
|
||||
promptgroup("10 - Common")
|
||||
interest(1)
|
||||
}
|
||||
field(PROC,DBF_UCHAR) {
|
||||
prompt("Force Processing")
|
||||
@@ -236,35 +241,46 @@ The B<SPVT> field is for internal use by the scanning system.
|
||||
|
||||
=head3 Alarm Fields
|
||||
|
||||
These fields indicate the status and severity of alarms, or else determine the
|
||||
Alarm fields indicate the status and severity of record alarms, or determine
|
||||
how and when alarms are triggered. Of course, many records have alarm-related
|
||||
fields not common to all records. These fields are listed and explained in the
|
||||
fields not common to all records. Those fields are listed and explained in the
|
||||
appropriate section on each record.
|
||||
|
||||
The B<STAT> field contains the current alarm status.
|
||||
|
||||
The B<SEVR> field contains the current alarm severity.
|
||||
|
||||
These two fields are seen outside database access. The B<NSTA> and B<NSEV>
|
||||
fields are used by the database access, record support, and device support
|
||||
routines to set new alarm status and severity values. Whenever any software
|
||||
component discovers an alarm condition, it uses the following macro function:
|
||||
recGblSetSevr(precord,new_status,new_severity) This ensures that the current
|
||||
alarm severity is set equal to the highest outstanding alarm. The file alarm.h
|
||||
defines all allowed alarm status and severity values.
|
||||
The B<AMSG> string field may contain more detailed information about the alarm.
|
||||
|
||||
The STAT, SEVR and AMSG fields hold alarm information as seen outside of the
|
||||
database. The B<NSTA>, B<NSEV> and B<NAMSG> fields are used during record
|
||||
processing by the database access, record support, and device support routines
|
||||
to set new alarm status and severity values and message text. Whenever any
|
||||
software component discovers an alarm condition, it calls one of these routines
|
||||
to register the alarm:
|
||||
|
||||
recGblSetSevr(precord, new_status, new_severity);
|
||||
recGblSetSevrMsg(precord, new_status, new_severity, "Message", ...);
|
||||
|
||||
These check the current alarm severity and update the NSTA, NSEV and NAMSG
|
||||
fields if appropriate so they always relate to the highest severity alarm seen
|
||||
so far during record processing. The file alarm.h defines the allowed alarm
|
||||
status and severity values. Towards the end of record processing these fields
|
||||
are copied into the STAT, SEVR and AMSG fields and alarm monitors triggered.
|
||||
|
||||
The B<ACKS> field contains the highest unacknowledged alarm severity.
|
||||
|
||||
The B<ACKT> field specifies if it is necessary to acknowledge transient
|
||||
The B<ACKT> field specifies whether it is necessary to acknowledge transient
|
||||
alarms.
|
||||
|
||||
The B<UDF> indicates if the record's value is B<U>nB<D>eB<F>ined. Typically
|
||||
this is caused by a failure in device support, the fact that the record has
|
||||
never been processed, or that the VAL field currently contains a NaN (not a
|
||||
number). UDF is initialized to TRUE at IOC initialization. Record and device
|
||||
support routines which write to the VAL field are responsible for setting UDF.
|
||||
The B<UDF> indicates if the record's value is B<U>nB<D>eB<F>ined. Typically this
|
||||
is caused by a failure in device support, the fact that the record has never
|
||||
been processed, or that the VAL field currently contains a NaN (not a number) or
|
||||
Inf (Infinite) value. UDF defaults to TRUE but can be set in a database file.
|
||||
Record and device support routines which write to the VAL field are generally
|
||||
responsible for setting and clearing UDF.
|
||||
|
||||
=fields STAT, SEVR, NSTA, NSEV, ACKS, ACKT, UDF
|
||||
=fields STAT, SEVR, AMSG, NSTA, NSEV, NAMSG, ACKS, ACKT, UDF
|
||||
|
||||
=cut
|
||||
|
||||
@@ -422,9 +438,11 @@ The B<DPVT> field is is for private use of the device support modules.
|
||||
|
||||
=head3 Debugging Fields
|
||||
|
||||
The B<TPRO> field is used for trace processing. If this field is non-zero a
|
||||
message is printed whenever this record is processed, and when any other
|
||||
record in the same lock-set is processed by a database link from this record.
|
||||
The B<TPRO> field can be used to trace record processing. When this field is
|
||||
non-zero and the record is processed, a trace message will be be printed for
|
||||
this record and any other record in the same lock-set that is triggered by a
|
||||
database link from this record. The trace message includes the name of the
|
||||
thread doing the processing, and the name of the record being processed.
|
||||
|
||||
The B<BKPT> field indicates if there is a breakpoint set at this record. This
|
||||
supports setting a debug breakpoint in the record processing. STEP through
|
||||
@@ -435,32 +453,27 @@ database processing can be supported using this.
|
||||
|
||||
=head3 Miscellaneous Fields
|
||||
|
||||
The B<ASG> field contains a character string value defining the access
|
||||
security group for this record. If left empty, the record is placed in group
|
||||
DEFAULT.
|
||||
The B<ASG> string field sets the name of the access security group used for this
|
||||
record. If left empty, the record is placed in group C<DEFAULT>.
|
||||
|
||||
The B<ASP> field is a field for private use of the access security system.
|
||||
The B<ASP> field is private for use by the access security system.
|
||||
|
||||
The B<DISP> field controls dbPutFields to this record which are normally
|
||||
issued by channel access. If the field is set to TRUE all dbPutFields
|
||||
directed to this record are ignored except to the field DISP itself.
|
||||
The B<DISP> field can be set to a non-zero value to reject puts from outside of
|
||||
the IOC (i.e. via Channel Access or PV Access) to any field of the record other
|
||||
than to the DISP field itself. Field changes and record processing can still be
|
||||
instigated from inside the IOC using DB links and the IOC scan mechanisms.
|
||||
|
||||
The B<DTYP> field specifies the device type for the record. Each record type
|
||||
has its own set of device support routines which are specified in
|
||||
devSup.ASCII. If a record type does not have any associated device support,
|
||||
DTYP and DSET are meaningless.
|
||||
The B<DTYP> field specifies the device type for the record. Most record types
|
||||
have their own set of device types which are specified in the IOC's database
|
||||
definition file. If a record type does not call any device support routines,
|
||||
the DTYP and DSET fields are not used.
|
||||
|
||||
The B<MLOK> field contains the monitor lock. The lock used by the monitor
|
||||
routines when the monitor list is being used. The list is locked whenever
|
||||
monitors are being scheduled, invoked, or when monitors are being added to or
|
||||
removed from the list. This field is accessed only by the dbEvent routines.
|
||||
The B<MLOK> field contains a mutex which is locked by the monitor routines in
|
||||
dbEvent.c whenever the monitor list for this record is accessed.
|
||||
|
||||
The B<MLIS> field is the head of the list of monitors connected to this
|
||||
The B<MLIS> field holds a linked list of client monitors connected to this
|
||||
record. Each record support module is responsible for triggering monitors for
|
||||
any fields that change as a result of record processing. Monitors are present
|
||||
if mlis count is greater than zero. The call to trigger monitors is:
|
||||
db_post_event(precord,&data,mask), where "mask" is some combination of
|
||||
DBE_ALARM, DBE_VALUE, and DBE_LOG.
|
||||
any fields that change as a result of record processing.
|
||||
|
||||
The B<PPN> field contains the address of a putNotify callback.
|
||||
|
||||
@@ -474,23 +487,44 @@ The B<RDES> field contains the address of dbRecordType
|
||||
The B<RPRO> field specifies a reprocessing of the record when current
|
||||
processing completes.
|
||||
|
||||
The B<TIME> field contains the time when this record was last processed in
|
||||
standard format.
|
||||
The B<TIME> field holds the time stamp when this record was last processed.
|
||||
|
||||
The B<TSE> field indicates the mechanism to use to get the time stamp. '0' -
|
||||
call get time as before '-1' - call the time stamp driver and use the best
|
||||
source available. '-2' - the device support provides the time stamp from the
|
||||
hardware. Values between 1-255 request the time of the last occurance of a
|
||||
generalTime event.
|
||||
The B<UTAG> field can be used to hold a site-specific 64-bit User Tag value
|
||||
that is associated with the record's time stamp.
|
||||
|
||||
The B<TSE> field value indicates the mechanism to use to get the time stamp:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
C< 0> E<mdash> Get the current time as normal
|
||||
|
||||
=item *
|
||||
|
||||
C<-1> E<mdash> Ask the time stamp driver for its best source of the current time, if
|
||||
available.
|
||||
|
||||
=item *
|
||||
|
||||
C<-2> E<mdash> Device support sets the time stamp and the optional User Tag from the
|
||||
hardware.
|
||||
|
||||
=item *
|
||||
|
||||
Positive values (normally between 1-255) get the time of the last occurance of
|
||||
the numbered generalTime event.
|
||||
|
||||
=back
|
||||
|
||||
The B<TSEL> field contains an input link for obtaining the time stamp. If this
|
||||
link references the .TIME field of a record then the time stamp of the
|
||||
referenced record becomes the time stamp for this record as well. In this
|
||||
case, an internal flag is set and ".TIME" is then overwritten by ".VAL". If
|
||||
any other field is referenced, the field value is read and stored in the .TSE
|
||||
field which is then used to acquire a timestamp.
|
||||
link points to the TIME field of a record then the time stamp and User Tag of
|
||||
that record are copied directly into this record (Channel Access links can only
|
||||
copy the time stamp, not the User Tag). If the link points to any other field,
|
||||
that field's value is read and stored in the TSE field which is then used to
|
||||
provide the time stamp as described above.
|
||||
|
||||
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, TSE, TSEL
|
||||
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, UTAG, TSE, TSEL
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=head1 Fields Common to Input Record Types
|
||||
=title Fields Common to Input Record Types
|
||||
|
||||
This section describes fields that are found in many input record types.
|
||||
These fields usually have the same meaning whenever they are used.
|
||||
@@ -206,3 +206,5 @@ If SIMM is not YES, NO or RAW, a SOFT alarm with a severity of INVALID is
|
||||
raised, and return status is set to -1.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user