Compare commits
170 Commits
merge_7.0.
...
R7.0.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f142e03f5 | ||
|
|
bb7b754730 | ||
|
|
a9ff175cf0 | ||
|
|
458c0af4e9 | ||
|
|
eacee1b548 | ||
|
|
6754404d0f | ||
|
|
6734918e6e | ||
|
|
1c566e2110 | ||
|
|
7f878d3074 | ||
|
|
12ab69402a | ||
|
|
0926f7db0f | ||
|
|
08eaea64d2 | ||
|
|
bee00658ae | ||
|
|
e881cb15c4 | ||
|
|
4a0f488657 | ||
|
|
2340c6e6c1 | ||
|
|
5593103c11 | ||
| 5a8b6e4111 | |||
|
|
c4348dc6e0 | ||
|
|
9d0597fc15 | ||
|
|
93208af61c | ||
|
|
9c23247c04 | ||
|
|
552b2d1766 | ||
|
|
1755a46bfe | ||
|
|
36d0fbd7be | ||
|
|
30e1431fb4 | ||
|
|
3f209efa3c | ||
|
|
2c1c35268e | ||
|
|
745c3f552e | ||
|
|
27918cb7a1 | ||
|
|
8723d4d9cb | ||
|
|
410921b5ef | ||
|
|
d3e96c4c2b | ||
|
|
43bd5ee1c2 | ||
|
|
34a0b387b0 | ||
|
|
78d685688c | ||
|
|
cf3173b6f4 | ||
|
|
c95cbe4a0f | ||
|
|
1e471832e9 | ||
|
|
40d9a21c0c | ||
|
|
dd9f38d711 | ||
|
|
7050bded31 | ||
|
|
c19605232a | ||
|
|
4e81eaa7e8 | ||
|
|
99852c6504 | ||
|
|
a9e3fa74aa | ||
|
|
d997690aa5 | ||
|
|
326ef00bc9 | ||
|
|
a043599e18 | ||
|
|
02be10069e | ||
|
|
4f14e9e674 | ||
|
|
ff4317d05a | ||
|
|
63919e199c | ||
|
|
f775e0b8f6 | ||
|
|
518bab9675 | ||
|
|
a8036d7f34 | ||
|
|
436ce4526b | ||
|
|
b49f06916e | ||
|
|
9ba0081a82 | ||
|
|
c60056d4d6 | ||
|
|
68c056f2f8 | ||
|
|
48a6d2f781 | ||
|
|
79bb9e000b | ||
|
|
c404eb3f83 | ||
|
|
7beb32e209 | ||
|
|
a365de2419 | ||
|
|
035ffdf045 | ||
|
|
5f0d52cd5c | ||
|
|
2035fc641a | ||
|
|
d25c9a74ad | ||
|
|
e20151439b | ||
|
|
4e055610b7 | ||
|
|
db027d4a7f | ||
|
|
17ee7dd6c7 | ||
|
|
dc99d63df8 | ||
|
|
53897d4a82 | ||
|
|
d24a297304 | ||
|
|
761edcae15 | ||
|
|
b890d584bc | ||
|
|
db2f7d8b92 | ||
|
|
d83e3b5de1 | ||
|
|
cbac1c54f5 | ||
|
|
2cfbf5c1c9 | ||
|
|
d108a1ff11 | ||
|
|
0a65707383 | ||
| 9048e998fb | |||
|
|
7632c355ee | ||
|
|
4730e14cc7 | ||
|
|
c969f05f51 | ||
|
|
3947b9a061 | ||
|
|
cf56a0e08e | ||
| 6b5abf76c8 | |||
| 3b3261c877 | |||
| 30d8febb0b | |||
| 4ad98d5b4f | |||
| 14b9ac3277 | |||
| 275c4c7cf4 | |||
| 5d808b7c02 | |||
| afdf34b791 | |||
| ea05bab26a | |||
| edb8f1a5df | |||
| 8f5be5f0ad | |||
| bc34526bcb | |||
| 0ee36388cb | |||
| c51c83b1d5 | |||
| d0ef45acc3 | |||
| 7ab56a68d1 | |||
| 39c8d5619a | |||
| e0dfb6cff8 | |||
| 3627c38a57 | |||
| 17a8dbc2d7 | |||
| b1f445925d | |||
|
|
297f04bddc | ||
|
|
a7bf59079f | ||
|
|
f44f4ac7ad | ||
|
|
f1e83b22f2 | ||
|
|
cdc627a15c | ||
|
|
8a90688880 | ||
|
|
bbdd9392fe | ||
|
|
fe35e6e703 | ||
|
|
f8a6735691 | ||
|
|
dc579b78db | ||
|
|
5f5cc85e28 | ||
|
|
7cc246afc1 | ||
|
|
75b89b40bf | ||
|
|
b34d3c83fc | ||
|
|
c1152f94fd | ||
|
|
8c9e42d15e | ||
|
|
0c800d4428 | ||
|
|
0fca5fc8a9 | ||
|
|
fe177e40fd | ||
|
|
fa4af8b27d | ||
|
|
980711589a | ||
|
|
b2ef47573c | ||
|
|
b0d78921fd | ||
|
|
c00f638f7e | ||
|
|
975e9ec553 | ||
|
|
de2de5e2fd | ||
|
|
a8e0de043c | ||
|
|
549d6f67e3 | ||
|
|
55f4e55383 | ||
|
|
e2256d0663 | ||
|
|
88e0ced03e | ||
|
|
baaf50c6d2 | ||
|
|
97b8df6912 | ||
|
|
98a358437f | ||
|
|
00ac15cec5 | ||
|
|
456e774d85 | ||
|
|
91c5b2fee2 | ||
|
|
ae604b2a55 | ||
|
|
d381a936b5 | ||
| d1491e0860 | |||
| 7709239636 | |||
| a9731b90f6 | |||
| 4368697f58 | |||
| 12cfd418d6 | |||
| e5a48f152a | |||
| 0a1fb25e6b | |||
| 473790124b | |||
| 0353ede517 | |||
| 73b86d4921 | |||
| dec4fc30d9 | |||
| e68e38ad95 | |||
| 3176651c71 | |||
| a42197f0d6 | |||
| f8035d8d5e | |||
| e4dcd3cefd | |||
| c4c13d8ce0 | |||
| 19c50d4c3d | |||
| 8cc20393f1 |
@@ -1,11 +1,5 @@
|
||||
# .appveyor.yml for use with EPICS Base ci-scripts
|
||||
# (see: https://github.com/epics-base/ci-scripts)
|
||||
|
||||
# branches to build
|
||||
branches:
|
||||
# whitelist
|
||||
only:
|
||||
- 7.0
|
||||
# Appveyor configuration file for EPICS Base 7 builds
|
||||
# (see also https://github.com/epics-base/ci-scripts)
|
||||
|
||||
# Version format
|
||||
version: base-{branch}-{build}
|
||||
@@ -35,9 +29,10 @@ clone_depth: 5
|
||||
skip_commits:
|
||||
files:
|
||||
- 'documentation/*'
|
||||
- 'startup/*'
|
||||
- '.github/*'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
- '.travis.yml'
|
||||
|
||||
#---------------------------------#
|
||||
# build matrix configuration #
|
||||
@@ -83,14 +78,17 @@ matrix:
|
||||
CMP: vs2012
|
||||
- platform: x64
|
||||
CMP: vs2010
|
||||
- platform: x64
|
||||
CMP: vs2008
|
||||
# Exclude more jobs to reduce build time
|
||||
# Skip 32-bit for "middle-aged" compilers
|
||||
- platform: x86
|
||||
CMP: vs2017
|
||||
- platform: x86
|
||||
CMP: vs2015
|
||||
# MinGW debug builds use the same libraries, unlike VS
|
||||
- configuration: dynamic-debug
|
||||
CMP: gcc
|
||||
- configuration: static-debug
|
||||
CMP: gcc
|
||||
|
||||
#---------------------------------#
|
||||
# building & testing #
|
||||
@@ -98,18 +96,23 @@ matrix:
|
||||
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive
|
||||
- cmd: pip install git+https://github.com/mdavidsaver/ci-core-dumper#egg=ci-core-dumper
|
||||
- cmd: python .ci/cue.py prepare
|
||||
|
||||
build_script:
|
||||
- cmd: python .ci/cue.py build
|
||||
|
||||
test_script:
|
||||
- cmd: python -m ci_core_dumper install
|
||||
- cmd: python .ci/cue.py test
|
||||
|
||||
on_finish:
|
||||
- ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
- cmd: python .ci/cue.py build test-results -s
|
||||
|
||||
on_failure:
|
||||
- cmd: python -m ci_core_dumper report
|
||||
|
||||
#---------------------------------#
|
||||
# debugging #
|
||||
#---------------------------------#
|
||||
|
||||
150
.appveyor/epics-base-7.yml
Normal file
150
.appveyor/epics-base-7.yml
Normal file
@@ -0,0 +1,150 @@
|
||||
# Appveyor configuration file for EPICS Base 7 builds
|
||||
# (see also https://github.com/epics-base/ci-scripts)
|
||||
|
||||
# branches to build
|
||||
branches:
|
||||
# whitelist
|
||||
only:
|
||||
- 7.0
|
||||
- /R7\.0\.\d+.*/
|
||||
|
||||
# Version format
|
||||
version: base-{branch}-{build}
|
||||
|
||||
#---------------------------------#
|
||||
# build cache #
|
||||
#---------------------------------#
|
||||
# The AppVeyor cache allowance is way too small (1GB per account across all projects, branches and jobs)
|
||||
# to be used for the dependency builds.
|
||||
|
||||
cache:
|
||||
- C:\Users\appveyor\.tools
|
||||
|
||||
#---------------------------------#
|
||||
# repository cloning #
|
||||
#---------------------------------#
|
||||
|
||||
# Called at very beginning, before repo cloning
|
||||
init:
|
||||
# Set autocrlf to make batch files work
|
||||
- git config --global core.autocrlf true
|
||||
|
||||
# Set clone depth (do not fetch complete history)
|
||||
clone_depth: 5
|
||||
|
||||
# Skipping commits affecting only specific files
|
||||
skip_commits:
|
||||
files:
|
||||
- 'documentation/*'
|
||||
- 'startup/*'
|
||||
- '.github/*'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
#---------------------------------#
|
||||
# build matrix configuration #
|
||||
#---------------------------------#
|
||||
|
||||
image: Visual Studio 2015
|
||||
|
||||
# Build Configurations: dll/static, regular/debug
|
||||
configuration:
|
||||
- dynamic
|
||||
- static
|
||||
- dynamic-debug
|
||||
- static-debug
|
||||
|
||||
# Environment variables: compiler toolchain, base version, setup file, ...
|
||||
environment:
|
||||
# common / default variables for all jobs
|
||||
SETUP_PATH: .ci-local:.ci
|
||||
BASE: SELF
|
||||
EPICS_TEST_IMPRECISE_TIMING: YES
|
||||
|
||||
matrix:
|
||||
- CMP: vs2019
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
- CMP: vs2017
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
- CMP: vs2015
|
||||
- CMP: vs2013
|
||||
- CMP: vs2012
|
||||
- CMP: vs2010
|
||||
- CMP: gcc
|
||||
|
||||
# Platform: processor architecture
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
|
||||
# Matrix configuration: exclude sets of jobs
|
||||
matrix:
|
||||
exclude:
|
||||
# VS2012 and older installs don't have the 64 bit compiler
|
||||
- platform: x64
|
||||
CMP: vs2012
|
||||
- platform: x64
|
||||
CMP: vs2010
|
||||
# Exclude more jobs to reduce build time
|
||||
# Skip 32-bit for "middle-aged" compilers
|
||||
- platform: x86
|
||||
CMP: vs2017
|
||||
- platform: x86
|
||||
CMP: vs2015
|
||||
# MinGW debug builds use the same libraries, unlike VS
|
||||
- configuration: dynamic-debug
|
||||
CMP: gcc
|
||||
- configuration: static-debug
|
||||
CMP: gcc
|
||||
|
||||
#---------------------------------#
|
||||
# building & testing #
|
||||
#---------------------------------#
|
||||
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive
|
||||
- cmd: pip install git+https://github.com/mdavidsaver/ci-core-dumper#egg=ci-core-dumper
|
||||
- cmd: python .ci/cue.py prepare
|
||||
|
||||
build_script:
|
||||
- cmd: python .ci/cue.py build
|
||||
|
||||
test_script:
|
||||
- cmd: python -m ci_core_dumper install
|
||||
- cmd: python .ci/cue.py test
|
||||
|
||||
on_finish:
|
||||
- ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
- cmd: python .ci/cue.py build test-results -s
|
||||
|
||||
on_failure:
|
||||
- cmd: python -m ci_core_dumper report
|
||||
|
||||
#---------------------------------#
|
||||
# debugging #
|
||||
#---------------------------------#
|
||||
|
||||
## if you want to connect by remote desktop to a failed build, uncomment these lines
|
||||
## note that you will need to connect within the usual build timeout limit (60 minutes)
|
||||
## so you may want to adjust the build matrix above to just build the one of interest
|
||||
|
||||
# print the connection info
|
||||
#init:
|
||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
# block a failed build (until the watchdog barks)
|
||||
#on_failure:
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
#---------------------------------#
|
||||
# notifications #
|
||||
#---------------------------------#
|
||||
|
||||
notifications:
|
||||
|
||||
- provider: Email
|
||||
to:
|
||||
- core-talk@aps.anl.gov
|
||||
on_build_success: false
|
||||
|
||||
- provider: GitHubPullRequest
|
||||
2
.ci
2
.ci
Submodule .ci updated: 87942a7c29...3db08b5977
152
.github/workflows/ci-scripts-build.yml
vendored
Normal file
152
.github/workflows/ci-scripts-build.yml
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
|
||||
# (see: https://github.com/epics-base/ci-scripts)
|
||||
|
||||
# This is YAML - indentation levels are crucial
|
||||
|
||||
# Workflow name, shared by all branches
|
||||
|
||||
name: Base
|
||||
|
||||
# Trigger on pushes and PRs to any branch
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'documentation/*'
|
||||
- 'startup/*'
|
||||
- '.appveyor/*'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
SETUP_PATH: .ci-local:.ci
|
||||
BASE: SELF
|
||||
EPICS_TEST_IMPRECISE_TIMING: YES
|
||||
|
||||
jobs:
|
||||
build-base:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
# Set environment variables from matrix parameters
|
||||
env:
|
||||
CMP: ${{ matrix.cmp }}
|
||||
BCFG: ${{ matrix.configuration }}
|
||||
WINE: ${{ matrix.wine }}
|
||||
RTEMS: ${{ matrix.rtems }}
|
||||
EXTRA: ${{ matrix.extra }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Job names also name artifacts, character limitations apply
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
wine: "64"
|
||||
name: "Ub-20 gcc-9 + MinGW"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: static
|
||||
wine: "64"
|
||||
name: "Ub-20 gcc-9 + MinGW, static"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: static
|
||||
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||
name: "Ub-20 gcc-9 C++11, static"
|
||||
|
||||
- os: ubuntu-16.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
name: "Ub-16 clang-9"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||
name: "Ub-20 clang-10 C++11"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
rtems: "4.10"
|
||||
name: "Ub-20 gcc-9 + RT-4.10"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
rtems: "4.9"
|
||||
name: "Ub-20 gcc-9 + RT-4.9"
|
||||
|
||||
- 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: clang
|
||||
configuration: default
|
||||
name: "Ub-20 clang-10"
|
||||
|
||||
- os: macos-latest
|
||||
cmp: clang
|
||||
configuration: default
|
||||
name: "MacOS clang-12"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: default
|
||||
name: "Win2019 MSC-19"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: static
|
||||
name: "Win2019 MSC-19, static"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@master
|
||||
- name: "apt-get install"
|
||||
run: |
|
||||
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 }}"
|
||||
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
|
||||
- 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 test
|
||||
- name: Upload tapfiles Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: tapfiles ${{ matrix.name }}
|
||||
path: '**/O.*/*.tap'
|
||||
- name: Collect and show test results
|
||||
run: python .ci/cue.py test-results
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,6 +11,8 @@
|
||||
/modules/Makefile.local
|
||||
O.*/
|
||||
/QtC-*
|
||||
/.vscode/
|
||||
*.orig
|
||||
*.log
|
||||
.*.swp
|
||||
.DS_Store
|
||||
|
||||
91
.travis.yml
91
.travis.yml
@@ -1,91 +0,0 @@
|
||||
# .travis.yml for use with EPICS Base ci-scripts
|
||||
# (see: https://github.com/epics-base/ci-scripts)
|
||||
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
dist: xenial
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache
|
||||
|
||||
env:
|
||||
global:
|
||||
- SETUP_PATH=.ci-local:.ci
|
||||
- BASE=SELF
|
||||
- EPICS_TEST_IMPRECISE_TIMING=YES
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
# for all EPICS builds
|
||||
- libreadline6-dev
|
||||
- libncurses5-dev
|
||||
- perl
|
||||
# for clang compiler
|
||||
- clang
|
||||
# for mingw builds (32bit and 64bit)
|
||||
- g++-mingw-w64-i686
|
||||
- g++-mingw-w64-x86-64
|
||||
# for RTEMS cross builds
|
||||
- qemu-system-x86
|
||||
homebrew:
|
||||
packages:
|
||||
# for all EPICS builds
|
||||
- bash
|
||||
update: true
|
||||
|
||||
install:
|
||||
- ./.ci-local/travis-fixup.sh
|
||||
- python .ci/cue.py prepare
|
||||
|
||||
script:
|
||||
- python .ci/cue.py build
|
||||
- python .ci/cue.py test
|
||||
- python .ci/cue.py test-results
|
||||
|
||||
# Define build jobs
|
||||
|
||||
jobs:
|
||||
include:
|
||||
|
||||
# Different configurations of default gcc and clang
|
||||
- dist: bionic
|
||||
|
||||
- dist: xenial
|
||||
|
||||
- dist: bionic
|
||||
env: BCFG=static EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
|
||||
- dist: trusty
|
||||
env: EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
|
||||
- dist: bionic
|
||||
compiler: clang
|
||||
|
||||
- compiler: clang
|
||||
|
||||
- dist: trusty
|
||||
compiler: clang
|
||||
env: BCFG=static
|
||||
|
||||
# Cross-compilations to Windows using MinGW and WINE
|
||||
|
||||
- env: WINE=32 TEST=NO BCFG=static
|
||||
|
||||
- env: WINE=32 TEST=NO
|
||||
|
||||
# Cross-compilation to RTEMS
|
||||
|
||||
- env: RTEMS=4.10
|
||||
|
||||
- env: RTEMS=4.9
|
||||
|
||||
# MacOS build
|
||||
|
||||
- os: osx
|
||||
env:
|
||||
- EXTRA="CMD_CFLAGS=-mmacosx-version-min=10.7"
|
||||
- EXTRA1="CMD_CXXFLAGS=-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++"
|
||||
- EXTRA2="CMD_LDXFLAGS=-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++"
|
||||
compiler: clang
|
||||
@@ -31,7 +31,7 @@ PROF_CFLAGS_YES = -p
|
||||
GPROF_CFLAGS_YES = -pg
|
||||
CODE_CFLAGS = $(PROF_CFLAGS_$(PROFILE)) $(GPROF_CFLAGS_$(GPROF))
|
||||
CODE_CFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
|
||||
WARN_CFLAGS_YES = -Wall
|
||||
WARN_CFLAGS_YES = -Wall -Werror-implicit-function-declaration
|
||||
WARN_CFLAGS_NO = -w
|
||||
OPT_CFLAGS_YES = -O3
|
||||
OPT_CFLAGS_NO = -g
|
||||
|
||||
@@ -64,10 +64,15 @@ DEPCLEAN = $(call FIND_TOOL,depclean.pl)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Tools for testing
|
||||
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
|
||||
PROVE = $(PERL) $(TOOLS)/epicsProve.pl
|
||||
PROVE.tap = $(PROVE) --ext .tap --exec "$(CAT)"
|
||||
TAPS_FAILED_LOG = .taps-failed.log
|
||||
TESTS_FAILED_LOG = .tests-failed.log
|
||||
TESTS_FAILED_PATH = $(abspath $(TOP)/$(TESTS_FAILED_LOG))
|
||||
|
||||
TEST_FAILURE_FILENAME = .tests-failed.log
|
||||
TEST_FAILURE_FILE = $(TOP)/$(TEST_FAILURE_FILENAME)
|
||||
PROVE_FAILURE = echo $(abspath .)>> $(TEST_FAILURE_FILE)
|
||||
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
|
||||
PROVE = $(PERL) $(TOOLS)/epicsProve.pl --failures --color
|
||||
PROVE.tap = $(PROVE) --ext .tap --exec "$(CAT)"
|
||||
TESTFAILURES = $(PERL) $(TOOLS)/testFailures.pl
|
||||
SHOWTESTFAILURES = $(TESTFAILURES) $(TESTS_FAILED_PATH) $(TAPS_FAILED_LOG)
|
||||
|
||||
PROVE_FAILURE = echo $(abspath .)>> $(TESTS_FAILED_PATH)
|
||||
TAPFILE_FAILURE = echo $@>> $(TAPS_FAILED_LOG)
|
||||
|
||||
@@ -48,15 +48,15 @@ EPICS_VERSION = 7
|
||||
EPICS_REVISION = 0
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 4
|
||||
EPICS_MODIFICATION = 5
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included in the official EPICS version number if zero
|
||||
EPICS_PATCH_LEVEL = 2
|
||||
EPICS_PATCH_LEVEL = 0
|
||||
|
||||
# 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=-DEV
|
||||
EPICS_DEV_SNAPSHOT=
|
||||
|
||||
# No changes should be needed below here
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ EPICS_CA_MAINTENANCE_VERSION = 8
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 1
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -80,12 +80,12 @@ IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
|
||||
#-------------------------------------------------------
|
||||
# Silencing the build - suppress messages during 'make -s'
|
||||
NOP = :
|
||||
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(findstring s,$(MFLAGS)),-q,)
|
||||
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(filter -s,$(MFLAGS)),-q,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
|
||||
QUESTION_FLAG := $(if $(findstring q,$(MFLAGS)),-i,)
|
||||
QUESTION_FLAG := $(if $(filter -q,$(MFLAGS)),-i,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
ifdef T_A
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Version number for the database APIs and shared library
|
||||
|
||||
EPICS_DATABASE_MAJOR_VERSION = 3
|
||||
EPICS_DATABASE_MINOR_VERSION = 18
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 2
|
||||
EPICS_DATABASE_MINOR_VERSION = 19
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 0
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Version number for the libcom APIs and shared library
|
||||
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 18
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 2
|
||||
EPICS_LIBCOM_MINOR_VERSION = 19
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 0
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -32,12 +32,12 @@ vpath %.l $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
include $(CONFIG)/CONFIG_ADDONS
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Set PROD, TESTPROD, OBJS, and LIBRARY
|
||||
|
||||
SCRIPTS_HOST += $(PERL_SCRIPTS)
|
||||
# PERL_SCRIPTS are installed into existing $(INSTALL_BIN) for Host systems
|
||||
|
||||
ifeq ($(findstring Host,$(VALID_BUILDS)),Host)
|
||||
# Host targets can compile and run programs
|
||||
ifneq (,$(findstring Host,$(VALID_BUILDS)))
|
||||
LIBRARY += $(LIBRARY_HOST)
|
||||
LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_HOST)
|
||||
OBJS += $(OBJS_HOST)
|
||||
@@ -49,7 +49,21 @@ TESTSCRIPTS += $(TESTSCRIPTS_HOST)
|
||||
TESTPROD += $(TESTPROD_HOST)
|
||||
endif
|
||||
|
||||
ifeq ($(findstring Ioc,$(VALID_BUILDS)),Ioc)
|
||||
# Command targets have a command line and support main()
|
||||
ifneq (,$(findstring Command,$(VALID_BUILDS)))
|
||||
LIBRARY += $(LIBRARY_CMD)
|
||||
LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_CMD)
|
||||
OBJS += $(OBJS_CMD)
|
||||
PROD += $(PROD_CMD)
|
||||
SCRIPTS += $(SCRIPTS_CMD)
|
||||
TARGETS += $(TARGETS_CMD)
|
||||
TESTLIBRARY += $(TESTLIBRARY_CMD)
|
||||
TESTSCRIPTS += $(TESTSCRIPTS_CMD)
|
||||
TESTPROD += $(TESTPROD_CMD)
|
||||
endif
|
||||
|
||||
# Ioc targets can run IOCs
|
||||
ifneq (,$(findstring Ioc,$(VALID_BUILDS)))
|
||||
LIBRARY += $(LIBRARY_IOC)
|
||||
LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_IOC)
|
||||
OBJS += $(OBJS_IOC)
|
||||
@@ -358,7 +372,8 @@ runtests: run-tap-tests
|
||||
run-tap-tests: $(TESTSCRIPTS.t)
|
||||
ifneq ($(TESTSCRIPTS.t),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(PROVE) --failures --color $^ || $(PROVE_FAILURE)
|
||||
$(ECHO) "$(PROVE) $^"
|
||||
@$(PROVE) $^ || $(PROVE_FAILURE)
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -369,7 +384,8 @@ test-results: tap-results
|
||||
tap-results: $(TAPFILES)
|
||||
ifneq ($(strip $(TAPFILES)),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(PROVE.tap) --failures --color $^ || $(PROVE_FAILURE)
|
||||
$(ECHO) "$(PROVE.tap) $^"
|
||||
@$(PROVE.tap) $^ || $(PROVE_FAILURE)
|
||||
endif
|
||||
|
||||
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
|
||||
@@ -377,8 +393,8 @@ CURRENT_JUNITFILES := $(wildcard $(JUNITFILES))
|
||||
endif
|
||||
|
||||
clean-tests:
|
||||
ifneq ($(CURRENT_TAPFILES),)
|
||||
$(RM) $(CURRENT_TAPFILES)
|
||||
ifneq ($(CURRENT_TAPFILES)$(TAPS_FAILED_LOG),)
|
||||
$(RM) $(CURRENT_TAPFILES) $(TAPS_FAILED_LOG)
|
||||
endif
|
||||
ifneq ($(CURRENT_JUNITFILES),)
|
||||
$(RM) $(CURRENT_JUNITFILES)
|
||||
@@ -387,7 +403,8 @@ endif
|
||||
# A .tap file is the output from running the associated test script
|
||||
$(TAPFILES.t): %.tap: %.t
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(PERL) $< -tap > $@
|
||||
$(ECHO) "$(PERL) $< -tap > $@"
|
||||
@$(PERL) $< -tap > $@ || $(TAPFILE_FAILURE)
|
||||
endif
|
||||
|
||||
$(JUNITFILES.t): %-results.xml: %.tap
|
||||
|
||||
@@ -86,8 +86,10 @@ expand_clean:
|
||||
ASSEMBLE_TOOL ?= $(PERL) $(TOOLS)/assembleSnippets.pl
|
||||
|
||||
define COMMON_ASSEMBLY_template
|
||||
ifneq '$$($1_PATTERN)' ''
|
||||
$1_SNIPPETS += $$(foreach dir, .. $$(SRC_DIRS), \
|
||||
$$(wildcard $$(dir)/$$($1_PATTERN)))
|
||||
endif
|
||||
$(COMMON_DIR)/$1: $$($1_SNIPPETS)
|
||||
$(ECHO) "Assembling common file $$@ from snippets"
|
||||
@$(RM) $1
|
||||
@@ -98,8 +100,10 @@ $(foreach asy, $(COMMON_ASSEMBLIES), \
|
||||
$(eval $(call COMMON_ASSEMBLY_template,$(strip $(asy)))))
|
||||
|
||||
define ASSEMBLY_template
|
||||
ifneq '$$($1_PATTERN)' ''
|
||||
$1_SNIPPETS += $$(foreach dir, .. $$(SRC_DIRS), \
|
||||
$$(wildcard $$(dir)/$$($1_PATTERN)))
|
||||
endif
|
||||
$1: $$($1_SNIPPETS)
|
||||
$(ECHO) "Assembling file $$@ from snippets"
|
||||
@$(RM) $$@
|
||||
|
||||
@@ -47,14 +47,9 @@ realclean:
|
||||
|
||||
.PHONY: RELEASE.host realclean
|
||||
|
||||
# Append all our live submodule failure files
|
||||
FAILURE_FILES = $(addsuffix /$(TEST_FAILURE_FILENAME), $(LIVE_SUBMODULES))
|
||||
|
||||
define combine_failure_files
|
||||
@$(TOUCH) $(FAILURE_FILES)
|
||||
@$(CAT) $(FAILURE_FILES) >> $(TEST_FAILURE_FILE)
|
||||
endef
|
||||
runtests: | $(addsuffix $(DIVIDER)runtests, $(LIVE_SUBMODULES))
|
||||
$(if $(FAILURE_FILES), $(combine_failure_files))
|
||||
test-results: | $(addsuffix $(DIVIDER)test-results, $(LIVE_SUBMODULES))
|
||||
$(if $(FAILURE_FILES), $(combine_failure_files))
|
||||
# Testing: Combine test failure logs from the live submodules
|
||||
TESTS_FAILED_LOGS = $(wildcard $(addsuffix /$(TESTS_FAILED_LOG), \
|
||||
$(LIVE_SUBMODULES)))
|
||||
runtests test-results: % : | $(addsuffix $(DIVIDER)%, $(LIVE_SUBMODULES))
|
||||
$(if $(TESTS_FAILED_LOGS), \
|
||||
@$(CAT) $(TESTS_FAILED_LOGS)>> $(TESTS_FAILED_PATH))
|
||||
|
||||
@@ -50,8 +50,9 @@ uninstall$(DIVIDER)%: | clean
|
||||
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
|
||||
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))
|
||||
|
||||
# Only run this at the top of the parent
|
||||
runtests test-results:
|
||||
@$(PERL) $(TOOLS)/testFailures.pl $(TEST_FAILURE_FILE)
|
||||
@$(SHOWTESTFAILURES)
|
||||
|
||||
else
|
||||
#
|
||||
@@ -63,10 +64,10 @@ else
|
||||
|
||||
endif # DISABLE_TOP_RULES
|
||||
|
||||
# Clean out old results
|
||||
before-runtests before-test-results: rm-failure-file
|
||||
rm-failure-file:
|
||||
@$(RM) $(TEST_FAILURE_FILE)
|
||||
@$(TOUCH) $(TEST_FAILURE_FILE)
|
||||
$(RM) $(TESTS_FAILED_PATH)
|
||||
|
||||
help:
|
||||
@echo "Usage: gnumake [options] [target] ..."
|
||||
|
||||
@@ -76,7 +76,7 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
|
||||
|
||||
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
|
||||
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Although RTEMS uses gcc, it wants to use gcc its own way
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Unix valid build types
|
||||
VALID_BUILDS = Host Ioc
|
||||
VALID_BUILDS = Host Ioc Command
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Unix prefix and suffix definitions
|
||||
|
||||
14
configure/os/CONFIG.Common.darwin-aarch64
Normal file
14
configure/os/CONFIG.Common.darwin-aarch64
Normal file
@@ -0,0 +1,14 @@
|
||||
# CONFIG.Common.darwin-aarch64
|
||||
#
|
||||
# This file is maintained by the build community.
|
||||
#
|
||||
# Definitions for darwin-aarch64 target builds
|
||||
# Sites may override these definitions in CONFIG_SITE.Common.darwin-aarch64
|
||||
#-------------------------------------------------------
|
||||
|
||||
#
|
||||
# To build universal binaries, configure ARCH_CLASS
|
||||
# in the file CONFIG_SITE.Common.darwin-aarch64
|
||||
|
||||
# Include definitions common to all Darwin targets
|
||||
include $(CONFIG)/os/CONFIG.darwinCommon.darwinCommon
|
||||
@@ -12,7 +12,7 @@ include $(CONFIG)/os/CONFIG.Common.linux-x86
|
||||
ARCH_DEP_CFLAGS = -march=i386
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
endif
|
||||
|
||||
# If your crosscompiler name has a GNU target prefix like <gnutarget>-gcc,
|
||||
|
||||
@@ -10,7 +10,7 @@ include $(CONFIG)/os/CONFIG.Common.linux-x86
|
||||
ARCH_DEP_CFLAGS = -march=i486
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
endif
|
||||
|
||||
# If your crosscompiler name has a GNU target prefix like <gnutarget>-gcc,
|
||||
|
||||
@@ -11,7 +11,7 @@ include $(CONFIG)/os/CONFIG.Common.linux-x86
|
||||
ARCH_DEP_CFLAGS = -march=i586
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
endif
|
||||
|
||||
# If your crosscompiler name has a GNU target prefix like <gnutarget>-gcc,
|
||||
|
||||
@@ -11,7 +11,7 @@ include $(CONFIG)/os/CONFIG.Common.linux-x86
|
||||
ARCH_DEP_CFLAGS = -march=i686
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
endif
|
||||
|
||||
# If your crosscompiler name has a GNU target prefix like <gnutarget>-gcc,
|
||||
|
||||
@@ -10,7 +10,7 @@ include $(CONFIG)/os/CONFIG.Common.linux-x86
|
||||
ARCH_DEP_CFLAGS += -march=athlon-mp -mfpmath=sse
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
endif
|
||||
|
||||
# If your crosscompiler name has a GNU target prefix like <gnutarget>-gcc,
|
||||
|
||||
@@ -15,7 +15,7 @@ include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
ARCH_CLASS = microblaze
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
GNU_TARGET = microblazeel-unknown-linux-gnu
|
||||
CMPLR_PREFIX = $(addsuffix -,$(GNU_TARGET))
|
||||
endif
|
||||
|
||||
@@ -13,7 +13,7 @@ include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
ARCH_CLASS = xscale
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
GNU_TARGET = xscale_be
|
||||
CMPLR_PREFIX = $(GNU_TARGET:%=%-)
|
||||
|
||||
|
||||
8
configure/os/CONFIG.darwin-aarch64.Common
Normal file
8
configure/os/CONFIG.darwin-aarch64.Common
Normal file
@@ -0,0 +1,8 @@
|
||||
# CONFIG.darwin-aarch64.Common
|
||||
#
|
||||
# Definitions for darwin-aarch64 host builds
|
||||
# Sites may override these definitions in CONFIG_SITE.darwin-aarch64.Common
|
||||
#-------------------------------------------------------
|
||||
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
@@ -4,7 +4,7 @@
|
||||
# Override these settings in CONFIG_SITE.linux-x86.linux-arm
|
||||
#-------------------------------------------------------
|
||||
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
GNU_TARGET = arm-linux
|
||||
|
||||
# prefix of compiler tools
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Sites may override these in CONFIG_SITE.linux-x86_64.linux-aarch64
|
||||
#-------------------------------------------------------
|
||||
|
||||
VALID_BUILDS = Ioc
|
||||
VALID_BUILDS = Ioc Command
|
||||
GNU_TARGET = aarch64-linux
|
||||
|
||||
# prefix of compiler tools
|
||||
|
||||
@@ -26,6 +26,3 @@ endif
|
||||
|
||||
# Needed to find dlls for base installed build tools (antelope,eflex,...)
|
||||
PATH := $(EPICS_BASE_BIN):$(PATH)
|
||||
|
||||
# Silence the tr1 namespace deprecation warnings
|
||||
USR_CXXFLAGS_WIN32 += -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
# Win32 valid build types and include directory suffixes
|
||||
|
||||
VALID_BUILDS = Host Ioc
|
||||
VALID_BUILDS = Host Ioc Command
|
||||
|
||||
CMPLR_CLASS = msvc
|
||||
|
||||
@@ -107,6 +107,9 @@ CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
|
||||
WARN_CXXFLAGS_YES = -W3 -w44355 -w44344 -w44251
|
||||
WARN_CXXFLAGS_NO = -W1
|
||||
|
||||
# Silence tr1 namespace deprecation warnings
|
||||
WARN_CXXFLAGS += -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING
|
||||
|
||||
#
|
||||
# -Ox maximum optimizations
|
||||
# -GL whole program optimization
|
||||
|
||||
9
configure/os/CONFIG_SITE.Common.darwin-aarch64
Normal file
9
configure/os/CONFIG_SITE.Common.darwin-aarch64
Normal file
@@ -0,0 +1,9 @@
|
||||
# CONFIG_SITE.Common.darwin-aarch64
|
||||
#
|
||||
# Site override definitions for darwin-aarch64 target builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
#
|
||||
# arm64 devices: Apple Silicon M1
|
||||
|
||||
ARCH_CLASS = arm64
|
||||
@@ -1,6 +1,6 @@
|
||||
# Installation Instructions {#install}
|
||||
|
||||
## EPICS Base Release 7.0.4.1
|
||||
## EPICS Base Release 7.0.5
|
||||
|
||||
-----
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
- [Supported platforms](#0_0_4)
|
||||
- [Supported compilers](#0_0_5)
|
||||
- [Software requirements](#0_0_6)
|
||||
- [Host system storage requirements](#0_0_7)
|
||||
- [Documentation](#0_0_8)
|
||||
- [Directory Structure](#0_0_10)
|
||||
- [Build related components](#0_0_11)
|
||||
@@ -39,7 +38,7 @@ interfaces) of various types.
|
||||
Please check the `RELEASE_NOTES` file in the distribution for
|
||||
description of changes and release migration details.
|
||||
|
||||
### <span id="0_0_3">Copyright</span>
|
||||
### <span id="0_0_3">Copyright Licenses</span>
|
||||
|
||||
Please review the LICENSE file included in the distribution for legal
|
||||
terms of usage.
|
||||
@@ -68,10 +67,10 @@ path to do EPICS builds; check the definitions of CC and CCC in
|
||||
|
||||
**GNU make**
|
||||
You must use GNU make, gnumake, for any EPICS builds. Set your path so
|
||||
that a gnumake version 3.81 or later is available.
|
||||
that a gnumake version 4.1 or later is available.
|
||||
|
||||
**Perl**
|
||||
You must have Perl version 5.8.1 or later installed. The EPICS
|
||||
You must have Perl version 5.10 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.
|
||||
|
||||
@@ -114,13 +113,6 @@ installed on linux-x86. Command-line editing and history will then be
|
||||
those supplied by the os. On vxWorks the ledLib command-line input
|
||||
library is used instead.
|
||||
|
||||
### <span id="0_0_7">Host system storage requirements</span>
|
||||
|
||||
The compressed tar file is approximately 1.6 MB in size. The
|
||||
distribution source tree takes up approximately 12 MB. Each host
|
||||
target will need around 40 MB for build files, and each cross-compiled
|
||||
target around 20 MB.
|
||||
|
||||
### <span id="0_0_8">Documentation</span>
|
||||
|
||||
EPICS documentation is available through the [EPICS
|
||||
@@ -242,17 +234,13 @@ Before you can build or use this EPICS base, the environment variable
|
||||
the base/startup directory has been provided to help set
|
||||
`EPICS_HOST_ARCH.` You should have `EPICS_HOST_ARCH` set to your
|
||||
host operating system followed by a dash and then your host
|
||||
architecture, e.g. solaris-sparc. If you are not using the OS
|
||||
architecture, e.g. linux-x86_64. If you are not using the OS
|
||||
vendor's c/c++ compiler for host builds, you will need another dash
|
||||
followed by the alternate compiler name (e.g. "-gnu" for GNU c/c++
|
||||
compilers on a solaris host or "-mingw" for MinGW c/c++ compilers on
|
||||
a WIN32 host). See `configure/CONFIG_SITE` for a list of supported
|
||||
Windows). See `configure/CONFIG_SITE` for a list of supported
|
||||
`EPICS_HOST_ARCH` values.
|
||||
|
||||
* `PERLLIB`
|
||||
On WIN32, some versions of Perl require that the environment
|
||||
variable PERLLIB be set to <perl directory location>.
|
||||
|
||||
* `PATH`
|
||||
As already mentioned, you must have the perl executable and you may
|
||||
need C and C++ compilers in your search path. For building base you
|
||||
|
||||
@@ -11,24 +11,269 @@ 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.**
|
||||
## EPICS Release 7.0.5
|
||||
|
||||
## Changes made on the 7.0 branch since 7.0.4.1
|
||||
### Fix aai's Device Support Initialization
|
||||
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
Krisztian Loki [reported](https://github.com/epics-base/epics-base/issues/97)
|
||||
segfaults occurring when a Soft Channel aai record INP field was a DB link to
|
||||
an array field of a compress record. This was caused by the aai record's
|
||||
pass-0 device support initialization clashing with the semantics of the new
|
||||
link support API.
|
||||
|
||||
The aai record
|
||||
[has been modified](https://github.com/epics-base/epics-base/pull/114) to
|
||||
allow the Soft Channel device support to request a pass-1 initialization
|
||||
callback. See the Device Support section of the Array Analogue Input Record
|
||||
Reference pages in this release for the API changes, which are fully backwards
|
||||
compatible for existing aai device support.
|
||||
|
||||
### Prevent default DTYPs from changing
|
||||
|
||||
[Kay Kasemir reported](https://bugs.launchpad.net/epics-base/+bug/1908305) that
|
||||
it is possible to change the Base record type's default DTYP if a `device()`
|
||||
entry is seen before the `recordtype()` definition to which it refers. The
|
||||
default DTYP is the first device loaded, which is normally the `Soft Channel`
|
||||
support from Base. A warning was being displayed by dbdExpand when a `device()`
|
||||
entry was see first, but that was easily missed.
|
||||
|
||||
The DBD file parser in dbdExpand.pl has now been modified to make this an error,
|
||||
although the registerRecordDeviceDriver.pl script will still accept `device()`
|
||||
entries without having their `recordtype()` loaded since this is necessary to
|
||||
compile device supports as loadable modules.
|
||||
|
||||
|
||||
### Priority inversion safe Posix mutexes
|
||||
|
||||
On Posix systems, epicsMutex now support priority inheritance if available.
|
||||
The IOC needs to run with SCHED_FIFO engaged to use these.
|
||||
Support for Posix implementations before POSIX.1-2001 (`_XOPEN_SOURCE < 500`,
|
||||
glibc version < 2.3.3) has been dropped.
|
||||
|
||||
The IOC shell's `epicsMutexShowAll` command prints "PI is enabled" if both
|
||||
libc and kernel support is present.
|
||||
|
||||
### Fix for Periodic Scan threads hanging on Windows
|
||||
|
||||
Since 7.0.3.1 a Windows IOC could not run for more than 49.7 days; at that
|
||||
time the periodic scan threads would stop processing. This issue should now
|
||||
have been fixed and the Monotonic time functions on Windows should return
|
||||
values which count at nanosecond resolution. However we have not waited 49.7
|
||||
days to test the final software, so there is a small chance that it's still
|
||||
broken.
|
||||
|
||||
This fixes [lauchpad bug #1896295](https://bugs.launchpad.net/bugs/1896295).
|
||||
|
||||
### Support for Apple M1 (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`.
|
||||
|
||||
It should also be possible to build universal binaries containing code for
|
||||
both the Intel and arm64 processors under either target name: In the
|
||||
appropriate `configure/os/CONFIG_SITE.Common.darwin-*` file add the other
|
||||
architecture class name to the `ARCH_CLASS` variable (after a space).
|
||||
|
||||
### New String Comparison Routine `epicsStrSimilarity()`
|
||||
|
||||
The new `epicsStrSimilarity()` routine in epicsString.h uses a modified
|
||||
Levenshtein distance to compare two strings, with a character case difference
|
||||
being half the weight of a full substitution. The double return value falls in
|
||||
the range 0.0 (identical) through 1.0 (no characters matching), or -1.0 for
|
||||
error. This is used to provide a new "Did you mean ..." suggestion when a .db
|
||||
file provides an invalid choice string for a `DBF_MENU` or `DBF_DEVICE` field.
|
||||
|
||||
### Build System: New `VALID_BUILDS` type "Command"
|
||||
|
||||
Target architectures that support command-line programs that run the `main()`
|
||||
routine can now be marked as such in their `VALID_BUILDS` definition. This
|
||||
enables a new set of Makefile target variables `PROD_CMD` (similar to
|
||||
`PROD_HOST`), `LIBRARY_CMD` (like `LIBRARY_HOST`, etc.), `LOADABLE_LIBRARY_CMD`,
|
||||
`OBJS_CMD`, `SCRIPTS_CMD`, `TARGETS_CMD`, `TESTLIBRARY_CMD`, `TESTSCRIPTS_CMD`
|
||||
and `TESTPROD_CMD`. The CA client tools and programs such as `caRepeater` are now built for all such targets (previously they were built for all targets except where the OS was VxWorks, RTEMS and iOS).
|
||||
|
||||
If you have created your own site-specific target architectures you may need to
|
||||
update the `VALID_BUILDS` variable if it gets set in your locally added
|
||||
`configure/os/CONFIG.Common.<arch>` files. This is usually only needed for
|
||||
cross-compiled targets though since `CONFIG.Common.UnixCommon` sets it.
|
||||
|
||||
The other `VALID_BUILDS` types are "Host" for target architectures that can
|
||||
compile and run their own programs (`PROD_HOST` etc.), and "Ioc" for targets
|
||||
that can run IOCs (`PROD_IOC` etc.).
|
||||
|
||||
### Support for JSON5
|
||||
|
||||
The YAJL parser and generator routines in libcom and in the IOC's dbStatic
|
||||
parser now support the JSON5 standard. This adds various features to JSON
|
||||
without altering the API for the code other than adding a new option to the
|
||||
YAJL parser which can be used to disable JSON5 support if desired. The new
|
||||
features include:
|
||||
|
||||
- The ability to handle numeric values `Infinity`, `-Infinity` and `NaN`.
|
||||
- String values and map keys may be enclosed in single quotes `'`, inside which
|
||||
the double-quote character `"` doesn't have to be escaped with a back-slash
|
||||
`\`, although a single-quote character `'` (or apostrophy) must be escaped
|
||||
inside a single-quoted string.
|
||||
- Numbers may start with a plus sign, `+`.
|
||||
- Integers may be expressed in hexadecimal with a leading `0x` or `0X`.
|
||||
- Floating-point numbers may start or end with their decimal point `.`
|
||||
(after the sign or before the exponent respectively if present).
|
||||
- Map keys that match the regex `[A-Za-z_][A-Za-z_0-9]*` don't have to be
|
||||
enclosed in quotes at all. The dbStatic parser adds `.+-` to the characters
|
||||
allowed but will add quotes around such keys before passing them to YAJL.
|
||||
- Arrays and maps allow a comma before the closing bracket/brace character.
|
||||
- The YAJL parser will elide a backslash followed by a newline characters from
|
||||
a string value. The dbStatic parser doesn't allow that however.
|
||||
|
||||
Code that must also compile against the older API can use the new C macro
|
||||
`HAS_JSON5` to detect the new version. This macro is defined on including
|
||||
either the `yajl_parse.h` or `yajl_gen.h` headers, which also provide the
|
||||
new configuration options to turn on JSON5 support.
|
||||
|
||||
All APIs in the IOC that previously accepted JSON will now accept JSON5.
|
||||
This includes JSON field modifiers (channel filters), JSON link addresses,
|
||||
constant input link array values and database info-tag values. JSON values
|
||||
that get parsed by the dbLoadRecords() routine are still more liberal than
|
||||
the other uses as the ability to use unquoted strings that was called
|
||||
"relaxed JSON" is still supported, whereas the JSON5 standard and the YAJL
|
||||
parser only allow unquoted strings to be used for keys in a JSON map.
|
||||
|
||||
This also fixes [lauchpad bug #1714455](https://bugs.launchpad.net/bugs/1714455).
|
||||
|
||||
|
||||
### Character Escape Changes
|
||||
|
||||
- The libCom routines `epicsStrnRawFromEscaped()` and `dbTranslateEscape()`
|
||||
declared in epicsString.h no longer accept octal escaped characters such as
|
||||
`\123` or `\41`.
|
||||
- The routine `epicsStrnEscapedFromRaw()` now generates hex
|
||||
excaped characters for unprintable characters such as `\x1f`.
|
||||
- Hex escape character sequences `\xXX` must now contain exactly 2 hex digits.
|
||||
- An escape sequence `\0` now generates a zero byte in the raw string, but the
|
||||
other digits `1-9` should not appear after a back-slash.
|
||||
|
||||
These changes are to more closely follow the JSON5 standard, which doesn't
|
||||
support octal character escapes or the `\a` (Bel, `\x07`) escape sequence.
|
||||
|
||||
### Filters in database input links
|
||||
|
||||
Input database links can now use channel filters, it is not necessary to
|
||||
make them CA links for the filters to work.
|
||||
|
||||
### ai Soft Channel support
|
||||
|
||||
The Soft Channel device support for ai records now returns failure when
|
||||
fetching the INP link fails.
|
||||
|
||||
### Support for zero-length arrays
|
||||
|
||||
Several modifications have been made to properly support zero-length
|
||||
array values inside the IOC and over Channel Access. Some of these changes
|
||||
may affect external code that interfaces with the IOC, either directly or
|
||||
over the CA client API so we recommend thorough testing of any external
|
||||
code that handles array fields when upgrading to this release.
|
||||
|
||||
Since these changes affect the Channel Access client-side API they will
|
||||
require rebuilding any CA Gateways against this version or Base to
|
||||
properly handle zero-length arrays. The `caget`, `caput` and `camonitor`
|
||||
client programs are known to work with empty arrays as long as they were
|
||||
built with this or a later version of EPICS.
|
||||
|
||||
#### Change to the db_access.h `dbr_size_n(TYPE, COUNT)` macro
|
||||
|
||||
When called with COUNT=0 this macro no longer returns the number of bytes
|
||||
required for a scalar (1 element) but for an empty array (0 elements).
|
||||
Make sure code that uses this doesn't call it with COUNT=0 when it really
|
||||
means COUNT=1.
|
||||
|
||||
Note that the db_access.h header file is included by cadef.h so the change
|
||||
can impact Channel Access client programs that use this macro.
|
||||
|
||||
#### Channel Access support for zero-length arrays
|
||||
|
||||
The `ca_array_put()` and `ca_array_put_callback()` routines now accept an
|
||||
element count of zero, and will write a zero-length array to the PV if
|
||||
possible. No error will be raised if the target is a scalar field though,
|
||||
and the field's value will not be changed.
|
||||
|
||||
The `ca_array_get_callback()` and `ca_create_subscription()` routines
|
||||
still accept a count of zero to mean fetch as many elements as the PV
|
||||
currently holds.
|
||||
|
||||
Client programs should be prepared for the `count` fields of any
|
||||
`struct event_handler_args` or `struct exception_handler_args` passed to
|
||||
their callback routines to be zero.
|
||||
|
||||
#### Array records
|
||||
|
||||
The soft device support for the array records aai, waveform, and subArray
|
||||
as well as the aSub record type now correctly report reading 0 elements
|
||||
when getting an empty array from an input link.
|
||||
|
||||
#### Array support for dbpf
|
||||
|
||||
The dbpf command now accepts array values, including empty arrays, when
|
||||
provided as a JSON string. This must be enclosed in quotes so the iocsh
|
||||
argument parser sees the JSON as a single argument:
|
||||
|
||||
```
|
||||
epics> dbpf wf10:i32 '[1, 2, 3, 4, 5]'
|
||||
DBF_LONG[5]: 1 = 0x1 2 = 0x2 3 = 0x3 4 = 0x4 5 = 0x5
|
||||
```
|
||||
|
||||
#### Reading empty arrays as scalar values
|
||||
|
||||
Record links that get a scalar value from an array that is currently
|
||||
empty will cause the record that has the link field to be set to an
|
||||
`INVALID/LINK` alarm status.
|
||||
The record code must call `dbGetLink()` with `pnRequest=NULL` for it to
|
||||
be recognized as a request for a scalar value though.
|
||||
|
||||
This changes the semantics of passing `pnRequest=NULL` to `dbGetLink()`,
|
||||
which now behaves differently than passing it a pointer to a long integer
|
||||
containing the value 1, which was previously equivalent.
|
||||
The latter can successfully fetch a zero-element array without triggering
|
||||
a LINK alarm.
|
||||
|
||||
#### Writing empty arrays to scalar fields
|
||||
|
||||
Record links that put a zero-element array into a scalar field will now set
|
||||
the target record to `INVALID/LINK` alarm without changing the field's value.
|
||||
Previously the field was set to 0 in this case (with no alarm).
|
||||
The target field must be marked as `special(SPC_DBADDR)` to be recognized
|
||||
as an array field, and its record support must define a `put_array_info()`
|
||||
routine.
|
||||
|
||||
### Timestamp before processing output links
|
||||
|
||||
The record processing code for records with output links has been modified to
|
||||
update the timestamp via recGblGetTimeStamp() _before_ processing the output
|
||||
links. This ensures that other records which get processed via an output link
|
||||
can use TSEL links to fetch the timestamp corresponding to the data processed
|
||||
by the output link.
|
||||
|
||||
This change could result in a slightly earlier timestamp for records whose
|
||||
output link is handled by a device driver, but only if the device driver does
|
||||
not handle its own timestamping via TSE -2 and instead uses TSE 0 or TSE -1 to
|
||||
get current time or best time, and the time spent in the device driver is
|
||||
greater than your timestamp provider resolution. For these situations it is
|
||||
recommended to set TSE to -2 and set the timestamp in the driver code.
|
||||
|
||||
### Add registerAllRecordDeviceDrivers()
|
||||
|
||||
Addition of registerAllRecordDeviceDrivers() as an iocsh function
|
||||
and in iocshRegisterCommon.h. This function uses dynamic lookup with epicsFindSymbol()
|
||||
to perform the same function as a generated \*_registerRecordDeviceDriver() function.
|
||||
This allows dynamic loading/linking of support modules without code generation.
|
||||
A new iocsh command `registerAllRecordDeviceDrivers` is provided and also
|
||||
defined as a function in iocshRegisterCommon.h. This uses dynamic symbol
|
||||
lookup with `epicsFindSymbol()` to perform the same function as a generated
|
||||
`*_registerRecordDeviceDriver()` function. This allows for an alternative
|
||||
approach to dynamic loading of support modules without code generation.
|
||||
|
||||
This feature is not intended for use by IOCs constructed using the standard EPICS application
|
||||
build process and booted from a startup script in an iocBoot subdirectory, although it might
|
||||
work in some of those cases (the IOC's registerRecordDeviceDriver.cpp file is still required
|
||||
to link everything into the executable). It also won't work with some static build
|
||||
configurations or where the symbol table has been stripped from the executable.
|
||||
This feature is not intended for use by IOCs constructed using the standard
|
||||
EPICS application build process and booted from a startup script in an iocBoot
|
||||
subdirectory, although it might work in some of those cases — the
|
||||
generated registerRecordDeviceDriver.cpp file is normally required to link
|
||||
everything referred to in the DBD file into the IOC's executable. It also
|
||||
won't work with some static build configurations, or if the symbol table has
|
||||
been stripped from the executable.
|
||||
|
||||
### Using a `{const:"string"}` to initialize an array of `DBF_CHAR`
|
||||
|
||||
@@ -51,6 +296,8 @@ GNUmake added the directive `undefine` in version 3.82 to allow variables to
|
||||
be undefined. Support for this has been added to the EPICS Release file parser,
|
||||
so `undefine` can now be used in configure/RELEASE files to unset variables.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.4.1
|
||||
|
||||
### ARM Architecture Changes
|
||||
@@ -98,6 +345,8 @@ Bad character ' ' in record name "bad practice"
|
||||
if a record name begins with a minus, plus, left square bracket,
|
||||
or left curly bracket.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.4
|
||||
|
||||
### Bug fixes
|
||||
@@ -282,6 +531,8 @@ devLsiEtherIP = {
|
||||
};
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.3.1
|
||||
|
||||
**IMPORTANT NOTE:** *Some record types in this release will not be compatible
|
||||
@@ -475,6 +726,8 @@ necessary, all RTEMS targets should now link although the IOC won't be able to
|
||||
be used with the VME I/O on those systems (that we don't have VMEbus I/O
|
||||
support for in libCom).
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.3
|
||||
|
||||
### `epicsTimeGetCurrent()` optimization
|
||||
@@ -495,6 +748,8 @@ This may result in slightly fewer, but larger frames being sent.
|
||||
Report NOBT as "precision" through the dbAccess API. This is not accessible
|
||||
through CA, but is planned to be used through QSRV.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.2.2
|
||||
|
||||
### Build System changes
|
||||
@@ -529,6 +784,8 @@ substantial than bug fixes.
|
||||
|
||||
Turns out this is ~10x slower to query than `CLOCK_MONOTONIC`.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.2.1
|
||||
|
||||
### Linking shared libraries on macOS
|
||||
@@ -580,6 +837,8 @@ rewrite of the link address parser code in dbStaticLib. This release fixes that
|
||||
issue, although in some cases the output may be slightly different than it used
|
||||
to be.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.2
|
||||
|
||||
### Launchpad Bugs
|
||||
@@ -597,6 +856,8 @@ modules. The layout of the source files has not changed at all however, so the
|
||||
source code for libcom, ca and the database are still found separately under
|
||||
the module subdirectory.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.1.1
|
||||
|
||||
### Changed SIML failure behavior
|
||||
@@ -655,7 +916,11 @@ than is currently available, but as developers we generally much prefer to
|
||||
write code than documentation. Send questions to the tech-talk mailing list
|
||||
and we'll be happy to try and answer them!
|
||||
|
||||
## Changes between 3.16.1 and 3.16.2
|
||||
-----
|
||||
|
||||
## Changes made between 3.16.1 and 3.16.2
|
||||
|
||||
### Launchpad Bugs
|
||||
|
||||
The list of tracked bugs fixed in this release can be found on the
|
||||
[Launchpad Milestone page for EPICS Base 3.16.2](https://launchpad.net/epics-base/+milestone/3.16.2).
|
||||
@@ -862,6 +1127,8 @@ array is made even larger; the previous array buffer was not being released
|
||||
correctly. See Launchpad
|
||||
[bug #1706703](https://bugs.launchpad.net/epics-base/+bug/1706703).
|
||||
|
||||
-----
|
||||
|
||||
## Changes made between 3.16.0.1 and 3.16.1
|
||||
|
||||
### IOC Database Support for 64-bit integers
|
||||
@@ -1298,6 +1565,7 @@ and then replace `(RECSUPFUN)` with `RECSUPFUN_CAST` when initializing the
|
||||
rset. Further changes might also be needed, e.g. to adapt `const`-ness of
|
||||
method parameters.
|
||||
|
||||
-----
|
||||
|
||||
## Changes made between 3.15.3 and 3.16.0.1
|
||||
|
||||
@@ -1406,6 +1674,8 @@ header and removed the need for dbScan.c to reach into the internals of its
|
||||
`CALLBACK` objects.
|
||||
|
||||
|
||||
-----
|
||||
|
||||
# Changes incorporated from the 3.15 branch
|
||||
|
||||
|
||||
@@ -1417,6 +1687,7 @@ The names of the generated junit xml test output files have been changed
|
||||
from `<testname>.xml` to `<testname>-results.xml`, to allow better
|
||||
distinction from other xml files. (I.e., for easy wildcard matching.)
|
||||
|
||||
-----
|
||||
|
||||
## Changes made between 3.15.7 and 3.15.8
|
||||
|
||||
@@ -1522,6 +1793,7 @@ don't provide it any more.
|
||||
If multiple IOCs were started at the same time, by systemd say, they could race
|
||||
to obtain the Channel Access TCP port number 5064. This issue has been fixed.
|
||||
|
||||
-----
|
||||
|
||||
## Changes made between 3.15.6 and 3.15.7
|
||||
|
||||
@@ -1665,6 +1937,8 @@ into the htmls directory. Thanks to Tony Pietryla.
|
||||
|
||||
This displays the version numbers of EPICS Base and the CA protocol.
|
||||
|
||||
-----
|
||||
|
||||
## Changes made between 3.15.5 and 3.15.6
|
||||
|
||||
### Unsetting environment variables
|
||||
@@ -1890,6 +2164,8 @@ choice string cannot be parsed, the associated periodic scan thread will no
|
||||
longer be started by the IOC and a warning message will be displayed at iocInit
|
||||
time. The `scanppl` command will also flag the faulty menuScan value.
|
||||
|
||||
-----
|
||||
|
||||
## Changes made between 3.15.4 and 3.15.5
|
||||
|
||||
### dbStatic Library Speedup and Cleanup
|
||||
@@ -2021,6 +2297,8 @@ will be installed into the target bin directory, from where it can be copied
|
||||
into the appropriate systemd location and modified as necessary. Installation
|
||||
instructions are included as comments in the file.
|
||||
|
||||
-----
|
||||
|
||||
## Changes made between 3.15.3 and 3.15.4
|
||||
|
||||
### New string input device support "getenv"
|
||||
@@ -2126,6 +2404,8 @@ variable to a non-zero value before loading the file, like this:
|
||||
This was [Launchpad bug
|
||||
541119](https://bugs.launchpad.net/bugs/541119).
|
||||
|
||||
-----
|
||||
|
||||
## Changes from the 3.14 branch between 3.15.3 and 3.15.4
|
||||
|
||||
### NTP Time Provider adjusts to OS tick rate changes
|
||||
|
||||
@@ -56,6 +56,9 @@ website where these original reference chapters are now being published.
|
||||
* [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)
|
||||
|
||||
@@ -147,17 +147,17 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Tag the module in Git, using these tag conventions:
|
||||
<ul>
|
||||
<li>
|
||||
<tt>R7.0.4.1-pre<i>n</i></tt>
|
||||
<tt>R7.0.5-pre<i>n</i></tt>
|
||||
— pre-release tag
|
||||
</li>
|
||||
<li>
|
||||
<tt>R7.0.4.1-rc<i>n</i></tt>
|
||||
<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.4.1-rc1' R7.0.4.1-rc1
|
||||
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
|
||||
@@ -171,11 +171,11 @@ 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.4.1-rc1 base-7.0.4.1-rc1.tar.gz base-7.0.4.1-rc1/
|
||||
./.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.4.1-rc1.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.5-rc1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -298,7 +298,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.4.1' <module-version>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.5' <module-version>
|
||||
</tt></blockquote>
|
||||
</li>
|
||||
|
||||
@@ -355,7 +355,7 @@ 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.4.1
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.5
|
||||
</tt></blockquote>
|
||||
<p>Don't push these commits or the new tag to the Launchpad repository
|
||||
yet.</p>
|
||||
@@ -387,12 +387,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.4.1 ../base-7.0.4.1.tar.gz base-7.0.4.1/
|
||||
./.tools/make-tar.sh R7.0.5 ../base-7.0.5.tar.gz base-7.0.5/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
cd ..<br />
|
||||
gpg --armor --sign --detach-sig base-7.0.4.1.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.5.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -457,7 +457,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
|
||||
epics-controls web-server.
|
||||
<blockquote><tt>
|
||||
scp base-7.0.4.1.tar.gz base-7.0.4.1.tar.gz.asc epics-controls:download/base<br />
|
||||
scp base-7.0.5.tar.gz base-7.0.5.tar.gz.asc epics-controls:download/base<br />
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -95,10 +95,7 @@ PROD_LIBS = ca Com
|
||||
# needed when its an object library build
|
||||
PROD_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
PROD_DEFAULT += caRepeater catime acctst caConnTest casw caEventRate
|
||||
PROD_vxWorks = -nil-
|
||||
PROD_RTEMS = -nil-
|
||||
PROD_iOS = -nil-
|
||||
PROD_CMD += caRepeater catime acctst caConnTest casw caEventRate
|
||||
|
||||
OBJS_vxWorks = catime acctst caConnTest casw caEventRate acctstRegister
|
||||
|
||||
|
||||
@@ -153,13 +153,13 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
|
||||
this->localPort = htons ( tmpAddr.ia.sin_port );
|
||||
}
|
||||
|
||||
std::auto_ptr < CallbackGuard > pCBGuard;
|
||||
ca::auto_ptr < CallbackGuard > pCBGuard;
|
||||
if ( ! enablePreemptiveCallback ) {
|
||||
pCBGuard.reset ( new CallbackGuard ( this->cbMutex ) );
|
||||
}
|
||||
|
||||
// multiple steps ensure exception safety
|
||||
this->pCallbackGuard = pCBGuard;
|
||||
this->pCallbackGuard = PTRMOVE(pCBGuard);
|
||||
}
|
||||
|
||||
ca_client_context::~ca_client_context ()
|
||||
|
||||
@@ -517,7 +517,7 @@ struct dbr_ctrl_double{
|
||||
};
|
||||
|
||||
#define dbr_size_n(TYPE,COUNT)\
|
||||
((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
|
||||
((unsigned)((COUNT)<0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
|
||||
|
||||
/* size for each type - array indexed by the DBR_ type code */
|
||||
LIBCA_API extern const unsigned short dbr_size[];
|
||||
|
||||
@@ -329,7 +329,7 @@ void nciu::write (
|
||||
if ( ! this->accessRightState.writePermit() ) {
|
||||
throw cacChannel::noWriteAccess();
|
||||
}
|
||||
if ( countIn > this->count || countIn == 0 ) {
|
||||
if ( countIn > this->count) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
if ( type == DBR_STRING ) {
|
||||
@@ -350,7 +350,7 @@ cacChannel::ioStatus nciu::write (
|
||||
if ( ! this->accessRightState.writePermit() ) {
|
||||
throw cacChannel::noWriteAccess();
|
||||
}
|
||||
if ( countIn > this->count || countIn == 0 ) {
|
||||
if ( countIn > this->count) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
if ( type == DBR_STRING ) {
|
||||
|
||||
@@ -38,6 +38,17 @@
|
||||
#include "cadef.h"
|
||||
#include "syncGroup.h"
|
||||
|
||||
namespace ca {
|
||||
#if __cplusplus>=201103L
|
||||
template<typename T>
|
||||
using auto_ptr = std::unique_ptr<T>;
|
||||
#define PTRMOVE(AUTO) std::move(AUTO)
|
||||
#else
|
||||
using std::auto_ptr;
|
||||
#define PTRMOVE(AUTO) (AUTO)
|
||||
#endif
|
||||
}
|
||||
|
||||
struct oldChannelNotify : private cacChannelNotify {
|
||||
public:
|
||||
oldChannelNotify (
|
||||
@@ -393,8 +404,8 @@ private:
|
||||
epicsEvent ioDone;
|
||||
epicsEvent callbackThreadActivityComplete;
|
||||
epicsThreadId createdByThread;
|
||||
std::auto_ptr < CallbackGuard > pCallbackGuard;
|
||||
std::auto_ptr < cacContext > pServiceContext;
|
||||
ca::auto_ptr < CallbackGuard > pCallbackGuard;
|
||||
ca::auto_ptr < cacContext > pServiceContext;
|
||||
caExceptionHandler * ca_exception_func;
|
||||
void * ca_exception_arg;
|
||||
caPrintfFunc * pVPrintfFunc;
|
||||
|
||||
@@ -40,6 +40,17 @@
|
||||
#include "repeaterSubscribeTimer.h"
|
||||
#include "SearchDest.h"
|
||||
|
||||
namespace ca {
|
||||
#if __cplusplus>=201103L
|
||||
template<typename T>
|
||||
using auto_ptr = std::unique_ptr<T>;
|
||||
#define PTRMOVE(AUTO) std::move(AUTO)
|
||||
#else
|
||||
using std::auto_ptr;
|
||||
#define PTRMOVE(AUTO) (AUTO)
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void cacRecvThreadUDP ( void *pParam );
|
||||
|
||||
LIBCA_API void epicsStdCall caStartRepeaterIfNotInstalled (
|
||||
@@ -161,7 +172,7 @@ private:
|
||||
epicsMutex & cacMutex;
|
||||
const unsigned nTimers;
|
||||
struct SearchArray {
|
||||
typedef std::auto_ptr <searchTimer> value_type;
|
||||
typedef ca::auto_ptr <searchTimer> value_type;
|
||||
value_type *arr;
|
||||
SearchArray(size_t n) : arr(new value_type[n]) {}
|
||||
~SearchArray() { delete[] arr; }
|
||||
|
||||
@@ -13,10 +13,7 @@ TOP = ../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_DEFAULT += caget camonitor cainfo caput
|
||||
PROD_vxWorks = -nil-
|
||||
PROD_RTEMS = -nil-
|
||||
PROD_iOS = -nil-
|
||||
PROD_CMD = caget camonitor cainfo caput
|
||||
|
||||
PROD_SRCS = tool_lib.c
|
||||
|
||||
|
||||
@@ -946,13 +946,18 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
if (offset == 0 && (!nRequest || no_elements == 1)) {
|
||||
if (nRequest)
|
||||
*nRequest = 1;
|
||||
else if (no_elements < 1) {
|
||||
status = S_db_onlyOne;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!pfl || pfl->type == dbfl_type_rec) {
|
||||
status = dbFastGetConvertRoutine[field_type][dbrType]
|
||||
(paddr->pfield, pbuf, paddr);
|
||||
} else {
|
||||
DBADDR localAddr = *paddr; /* Structure copy */
|
||||
|
||||
if (pfl->no_elements < 1) {
|
||||
if (no_elements < 1) {
|
||||
status = S_db_badField;
|
||||
goto done;
|
||||
}
|
||||
@@ -996,6 +1001,11 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
} else {
|
||||
DBADDR localAddr = *paddr; /* Structure copy */
|
||||
|
||||
if (pfl->no_elements < 1) {
|
||||
status = S_db_badField;
|
||||
goto done;
|
||||
}
|
||||
|
||||
localAddr.field_type = pfl->field_type;
|
||||
localAddr.field_size = pfl->field_size;
|
||||
localAddr.no_elements = pfl->no_elements;
|
||||
@@ -1037,7 +1047,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
short dbrType, const void *pbuffer, long nRequest)
|
||||
{
|
||||
dbLinkInfo link_info;
|
||||
DBADDR *pdbaddr = NULL;
|
||||
dbChannel *chan = NULL;
|
||||
dbCommon *precord = paddr->precord;
|
||||
dbCommon *lockrecs[2];
|
||||
dbLocker locker;
|
||||
@@ -1075,16 +1085,11 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
|
||||
if (link_info.ltype == PV_LINK &&
|
||||
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
|
||||
DBADDR tempaddr;
|
||||
|
||||
if (dbNameToAddr(link_info.target, &tempaddr)==0) {
|
||||
/* This will become a DB link. */
|
||||
pdbaddr = malloc(sizeof(*pdbaddr));
|
||||
if (!pdbaddr) {
|
||||
status = S_db_noMemory;
|
||||
goto cleanup;
|
||||
}
|
||||
*pdbaddr = tempaddr; /* struct copy */
|
||||
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);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1093,7 +1098,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
|
||||
memset(&locker, 0, sizeof(locker));
|
||||
lockrecs[0] = precord;
|
||||
lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL;
|
||||
lockrecs[1] = chan ? dbChannelRecord(chan) : NULL;
|
||||
dbLockerPrepare(&locker, lockrecs, 2);
|
||||
|
||||
dbScanLockMany(&locker);
|
||||
@@ -1181,7 +1186,8 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
case PV_LINK:
|
||||
case CONSTANT:
|
||||
case JSON_LINK:
|
||||
dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr);
|
||||
dbAddLink(&locker, plink, pfldDes->field_type, chan);
|
||||
chan = NULL; /* don't clean it up */
|
||||
break;
|
||||
|
||||
case DB_LINK:
|
||||
@@ -1211,6 +1217,8 @@ unlock:
|
||||
dbScanUnlockMany(&locker);
|
||||
dbLockerFinalize(&locker);
|
||||
cleanup:
|
||||
if (chan)
|
||||
dbChannelDelete(chan);
|
||||
free(link_info.target);
|
||||
return status;
|
||||
}
|
||||
@@ -1330,25 +1338,21 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
} else
|
||||
offset = 0;
|
||||
|
||||
if (no_elements <= 1) {
|
||||
status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
|
||||
paddr->pfield, paddr);
|
||||
nRequest = 1;
|
||||
} else {
|
||||
if (no_elements < nRequest)
|
||||
nRequest = no_elements;
|
||||
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
|
||||
nRequest, no_elements, offset);
|
||||
}
|
||||
|
||||
/* update array info */
|
||||
if (!status &&
|
||||
paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->put_array_info) {
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
/* update array info */
|
||||
if (!status && prset->put_array_info)
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
} else {
|
||||
if (nRequest < 1) {
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
} else {
|
||||
status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
|
||||
paddr->pfield, paddr);
|
||||
nRequest = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always do special processing if needed */
|
||||
|
||||
@@ -173,9 +173,8 @@ struct dbr_alDouble {DBRalDouble};
|
||||
#define dbr_alLong_size sizeof(struct dbr_alLong)
|
||||
#define dbr_alDouble_size sizeof(struct dbr_alDouble)
|
||||
|
||||
#ifndef INCerrMdefh
|
||||
#include "errMdef.h"
|
||||
#endif
|
||||
|
||||
#define S_db_notFound (M_dbAccess| 1) /*Process Variable Not Found*/
|
||||
#define S_db_badDbrtype (M_dbAccess| 3) /*Illegal Database Request Type*/
|
||||
#define S_db_noMod (M_dbAccess| 5) /*Attempt to modify noMod field*/
|
||||
|
||||
@@ -48,6 +48,17 @@
|
||||
#include "db_convert.h"
|
||||
#include "resourceLib.h"
|
||||
|
||||
namespace ca {
|
||||
#if __cplusplus>=201103L
|
||||
template<typename T>
|
||||
using auto_ptr = std::unique_ptr<T>;
|
||||
#define PTRMOVE(AUTO) std::move(AUTO)
|
||||
#else
|
||||
using std::auto_ptr;
|
||||
#define PTRMOVE(AUTO) (AUTO)
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType notifyPutType );
|
||||
extern "C" void putNotifyCompletion ( processNotify *ppn );
|
||||
|
||||
@@ -194,7 +205,7 @@ private:
|
||||
epicsMutex & mutex;
|
||||
epicsMutex & cbMutex;
|
||||
cacContextNotify & notify;
|
||||
std::auto_ptr < cacContext > pNetContext;
|
||||
ca::auto_ptr < cacContext > pNetContext;
|
||||
char * pStateNotifyCache;
|
||||
bool isolated;
|
||||
|
||||
|
||||
@@ -411,9 +411,15 @@ long dbCaGetLink(struct link *plink, short dbrType, void *pdest,
|
||||
goto done;
|
||||
}
|
||||
newType = dbDBRoldToDBFnew[pca->dbrType];
|
||||
if (!nelements || *nelements == 1) {
|
||||
if (!nelements) {
|
||||
long (*fConvert)(const void *from, void *to, struct dbAddr *paddr);
|
||||
|
||||
if (pca->usedelements < 1) {
|
||||
pca->sevr = INVALID_ALARM;
|
||||
pca->stat = LINK_ALARM;
|
||||
status = -1;
|
||||
goto done;
|
||||
}
|
||||
fConvert = dbFastGetConvertRoutine[newType][dbrType];
|
||||
assert(pca->pgetNative);
|
||||
status = fConvert(pca->pgetNative, pdest, 0);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#define EPICS_PRIVATE_API
|
||||
|
||||
#include "cantProceed.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsString.h"
|
||||
@@ -68,6 +70,7 @@ void dbChannelInit (void)
|
||||
freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
|
||||
freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
|
||||
freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
|
||||
db_init_event_freelists();
|
||||
}
|
||||
|
||||
static void chf_value(parseContext *parser, parse_result *presult)
|
||||
|
||||
@@ -169,6 +169,9 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
|
||||
return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq);
|
||||
}
|
||||
|
||||
if(dbrType>=NELEMENTS(convert))
|
||||
return S_db_badDbrtype;
|
||||
|
||||
return convert[dbrType](pstr, pbuffer, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ dbContext::dbContext ( epicsMutex & cbMutexIn,
|
||||
epicsMutex & mutexIn, cacContextNotify & notifyIn ) :
|
||||
readNotifyCache ( mutexIn ), ctx ( 0 ),
|
||||
stateNotifyCacheSize ( 0 ), mutex ( mutexIn ), cbMutex ( cbMutexIn ),
|
||||
notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 ),
|
||||
notify ( notifyIn ), pStateNotifyCache ( 0 ),
|
||||
isolated(dbServiceIsolate)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbConvert.h"
|
||||
#include "db_field_log.h"
|
||||
#include "db_access_routines.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbLockPvt.h"
|
||||
@@ -74,7 +75,7 @@
|
||||
#include "recSup.h"
|
||||
#include "special.h"
|
||||
#include "dbDbLink.h"
|
||||
|
||||
#include "dbChannel.h"
|
||||
|
||||
/***************************** Database Links *****************************/
|
||||
|
||||
@@ -83,45 +84,51 @@ static lset dbDb_lset;
|
||||
|
||||
static long processTarget(dbCommon *psrc, dbCommon *pdst);
|
||||
|
||||
#define linkChannel(plink) ((dbChannel *) (plink)->value.pv_link.pvt)
|
||||
|
||||
long dbDbInitLink(struct link *plink, short dbfType)
|
||||
{
|
||||
DBADDR dbaddr;
|
||||
long status;
|
||||
DBADDR *pdbAddr;
|
||||
dbChannel *chan;
|
||||
dbCommon *precord;
|
||||
|
||||
status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
|
||||
chan = dbChannelCreate(plink->value.pv_link.pvname);
|
||||
if (!chan)
|
||||
return S_db_notFound;
|
||||
status = dbChannelOpen(chan);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
precord = dbChannelRecord(chan);
|
||||
|
||||
plink->lset = &dbDb_lset;
|
||||
plink->type = DB_LINK;
|
||||
pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
|
||||
*pdbAddr = dbaddr; /* structure copy */
|
||||
plink->value.pv_link.pvt = pdbAddr;
|
||||
ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
plink->value.pv_link.pvt = chan;
|
||||
ellAdd(&precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
/* merging into the same lockset is deferred to the caller.
|
||||
* cf. initPVLinks()
|
||||
*/
|
||||
dbLockSetMerge(NULL, plink->precord, dbaddr.precord);
|
||||
assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);
|
||||
dbLockSetMerge(NULL, plink->precord, precord);
|
||||
assert(plink->precord->lset->plockSet == precord->lset->plockSet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
|
||||
DBADDR *ptarget)
|
||||
dbChannel *chan)
|
||||
{
|
||||
plink->lset = &dbDb_lset;
|
||||
plink->type = DB_LINK;
|
||||
plink->value.pv_link.pvt = ptarget;
|
||||
ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
plink->value.pv_link.pvt = chan;
|
||||
ellAdd(&dbChannelRecord(chan)->bklnk, &plink->value.pv_link.backlinknode);
|
||||
|
||||
/* target record is already locked in dbPutFieldLink() */
|
||||
dbLockSetMerge(locker, plink->precord, ptarget->precord);
|
||||
dbLockSetMerge(locker, plink->precord, dbChannelRecord(chan));
|
||||
}
|
||||
|
||||
static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
|
||||
{
|
||||
DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
dbCommon *precord = dbChannelRecord(chan);
|
||||
|
||||
plink->type = PV_LINK;
|
||||
|
||||
@@ -131,10 +138,10 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
|
||||
plink->value.pv_link.getCvt = 0;
|
||||
plink->value.pv_link.pvlMask = 0;
|
||||
plink->value.pv_link.lastGetdbrType = 0;
|
||||
ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
|
||||
ellDelete(&precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
dbLockSetSplit(locker, plink->precord, precord);
|
||||
}
|
||||
free(pdbAddr);
|
||||
dbChannelDelete(chan);
|
||||
}
|
||||
|
||||
static int dbDbIsConnected(const struct link *plink)
|
||||
@@ -144,16 +151,14 @@ static int dbDbIsConnected(const struct link *plink)
|
||||
|
||||
static int dbDbGetDBFtype(const struct link *plink)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
return paddr->field_type;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
return dbChannelFinalFieldType(chan);
|
||||
}
|
||||
|
||||
static long dbDbGetElements(const struct link *plink, long *nelements)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
*nelements = paddr->no_elements;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
*nelements = dbChannelFinalElements(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -161,47 +166,75 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
DBADDR *paddr = ppv_link->pvt;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
DBADDR *paddr = &chan->addr;
|
||||
dbCommon *precord = plink->precord;
|
||||
db_field_log *pfl = NULL;
|
||||
long status;
|
||||
|
||||
/* scan passive records if link is process passive */
|
||||
if (ppv_link->pvlMask & pvlOptPP) {
|
||||
status = dbScanPassive(precord, paddr->precord);
|
||||
status = dbScanPassive(precord, dbChannelRecord(chan));
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
} else {
|
||||
unsigned short dbfType = paddr->field_type;
|
||||
if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType)
|
||||
{
|
||||
/* shortcut: scalar with known conversion, no filter */
|
||||
status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
|
||||
}
|
||||
else if (dbChannelFinalElements(chan) == 1 && (!pnRequest || *pnRequest == 1)
|
||||
&& dbChannelSpecial(chan) != SPC_DBADDR
|
||||
&& dbChannelSpecial(chan) != SPC_ATTRIBUTE
|
||||
&& ellCount(&chan->filters) == 0)
|
||||
{
|
||||
/* simple scalar: set up shortcut */
|
||||
unsigned short dbfType = dbChannelFinalFieldType(chan);
|
||||
|
||||
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
|
||||
return S_db_badDbrtype;
|
||||
|
||||
if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
|
||||
&& paddr->special != SPC_DBADDR
|
||||
&& paddr->special != SPC_ATTRIBUTE) {
|
||||
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
} else {
|
||||
ppv_link->getCvt = NULL;
|
||||
status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
|
||||
}
|
||||
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
|
||||
ppv_link->lastGetdbrType = dbrType;
|
||||
status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* filter, array, or special */
|
||||
ppv_link->getCvt = NULL;
|
||||
|
||||
if (ellCount(&chan->filters)) {
|
||||
/* If filters are involved in a read, create field log and run filters */
|
||||
pfl = db_create_read_log(chan);
|
||||
if (!pfl)
|
||||
return S_db_noMemory;
|
||||
|
||||
pfl = dbChannelRunPreChain(chan, pfl);
|
||||
pfl = dbChannelRunPostChain(chan, pfl);
|
||||
}
|
||||
|
||||
status = dbChannelGet(chan, dbrType, pbuffer, NULL, pnRequest, pfl);
|
||||
|
||||
if (pfl)
|
||||
db_delete_field_log(pfl);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!status && precord != paddr->precord)
|
||||
if (!status && precord != dbChannelRecord(chan))
|
||||
recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
|
||||
plink->precord, paddr->precord->stat, paddr->precord->sevr);
|
||||
plink->precord,
|
||||
dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr);
|
||||
return status;
|
||||
}
|
||||
|
||||
static long dbDbGetControlLimits(const struct link *plink, double *low,
|
||||
double *high)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
DBADDR *paddr = &chan->addr;
|
||||
struct buffer {
|
||||
DBRctrlDouble
|
||||
double value;
|
||||
@@ -222,7 +255,8 @@ static long dbDbGetControlLimits(const struct link *plink, double *low,
|
||||
static long dbDbGetGraphicLimits(const struct link *plink, double *low,
|
||||
double *high)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
DBADDR *paddr = &chan->addr;
|
||||
struct buffer {
|
||||
DBRgrDouble
|
||||
double value;
|
||||
@@ -243,7 +277,8 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low,
|
||||
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
|
||||
double *low, double *high, double *hihi)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
DBADDR *paddr = &chan->addr;
|
||||
struct buffer {
|
||||
DBRalDouble
|
||||
double value;
|
||||
@@ -265,7 +300,8 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
|
||||
|
||||
static long dbDbGetPrecision(const struct link *plink, short *precision)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
DBADDR *paddr = &chan->addr;
|
||||
struct buffer {
|
||||
DBRprecision
|
||||
double value;
|
||||
@@ -284,7 +320,8 @@ static long dbDbGetPrecision(const struct link *plink, short *precision)
|
||||
|
||||
static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
DBADDR *paddr = &chan->addr;
|
||||
struct buffer {
|
||||
DBRunits
|
||||
double value;
|
||||
@@ -304,20 +341,20 @@ static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
|
||||
static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
dbCommon *precord = dbChannelRecord(chan);
|
||||
if (status)
|
||||
*status = paddr->precord->stat;
|
||||
*status = precord->stat;
|
||||
if (severity)
|
||||
*severity = paddr->precord->sevr;
|
||||
*severity = precord->sevr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
*pstamp = paddr->precord->time;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
dbCommon *precord = dbChannelRecord(chan);
|
||||
*pstamp = precord->time;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -325,9 +362,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
struct dbCommon *psrce = plink->precord;
|
||||
DBADDR *paddr = (DBADDR *) ppv_link->pvt;
|
||||
dbCommon *pdest = paddr->precord;
|
||||
DBADDR *paddr = &chan->addr;
|
||||
dbCommon *pdest = dbChannelRecord(chan);
|
||||
long status = dbPut(paddr, dbrType, pbuffer, nRequest);
|
||||
|
||||
recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,
|
||||
@@ -335,7 +373,7 @@ static long dbDbPutValue(struct link *plink, short dbrType,
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (paddr->pfield == (void *) &pdest->proc ||
|
||||
if (dbChannelField(chan) == (void *) &pdest->proc ||
|
||||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
|
||||
status = processTarget(psrce, pdest);
|
||||
}
|
||||
@@ -346,9 +384,8 @@ static long dbDbPutValue(struct link *plink, short dbrType,
|
||||
static void dbDbScanFwdLink(struct link *plink)
|
||||
{
|
||||
dbCommon *precord = plink->precord;
|
||||
dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
|
||||
|
||||
dbScanPassive(precord, paddr->precord);
|
||||
dbChannel *chan = linkChannel(plink);
|
||||
dbScanPassive(precord, dbChannelRecord(chan));
|
||||
}
|
||||
|
||||
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
|
||||
|
||||
@@ -27,7 +27,7 @@ struct dbLocker;
|
||||
|
||||
epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);
|
||||
epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,
|
||||
short dbfType, DBADDR *ptarget);
|
||||
short dbfType, dbChannel *ptarget);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -252,18 +252,15 @@ int dbel ( const char *pname, unsigned level )
|
||||
}
|
||||
|
||||
/*
|
||||
* DB_INIT_EVENTS()
|
||||
* DB_INIT_EVENT_FREELISTS()
|
||||
*
|
||||
*
|
||||
* Initialize the event facility for this task. Must be called at least once
|
||||
* by each task which uses the db event facility
|
||||
* Initialize the free lists used by the event facility.
|
||||
* Safe to be called multiple times.
|
||||
*
|
||||
* returns: ptr to event user block or NULL if memory can't be allocated
|
||||
*/
|
||||
dbEventCtx db_init_events (void)
|
||||
void db_init_event_freelists (void)
|
||||
{
|
||||
struct event_user * evUser;
|
||||
|
||||
if (!dbevEventUserFreeList) {
|
||||
freeListInitPvt(&dbevEventUserFreeList,
|
||||
sizeof(struct event_user),8);
|
||||
@@ -280,6 +277,22 @@ dbEventCtx db_init_events (void)
|
||||
freeListInitPvt(&dbevFieldLogFreeList,
|
||||
sizeof(struct db_field_log),2048);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DB_INIT_EVENTS()
|
||||
*
|
||||
*
|
||||
* Initialize the event facility for this task. Must be called at least once
|
||||
* by each task which uses the db event facility
|
||||
*
|
||||
* returns: ptr to event user block or NULL if memory can't be allocated
|
||||
*/
|
||||
dbEventCtx db_init_events (void)
|
||||
{
|
||||
struct event_user * evUser;
|
||||
|
||||
db_init_event_freelists();
|
||||
|
||||
evUser = (struct event_user *)
|
||||
freeListCalloc(dbevEventUserFreeList);
|
||||
|
||||
@@ -66,6 +66,7 @@ epicsShareFunc void db_event_change_priority ( dbEventCtx ctx, unsigned epicsPri
|
||||
|
||||
#ifdef EPICS_PRIVATE_API
|
||||
epicsShareFunc void db_cleanup_events(void);
|
||||
epicsShareFunc void db_init_event_freelists (void);
|
||||
#endif
|
||||
|
||||
typedef void EVENTFUNC (void *user_arg, struct dbChannel *chan,
|
||||
|
||||
@@ -144,7 +144,7 @@ void dbInitLink(struct link *plink, short dbfType)
|
||||
}
|
||||
|
||||
void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
|
||||
DBADDR *ptarget)
|
||||
dbChannel *ptarget)
|
||||
{
|
||||
struct dbCommon *precord = plink->precord;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsTime.h"
|
||||
#include "dbAddr.h"
|
||||
#include "dbChannel.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -369,7 +370,7 @@ epicsShareFunc const char * dbLinkFieldName(const struct link *plink);
|
||||
|
||||
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
|
||||
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
|
||||
short dbfType, DBADDR *ptarget);
|
||||
short dbfType, dbChannel *ptarget);
|
||||
|
||||
epicsShareFunc void dbLinkOpen(struct link *plink);
|
||||
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
|
||||
|
||||
@@ -743,14 +743,14 @@ void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
|
||||
for(i=0; i<rtype->no_links; i++) {
|
||||
dbFldDes *pdesc = rtype->papFldDes[rtype->link_ind[i]];
|
||||
DBLINK *plink = (DBLINK*)((char*)prec + pdesc->offset);
|
||||
DBADDR *ptarget;
|
||||
dbChannel *chan;
|
||||
lockRecord *lr;
|
||||
|
||||
if(plink->type!=DB_LINK)
|
||||
continue;
|
||||
|
||||
ptarget = plink->value.pv_link.pvt;
|
||||
lr = ptarget->precord->lset;
|
||||
chan = plink->value.pv_link.pvt;
|
||||
lr = dbChannelRecord(chan)->lset;
|
||||
assert(lr);
|
||||
|
||||
if(lr->precord==pfirst) {
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "special.h"
|
||||
#include "dbConvertJSON.h"
|
||||
|
||||
#define MAXLINE 80
|
||||
#define MAXMESS 128
|
||||
@@ -364,8 +365,9 @@ long dbpf(const char *pname,const char *pvalue)
|
||||
{
|
||||
DBADDR addr;
|
||||
long status;
|
||||
short dbrType;
|
||||
size_t n = 1;
|
||||
short dbrType = DBR_STRING;
|
||||
long n = 1;
|
||||
char *array = NULL;
|
||||
|
||||
if (!pname || !*pname || !pvalue) {
|
||||
printf("Usage: dbpf \"pv name\", \"value\"\n");
|
||||
@@ -380,16 +382,25 @@ long dbpf(const char *pname,const char *pvalue)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr.no_elements > 1 &&
|
||||
(addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR)) {
|
||||
if (addr.no_elements > 1) {
|
||||
dbrType = addr.dbr_field_type;
|
||||
n = strlen(pvalue) + 1;
|
||||
if (addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR) {
|
||||
n = (long)strlen(pvalue) + 1;
|
||||
} else {
|
||||
n = addr.no_elements;
|
||||
array = calloc(n, dbValueSize(dbrType));
|
||||
if (!array) {
|
||||
printf("Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
status = dbPutConvertJSON(pvalue, dbrType, array, &n);
|
||||
if (status)
|
||||
return status;
|
||||
pvalue = array;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbrType = DBR_STRING;
|
||||
}
|
||||
|
||||
status = dbPutField(&addr, dbrType, pvalue, (long) n);
|
||||
status = dbPutField(&addr, dbrType, pvalue, n);
|
||||
free(array);
|
||||
dbgf(pname);
|
||||
return status;
|
||||
}
|
||||
@@ -943,13 +954,13 @@ static void printBuffer(
|
||||
}
|
||||
|
||||
/* Now print values */
|
||||
if (no_elements == 0)
|
||||
return;
|
||||
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBF_%s: ", dbr[dbr_type]);
|
||||
else
|
||||
else {
|
||||
sprintf(pmsg, "DBF_%s[%ld]: ", dbr[dbr_type], no_elements);
|
||||
if (no_elements == 0)
|
||||
strcat(pmsg, "(empty)");
|
||||
}
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
|
||||
if (status != 0) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
=head1 Menu menuIvoa
|
||||
|
||||
This menu specifies the possibile actions to take when the INVALID alarm is
|
||||
This menu specifies the possible actions to take when the INVALID alarm is
|
||||
triggered. See individual record types for more information.
|
||||
|
||||
=menu menuIvoa
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
menu(menuPini) {
|
||||
choice(menuPiniNO,"NO")
|
||||
choice(menuPiniYES,"YES")
|
||||
choice(menuPiniRUN,"RUN")
|
||||
choice(menuPiniRUNNING,"RUNNING")
|
||||
choice(menuPiniPAUSE,"PAUSE")
|
||||
choice(menuPiniPAUSED,"PAUSED")
|
||||
}
|
||||
66
modules/database/src/ioc/db/menuPini.dbd.pod
Normal file
66
modules/database/src/ioc/db/menuPini.dbd.pod
Normal file
@@ -0,0 +1,66 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=head1 Menu menuPini
|
||||
|
||||
This menu defines the choices for the C<PINI> field, which controls whether
|
||||
and when each record should be processed during initialization or pausing
|
||||
of the IOC. Choices other than C<NO> cause record processing at the
|
||||
following initHook transitions:
|
||||
|
||||
=over 4
|
||||
|
||||
=item YES
|
||||
|
||||
C<initHookAfterScanInit> E<mdash> All records and links have been
|
||||
initialized but the scan threads and CA server are not running yet, nor
|
||||
have CA links been connected up. The initHook C<initHookAfterInitialProcess>
|
||||
immediately follows this procssing.
|
||||
|
||||
=item RUN
|
||||
|
||||
C<initHookAtIocRun> E<mdash> The C<iocRun()> routine has just been called,
|
||||
although not necessarily for the first time.
|
||||
|
||||
=item RUNNING
|
||||
|
||||
C<initHookAfterIocRunning> E<mdash> All remaining initializations have
|
||||
taken place, C<interruptAccept> is enabled, the scan threads and CA server
|
||||
are running and the IOC is processing records. CA links might not have
|
||||
finished connecting though, and sequence programs won't usually have been
|
||||
started yet.
|
||||
|
||||
=item PAUSE
|
||||
|
||||
C<initHookAtIocPause> E<mdash> The C<iocPause()> routine has just been
|
||||
called and the IOC is about to suspend operations.
|
||||
|
||||
=item PAUSED
|
||||
|
||||
C<initHookAfterIocPaused> E<mdash> The CA server, CA link operations and
|
||||
the scan threads have been paused and C<interruptAccept> disabled.
|
||||
|
||||
=back
|
||||
|
||||
Note that the order in which records that have the same C<PINI> value get
|
||||
processed can be controlled by setting their C<PHAS> field, which is honored
|
||||
for C<PINI> processing as well as for regular scanning.
|
||||
|
||||
=menu menuPini
|
||||
|
||||
=cut
|
||||
|
||||
menu(menuPini) {
|
||||
choice(menuPiniNO,"NO")
|
||||
choice(menuPiniYES,"YES")
|
||||
choice(menuPiniRUN,"RUN")
|
||||
choice(menuPiniRUNNING,"RUNNING")
|
||||
choice(menuPiniPAUSE,"PAUSE")
|
||||
choice(menuPiniPAUSED,"PAUSED")
|
||||
}
|
||||
@@ -5,6 +5,16 @@
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=head1 Menu menuPost
|
||||
|
||||
This menu is used by the long string record types to specify whether they
|
||||
should generate a monitor event only when their string value changes, or
|
||||
every time it gets written to even if the value is the same.
|
||||
|
||||
=menu menuPost
|
||||
|
||||
=cut
|
||||
|
||||
menu(menuPost) {
|
||||
choice(menuPost_OnChange, "On Change")
|
||||
choice(menuPost_Always, "Always")
|
||||
@@ -7,6 +7,20 @@
|
||||
# EPICS Base is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=head1 Menu menuPriority
|
||||
|
||||
This menu is used for the C<PRIO> field of all record types. It controls
|
||||
the relative priority of records scheduled with C<SCAN=Event> or
|
||||
C<SCAN=I/O Intr>, and also of records that use asynchronous completion.
|
||||
|
||||
=menu menuPriority
|
||||
|
||||
The number of priorities is set in various other places in the code too,
|
||||
so adding new entries to this menu will probably break the IOC build.
|
||||
|
||||
=cut
|
||||
|
||||
menu(menuPriority) {
|
||||
choice(menuPriorityLOW,"LOW")
|
||||
choice(menuPriorityMEDIUM,"MEDIUM")
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
newline "\n"
|
||||
backslash "\\"
|
||||
singlequote "'"
|
||||
doublequote "\""
|
||||
comment "#"
|
||||
whitespace [ \t\r\n]
|
||||
@@ -18,17 +19,30 @@ stringchar [^"\n\\]
|
||||
bareword [a-zA-Z0-9_\-+:.\[\]<>;]
|
||||
|
||||
punctuation [:,\[\]{}]
|
||||
normalchar [^"\\\0-\x1f]
|
||||
normalchar [^"'\\\0-\x1f]
|
||||
barechar [a-zA-Z0-9_\-+.]
|
||||
escapedchar ({backslash}["\\/bfnrt])
|
||||
escapedchar ({backslash}[^ux1-9])
|
||||
hexdigit [0-9a-fA-F]
|
||||
latinchar ({backslash}"x"{hexdigit}{2})
|
||||
unicodechar ({backslash}"u"{hexdigit}{4})
|
||||
jsonchar ({normalchar}|{escapedchar}|{unicodechar})
|
||||
jsondqstr ({doublequote}{jsonchar}*{doublequote})
|
||||
int ("-"?([0-9]|[1-9][0-9]+))
|
||||
jsondqchar ({normalchar}|{singlequote}|{escapedchar}|{latinchar}|{unicodechar})
|
||||
jsondqstr ({doublequote}{jsondqchar}*{doublequote})
|
||||
jsonsqchar ({normalchar}|{doublequote}|{escapedchar}|{latinchar}|{unicodechar})
|
||||
jsonsqstr ({singlequote}{jsonsqchar}*{singlequote})
|
||||
jsonstr ({jsondqstr}|{jsonsqstr})
|
||||
|
||||
sign ([+-]?)
|
||||
int ({sign}([0-9]|[1-9][0-9]+))
|
||||
frac ("."[0-9]+)
|
||||
exp ([eE][+-]?[0-9]+)
|
||||
number ({int}{frac}?{exp}?)
|
||||
exp ([eE]{sign}[0-9]+)
|
||||
jsonnum ({int}{frac}?{exp}?)
|
||||
intexp ({int}"."{exp}?)
|
||||
fracexp ({sign}{frac}{exp}?)
|
||||
specialnum ("NaN"|{sign}"Infinity")
|
||||
|
||||
zerox ("0x"|"0X")
|
||||
hexint ({sign}{zerox}{hexdigit}+)
|
||||
number ({jsonnum}|{intexp}|{fracexp}|{specialnum}|{hexint})
|
||||
|
||||
%{
|
||||
#undef YY_INPUT
|
||||
@@ -97,7 +111,7 @@ static int yyreset(void)
|
||||
|
||||
<JSON>{punctuation} return yytext[0];
|
||||
|
||||
<JSON>{jsondqstr} {
|
||||
<JSON>{jsonstr} {
|
||||
yylval.Str = dbmfStrdup((char *) yytext);
|
||||
return jsonSTRING;
|
||||
}
|
||||
|
||||
@@ -1172,19 +1172,22 @@ static void dbRecordField(char *name,char *value)
|
||||
yyerror(NULL);
|
||||
return;
|
||||
}
|
||||
if (*value == '"') {
|
||||
|
||||
if (*value == '"' || *value == '\'') {
|
||||
/* jsonSTRING values still have their quotes */
|
||||
value++;
|
||||
value[strlen(value) - 1] = 0;
|
||||
dbTranslateEscape(value, value); /* in-place; safe & legal */
|
||||
}
|
||||
dbTranslateEscape(value, value); /* in-place; safe & legal */
|
||||
|
||||
status = dbPutString(pdbentry,value);
|
||||
if (status) {
|
||||
char msg[128];
|
||||
|
||||
errSymLookup(status, msg, sizeof(msg));
|
||||
epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s\n",
|
||||
dbGetRecordName(pdbentry), name, value, msg);
|
||||
epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s : %s\n",
|
||||
dbGetRecordName(pdbentry), name, value, pdbentry->message ? pdbentry->message : "", msg);
|
||||
dbPutStringSuggest(pdbentry, value);
|
||||
yyerror(NULL);
|
||||
return;
|
||||
}
|
||||
@@ -1203,12 +1206,14 @@ static void dbRecordInfo(char *name, char *value)
|
||||
if (duplicate) return;
|
||||
ptempListNode = (tempListNode *)ellFirst(&tempList);
|
||||
pdbentry = ptempListNode->item;
|
||||
if (*value == '"') {
|
||||
|
||||
if (*value == '"' || *value == '\'') {
|
||||
/* jsonSTRING values still have their quotes */
|
||||
value++;
|
||||
value[strlen(value) - 1] = 0;
|
||||
dbTranslateEscape(value, value); /* in-place; safe & legal */
|
||||
}
|
||||
dbTranslateEscape(value, value); /* yuck: in-place, but safe */
|
||||
|
||||
status = dbPutInfo(pdbentry,name,value);
|
||||
if (status) {
|
||||
epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
|
||||
|
||||
@@ -81,8 +81,6 @@ maplinkType pamaplinkType[LINK_NTYPES] = {
|
||||
};
|
||||
|
||||
/*forward references for private routines*/
|
||||
static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
|
||||
EPICS_PRINTF_STYLE(2,3);
|
||||
static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length);
|
||||
|
||||
/* internal routines*/
|
||||
@@ -199,7 +197,6 @@ void dbMsgNCpy(DBENTRY *pdbentry, const char *msg, size_t len)
|
||||
pdbentry->message[len] = '\0';
|
||||
}
|
||||
|
||||
static
|
||||
void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -2635,6 +2632,52 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
return(status);
|
||||
}
|
||||
|
||||
void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring)
|
||||
{
|
||||
dbFldDes *pflddes = pdbentry->pflddes;
|
||||
|
||||
switch (pflddes->field_type) {
|
||||
case DBF_MENU:
|
||||
case DBF_DEVICE: {
|
||||
int i, nchoices = 0;
|
||||
char** choices = NULL;
|
||||
const char *best = NULL;
|
||||
double maxdist = 0.0; /* don't offer suggestions which have no similarity */
|
||||
|
||||
if(pflddes->field_type==DBF_MENU) {
|
||||
dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
|
||||
if(!pdbMenu)
|
||||
return;
|
||||
|
||||
choices = pdbMenu->papChoiceValue;
|
||||
nchoices = pdbMenu->nChoice;
|
||||
|
||||
} else {
|
||||
dbDeviceMenu *pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
|
||||
if(!pdbDeviceMenu)
|
||||
return;
|
||||
|
||||
choices = pdbDeviceMenu->papChoice;
|
||||
nchoices = pdbDeviceMenu->nChoice;
|
||||
}
|
||||
|
||||
for(i=0; i<nchoices; i++) {
|
||||
double dist = epicsStrSimilarity(pstring, choices[i]);
|
||||
if(dist>maxdist) {
|
||||
best = choices[i];
|
||||
maxdist = dist;
|
||||
}
|
||||
}
|
||||
if(best) {
|
||||
epicsPrintf(" Did you mean \"%s\"?\n", best);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char * dbVerify(DBENTRY *pdbentry, const char *pstring)
|
||||
{
|
||||
dbFldDes *pflddes = pdbentry->pflddes;
|
||||
|
||||
@@ -36,6 +36,10 @@ char *dbRecordName(DBENTRY *pdbentry);
|
||||
char *dbGetStringNum(DBENTRY *pdbentry);
|
||||
long dbPutStringNum(DBENTRY *pdbentry,const char *pstring);
|
||||
|
||||
void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) EPICS_PRINTF_STYLE(2,3);
|
||||
|
||||
void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring);
|
||||
|
||||
struct jlink;
|
||||
|
||||
typedef struct dbLinkInfo {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "dbCommonPvt.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbStaticPvt.h"
|
||||
#include "dbAccess.h"
|
||||
#include "devSup.h"
|
||||
#include "special.h"
|
||||
|
||||
@@ -479,8 +480,17 @@ long dbPutStringNum(DBENTRY *pdbentry, const char *pstring)
|
||||
epicsEnum16 value;
|
||||
long status = epicsParseUInt16(pstring, &value, 0, NULL);
|
||||
|
||||
if (status)
|
||||
if (status) {
|
||||
status = S_db_badChoice;
|
||||
if(pflddes->field_type==DBF_MENU) {
|
||||
dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
|
||||
dbMsgPrint(pdbentry, "using menu %s", pdbMenu->name);
|
||||
|
||||
} else if(pflddes->field_type==DBF_DEVICE) {
|
||||
dbMsgPrint(pdbentry, "no such device support for '%s' record type", pdbentry->precordType->name);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
index = dbGetNMenuChoices(pdbentry);
|
||||
if (value > index && index > 0 && value < USHRT_MAX)
|
||||
|
||||
@@ -32,8 +32,8 @@ static int yyAbort = 0;
|
||||
|
||||
%token jsonNULL jsonTRUE jsonFALSE
|
||||
%token <Str> jsonNUMBER jsonSTRING jsonBARE
|
||||
%type <Str> json_value json_object json_array
|
||||
%type <Str> json_members json_pair json_elements json_string
|
||||
%type <Str> json_value json_string json_object json_array
|
||||
%type <Str> json_members json_pair json_key json_elements
|
||||
|
||||
%%
|
||||
|
||||
@@ -299,13 +299,24 @@ json_members: json_pair
|
||||
if (dbStaticDebug>2) printf("json %s\n", $$);
|
||||
};
|
||||
|
||||
json_pair: json_string ':' json_value
|
||||
json_pair: json_key ':' json_value
|
||||
{
|
||||
$$ = dbmfStrcat3($1, ":", $3);
|
||||
dbmfFree($1); dbmfFree($3);
|
||||
if (dbStaticDebug>2) printf("json %s\n", $$);
|
||||
};
|
||||
|
||||
json_key: jsonSTRING
|
||||
| jsonBARE
|
||||
{
|
||||
/* A key containing any of these characters must be quoted for YAJL */
|
||||
if (strcspn($1, "+-.") < strlen($1)) {
|
||||
$$ = dbmfStrcat3("\"", $1, "\"");
|
||||
dbmfFree($1);
|
||||
}
|
||||
if (dbStaticDebug>2) printf("json %s\n", $$);
|
||||
};
|
||||
|
||||
json_string: jsonSTRING
|
||||
| jsonBARE
|
||||
{
|
||||
|
||||
@@ -185,6 +185,21 @@ registerAllRecordDeviceDrivers(DBBASE *pdbbase)
|
||||
registerJLinks(pdbbase, 1, ptr);
|
||||
}
|
||||
|
||||
// for each function()
|
||||
for(ELLNODE *cur = ellFirst(&pdbbase->functionList); cur; cur = ellNext(cur)) {
|
||||
dbText& reg = *CONTAINER(cur, dbText, node);
|
||||
|
||||
typedef void(*registrar)(void);
|
||||
registrar* ptr = lookupAs<registrar*>("pvar_func_register_func_", reg.text);
|
||||
|
||||
if(!ptr || !*ptr) {
|
||||
fprintf(stderr, "Unable to find function '%s' : %s\n", reg.text, epicsLoadError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
runRegistrarOnce(*ptr);
|
||||
}
|
||||
|
||||
// for each registrar()
|
||||
for(ELLNODE *cur = ellFirst(&pdbbase->registrarList); cur; cur = ellNext(cur)) {
|
||||
dbText& reg = *CONTAINER(cur, dbText, node);
|
||||
@@ -193,7 +208,7 @@ registerAllRecordDeviceDrivers(DBBASE *pdbbase)
|
||||
registrar* ptr = lookupAs<registrar*>("pvar_func_", reg.text);
|
||||
|
||||
if(!ptr || !*ptr) {
|
||||
fprintf(stderr, "Unable to find registar '%s' : %s\n", reg.text, epicsLoadError());
|
||||
fprintf(stderr, "Unable to find registrar '%s' : %s\n", reg.text, epicsLoadError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,23 +47,20 @@ static long init_record(dbCommon *pcommon)
|
||||
aaiRecord *prec = (aaiRecord *)pcommon;
|
||||
DBLINK *plink = &prec->inp;
|
||||
|
||||
/* This is pass 0, link hasn't been initialized yet */
|
||||
dbInitLink(plink, DBF_INLINK);
|
||||
/* Ask record to call us in pass 1 instead */
|
||||
if (prec->pact != AAI_DEVINIT_PASS1) {
|
||||
return AAI_DEVINIT_PASS1;
|
||||
}
|
||||
|
||||
if (dbLinkIsConstant(plink)) {
|
||||
long nRequest = prec->nelm;
|
||||
long status;
|
||||
|
||||
/* Allocate a buffer, record support hasn't done that yet */
|
||||
if (!prec->bptr) {
|
||||
prec->bptr = callocMustSucceed(nRequest, dbValueSize(prec->ftvl),
|
||||
"devAaiSoft: buffer calloc failed");
|
||||
}
|
||||
|
||||
status = dbLoadLinkArray(plink, prec->ftvl, prec->bptr, &nRequest);
|
||||
if (!status && nRequest > 0) {
|
||||
if (!status) {
|
||||
prec->nord = nRequest;
|
||||
prec->udf = FALSE;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -75,7 +72,7 @@ static long readLocked(struct link *pinp, void *dummy)
|
||||
long nRequest = prec->nelm;
|
||||
long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
|
||||
|
||||
if (!status && nRequest > 0) {
|
||||
if (!status) {
|
||||
prec->nord = nRequest;
|
||||
prec->udf = FALSE;
|
||||
|
||||
@@ -90,8 +87,12 @@ static long read_aai(aaiRecord *prec)
|
||||
{
|
||||
epicsUInt32 nord = prec->nord;
|
||||
struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp;
|
||||
long status = dbLinkDoLocked(pinp, readLocked, NULL);
|
||||
long status;
|
||||
|
||||
if (dbLinkIsConstant(pinp))
|
||||
return 0;
|
||||
|
||||
status = dbLinkDoLocked(pinp, readLocked, NULL);
|
||||
if (status == S_db_noLSET)
|
||||
status = readLocked(pinp, NULL);
|
||||
|
||||
|
||||
@@ -86,9 +86,10 @@ static long read_ai(aiRecord *prec)
|
||||
|
||||
prec->udf = FALSE;
|
||||
prec->dpvt = &devAiSoft; /* Any non-zero value */
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
prec->dpvt = NULL;
|
||||
|
||||
return 2;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ static long init_record(dbCommon *pcommon)
|
||||
|
||||
status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nRequest);
|
||||
|
||||
if (!status && nRequest > 0)
|
||||
if (!status)
|
||||
subset(prec, nRequest);
|
||||
|
||||
return status;
|
||||
@@ -116,7 +116,7 @@ static long read_sa(subArrayRecord *prec)
|
||||
status = readLocked(&prec->inp, &rt);
|
||||
}
|
||||
|
||||
if (!status && rt.nRequest > 0) {
|
||||
if (!status) {
|
||||
subset(prec, rt.nRequest);
|
||||
|
||||
if (nord != prec->nord)
|
||||
|
||||
@@ -42,7 +42,7 @@ static long init_record(dbCommon *pcommon)
|
||||
long nelm = prec->nelm;
|
||||
long status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nelm);
|
||||
|
||||
if (!status && nelm > 0) {
|
||||
if (!status) {
|
||||
prec->nord = nelm;
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
@@ -78,11 +78,14 @@ static long read_wf(waveformRecord *prec)
|
||||
rt.ptime = (dbLinkIsConstant(&prec->tsel) &&
|
||||
prec->tse == epicsTimeEventDeviceTime) ? &prec->time : NULL;
|
||||
|
||||
if (dbLinkIsConstant(&prec->inp))
|
||||
return 0;
|
||||
|
||||
status = dbLinkDoLocked(&prec->inp, readLocked, &rt);
|
||||
if (status == S_db_noLSET)
|
||||
status = readLocked(&prec->inp, &rt);
|
||||
|
||||
if (!status && rt.nRequest > 0) {
|
||||
if (!status) {
|
||||
prec->nord = rt.nRequest;
|
||||
prec->udf = FALSE;
|
||||
if (nord != prec->nord)
|
||||
|
||||
@@ -227,6 +227,7 @@ static long process(struct dbCommon *pcommon)
|
||||
return 0;
|
||||
|
||||
prec->pact = TRUE;
|
||||
recGblGetTimeStamp(prec);
|
||||
|
||||
/* Push the output link values */
|
||||
if (!status) {
|
||||
@@ -237,7 +238,6 @@ static long process(struct dbCommon *pcommon)
|
||||
(&prec->neva)[i]);
|
||||
}
|
||||
|
||||
recGblGetTimeStamp(prec);
|
||||
monitor(prec);
|
||||
recGblFwdLink(prec);
|
||||
prec->pact = FALSE;
|
||||
@@ -278,10 +278,9 @@ static long fetch_values(aSubRecord *prec)
|
||||
long nRequest = (&prec->noa)[i];
|
||||
status = dbGetLink(&(&prec->inpa)[i], (&prec->fta)[i], (&prec->a)[i], 0,
|
||||
&nRequest);
|
||||
if (nRequest > 0)
|
||||
(&prec->nea)[i] = nRequest;
|
||||
if (status)
|
||||
return status;
|
||||
(&prec->nea)[i] = nRequest;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -112,16 +112,18 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
prec->ftvl = DBF_UCHAR;
|
||||
prec->nord = (prec->nelm == 1);
|
||||
|
||||
/* we must call pdset->init_record in pass 0
|
||||
because it may set prec->bptr which must
|
||||
not change after links are established before pass 1
|
||||
*/
|
||||
|
||||
/* call pdset->init_record() in pass 0 so it can do its own
|
||||
* memory allocation and set prec->bptr, which must be set by
|
||||
* the end of pass 0.
|
||||
*/
|
||||
if (pdset->common.init_record) {
|
||||
long status = pdset->common.init_record(pcommon);
|
||||
|
||||
/* init_record may set the bptr to point to the data */
|
||||
if (status)
|
||||
if (status == AAI_DEVINIT_PASS1) {
|
||||
/* requesting pass 1 callback, remember to do that */
|
||||
prec->pact = AAI_DEVINIT_PASS1;
|
||||
}
|
||||
else if (status)
|
||||
return status;
|
||||
}
|
||||
if (!prec->bptr) {
|
||||
@@ -132,6 +134,14 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (prec->pact == AAI_DEVINIT_PASS1) {
|
||||
/* device support asked for an init_record() callback in pass 1 */
|
||||
long status = pdset->common.init_record(pcommon);
|
||||
if (status)
|
||||
return status;
|
||||
prec->pact = FALSE;
|
||||
}
|
||||
|
||||
recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
|
||||
|
||||
/* must have read_aai function defined */
|
||||
|
||||
@@ -151,10 +151,15 @@ for more information on simulation mode and its fields.
|
||||
|
||||
static long init_record(aaiRecord *prec, int pass)
|
||||
|
||||
If device support includes C<init_record()>, it is called.
|
||||
If device support includes an C<init_record()> routine it is called, but unlike
|
||||
most record types this occurs in pass 0, which allows the device support to
|
||||
allocate the array buffer itself.
|
||||
|
||||
Since EPICS 7.0.5 the device support may return C<AAI_DEVINIT_PASS1> to request
|
||||
a second call to its C<init_record()> routine in pass 1.
|
||||
|
||||
Checks if device support allocated array space. If not, space for the array is
|
||||
allocated using NELM and FTVL. The array address is stored in the record.
|
||||
allocated using NELM and FTVL. The array address is stored in BPTR.
|
||||
|
||||
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT
|
||||
link or creates a channel access link if SIML type is PV_LINK. VAL is likewise
|
||||
@@ -294,10 +299,11 @@ Scan forward link if necessary, set PACT FALSE, and return.
|
||||
%/* Declare Device Support Entry Table */
|
||||
%struct aaiRecord;
|
||||
%typedef struct aaidset {
|
||||
% dset common; /*init_record returns: (-1,0)=>(failure,success)*/
|
||||
% dset common; /*init_record returns: (-1,0,AAI_DEVINIT_PASS1)=>(failure,success,callback)*/
|
||||
% long (*read_aai)(struct aaiRecord *prec); /*returns: (-1,0)=>(failure,success)*/
|
||||
%} aaidset;
|
||||
%#define HAS_aaidset
|
||||
%#define AAI_DEVINIT_PASS1 2
|
||||
%
|
||||
field(VAL,DBF_NOACCESS) {
|
||||
prompt("Value")
|
||||
@@ -469,8 +475,19 @@ with C<after> set to 1.
|
||||
|
||||
long init_record(dbCommon *precord)
|
||||
|
||||
This routine is optional. If provided, it is called by the record support
|
||||
C<init_record()> routine.
|
||||
This routine is optional.
|
||||
If provided, it is called by the record support's C<init_record()> routine in
|
||||
pass 0.
|
||||
The device support may allocate memory for the VAL field's array (enough space
|
||||
for NELM elements of type FTVA) from its own memory pool if desired, and store
|
||||
the pointer to this buffer in the BPTR field.
|
||||
The record will use C<calloc()> for this memory allocation if BPTR has not been
|
||||
set by this routine.
|
||||
The routine must return 0 for success, -1 or a error status on failure.
|
||||
|
||||
Since EPICS 7.0.5 if this routine returns C<AAI_DEVINIT_PASS1> in pass 0, it
|
||||
will be called again in pass 1 with the PACT field set to C<AAI_DEVINIT_PASS1>.
|
||||
In pass 0 the PACT field is set to zero (FALSE).
|
||||
|
||||
=head4 get_ioint_info
|
||||
|
||||
@@ -485,7 +502,8 @@ provided for any device type that can use the ioEvent scanner.
|
||||
|
||||
long read_aai(dbCommon *precord)
|
||||
|
||||
This routine must provide a new input value. It returns the following values:
|
||||
This routine should provide a new input value.
|
||||
It returns the following values:
|
||||
|
||||
=over
|
||||
|
||||
@@ -501,16 +519,15 @@ Other: Error.
|
||||
|
||||
=head3 Device Support For Soft Records
|
||||
|
||||
The C<<< Soft Channel >>> device support module is provided to read values from
|
||||
other records and store them in arrays. If INP is a constant link, then read_aai
|
||||
does nothing. In this case, the record can be used to hold arrays written via
|
||||
dbPuts. If INP is a database or channel access link, the new array value is read
|
||||
from the link. NORD is set.
|
||||
The C<<< Soft Channel >>> device support is provided to read values from other
|
||||
records via the INP link, or to hold array values that are written into it.
|
||||
|
||||
This module places a value directly in VAL and NORD is set to the number of items
|
||||
in the array.
|
||||
If INP is a constant link the array value gets loaded from the link constant by
|
||||
the C<record_init()> routine, which also sets NORD.
|
||||
The C<read_aai()> routine does nothing in this case.
|
||||
|
||||
If the INP link type is constant, then NORD is set to zero.
|
||||
If INP is a database or channel access link, the C<read_aai()> routine gets a
|
||||
new array value from the link and sets NORD.
|
||||
|
||||
=cut
|
||||
}
|
||||
|
||||
@@ -158,12 +158,22 @@ static long process(struct dbCommon *pcommon)
|
||||
return S_dev_missingSup;
|
||||
}
|
||||
|
||||
if ( !pact ) {
|
||||
prec->udf = FALSE;
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
status = writeValue(prec); /* write the data */
|
||||
if (!pact && prec->pact) return 0;
|
||||
prec->pact = TRUE;
|
||||
|
||||
prec->udf = FALSE;
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
monitor(prec);
|
||||
/* process the forward scan link record */
|
||||
|
||||
@@ -82,7 +82,7 @@ rset aoRSET={
|
||||
put_enum_str,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_alarm_double
|
||||
get_alarm_double
|
||||
};
|
||||
epicsExportAddress(rset,aoRSET);
|
||||
|
||||
@@ -187,6 +187,9 @@ static long process(struct dbCommon *pcommon)
|
||||
}
|
||||
if(!status) convert(prec, value);
|
||||
prec->udf = isnan(prec->val);
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
@@ -220,7 +223,10 @@ static long process(struct dbCommon *pcommon)
|
||||
if ( !pact && prec->pact ) return(0);
|
||||
prec->pact = TRUE;
|
||||
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* check event list */
|
||||
monitor(prec);
|
||||
|
||||
@@ -155,7 +155,7 @@ static long init_record(struct dbCommon *pcommon,int pass)
|
||||
pcallback->precord = (struct dbCommon *) prec;
|
||||
|
||||
if (pdset->common.init_record) {
|
||||
status=(*pdset->common.init_record)(pcommon);
|
||||
status=(*pdset->common.init_record)(pcommon);
|
||||
if(status==0) {
|
||||
if(prec->rval==0) prec->val = 0;
|
||||
else prec->val = 1;
|
||||
@@ -209,6 +209,10 @@ static long process(struct dbCommon *pcommon)
|
||||
if(prec->val==0) prec->rval = 0;
|
||||
else prec->rval = prec->mask;
|
||||
} else prec->rval = (epicsUInt32)prec->val;
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
@@ -245,7 +249,10 @@ static long process(struct dbCommon *pcommon)
|
||||
if ( !pact && prec->pact ) return(0);
|
||||
prec->pact = TRUE;
|
||||
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
if((prec->val==1) && (prec->high>0)){
|
||||
myCallback *pcallback;
|
||||
|
||||
@@ -226,6 +226,7 @@ static long process(struct dbCommon *pcommon)
|
||||
struct calcoutRecord *prec = (struct calcoutRecord *)pcommon;
|
||||
rpvtStruct *prpvt = prec->rpvt;
|
||||
int doOutput;
|
||||
unsigned char pact=prec->pact;
|
||||
|
||||
if (!prec->pact) {
|
||||
prec->pact = TRUE;
|
||||
@@ -241,6 +242,12 @@ static long process(struct dbCommon *pcommon)
|
||||
}
|
||||
}
|
||||
checkAlarms(prec);
|
||||
|
||||
if ( !pact ) {
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStamp(prec);
|
||||
}
|
||||
/* check for output link execution */
|
||||
switch (prec->oopt) {
|
||||
case calcoutOOPT_Every_Time:
|
||||
@@ -269,7 +276,6 @@ static long process(struct dbCommon *pcommon)
|
||||
if (doOutput) {
|
||||
if (prec->odly > 0.0) {
|
||||
prec->dlya = 1;
|
||||
recGblGetTimeStamp(prec);
|
||||
db_post_events(prec, &prec->dlya, DBE_VALUE);
|
||||
callbackRequestProcessCallbackDelayed(&prpvt->doOutCb,
|
||||
prec->prio, prec, (double)prec->odly);
|
||||
@@ -281,11 +287,12 @@ static long process(struct dbCommon *pcommon)
|
||||
prec->pact = TRUE;
|
||||
}
|
||||
}
|
||||
recGblGetTimeStamp(prec);
|
||||
} else { /* pact == TRUE */
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStamp(prec);
|
||||
|
||||
if (prec->dlya) {
|
||||
prec->dlya = 0;
|
||||
recGblGetTimeStamp(prec);
|
||||
db_post_events(prec, &prec->dlya, DBE_VALUE);
|
||||
/* Make pact FALSE for asynchronous device support*/
|
||||
prec->pact = FALSE;
|
||||
@@ -294,7 +301,6 @@ static long process(struct dbCommon *pcommon)
|
||||
prec->pact = TRUE;
|
||||
} else {/*Device Support is asynchronous*/
|
||||
writeValue(prec);
|
||||
recGblGetTimeStamp(prec);
|
||||
}
|
||||
}
|
||||
monitor(prec);
|
||||
|
||||
@@ -106,7 +106,7 @@ static void monitor(compressRecord *prec)
|
||||
db_post_events(prec, &prec->nuse, monitor_mask);
|
||||
prec->ouse = prec->nuse;
|
||||
}
|
||||
db_post_events(prec, prec->bptr, monitor_mask);
|
||||
db_post_events(prec, (void*)&prec->val, monitor_mask);
|
||||
}
|
||||
|
||||
static void put_value(compressRecord *prec, double *psource, int n)
|
||||
@@ -404,7 +404,6 @@ static long cvt_dbaddr(DBADDR *paddr)
|
||||
{
|
||||
compressRecord *prec = (compressRecord *) paddr->precord;
|
||||
|
||||
paddr->pfield = prec->bptr;
|
||||
paddr->no_elements = prec->nsam;
|
||||
paddr->field_type = DBF_DOUBLE;
|
||||
paddr->field_size = sizeof(double);
|
||||
@@ -426,6 +425,8 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
|
||||
epicsUInt32 off = prec->off;
|
||||
epicsUInt32 nuse = prec->nuse;
|
||||
|
||||
paddr->pfield = prec->bptr;
|
||||
|
||||
if (prec->balg == bufferingALG_FIFO) {
|
||||
epicsUInt32 nsam = prec->nsam;
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ static void wdogCallback(epicsCallback *arg)
|
||||
if (prec->mcnt > 0){
|
||||
dbScanLock((struct dbCommon *)prec);
|
||||
recGblGetTimeStamp(prec);
|
||||
db_post_events(prec, prec->bptr, DBE_VALUE | DBE_LOG);
|
||||
db_post_events(prec, (void*)&prec->val, DBE_VALUE | DBE_LOG);
|
||||
prec->mcnt = 0;
|
||||
dbScanUnlock((struct dbCommon *)prec);
|
||||
}
|
||||
@@ -291,7 +291,7 @@ static void monitor(histogramRecord *prec)
|
||||
}
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask)
|
||||
db_post_events(prec, prec->bptr, monitor_mask);
|
||||
db_post_events(prec, (void*)&prec->val, monitor_mask);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -300,7 +300,6 @@ static long cvt_dbaddr(DBADDR *paddr)
|
||||
{
|
||||
histogramRecord *prec = (histogramRecord *) paddr->precord;
|
||||
|
||||
paddr->pfield = prec->bptr;
|
||||
paddr->no_elements = prec->nelm;
|
||||
paddr->field_type = DBF_ULONG;
|
||||
paddr->field_size = sizeof(epicsUInt32);
|
||||
@@ -312,6 +311,7 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
|
||||
{
|
||||
histogramRecord *prec = (histogramRecord *) paddr->precord;
|
||||
|
||||
paddr->pfield = prec->bptr;
|
||||
*no_elements = prec->nelm;
|
||||
*offset = 0;
|
||||
return 0;
|
||||
|
||||
@@ -111,7 +111,7 @@ static long init_record(dbCommon *pcommon, int pass)
|
||||
prec->udf=FALSE;
|
||||
}
|
||||
if (pdset->common.init_record) {
|
||||
if ((status = pdset->common.init_record(pcommon))) return status;
|
||||
if ((status = pdset->common.init_record(pcommon))) return status;
|
||||
}
|
||||
prec->mlst = prec->val;
|
||||
prec->alst = prec->val;
|
||||
@@ -122,7 +122,7 @@ static long init_record(dbCommon *pcommon, int pass)
|
||||
static long process(dbCommon *pcommon)
|
||||
{
|
||||
int64outRecord *prec = (int64outRecord*)pcommon;
|
||||
int64outdset *pdset = (int64outdset *)(prec->dset);
|
||||
int64outdset *pdset = (int64outdset *)(prec->dset);
|
||||
long status=0;
|
||||
epicsInt64 value;
|
||||
unsigned char pact=prec->pact;
|
||||
@@ -144,6 +144,10 @@ static long process(dbCommon *pcommon)
|
||||
value = prec->val;
|
||||
}
|
||||
if (!status) convert(prec,value);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
@@ -175,7 +179,10 @@ static long process(dbCommon *pcommon)
|
||||
if ( !pact && prec->pact ) return(0);
|
||||
prec->pact = TRUE;
|
||||
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* check event list */
|
||||
monitor(prec);
|
||||
|
||||
@@ -146,6 +146,10 @@ static long process(struct dbCommon *pcommon)
|
||||
value = prec->val;
|
||||
}
|
||||
if (!status) convert(prec,value);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
@@ -177,7 +181,10 @@ static long process(struct dbCommon *pcommon)
|
||||
if ( !pact && prec->pact ) return(0);
|
||||
prec->pact = TRUE;
|
||||
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* check event list */
|
||||
monitor(prec);
|
||||
|
||||
@@ -194,6 +194,10 @@ static long process(struct dbCommon *pcommon)
|
||||
prec->udf = FALSE;
|
||||
/* Convert VAL to RVAL */
|
||||
convert(prec);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
CONTINUE:
|
||||
@@ -224,7 +228,11 @@ CONTINUE:
|
||||
return 0;
|
||||
|
||||
prec->pact = TRUE;
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
monitor(prec);
|
||||
|
||||
|
||||
@@ -215,6 +215,10 @@ static long process(struct dbCommon *pcommon)
|
||||
prec->udf = FALSE;
|
||||
/* Convert VAL to RVAL */
|
||||
convert(prec);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
CONTINUE:
|
||||
@@ -248,7 +252,11 @@ CONTINUE:
|
||||
return 0;
|
||||
|
||||
prec->pact = TRUE;
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
monitor(prec);
|
||||
|
||||
|
||||
@@ -147,6 +147,10 @@ static long process(struct dbCommon *pcommon)
|
||||
recGblSetSevr(prec,UDF_ALARM,prec->udfs);
|
||||
}
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
|
||||
if (prec->nsev < INVALID_ALARM )
|
||||
status=writeValue(prec); /* write the new value */
|
||||
else {
|
||||
@@ -173,7 +177,10 @@ static long process(struct dbCommon *pcommon)
|
||||
if ( !pact && prec->pact ) return(0);
|
||||
|
||||
prec->pact = TRUE;
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
if ( pact ) {
|
||||
/* Update timestamp again for asynchronous devices */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
monitor(prec);
|
||||
recGblFwdLink(prec);
|
||||
|
||||
@@ -161,7 +161,6 @@ static long cvt_dbaddr(DBADDR *paddr)
|
||||
{
|
||||
subArrayRecord *prec = (subArrayRecord *) paddr->precord;
|
||||
|
||||
paddr->pfield = prec->bptr;
|
||||
paddr->no_elements = prec->malm;
|
||||
paddr->field_type = prec->ftvl;
|
||||
paddr->field_size = dbValueSize(prec->ftvl);
|
||||
@@ -174,6 +173,7 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
|
||||
{
|
||||
subArrayRecord *prec = (subArrayRecord *) paddr->precord;
|
||||
|
||||
paddr->pfield = prec->bptr;
|
||||
if (prec->udf)
|
||||
*no_elements = 0;
|
||||
else
|
||||
@@ -293,7 +293,7 @@ static void monitor(subArrayRecord *prec)
|
||||
monitor_mask = recGblResetAlarms(prec);
|
||||
monitor_mask |= (DBE_LOG|DBE_VALUE);
|
||||
|
||||
db_post_events(prec, prec->bptr, monitor_mask);
|
||||
db_post_events(prec, (void*)&prec->val, monitor_mask);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ int main(int argc, char *argv[])
|
||||
xmacro;
|
||||
bool interactive = true;
|
||||
bool loadedDb = false;
|
||||
bool ranScript = false;
|
||||
|
||||
// attempt to compute relative paths
|
||||
{
|
||||
@@ -228,7 +229,7 @@ int main(int argc, char *argv[])
|
||||
std::cout<<"# End "<<argv[optind]<<"\n";
|
||||
|
||||
epicsThreadSleep(0.2);
|
||||
loadedDb = true; /* Give it the benefit of the doubt... */
|
||||
ranScript = true; /* Assume the script has done any necessary initialization */
|
||||
}
|
||||
|
||||
if (loadedDb) {
|
||||
@@ -247,7 +248,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
} else {
|
||||
if (loadedDb) {
|
||||
if (loadedDb || ranScript) {
|
||||
epicsThreadExitMain();
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
include "xxxRecord.dbd"
|
||||
device(xxx,CONSTANT,devXxxSoft,"SoftChannel")
|
||||
device(xxx,CONSTANT,devXxxSoft,"Soft Channel")
|
||||
|
||||
@@ -29,6 +29,7 @@ use DBD::Function;
|
||||
use DBD::Variable;
|
||||
|
||||
our $debug=0;
|
||||
our $allowAutoDeclarations=0;
|
||||
|
||||
sub ParseDBD {
|
||||
(my $dbd, $_) = @_;
|
||||
@@ -102,8 +103,11 @@ sub ParseDBD {
|
||||
unquote($1, $2, $3, $4);
|
||||
my $rtyp = $dbd->recordtype($record_type);
|
||||
if (!defined $rtyp) {
|
||||
my $msg = "Device '$choice' refers to unknown record type '$record_type'.";
|
||||
dieContext($msg, "DBD files must be combined in the correct order.")
|
||||
unless $allowAutoDeclarations;
|
||||
warn "$msg\nRecord type '$record_type' declared.\n";
|
||||
$rtyp = DBD::Recordtype->new($record_type);
|
||||
warn "Device using unknown record type '$record_type', declaration created\n";
|
||||
$dbd->add($rtyp);
|
||||
}
|
||||
$rtyp->add_device(DBD::Device->new($link_type, $dset, $choice));
|
||||
|
||||
@@ -111,31 +111,47 @@ if ($opt_D) { # Output dependencies only, to stdout
|
||||
|
||||
sub oldtables {
|
||||
# Output compatible with R3.14.x
|
||||
|
||||
my @fields = $rtyp->fields;
|
||||
my $no_fields = scalar @fields;
|
||||
|
||||
print OUTFILE << "__EOF__";
|
||||
#include <epicsExport.h>
|
||||
#include <cantProceed.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
static int ${rn}RecordSizeOffset(dbRecordType *prt)
|
||||
{
|
||||
${rn}Record *prec = 0;
|
||||
|
||||
if (prt->no_fields != ${no_fields}) {
|
||||
cantProceed("IOC build or installation error:\\n"
|
||||
" The ${rn}Record defined in the DBD file has %d fields,\\n"
|
||||
" but the record support code was built with ${no_fields}.\\n",
|
||||
prt->no_fields);
|
||||
}
|
||||
__EOF__
|
||||
|
||||
print OUTFILE
|
||||
"#include <epicsAssert.h>\n" .
|
||||
"#include <epicsExport.h>\n" .
|
||||
"#ifdef __cplusplus\n" .
|
||||
"extern \"C\" {\n" .
|
||||
"#endif\n" .
|
||||
"static int ${rn}RecordSizeOffset(dbRecordType *prt)\n" .
|
||||
"{\n" .
|
||||
" ${rn}Record *prec = 0;\n\n" .
|
||||
" assert(prt->no_fields == " . scalar($rtyp->fields) . ");\n" .
|
||||
join("\n", map {
|
||||
" prt->papFldDes[${rn}Record" . $_->name . "]->size = " .
|
||||
"sizeof(prec->" . $_->C_name . ");"
|
||||
} $rtyp->fields) . "\n" .
|
||||
join("\n", map {
|
||||
" prt->papFldDes[${rn}Record" . $_->name . "]->offset = (unsigned short)(" .
|
||||
"(char *)&prec->" . $_->C_name . " - (char *)prec);"
|
||||
} $rtyp->fields) . "\n" .
|
||||
" prt->rec_size = sizeof(*prec);\n" .
|
||||
" return 0;\n" .
|
||||
"}\n" .
|
||||
"epicsExportRegistrar(${rn}RecordSizeOffset);\n\n" .
|
||||
"#ifdef __cplusplus\n" .
|
||||
"}\n" .
|
||||
"#endif\n";
|
||||
my $fn = $_->name;
|
||||
my $cn = $_->C_name;
|
||||
" prt->papFldDes[${rn}Record${fn}]->size = " .
|
||||
"sizeof(prec->${cn});\n" .
|
||||
" prt->papFldDes[${rn}Record${fn}]->offset = " .
|
||||
"(unsigned short)((char *)&prec->${cn} - (char *)prec);"
|
||||
} @fields), << "__EOF__";
|
||||
|
||||
prt->rec_size = sizeof(*prec);
|
||||
return 0;
|
||||
}
|
||||
epicsExportRegistrar(${rn}RecordSizeOffset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
__EOF__
|
||||
}
|
||||
|
||||
sub newtables {
|
||||
|
||||
@@ -31,6 +31,9 @@ my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32?
|
||||
|
||||
my ($file, $subname, $bldTop) = @ARGV;
|
||||
|
||||
# Auto-declaration of record types is needed to build loadable modules
|
||||
$DBD::Parser::allowAutoDeclarations = 1;
|
||||
|
||||
my $dbd = DBD->new();
|
||||
ParseDBD($dbd, Readfile($file, "", \@path));
|
||||
|
||||
|
||||
@@ -612,7 +612,7 @@ MAIN(chfPluginTest)
|
||||
/* tag i */
|
||||
e1 = e_alloc; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"alloc-fail\":{\"i\":1}}")),
|
||||
"x.{'alloc-fail':{i:1}}")),
|
||||
"create channel for alloc-fail: allocPvt returning NULL");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
@@ -627,7 +627,7 @@ MAIN(chfPluginTest)
|
||||
/* tag D (t and d) and f */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"D\":1.2e15,\"f\":false}}")),
|
||||
"x.{'strict-tagged':{D:1.2e15,f:false}}")),
|
||||
"create channel for strict-tagged parsing: D (t and d) and f");
|
||||
testOk(checkValues(puser1, 3, 12, 0, 1.2e15, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
@@ -641,7 +641,7 @@ MAIN(chfPluginTest)
|
||||
/* tag D2 (t and d) and f */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"D2\":1.2e15,\"f\":false}}")),
|
||||
"x.{'strict-tagged':{D2:1.2e15,f:false}}")),
|
||||
"create channel for strict-tagged parsing: D2 (t and d) and f");
|
||||
testOk(checkValues(puser1, 4, 12, 0, 1.2e15, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
@@ -655,7 +655,7 @@ MAIN(chfPluginTest)
|
||||
/* tag F: (t and f), d missing) */
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"F\":false}}")),
|
||||
"x.{'strict-tagged':{F:false}}")),
|
||||
"create channel for strict-tagged parsing: F (t and f), d missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
@@ -663,7 +663,7 @@ MAIN(chfPluginTest)
|
||||
/* tag I: (t and i) and f, d missing) */
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"I\":1,\"f\":false}}")),
|
||||
"x.{'strict-tagged':{I:1,f:false}}")),
|
||||
"create channel for strict-tagged parsing: I (t and i) and f, d missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
@@ -676,7 +676,7 @@ MAIN(chfPluginTest)
|
||||
/* tag i */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"I\":1}}")),
|
||||
"x.{'sloppy-tagged':{I:1}}")),
|
||||
"create channel for sloppy-tagged parsing: I");
|
||||
testOk(checkValues(puser1, 1, 1, 1, 1.234e5, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
@@ -690,7 +690,7 @@ MAIN(chfPluginTest)
|
||||
/* tag f */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"F\":false}}")),
|
||||
"x.{'sloppy-tagged':{F:false}}")),
|
||||
"create channel for sloppy-tagged parsing: F");
|
||||
testOk(checkValues(puser1, 2, 12, 0, 1.234e5, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
@@ -704,7 +704,7 @@ MAIN(chfPluginTest)
|
||||
/* tag d */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"D\":1.2e15}}")),
|
||||
"x.{'sloppy-tagged':{D:1.2e15}}")),
|
||||
"create channel for sloppy-tagged parsing: D");
|
||||
testOk(checkValues(puser1, 3, 12, 1, 1.2e15, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
@@ -718,7 +718,7 @@ MAIN(chfPluginTest)
|
||||
/* tag s */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"S\":\"bar\"}}")),
|
||||
"x.{'sloppy-tagged':{S:'bar'}}")),
|
||||
"create channel for sloppy-tagged parsing: S");
|
||||
testOk(checkValues(puser1, 4, 12, 1, 1.234e5, "bar", 0, 4),
|
||||
"guards intact, values correct");
|
||||
@@ -732,7 +732,7 @@ MAIN(chfPluginTest)
|
||||
/* tag c */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"C\":\"R\"}}")),
|
||||
"x.{'sloppy-tagged':{C:'R'}}")),
|
||||
"create channel for sloppy-tagged parsing: C");
|
||||
testOk(checkValues(puser1, 5, 12, 1, 1.234e5, "hello", 0, 1),
|
||||
"guards intact, values correct");
|
||||
@@ -749,7 +749,7 @@ MAIN(chfPluginTest)
|
||||
/* All perfect */
|
||||
testHead("STRICT parsing: all ok");
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate("x.{\"strict\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
testOk(!!(pch = dbChannelCreate("x.{strict:{i:1,f:false,d:1.2e15,s:'bar',c:'R'}}")),
|
||||
"create channel for strict parsing: JSON correct");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.2e15, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
@@ -765,35 +765,35 @@ MAIN(chfPluginTest)
|
||||
testHead("STRICT parsing: any missing parameter must fail");
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\"}}")),
|
||||
"x.{strict:{i:1,f:false,d:1.2e15,s:'bar'}}")),
|
||||
"create channel for strict parsing: c missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"f\":false,\"i\":1,\"d\":1.2e15,\"c\":\"R\"}}")),
|
||||
"x.{strict:{f:false,i:1,d:1.2e15,c:'R'}}")),
|
||||
"create channel for strict parsing: s missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"i\":1,\"c\":\"R\",\"f\":false,\"s\":\"bar\"}}")),
|
||||
"x.{strict:{i:1,c:'R',f:false,s:'bar'}}")),
|
||||
"create channel for strict parsing: d missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"d\":1.2e15,\"c\":\"R\",\"i\":1,\"s\":\"bar\"}}")),
|
||||
"x.{strict:{d:1.2e15,c:'R',i:1,s:'bar'}}")),
|
||||
"create channel for strict parsing: f missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"c\":\"R\",\"s\":\"bar\",\"f\":false,\"d\":1.2e15}}")),
|
||||
"x.{strict:{c:'R',s:'bar',f:false,d:1.2e15}}")),
|
||||
"create channel for strict parsing: i missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
@@ -805,7 +805,7 @@ MAIN(chfPluginTest)
|
||||
testHead("NOCONV parsing: missing parameters get default value");
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\"}}")),
|
||||
"x.{noconv:{i:1,f:false,d:1.2e15,s:'bar'}}")),
|
||||
"create channel for noconv parsing: c missing");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.2e15, "bar", 0, 4),
|
||||
"guards intact, values correct");
|
||||
@@ -819,28 +819,28 @@ MAIN(chfPluginTest)
|
||||
|
||||
e1 = e_any;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"c\":\"R\"}}")),
|
||||
"x.{noconv:{i:1,f:false,d:1.2e15,c:'R'}}")),
|
||||
"create channel for noconv parsing: s missing");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.2e15, "hello", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"f\":false,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
"x.{noconv:{i:1,f:false,s:'bar',c:'R'}}")),
|
||||
"create channel for noconv parsing: d missing");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.234e5, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
"x.{noconv:{i:1,d:1.2e15,s:'bar',c:'R'}}")),
|
||||
"create channel for noconv parsing: f missing");
|
||||
testOk(checkValues(puser1, 99, 1, 1, 1.2e15, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"f\":false,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
"x.{noconv:{f:false,d:1.2e15,s:'bar',c:'R'}}")),
|
||||
"create channel for noconv parsing: i missing");
|
||||
testOk(checkValues(puser1, 99, 12, 0, 1.2e15, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
@@ -849,7 +849,7 @@ MAIN(chfPluginTest)
|
||||
/* Reject wrong types */
|
||||
#define WRONGTYPETEST(Var, Val, Typ) \
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0; \
|
||||
testOk(!(pch = dbChannelCreate("x.{\"noconv\":{\""#Var"\":"#Val"}}")), \
|
||||
testOk(!(pch = dbChannelCreate("x.{noconv:{'"#Var"':"#Val"}}")), \
|
||||
"create channel for noconv parsing: wrong type "#Typ" for "#Var); \
|
||||
testOk(!puser1, "user part cleaned up"); \
|
||||
if (!testOk(c1 == e1, "all expected calls happened")) \
|
||||
@@ -877,8 +877,8 @@ MAIN(chfPluginTest)
|
||||
|
||||
#define CONVTESTGOOD(Var, Val, Typ, Ival, Fval, Dval, Sval1, Sval2, Cval) \
|
||||
e1 = e_alloc | e_ok; c1 = 0; \
|
||||
testDiag("Calling dbChannelCreate x.{\"sloppy\":{\""#Var"\":"#Val"}}"); \
|
||||
testOk(!!(pch = dbChannelCreate("x.{\"sloppy\":{\""#Var"\":"#Val"}}")), \
|
||||
testDiag("Calling dbChannelCreate x.{sloppy:{"#Var":"#Val"}}"); \
|
||||
testOk(!!(pch = dbChannelCreate("x.{sloppy:{"#Var":"#Val"}}")), \
|
||||
"create channel for sloppy parsing: "#Typ" (good) for "#Var); \
|
||||
testOk(checkValues(puser1, 99, Ival, Fval, Dval, Sval1, Sval2, Cval), \
|
||||
"guards intact, values correct"); \
|
||||
@@ -892,8 +892,8 @@ MAIN(chfPluginTest)
|
||||
|
||||
#define CONVTESTBAD(Var, Val, Typ) \
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0; \
|
||||
testDiag("Calling dbChannelCreate x.{\"sloppy\":{\""#Var"\":"#Val"}}"); \
|
||||
testOk(!(pch = dbChannelCreate("x.{\"sloppy\":{\""#Var"\":"#Val"}}")), \
|
||||
testDiag("Calling dbChannelCreate x.{sloppy:{"#Var":"#Val"}}"); \
|
||||
testOk(!(pch = dbChannelCreate("x.{sloppy:{"#Var":"#Val"}}")), \
|
||||
"create channel for sloppy parsing: "#Typ" (bad) for "#Var); \
|
||||
testOk(!puser1, "user part cleaned up"); \
|
||||
if (!testOk(c1 == e1, "create channel: all expected calls happened")) \
|
||||
@@ -1018,36 +1018,36 @@ MAIN(chfPluginTest)
|
||||
if (!testOk(c1 == e1, "delete channel (1): all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
|
||||
if (!testOk(c2 == e2, "delete channel (2): all expected calls happened")) testDiag("expected %#x - called %#x", e2, c2);
|
||||
|
||||
CHAINTEST1("1 pre", "{\"pre\":{}}", e_reg_pre, e_pre | e_dtor, 1); /* One filter, pre chain */
|
||||
CHAINTEST1("1 post", "{\"post\":{}}", e_reg_post, e_post | e_dtor, 1); /* One filter, post chain */
|
||||
CHAINTEST1("1 both", "{\"sloppy\":{}}", e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, 2); /* One, both chains */
|
||||
CHAINTEST2("2 pre", "{\"pre\":{},\"pre\":{}}", e_reg_pre, e_pre | e_dtor, e_reg_pre, e_pre, 2); /* Two filters, pre chain */
|
||||
CHAINTEST2("2 post", "{\"post\":{},\"post\":{}}", e_reg_post, e_post | e_dtor, e_reg_post, e_post, 2); /* Two filters, post chain */
|
||||
CHAINTEST2("2 both", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains */
|
||||
CHAINTEST1("1 pre", "{pre:{}}", e_reg_pre, e_pre | e_dtor, 1); /* One filter, pre chain */
|
||||
CHAINTEST1("1 post", "{post:{}}", e_reg_post, e_post | e_dtor, 1); /* One filter, post chain */
|
||||
CHAINTEST1("1 both", "{sloppy:{}}", e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, 2); /* One, both chains */
|
||||
CHAINTEST2("2 pre", "{pre:{},pre:{}}", e_reg_pre, e_pre | e_dtor, e_reg_pre, e_pre, 2); /* Two filters, pre chain */
|
||||
CHAINTEST2("2 post", "{post:{},post:{}}", e_reg_post, e_post | e_dtor, e_reg_post, e_post, 2); /* Two filters, post chain */
|
||||
CHAINTEST2("2 both", "{sloppy:{},sloppy:{}}", /* Two, both chains */
|
||||
e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, e_reg_pre | e_reg_post, e_pre | e_post, 4);
|
||||
CHAINTEST2("1 pre, 1 post", "{\"pre\":{},\"post\":{}}", e_reg_pre, e_pre | e_dtor, e_reg_post, e_post, 2); /* Two, pre then post */
|
||||
CHAINTEST2("1 post, 1 pre", "{\"post\":{},\"pre\":{}}", e_reg_post, e_post, e_reg_pre, e_pre | e_dtor, 2); /* Two, post then pre */
|
||||
CHAINTEST2("1 pre, 1 both", "{\"pre\":{},\"sloppy\":{}}", /* Two, pre then both */
|
||||
CHAINTEST2("1 pre, 1 post", "{pre:{},post:{}}", e_reg_pre, e_pre | e_dtor, e_reg_post, e_post, 2); /* Two, pre then post */
|
||||
CHAINTEST2("1 post, 1 pre", "{post:{},pre:{}}", e_reg_post, e_post, e_reg_pre, e_pre | e_dtor, 2); /* Two, post then pre */
|
||||
CHAINTEST2("1 pre, 1 both", "{pre:{},sloppy:{}}", /* Two, pre then both */
|
||||
e_reg_pre, e_pre | e_dtor, e_reg_pre | e_reg_post, e_pre | e_post, 3);
|
||||
CHAINTEST2("1 both, 1 pre", "{\"sloppy\":{},\"pre\":{}}", /* Two, both then pre */
|
||||
CHAINTEST2("1 both, 1 pre", "{sloppy:{},pre:{}}", /* Two, both then pre */
|
||||
e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, e_reg_pre, e_pre, 3);
|
||||
CHAINTEST2("1 post, 1 both", "{\"post\":{},\"sloppy\":{}}", /* Two, post then both */
|
||||
CHAINTEST2("1 post, 1 both", "{post:{},sloppy:{}}", /* Two, post then both */
|
||||
e_reg_post, e_post, e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, 3);
|
||||
CHAINTEST2("1 both, 1 post", "{\"sloppy\":{},\"post\":{}}", /* Two, both then post */
|
||||
CHAINTEST2("1 both, 1 post", "{sloppy:{},post:{}}", /* Two, both then post */
|
||||
e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, e_reg_post, e_post, 3);
|
||||
|
||||
/* Plugins dropping updates */
|
||||
drop = 0;
|
||||
CHAINTEST2("2 both (drop at 0)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 0 */
|
||||
CHAINTEST2("2 both (drop at 0)", "{sloppy:{},sloppy:{}}", /* Two, both chains, drop at filter 0 */
|
||||
e_reg_pre | e_reg_post, e_pre, e_reg_pre | e_reg_post, 0, -1);
|
||||
drop = 1;
|
||||
CHAINTEST2("2 both (drop at 1)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 1 */
|
||||
CHAINTEST2("2 both (drop at 1)", "{sloppy:{},sloppy:{}}", /* Two, both chains, drop at filter 1 */
|
||||
e_reg_pre | e_reg_post, e_pre, e_reg_pre | e_reg_post, e_pre, -1);
|
||||
drop = 2;
|
||||
CHAINTEST2("2 both (drop at 2)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 2 */
|
||||
CHAINTEST2("2 both (drop at 2)", "{sloppy:{},sloppy:{}}", /* Two, both chains, drop at filter 2 */
|
||||
e_reg_pre | e_reg_post, e_pre | e_post, e_reg_pre | e_reg_post, e_pre, -1);
|
||||
drop = 3;
|
||||
CHAINTEST2("2 both (drop at 3)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 3 */
|
||||
CHAINTEST2("2 both (drop at 3)", "{sloppy:{},sloppy:{}}", /* Two, both chains, drop at filter 3 */
|
||||
e_reg_pre | e_reg_post, e_pre | e_post, e_reg_pre | e_reg_post, e_pre | e_post, -1);
|
||||
drop = -1;
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
|
||||
/* dbChannelTest() allows but ignores field modifiers */
|
||||
testOk1(!dbChannelTest("x.NAME$"));
|
||||
testOk1(!dbChannelTest("x.{}"));
|
||||
testOk1(!dbChannelTest("x.VAL{\"json\":true}"));
|
||||
testOk1(!dbChannelTest("x.VAL{json:true}"));
|
||||
|
||||
/* dbChannelCreate() accepts field modifiers */
|
||||
testOk1(!!(pch = dbChannelCreate("x.{}")));
|
||||
@@ -212,34 +212,34 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
|
||||
testOk(!dbChannelCreate("x.NOFIELD"), "Create, bad field");
|
||||
testOk(!dbChannelCreate("x.{not-json}"), "Create, bad JSON");
|
||||
eltc(0);
|
||||
testOk(!dbChannelCreate("x.{\"none\":null}"), "Create, bad filter");
|
||||
testOk(!dbChannelCreate("x.{none:null}"), "Create, bad filter");
|
||||
eltc(1);
|
||||
|
||||
dbRegisterFilter("any", &testIf, NULL);
|
||||
|
||||
/* Parser event rejection by filter */
|
||||
e = e_start;
|
||||
testOk1(!dbChannelCreate("x.{\"any\":null}"));
|
||||
testOk1(!dbChannelCreate("x.{any:null}"));
|
||||
|
||||
r = e_start;
|
||||
e = e_start | e_null | e_abort;
|
||||
testOk1(!dbChannelCreate("x.{\"any\":null}"));
|
||||
testOk1(!dbChannelCreate("x.{any:null}"));
|
||||
|
||||
r = e_start | e_null;
|
||||
e = e_start | e_null | e_end;
|
||||
testOk1(!dbChannelCreate("x.{\"any\":null}"));
|
||||
testOk1(!dbChannelCreate("x.{any:null}"));
|
||||
|
||||
/* Successful parsing... */
|
||||
r = r_any;
|
||||
e = e_start | e_null | e_end;
|
||||
testOk1(!!(pch = dbChannelCreate("x.{\"any\":null}")));
|
||||
testOk1(!!(pch = dbChannelCreate("x.{any:null}")));
|
||||
e = e_close;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
dbRegisterFilter("scalar", &testIf, NULL);
|
||||
|
||||
e = e_start | e_null | e_end;
|
||||
testOk1(!!(pch = dbChannelCreate("x.{\"scalar\":null}")));
|
||||
testOk1(!!(pch = dbChannelCreate("x.{scalar:null}")));
|
||||
|
||||
e = e_report;
|
||||
dbChannelShow(pch, 2, 2);
|
||||
@@ -249,23 +249,23 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
|
||||
|
||||
e = e_start | e_start_array | e_boolean | e_integer | e_end_array
|
||||
| e_end;
|
||||
testOk1(!!(pch = dbChannelCreate("x.{\"any\":[true,1]}")));
|
||||
testOk1(!!(pch = dbChannelCreate("x.{any:[true,1]}")));
|
||||
e = e_close;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
e = e_start | e_start_map | e_map_key | e_double | e_string | e_end_map
|
||||
| e_end;
|
||||
testOk1(!!(pch = dbChannelCreate("x.{\"any\":{\"a\":2.7183,\"b\":\"c\"}}")));
|
||||
testOk1(!!(pch = dbChannelCreate("x.{any:{a:2.7183,b:'c'}}")));
|
||||
e = e_close;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
/* More event rejection */
|
||||
r = r_scalar;
|
||||
e = e_start | e_start_array | e_abort;
|
||||
testOk1(!dbChannelCreate("x.{\"scalar\":[null]}"));
|
||||
testOk1(!dbChannelCreate("x.{scalar:[null]}"));
|
||||
|
||||
e = e_start | e_start_map | e_abort;
|
||||
testOk1(!dbChannelCreate("x.{\"scalar\":{}}"));
|
||||
testOk1(!dbChannelCreate("x.{scalar:{}}"));
|
||||
|
||||
testIocShutdownOk();
|
||||
testdbCleanup();
|
||||
|
||||
@@ -67,6 +67,7 @@ static const struct testParseDataT {
|
||||
{" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}},
|
||||
{" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}},
|
||||
{" {\"x\":true} ", {JSON_LINK, "{\"x\":true}", 0, "", /*{}*/}},
|
||||
{" {'x':true} ", {JSON_LINK, "{'x':true}", 0, "", /*{}*/}},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
@@ -255,7 +256,7 @@ typedef struct {
|
||||
} testHWDataT;
|
||||
|
||||
static const testHWDataT testHWData[] = {
|
||||
{"rJSON_LINK", JSON_LINK, "{\"x\":true}", {0}, "{\"x\":true}"},
|
||||
{"rJSON_LINK", JSON_LINK, "{x:true}", {0}, "{x:true}"},
|
||||
{"rVME_IO", VME_IO, "#C100 S101 @parm VME_IO", {100, 101}, "parm VME_IO"},
|
||||
{"rCAMAC_IO", CAMAC_IO, "#B11 C12 N13 A14 F15 @parm CAMAC_IO", {11, 12, 13, 14, 15}, "parm CAMAC_IO"},
|
||||
{"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"},
|
||||
@@ -585,9 +586,11 @@ void testJLink(void)
|
||||
testdbPutFieldOk("j2.PROC", DBF_LONG, 1);
|
||||
testdbPutFieldOk("j3.PROC", DBF_LONG, 1);
|
||||
|
||||
testdbGetFieldEqual("j1.INP", DBF_STRING, "{\"z\":{\"good\":1}}");
|
||||
testdbGetFieldEqual("j1.INP", DBF_STRING, "{z:{good:1}}");
|
||||
testdbGetFieldEqual("j1.VAL", DBF_LONG, 1);
|
||||
testdbGetFieldEqual("j2.INP", DBF_STRING, "{\"z\":{'good':2}}");
|
||||
testdbGetFieldEqual("j2.VAL", DBF_LONG, 2);
|
||||
testdbGetFieldEqual("j2.TSEL", DBF_STRING, "j1.TIME NPP NMS");
|
||||
testdbGetFieldEqual("j3.VAL", DBF_LONG, 3);
|
||||
|
||||
testNumZ(6);
|
||||
@@ -596,7 +599,7 @@ void testJLink(void)
|
||||
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
|
||||
testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
|
||||
|
||||
testdbPutFieldOk("j2.TSEL", DBF_STRING, "{\"z\":{\"good\":0}}");
|
||||
testdbPutFieldOk("j2.TSEL", DBF_STRING, "{'z':{good:0}}");
|
||||
testdbPutFieldOk("j2.PROC", DBF_LONG, 1);
|
||||
|
||||
testNumZ(7);
|
||||
@@ -611,8 +614,8 @@ void testJLink(void)
|
||||
testNumZ(7);
|
||||
|
||||
/* Check SDIS using a JSON link prevents processing */
|
||||
testdbPutFieldOk("j1.SDIS", DBF_STRING, "{\"z\":{\"good\":1}}");
|
||||
testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":1}}");
|
||||
testdbPutFieldOk("j1.SDIS", DBF_STRING, "{z:{good:1}}");
|
||||
testdbPutFieldOk("j1.INP", DBF_STRING, "{z:{good:1}}");
|
||||
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
|
||||
testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
|
||||
|
||||
@@ -697,7 +700,7 @@ void testTSEL(void)
|
||||
|
||||
MAIN(dbPutLinkTest)
|
||||
{
|
||||
testPlan(337);
|
||||
testPlan(342);
|
||||
testLinkParse();
|
||||
testLinkFailParse();
|
||||
testCADBSet();
|
||||
|
||||
@@ -7,8 +7,8 @@ record(x, "j1") {
|
||||
}
|
||||
|
||||
record(x, "j2") {
|
||||
field(INP, {z:{good:2}})
|
||||
field(TSEL, "j1.TIME")
|
||||
field(INP, {"z":{'good':2}})
|
||||
field(TSEL, 'j1.TIME')
|
||||
}
|
||||
|
||||
record(x, "j3") {
|
||||
|
||||
@@ -148,27 +148,128 @@ static void testDbVerify(const char *record)
|
||||
if (dbFindRecord(&entry, record) != 0)
|
||||
testAbort("Can't find record '%s'", record);
|
||||
|
||||
dbFindField(&entry, "UDF");
|
||||
dbFindField(&entry, "C8");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "-128", NULL);
|
||||
verify(&entry, "127", NULL);
|
||||
verify(&entry, "128", "Number too large for field type");
|
||||
verify(&entry, "0x7f", NULL);
|
||||
verify(&entry, "0x80", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "U8");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "128", NULL);
|
||||
verify(&entry, "255", NULL);
|
||||
verify(&entry, "256", "Number too large for field type");
|
||||
verify(&entry, "0xff", NULL);
|
||||
verify(&entry, "0x100", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "PHAS");
|
||||
dbFindField(&entry, "I16");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "-32768", NULL);
|
||||
verify(&entry, "-32769", "Number too large for field type");
|
||||
verify(&entry, "0x7fff", NULL);
|
||||
verify(&entry, "32768", "Number too large for field type");
|
||||
verify(&entry, "-0x8000", NULL);
|
||||
verify(&entry, "0x7fff", NULL);
|
||||
verify(&entry, "0x8000", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "VAL");
|
||||
dbFindField(&entry, "U16");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "-32768", NULL);
|
||||
verify(&entry, "-65535", NULL);
|
||||
verify(&entry, "-65536", "Number too large for field type");
|
||||
verify(&entry, "65535", NULL);
|
||||
verify(&entry, "0xffff", NULL);
|
||||
verify(&entry, "0x10000", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "I32");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "-123456789", NULL);
|
||||
verify(&entry, "123456789", NULL);
|
||||
verify(&entry, "-0x80000000", NULL);
|
||||
verify(&entry, "-0x80000001", "Number too large for field type");
|
||||
verify(&entry, "0x1234FEDC", NULL);
|
||||
verify(&entry, "0x7fffffff", NULL);
|
||||
verify(&entry, "0x100000000", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "U32");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "-123456789", NULL);
|
||||
verify(&entry, "123456789", NULL);
|
||||
verify(&entry, "-0xffffffff", NULL);
|
||||
verify(&entry, "-0x100000000", "Number too large for field type");
|
||||
verify(&entry, "0x1234FEDC", NULL);
|
||||
verify(&entry, "0xffffffff", NULL);
|
||||
verify(&entry, "0x100000000", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "I64");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "-1234567890123456789", NULL);
|
||||
verify(&entry, "1234567890123456789", NULL);
|
||||
verify(&entry, "-0x8000000000000000", NULL);
|
||||
verify(&entry, "-0x8000000000000001", "Number too large for field type");
|
||||
verify(&entry, "0x123456780FEDCBA9", NULL);
|
||||
verify(&entry, "0x7fffffffffffffff", NULL);
|
||||
verify(&entry, "0x10000000000000000", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "U64");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "-1234567890123456789", NULL);
|
||||
verify(&entry, "1234567890123456789", NULL);
|
||||
verify(&entry, "-0xffffffffffffffff", NULL);
|
||||
verify(&entry, "-0x10000000000000000", "Number too large for field type");
|
||||
verify(&entry, "0x123456780FEDCBA9", NULL);
|
||||
verify(&entry, "0x7fffffffffffffff", NULL);
|
||||
verify(&entry, "0x10000000000000000", "Number too large for field type");
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2345", "Extraneous characters after number");
|
||||
|
||||
dbFindField(&entry, "F32");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "1.2345", NULL);
|
||||
verify(&entry, ".12345", NULL);
|
||||
verify(&entry, "-.12345", NULL);
|
||||
verify(&entry, "+.12345", NULL);
|
||||
verify(&entry, "1.e23", NULL);
|
||||
verify(&entry, "1.e-23", NULL);
|
||||
verify(&entry, "Infinity", NULL);
|
||||
verify(&entry, "-Infinity", NULL);
|
||||
verify(&entry, "+Infinity", NULL);
|
||||
verify(&entry, "Nan", NULL);
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2e-345", "Number too small for field type");
|
||||
verify(&entry, "1.2e345", "Number too large for field type");
|
||||
|
||||
dbFindField(&entry, "F64");
|
||||
verify(&entry, "0", NULL);
|
||||
verify(&entry, "1.2345", NULL);
|
||||
verify(&entry, ".12345", NULL);
|
||||
verify(&entry, "-.12345", NULL);
|
||||
verify(&entry, "+.12345", NULL);
|
||||
verify(&entry, "1.e234", NULL);
|
||||
verify(&entry, "1.e-234", NULL);
|
||||
verify(&entry, "Infinity", NULL);
|
||||
verify(&entry, "-Infinity", NULL);
|
||||
verify(&entry, "+Infinity", NULL);
|
||||
verify(&entry, "Nan", NULL);
|
||||
verify(&entry, "None", "Not a valid integer");
|
||||
verify(&entry, "1.2e-345", "Number too small for field type");
|
||||
verify(&entry, "1.2e345", "Number too large for field type");
|
||||
|
||||
dbFindField(&entry, "DESC");
|
||||
verify(&entry, "", NULL);
|
||||
verify(&entry, "abcdefghijklmnopqrstuvwxyz", NULL);
|
||||
@@ -193,7 +294,7 @@ void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(dbStaticTest)
|
||||
{
|
||||
testPlan(223);
|
||||
testPlan(310);
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user