Compare commits
291 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fab3cafc5 | ||
|
|
e4811d5a28 | ||
|
|
34af1a12bc | ||
|
|
0301e60629 | ||
|
|
759a737983 | ||
|
|
eeddf54b84 | ||
|
|
6f6ab3b758 | ||
|
|
59d16c56a1 | ||
|
|
58edb984c9 | ||
|
|
eb3207ee21 | ||
|
|
098ee6c063 | ||
|
|
54c02e2c24 | ||
|
|
efc7cbaf7f | ||
|
|
ede35aa152 | ||
|
|
a8e8d22c31 | ||
| c2df1c6fe5 | |||
| c5a7548526 | |||
| dc70dfd625 | |||
| 20e20cbf2b | |||
| 2e44ca586f | |||
| c9619d013a | |||
| ec650e8c3f | |||
|
|
d47fa4caa4 | ||
|
|
f0369058bb | ||
|
|
df96c0170a | ||
|
|
a411a19b2a | ||
|
|
c0db7a0beb | ||
|
|
52dfb89741 | ||
|
|
b652e8230a | ||
|
|
0efffc1bcb | ||
|
|
d7030ae8a5 | ||
|
|
24f30ede22 | ||
|
|
04ee3f2888 | ||
|
|
a373327b59 | ||
|
|
1fa98d489f | ||
|
|
5cef60a3e4 | ||
|
|
20fb6b9ef5 | ||
|
|
a249561677 | ||
|
|
96887926bf | ||
|
|
c8647ffab7 | ||
|
|
e28c914966 | ||
|
|
f086be93a9 | ||
|
|
6feaaebd75 | ||
|
|
5d92d406a1 | ||
|
|
ad1a13730a | ||
|
|
a24a84c315 | ||
|
|
6e7a715380 | ||
|
|
b88b35d117 | ||
|
|
0a20825c6e | ||
|
|
424d678abf | ||
|
|
007279cf29 | ||
|
|
752ca97f7e | ||
|
|
bf0b4d2f61 | ||
|
|
87d5c01853 | ||
|
|
956af730a9 | ||
|
|
32564b1a94 | ||
|
|
5b690d5467 | ||
|
|
9efebb6d3d | ||
|
|
1df973b234 | ||
|
|
c71ebd1221 | ||
|
|
167807f0c4 | ||
|
|
e6b8ecd55e | ||
|
|
9048aa3438 | ||
|
|
5ba8080f6e | ||
|
|
a0a7a94944 | ||
|
|
42c7dbcd21 | ||
|
|
4b8edd2b6f | ||
|
|
d82ab819ef | ||
|
|
5f02bad3fc | ||
|
|
83a685867c | ||
|
|
05311e0c94 | ||
|
|
35f4d3f8dd | ||
|
|
9864f79d67 | ||
|
|
91800787ed | ||
|
|
05b27067cf | ||
|
|
ccdd2808d9 | ||
|
|
00183fcd4b | ||
|
|
1be06fc0e9 | ||
|
|
7cdc44434c | ||
|
|
f3dfb36117 | ||
|
|
500e901e3d | ||
|
|
a3b09ef1b8 | ||
|
|
55d4801eb0 | ||
|
|
af41b95b98 | ||
|
|
c6605b5d87 | ||
|
|
9b9ed04ae2 | ||
|
|
50f9b12e7d | ||
|
|
bfd2684e58 | ||
|
|
95fcf690ad | ||
|
|
0fa3337404 | ||
|
|
e5b6ef9893 | ||
|
|
5b64eaac73 | ||
|
|
30d4a583d0 | ||
|
|
6249ef08f7 | ||
|
|
b5105740e6 | ||
|
|
818f33e78f | ||
|
|
571165df26 | ||
|
|
4df48c91f4 | ||
|
|
32652414b3 | ||
|
|
9c8aaa93cd | ||
|
|
abe819b51d | ||
|
|
cf278b4159 | ||
|
|
50594a8cc3 | ||
|
|
ce420588db | ||
|
|
4d3a27fdb0 | ||
|
|
6176a81a76 | ||
|
|
a722bb9289 | ||
|
|
19daf6136f | ||
|
|
0552f2bb72 | ||
|
|
9bb11e6e88 | ||
|
|
2f8272d3a1 | ||
|
|
7cf2a1daca | ||
|
|
d019e9787a | ||
|
|
4b884c15b1 | ||
|
|
0ace4e4a30 | ||
|
|
3cf2d3737f | ||
|
|
5997018fb0 | ||
|
|
2afa4ea390 | ||
|
|
f0c86c5cb3 | ||
|
|
8e4ffd46a0 | ||
|
|
f109371268 | ||
|
|
e566c52a78 | ||
|
|
8d0bfcbc5b | ||
|
|
3fadf4a26c | ||
|
|
9ebd841738 | ||
|
|
94b0e2621f | ||
|
|
a44ddd586e | ||
|
|
6fbf95ab18 | ||
|
|
5485adacb9 | ||
|
|
6ecc384116 | ||
|
|
66537d01bd | ||
|
|
b6f69241e1 | ||
|
|
4fc549234c | ||
|
|
0bcffb56bb | ||
|
|
60001c0571 | ||
|
|
37b95bc242 | ||
|
|
4e9bb9fe50 | ||
|
|
371cdde6df | ||
|
|
cbae8d37b3 | ||
|
|
9eb88f27d9 | ||
|
|
e329fa3296 | ||
|
|
492672c718 | ||
|
|
b4d7ebd648 | ||
|
|
0f0f9f49d6 | ||
|
|
6d3821adb8 | ||
|
|
92e97af610 | ||
|
|
b0e2e8426f | ||
|
|
3e371da8ec | ||
|
|
91941af992 | ||
|
|
d2644baf38 | ||
|
|
62092d4399 | ||
|
|
6c5d56688d | ||
|
|
a6779df21c | ||
|
|
d8c5379453 | ||
|
|
7a9801a4cb | ||
|
|
f33add020e | ||
|
|
3bebe6e873 | ||
|
|
2fbaa7f926 | ||
|
|
e55e4d7646 | ||
|
|
5efc0cbfce | ||
|
|
3a182a9eea | ||
|
|
0e56e202fc | ||
|
|
d9fd73a850 | ||
|
|
d508962211 | ||
|
|
7cb80d5a17 | ||
|
|
051e3f3bc3 | ||
|
|
db216e63a7 | ||
|
|
7a3c9eaaa0 | ||
|
|
4bece4ad92 | ||
|
|
36f11fba95 | ||
|
|
7017e54930 | ||
|
|
43b623d80e | ||
|
|
132f9105d0 | ||
|
|
1655d68ec4 | ||
|
|
e4a81bb361 | ||
|
|
d1094ee787 | ||
|
|
34baa485bc | ||
| c5012d9f73 | |||
|
|
7c168f20f4 | ||
|
|
1c3aa01846 | ||
|
|
191ff137f1 | ||
|
|
156945c458 | ||
|
|
31fcb77412 | ||
|
|
631f514c7c | ||
|
|
6e496e80d1 | ||
|
|
de7ad13b3c | ||
|
|
2256c979b0 | ||
|
|
5e2a52401f | ||
|
|
7529577e3b | ||
| 6173baed1e | |||
| 71efed8c1b | |||
| 9a09436ac8 | |||
|
|
1c96fd1cb4 | ||
|
|
8d078a0c7d | ||
|
|
8a4051964f | ||
|
|
5ef537684e | ||
|
|
c1dcd728d7 | ||
|
|
78684e0e57 | ||
|
|
f57acd2c10 | ||
|
|
ba5ade1852 | ||
|
|
8a0fc0373b | ||
|
|
4340e76445 | ||
|
|
ce910f52c3 | ||
|
|
219ab33625 | ||
|
|
e9e576f4bb | ||
|
|
5bb1138b87 | ||
|
|
955dcfc7b5 | ||
|
|
07a371703f | ||
|
|
1950a8240c | ||
|
|
a662cae239 | ||
|
|
2b3c6f2e26 | ||
|
|
b1d9c57101 | ||
|
|
446e0d4af8 | ||
|
|
2f51653a9e | ||
|
|
b9899213d4 | ||
|
|
0c12b02d4f | ||
|
|
ac12ccad38 | ||
|
|
8fdaa13c97 | ||
|
|
29fa0621d7 | ||
|
|
6063de9a8b | ||
|
|
465920fcf1 | ||
|
|
b9e9537376 | ||
|
|
fb46786ccb | ||
|
|
abfe30ef13 | ||
|
|
9895ee8b53 | ||
|
|
78b7441383 | ||
|
|
48d070d29d | ||
|
|
a5864e152b | ||
|
|
b6da758275 | ||
|
|
59ee7b32bc | ||
|
|
3f43b0bb8a | ||
|
|
e867b0a095 | ||
|
|
dabcf893f7 | ||
|
|
bf2cdc9f61 | ||
|
|
2ce583ffff | ||
|
|
98aac49a8b | ||
|
|
66ff5a7bb6 | ||
|
|
23e55bf247 | ||
|
|
687dad47da | ||
|
|
7d2ca62a78 | ||
|
|
3d09106b51 | ||
|
|
5cddcea829 | ||
|
|
9b69e63a69 | ||
|
|
422513990e | ||
|
|
3313860691 | ||
|
|
2b8eb97b79 | ||
|
|
9842bd1b20 | ||
|
|
e7ea81c7a2 | ||
|
|
c528948f45 | ||
|
|
00e9ecf7b5 | ||
|
|
65b34874bd | ||
|
|
939d84f31a | ||
|
|
fe4050b8c9 | ||
|
|
1fd7190cf5 | ||
|
|
8e2f78caf5 | ||
|
|
33ffabaa93 | ||
|
|
9c1340d7d5 | ||
|
|
420fb45fbc | ||
|
|
7ce69155a9 | ||
|
|
f6e8a75026 | ||
|
|
88079c9107 | ||
|
|
82ec539e49 | ||
|
|
e34b6c5c0c | ||
| 42d06d6a38 | |||
|
|
21e7e4ddfb | ||
|
|
4efa937429 | ||
|
|
a0ab5aa4a3 | ||
|
|
7c6d049698 | ||
|
|
8175cc8e64 | ||
|
|
72626cd5dd | ||
|
|
8beb7bd2c8 | ||
|
|
51191e6155 | ||
|
|
cb8c7998b6 | ||
|
|
7c991f3f2a | ||
|
|
32d76623f2 | ||
|
|
540a5c87d9 | ||
|
|
a667cc7aa4 | ||
|
|
78d2f20fa8 | ||
|
|
3091f7c56f | ||
|
|
ec87b2a867 | ||
|
|
7a6aa3edd1 | ||
|
|
16c3202992 | ||
| 8e11406fc6 | |||
|
|
967846b950 | ||
|
|
e5aece682e | ||
|
|
f801ca0501 | ||
|
|
9363052956 | ||
|
|
f5cb3cf8f6 | ||
|
|
2f0a7c7342 | ||
|
|
edb9208b01 | ||
|
|
4f0cc20e2b |
@@ -33,6 +33,7 @@ skip_commits:
|
||||
- '.github/*'
|
||||
- '.tools/*'
|
||||
- '.gitattributes'
|
||||
- '.lgtm.yml'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ skip_commits:
|
||||
- 'startup/*'
|
||||
- '.github/*'
|
||||
- '.tools/*'
|
||||
- '.lgtm.yml'
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
2
.ci
2
.ci
Submodule .ci updated: d675de24e6...8a2666a9de
125
.github/workflows/ci-scripts-build.yml
vendored
125
.github/workflows/ci-scripts-build.yml
vendored
@@ -15,6 +15,7 @@ on:
|
||||
- 'startup/*'
|
||||
- '.appveyor/*'
|
||||
- '.tools/*'
|
||||
- '.lgtm.yml'
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
@@ -24,6 +25,7 @@ on:
|
||||
- 'startup/*'
|
||||
- '.appveyor/*'
|
||||
- '.tools/*'
|
||||
- '.lgtm.yml'
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
@@ -34,7 +36,7 @@ env:
|
||||
EPICS_TEST_IMPRECISE_TIMING: YES
|
||||
|
||||
jobs:
|
||||
build-base:
|
||||
native:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
# Set environment variables from matrix parameters
|
||||
@@ -69,10 +71,10 @@ jobs:
|
||||
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||
name: "Ub-20 gcc-9 C++11, static"
|
||||
|
||||
- os: ubuntu-16.04
|
||||
- os: ubuntu-20.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
name: "Ub-16 clang-9"
|
||||
name: "Ub-20 clang-10"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: clang
|
||||
@@ -85,7 +87,6 @@ jobs:
|
||||
configuration: default
|
||||
rtems: "5"
|
||||
rtems_target: RTEMS-pc686-qemu
|
||||
test: NO
|
||||
name: "Ub-20 gcc-9 + RT-5.1 pc686"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
@@ -137,6 +138,7 @@ jobs:
|
||||
rtems: "4.10"
|
||||
name: "Ub-20 gcc-9 + RT-4.10"
|
||||
rtems_target: RTEMS-pc386-qemu
|
||||
test: NO
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
@@ -145,35 +147,6 @@ jobs:
|
||||
name: "Ub-20 gcc-9 + RT-4.9"
|
||||
rtems_target: RTEMS-pc386-qemu
|
||||
|
||||
- os: ubuntu-16.04
|
||||
cmp: gcc-4.8
|
||||
utoolchain: "4.8"
|
||||
configuration: default
|
||||
name: "Ub-16 gcc-4.8"
|
||||
|
||||
- os: ubuntu-16.04
|
||||
cmp: gcc-4.9
|
||||
utoolchain: "4.9"
|
||||
configuration: default
|
||||
name: "Ub-16 gcc-4.9"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc-8
|
||||
utoolchain: "8"
|
||||
configuration: default
|
||||
name: "Ub-20 gcc-8"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc-9
|
||||
utoolchain: "9"
|
||||
configuration: default
|
||||
name: "Ub-20 gcc-9"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
name: "Ub-20 clang-10"
|
||||
|
||||
- os: macos-latest
|
||||
cmp: clang
|
||||
configuration: default
|
||||
@@ -210,14 +183,86 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
|
||||
if: runner.os == 'Linux'
|
||||
- name: "apt-get install ${{ matrix.cmp }}"
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
- name: Build main module
|
||||
run: python .ci/cue.py build
|
||||
- name: Run main module tests
|
||||
run: python .ci/cue.py -T 60M test
|
||||
- name: Upload tapfiles Artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: tapfiles ${{ matrix.name }}
|
||||
path: '**/O.*/*.tap'
|
||||
if-no-files-found: ignore
|
||||
- name: Collect and show test results
|
||||
if: ${{ always() }}
|
||||
run: python .ci/cue.py -T 5M test-results
|
||||
|
||||
docker:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ matrix.image }}
|
||||
# Set environment variables from matrix parameters
|
||||
env:
|
||||
CMP: ${{ matrix.cmp }}
|
||||
BCFG: ${{ matrix.configuration }}
|
||||
EXTRA: ${{ matrix.extra }}
|
||||
TEST: ${{ matrix.test }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Job names also name artifacts, character limitations apply
|
||||
include:
|
||||
- name: "CentOS-7"
|
||||
image: centos:7
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
|
||||
- name: "Fedora-33"
|
||||
image: fedora:33
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
|
||||
- name: "Fedora-latest"
|
||||
image: fedora:latest
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
|
||||
steps:
|
||||
- name: "Build newer Git"
|
||||
# actions/checkout@v2 wants git >=2.18
|
||||
# centos:7 has 1.8
|
||||
if: matrix.image=='centos:7'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install software-properties-common
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install g++-${{ matrix.utoolchain }}
|
||||
if: matrix.utoolchain
|
||||
yum -y install curl make gcc curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker
|
||||
curl https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.29.0.tar.gz | tar -xz
|
||||
cd git-*
|
||||
make -j2 prefix=/usr/local all
|
||||
make prefix=/usr/local install
|
||||
cd ..
|
||||
rm -rf git-*
|
||||
type -a git
|
||||
git --version
|
||||
- name: "Redhat setup"
|
||||
run: |
|
||||
dnfyum() {
|
||||
dnf -y "$@" || yum -y "$@"
|
||||
return $?
|
||||
}
|
||||
dnfyum install python3 gdb make perl gcc-c++ glibc-devel readline-devel ncurses-devel perl-devel perl-Test-Simple
|
||||
git --version || dnfyum install git
|
||||
# rather than just bite the bullet and link python3 -> python,
|
||||
# people would rather just break all existing scripts...
|
||||
[ -e /usr/bin/python ] || ln -sf python3 /usr/bin/python
|
||||
python --version
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@master
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
- name: Build main module
|
||||
|
||||
50
.lgtm.yml
Normal file
50
.lgtm.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
# Configuration for lgtm.com
|
||||
#
|
||||
|
||||
path_classifiers:
|
||||
test:
|
||||
- exclude: /
|
||||
- test
|
||||
- "modules/*/test*"
|
||||
library:
|
||||
- modules/libcom/src/yacc
|
||||
- modules/libcom/src/flex
|
||||
template:
|
||||
- src/template
|
||||
- modules/ca/src/template
|
||||
- modules/database/src/template
|
||||
|
||||
extraction:
|
||||
cpp:
|
||||
prepare:
|
||||
packages:
|
||||
- "libreadline-dev"
|
||||
index:
|
||||
build_command:
|
||||
- "g++ --version"
|
||||
- "make --version"
|
||||
- "perl --version"
|
||||
- "make -sj2 || echo '*** Build failed, ignored for lgtm ***'"
|
||||
|
||||
python:
|
||||
index:
|
||||
include:
|
||||
- src/tools
|
||||
|
||||
# Interpreted languages to be excluded
|
||||
javascript:
|
||||
index:
|
||||
exclude:
|
||||
- "*"
|
||||
|
||||
# Compiled languages to be excluded
|
||||
java:
|
||||
index:
|
||||
build_command: "echo No Java code in this project"
|
||||
csharp:
|
||||
index:
|
||||
build_command: "echo No C# code in this project"
|
||||
go:
|
||||
index:
|
||||
build_command: "echo No Go code in this project"
|
||||
|
||||
@@ -34,6 +34,11 @@ ifeq ($(origin EPICS_HOST_ARCH), undefined)
|
||||
EHA :=
|
||||
endif
|
||||
|
||||
# Make Perl hash iteration reproducible.
|
||||
# See: https://reproducible-builds.org/docs/stable-outputs/
|
||||
#
|
||||
export PERL_HASH_SEED = 0
|
||||
|
||||
-include $(CONFIG)/RELEASE
|
||||
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH)
|
||||
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
|
||||
@@ -47,6 +47,7 @@ OPT_CXXFLAGS_NO = -g
|
||||
|
||||
CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
|
||||
CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))
|
||||
OPT_LDFLAGS_NO = -g
|
||||
|
||||
PIPE_CFLAGS_YES_YES = -pipe
|
||||
PIPE_CFLAGS = $(PIPE_CFLAGS_$(GCC_PIPE)_$(GNU))
|
||||
|
||||
@@ -48,7 +48,7 @@ EPICS_VERSION = 7
|
||||
EPICS_REVISION = 0
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 6
|
||||
EPICS_MODIFICATION = 7
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included in the official EPICS version number if zero
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
EPICS_CA_MAJOR_VERSION = 4
|
||||
EPICS_CA_MINOR_VERSION = 14
|
||||
EPICS_CA_MAINTENANCE_VERSION = 0
|
||||
EPICS_CA_MAINTENANCE_VERSION = 2
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ GNU_DIR = /usr
|
||||
# Directories
|
||||
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
INSTALL_ABSOLUTE = $(abspath $(INSTALL_LOCATION))
|
||||
|
||||
INSTALL_LOCATION_LIB = $(INSTALL_LOCATION)/lib
|
||||
INSTALL_LOCATION_BIN = $(INSTALL_LOCATION)/bin
|
||||
@@ -71,23 +72,30 @@ INSTALL_DBD = $(INSTALL_LOCATION)/dbd
|
||||
INSTALL_DB = $(INSTALL_LOCATION)/db
|
||||
INSTALL_CONFIG = $(INSTALL_LOCATION)/configure
|
||||
|
||||
FINAL_LOCATION = $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
|
||||
#-------------------------------------------------------
|
||||
# These are default settings that may be overridden later
|
||||
|
||||
# Directory for OS independant build created files
|
||||
COMMON_DIR = ../O.Common
|
||||
# Eventual install path (to be compiled into binaries)
|
||||
FINAL_LOCATION = $(INSTALL_ABSOLUTE)
|
||||
|
||||
# IOC's absolute path to $(TOP), may be overridden inside the application
|
||||
IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
|
||||
# IOC's view of install path
|
||||
IOCS_APPL_TOP = $(INSTALL_ABSOLUTE)
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Silencing the build - suppress messages during 'make -s'
|
||||
# How to portably check the flags to make
|
||||
define checkflags
|
||||
make-$1 = $(findstring $1,$(filter-out --%,$(MAKEFLAGS)))
|
||||
endef
|
||||
# This is extensible to most single letter flags:
|
||||
$(foreach flag,s q, $(eval $(call checkflags,$(flag))))
|
||||
|
||||
# Silent builds - suppress messages during 'make -s'
|
||||
NOP = :
|
||||
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(filter -s,$(MFLAGS)),-q,)
|
||||
ECHO = @$(if $(make-s),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(make-s),-q,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
|
||||
QUESTION_FLAG := $(if $(filter -q,$(MFLAGS)),-i,)
|
||||
QUESTION_FLAG := $(if $(make-q),-i,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
ifdef T_A
|
||||
@@ -133,6 +141,8 @@ LIB_SUFFIX =
|
||||
SHRLIB_PREFIX = $(LIB_PREFIX)
|
||||
DLLSTUB_PREFIX = $(LIB_PREFIX)
|
||||
DLLSTUB_SUFFIX = $(LIB_SUFFIX)
|
||||
LOADABLE_SHRLIB_PREFIX = $(SHRLIB_PREFIX)
|
||||
LOADABLE_SHRLIB_SUFFIX = $(SHRLIB_SUFFIX)
|
||||
|
||||
BUILDLIB_PREFIX_YES = $(DLLSTUB_PREFIX)
|
||||
BUILDLIB_PREFIX_NO = $(LIB_PREFIX)
|
||||
@@ -153,12 +163,14 @@ CMPLR_SRC_DIRS += . $(foreach dir, .. $(SRC_DIRS), \
|
||||
ALL_SRC_DIRS = $(CMPLR_SRC_DIRS) $(OS_SRC_DIRS) $(GENERIC_SRC_DIRS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Directory for OS independant build created files
|
||||
COMMON_DIR = ../O.Common
|
||||
|
||||
# compile line include directories
|
||||
INSTALL_INCLUDES += \
|
||||
-I$(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) \
|
||||
-I$(INSTALL_INCLUDE)/os/$(OS_CLASS) \
|
||||
-I$(INSTALL_INCLUDE)
|
||||
SRC_INCLUDES = -I$(COMMON_DIR) $(addprefix -I, $(wildcard $(ALL_SRC_DIRS)))
|
||||
INSTALL_INCLUDE_DIRS = $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) \
|
||||
$(INSTALL_INCLUDE)/os/$(OS_CLASS) $(INSTALL_INCLUDE)
|
||||
INSTALL_INCLUDES += $(addprefix -I, $(INSTALL_INCLUDE_DIRS))
|
||||
SRC_INCLUDES = $(addprefix -I, $(COMMON_DIR) $(wildcard $(ALL_SRC_DIRS)))
|
||||
|
||||
#--------------------------------------------------
|
||||
# Target filename definitions
|
||||
@@ -172,23 +184,27 @@ TESTSHRLIBNAME = $(TESTSHRLIBNAME_$(SHARED_LIBRARIES))
|
||||
#--------------------------------------------------
|
||||
# obj files
|
||||
|
||||
TARGET_OBJS = $($*_LDOBJS) $(addsuffix $(OBJ),$(basename $($*_OBJS) $($*_SRCS)))
|
||||
TARGET_OBJS = $($*_LDOBJS) $(addsuffix $(OBJ), \
|
||||
$(basename $($*_OBJS) $($*_SRCS)))
|
||||
|
||||
PRODUCT_OBJS = $(addsuffix $(OBJ),$(basename $(SRCS) $(USR_SRCS) $(PROD_SRCS) $(USR_OBJS) $(PROD_OBJS)))
|
||||
PRODUCT_OBJS = $(addsuffix $(OBJ), \
|
||||
$(basename $(SRCS) $(USR_SRCS) $(PROD_SRCS) $(USR_OBJS) $(PROD_OBJS)))
|
||||
PROD_LD_OBJS = $(TARGET_OBJS) $(PRODUCT_OBJS)
|
||||
|
||||
LIBRARY_OBJS = $(addsuffix $(OBJ),$(basename $(SRCS) $(USR_SRCS) $(LIB_SRCS) $(LIBSRCS) $(USR_OBJS) $(LIB_OBJS)))
|
||||
LIBRARY_OBJS = $(addsuffix $(OBJ), \
|
||||
$(basename $(SRCS) $(USR_SRCS) $(LIB_SRCS) $(LIBSRCS) $(USR_OBJS) $(LIB_OBJS)))
|
||||
LIBRARY_LD_OBJS = $(TARGET_OBJS) $(LIBRARY_OBJS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Windows resource files
|
||||
|
||||
TARGET_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $($*_RCS))),)
|
||||
TARGET_RESS = $(if $(RES), $(addsuffix $(RES), $(basename $($*_RCS))))
|
||||
|
||||
PROD_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $(RCS) $(PROD_RCS))),)
|
||||
PROD_RESS = $(if $(RES), $(addsuffix $(RES), $(basename $(RCS) $(PROD_RCS))))
|
||||
PROD_LD_RESS = $(TARGET_RESS) $(PROD_RESS)
|
||||
|
||||
LIBRARY_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $(RCS) $(LIB_RCS) $(LIBRARY_RCS))),)
|
||||
LIBRARY_RESS = $(if $(RES), $(addsuffix $(RES), \
|
||||
$(basename $(RCS) $(LIB_RCS) $(LIBRARY_RCS))))
|
||||
LIBRARY_LD_RESS = $(TARGET_RESS) $(LIBRARY_RESS)
|
||||
|
||||
#--------------------------------------------------
|
||||
@@ -257,6 +273,7 @@ WARN_CXXFLAGS = $(WARN_CXXFLAGS_$($(BUILD_CLASS)_WARN))
|
||||
OPT_CPPFLAGS = $(OPT_CPPFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
OPT_CFLAGS = $(OPT_CFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
OPT_CXXFLAGS = $(OPT_CXXFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
OPT_LDFLAGS = $(OPT_LDFLAGS_$($(BUILD_CLASS)_OPT))
|
||||
|
||||
# Static build flags
|
||||
STATIC_CFLAGS = $(STATIC_CFLAGS_$(STATIC_BUILD))
|
||||
@@ -265,19 +282,19 @@ STATIC_LDFLAGS = $(STATIC_LDFLAGS_$(STATIC_BUILD))
|
||||
STATIC_LDLIBS = $(STATIC_LDLIBS_$(STATIC_BUILD))
|
||||
|
||||
#--------------------------------------------------
|
||||
# cflags for shared library src files (from SHRLIB_CFLAGS)
|
||||
LIBRARY_SRCS=$(basename $(foreach lib,$(LIBRARY) $(TESTLIBRARY) $(LOADABLE_LIBRARY),$($(lib)_OBJSNAME) $(LIBRARY_OBJS)))
|
||||
LIBRARY_SRC_CFLAGS=$($(patsubst $*,SHRLIB,$(findstring $*,$(LIBRARY_SRCS)))_CFLAGS)
|
||||
# cflags for shared library src files
|
||||
LIBRARY_SRCS = $(basename $(foreach lib, \
|
||||
$(LIBRARY) $(TESTLIBRARY) $(LOADABLE_LIBRARY), \
|
||||
$($(lib)_OBJSNAME) $(LIBRARY_OBJS)))
|
||||
LIBRARY_SRC_CFLAGS = $(if $(findstring $*, $(LIBRARY_SRCS)), $(SHRLIB_CFLAGS))
|
||||
|
||||
#--------------------------------------------------
|
||||
# prefix, suffix, and ldflags for loadable shared libraries
|
||||
TARGET_LIB_LDFLAGS=$($(patsubst $*,LOADABLE_,$(findstring $*,$(LOADABLE_LIBRARY)))SHRLIB_LDFLAGS)
|
||||
LOADABLE_SHRLIB_PREFIX=$(SHRLIB_PREFIX)
|
||||
LOADABLE_SHRLIB_SUFFIX=$(SHRLIB_SUFFIX)
|
||||
# ldflags for loadable and shared libraries
|
||||
TARGET_LIB_LDFLAGS = $(if $(findstring $*, $(LOADABLE_LIBRARY)), \
|
||||
$(LOADABLE_SHRLIB_LDFLAGS), $(SHRLIB_LDFLAGS))
|
||||
|
||||
#--------------------------------------------------
|
||||
# Command-line input support default
|
||||
COMMANDLINE_LIBRARY = EPICS
|
||||
OP_SYS_LDLIBS += $(LDLIBS_$(COMMANDLINE_LIBRARY))
|
||||
OP_SYS_LDFLAGS += $(LDFLAGS_$(COMMANDLINE_LIBRARY))
|
||||
RUNTIME_LDFLAGS += $(RUNTIME_LDFLAGS_$(COMMANDLINE_LIBRARY))
|
||||
@@ -285,31 +302,31 @@ RUNTIME_LDFLAGS += $(RUNTIME_LDFLAGS_$(COMMANDLINE_LIBRARY))
|
||||
#--------------------------------------------------
|
||||
# Flags
|
||||
|
||||
INCLUDES = -I. $(SRC_INCLUDES) $(INSTALL_INCLUDES) $(RELEASE_INCLUDES)\
|
||||
$(TARGET_INCLUDES) $(USR_INCLUDES) $(CMD_INCLUDES) $(OP_SYS_INCLUDES)\
|
||||
$($(BUILD_CLASS)_INCLUDES)
|
||||
INCLUDES = -I. $(SRC_INCLUDES) $(INSTALL_INCLUDES) $(RELEASE_INCLUDES) \
|
||||
$(TARGET_INCLUDES) $(USR_INCLUDES) $(CMD_INCLUDES) $(OP_SYS_INCLUDES) \
|
||||
$($(BUILD_CLASS)_INCLUDES)
|
||||
|
||||
CFLAGS = $($(BUILD_CLASS)_CFLAGS) $(POSIX_CFLAGS) $(OPT_CFLAGS)\
|
||||
$(DEBUG_CFLAGS) $(PIPE_CFLAGS) $(WARN_CFLAGS) $(TARGET_CFLAGS)\
|
||||
$(USR_CFLAGS) $(CMD_CFLAGS) $(ARCH_DEP_CFLAGS) $(CODE_CFLAGS)\
|
||||
$(STATIC_CFLAGS) $(OP_SYS_CFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
CFLAGS = $($(BUILD_CLASS)_CFLAGS) $(POSIX_CFLAGS) $(OPT_CFLAGS) \
|
||||
$(DEBUG_CFLAGS) $(PIPE_CFLAGS) $(WARN_CFLAGS) $(TARGET_CFLAGS) \
|
||||
$(USR_CFLAGS) $(CMD_CFLAGS) $(ARCH_DEP_CFLAGS) $(CODE_CFLAGS) \
|
||||
$(STATIC_CFLAGS) $(OP_SYS_CFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
|
||||
CXXFLAGS = $($(BUILD_CLASS)_CXXFLAGS) $(POSIX_CXXFLAGS) $(OPT_CXXFLAGS)\
|
||||
$(DEBUG_CXXFLAGS) $(PIPE_CFLAGS) $(WARN_CXXFLAGS) $(TARGET_CXXFLAGS)\
|
||||
$(USR_CXXFLAGS) $(CMD_CXXFLAGS) $(ARCH_DEP_CXXFLAGS) $(CODE_CXXFLAGS)\
|
||||
$(STATIC_CXXFLAGS) $(OP_SYS_CXXFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
CXXFLAGS = $($(BUILD_CLASS)_CXXFLAGS) $(POSIX_CXXFLAGS) $(OPT_CXXFLAGS) \
|
||||
$(DEBUG_CXXFLAGS) $(PIPE_CFLAGS) $(WARN_CXXFLAGS) $(TARGET_CXXFLAGS) \
|
||||
$(USR_CXXFLAGS) $(CMD_CXXFLAGS) $(ARCH_DEP_CXXFLAGS) $(CODE_CXXFLAGS) \
|
||||
$(STATIC_CXXFLAGS) $(OP_SYS_CXXFLAGS) $(LIBRARY_SRC_CFLAGS)
|
||||
|
||||
LDFLAGS = $(OPT_LDFLAGS) $(TARGET_LDFLAGS) $(USR_LDFLAGS) $(CMD_LDFLAGS)\
|
||||
$(POSIX_LDFLAGS) $(ARCH_DEP_LDFLAGS) $(DEBUG_LDFLAGS) $(OP_SYS_LDFLAGS)\
|
||||
$($(BUILD_CLASS)_LDFLAGS) $(RUNTIME_LDFLAGS) $(CODE_LDFLAGS)
|
||||
LDFLAGS = $(OPT_LDFLAGS) $(TARGET_LDFLAGS) $(USR_LDFLAGS) $(CMD_LDFLAGS) \
|
||||
$(POSIX_LDFLAGS) $(ARCH_DEP_LDFLAGS) $(DEBUG_LDFLAGS) $(OP_SYS_LDFLAGS) \
|
||||
$($(BUILD_CLASS)_LDFLAGS) $(RUNTIME_LDFLAGS) $(CODE_LDFLAGS)
|
||||
|
||||
LDLIBS = $(POSIX_LDLIBS) $(ARCH_DEP_LDLIBS) $(DEBUG_LDLIBS) $(OP_SYS_LDLIBS)\
|
||||
$(GNU_LDLIBS_$(GNU))
|
||||
LDLIBS = $(POSIX_LDLIBS) $(ARCH_DEP_LDLIBS) $(DEBUG_LDLIBS) $(OP_SYS_LDLIBS) \
|
||||
$(GNU_LDLIBS_$(GNU))
|
||||
|
||||
CPPFLAGS = $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
|
||||
$(DEBUG_CPPFLAGS) $(WARN_CPPFLAGS) $(BASE_CPPFLAGS) $(TARGET_CPPFLAGS)\
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS) $(API_CPPFLAGS)
|
||||
CPPFLAGS = $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS) \
|
||||
$(DEBUG_CPPFLAGS) $(WARN_CPPFLAGS) $(BASE_CPPFLAGS) $(TARGET_CPPFLAGS) \
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS) \
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS) $(API_CPPFLAGS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# ar definition default
|
||||
@@ -396,7 +413,7 @@ INSTALL_DOCS = $(DOCS:%= $(INSTALL_DOC)/%)
|
||||
INSTALL_HTMLS = $(HTMLS:%= $(INSTALL_HTML)/$(HTMLS_DIR)/%)
|
||||
|
||||
INSTALL_TEMPLATE = $(addprefix $(INSTALL_TEMPLATES_SUBDIR)/, \
|
||||
$(subst $(CONFIG),top/configure,$(TEMPLATES)))
|
||||
$(subst $(CONFIG),top/configure,$(TEMPLATES)))
|
||||
INSTALL_CONFIGS = $(CONFIGS:%= $(INSTALL_CONFIG)/%)
|
||||
|
||||
INSTALL_BIN_INSTALLS = $(addprefix $(INSTALL_BIN)/,$(notdir $(BIN_INSTALLS)))
|
||||
@@ -431,42 +448,41 @@ INSTALL_INC += $(foreach inc, $(INC), \
|
||||
$(CMPLR_INSTALL_INC) \
|
||||
$(OS_INSTALL_INC) \
|
||||
$(GENERIC_INSTALL_INC) \
|
||||
$(GENERATED_INSTALL_INC) ) )
|
||||
INSTALL_INC += $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INC_$(OS_CLASS)) )
|
||||
$(GENERATED_INSTALL_INC)))
|
||||
INSTALL_INC += $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INC_$(OS_CLASS)))
|
||||
|
||||
#
|
||||
# Rule 0
|
||||
#
|
||||
CMPLR_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/, $(INSTALL_INC_jjj) )
|
||||
INSTALL_INC_jjj = $(foreach dir, $(CMPLR_SRC_DIRS), $(INSTALL_INC_iii) )
|
||||
INSTALL_INC_iii = $(subst $(dir)/, , $(INSTALL_INC_hhh) )
|
||||
INSTALL_INC_hhh = $(wildcard $(addsuffix /$(inc), $(dir)) )
|
||||
CMPLR_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/, \
|
||||
$(foreach dir, $(CMPLR_SRC_DIRS), \
|
||||
$(subst $(dir)/,, $(wildcard $(addsuffix /$(inc), $(dir))))))
|
||||
|
||||
#
|
||||
# Rule 1
|
||||
#
|
||||
OS_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INSTALL_INC_ggg) )
|
||||
INSTALL_INC_ggg = $(foreach dir, $(OS_SRC_DIRS), $(INSTALL_INC_fff) )
|
||||
INSTALL_INC_fff = $(subst $(dir)/, , $(INSTALL_INC_eee) )
|
||||
INSTALL_INC_eee = $(wildcard $(addsuffix /$(inc), $(dir)) )
|
||||
OS_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, \
|
||||
$(foreach dir, $(OS_SRC_DIRS), \
|
||||
$(subst $(dir)/,, $(wildcard $(addsuffix /$(inc), $(dir))))))
|
||||
|
||||
#
|
||||
# Rule 2
|
||||
#
|
||||
GENERIC_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/, $(INSTALL_INC_ccc) )
|
||||
INSTALL_INC_ccc = $(foreach dir, .. $(SRC_DIRS), $(INSTALL_INC_bbb) )
|
||||
INSTALL_INC_bbb = $(subst $(dir)/, , $(INSTALL_INC_aaa) )
|
||||
INSTALL_INC_aaa = $(wildcard $(addsuffix /$(inc), $(dir)) )
|
||||
GENERIC_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/, \
|
||||
$(foreach dir, .. $(SRC_DIRS), \
|
||||
$(subst $(dir)/,, $(wildcard $(addsuffix /$(inc), $(dir))))))
|
||||
|
||||
#
|
||||
# Rule 3
|
||||
#
|
||||
GENERATED_INSTALL_INC = $(INSTALL_INCLUDE)/$(inc)
|
||||
|
||||
COMMON_INC += $(filter $(COMMON_DIR)/%, $(foreach file, $(INC), \
|
||||
$(firstword $(SOURCE_INC) $(COMMON_DIR)/$(file) ) ) )
|
||||
SOURCE_INC = $(wildcard $(file) $(SOURCE_INC_bbb) )
|
||||
SOURCE_INC_bbb = $(foreach dir, $(ALL_SRC_DIRS), $(SOURCE_INC_aaa) )
|
||||
SOURCE_INC_aaa = $(addsuffix /$(file), $(dir) )
|
||||
#---------------------------------------------------------------
|
||||
# Files listed in INC that must first be created in O.Common
|
||||
COMMON_INC += $(filter $(COMMON_DIR)/%, \
|
||||
$(foreach file, $(INC), \
|
||||
$(firstword $(wildcard $(file) \
|
||||
$(foreach dir, $(ALL_SRC_DIRS), \
|
||||
$(addsuffix /$(file), $(dir)))) $(COMMON_DIR)/$(file))))
|
||||
|
||||
endif
|
||||
|
||||
@@ -5,22 +5,16 @@
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# Set EPICS_DATABASE if necessary
|
||||
ifndef EPICS_DATABASE
|
||||
EPICS_DATABASE = $(if $(BUILDING_DATABASE),$(INSTALL_LOCATION),$(EPICS_BASE))
|
||||
# Our locally-built tools
|
||||
DBEXPAND = $(PERL) $(EPICS_BASE_HOST_BIN)/dbdExpand.pl
|
||||
DBTORECORDTYPEH = $(PERL) $(EPICS_BASE_HOST_BIN)/dbdToRecordtypeH.pl
|
||||
DBTOMENUH = $(PERL) $(EPICS_BASE_HOST_BIN)/dbdToMenuH.pl
|
||||
DBDTOHTML = $(PERL) $(EPICS_BASE_HOST_BIN)/dbdToHtml.pl
|
||||
REGISTERRECORDDEVICEDRIVER = $(PERL) $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
|
||||
# Paths to tools built here
|
||||
EPICS_DATABASE_HOST_BIN = $(EPICS_DATABASE)/bin/$(EPICS_HOST_ARCH)
|
||||
endif
|
||||
|
||||
# Set location of locally-built tools
|
||||
MAKEBPT = $(EPICS_DATABASE_HOST_BIN)/makeBpt$(HOSTEXE)
|
||||
DBEXPAND = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdExpand.pl
|
||||
DBTORECORDTYPEH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToRecordtypeH.pl
|
||||
DBTOMENUH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToMenuH.pl
|
||||
DBDTOHTML = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToHtml.pl
|
||||
REGISTERRECORDDEVICEDRIVER = $(PERL) $(EPICS_DATABASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
MSI3_15 = $(EPICS_DATABASE_HOST_BIN)/msi$(HOSTEXE)
|
||||
# Windows can need these paths to be quoted
|
||||
MAKEBPT = "$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)"
|
||||
MSI3_15 = "$(EPICS_BASE_HOST_BIN)/msi$(HOSTEXE)"
|
||||
|
||||
# Libraries needed to link a basic IOC
|
||||
EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Version number for the database APIs and shared library
|
||||
|
||||
EPICS_DATABASE_MAJOR_VERSION = 3
|
||||
EPICS_DATABASE_MINOR_VERSION = 20
|
||||
EPICS_DATABASE_MINOR_VERSION = 22
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 0
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# Set location of locally generated tools
|
||||
YACC = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/antelope$(HOSTEXE)
|
||||
LEX = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/e_flex$(HOSTEXE) \
|
||||
# Our locally-built tools
|
||||
# Windows can need these paths to be quoted
|
||||
YACC = "$(EPICS_BASE_HOST_BIN)/antelope$(HOSTEXE)"
|
||||
LEX = "$(EPICS_BASE_HOST_BIN)/e_flex$(HOSTEXE)" \
|
||||
-S$(EPICS_BASE)/include/flex.skel.static
|
||||
|
||||
# Default stack size for osiThread
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Version number for the libcom APIs and shared library
|
||||
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 20
|
||||
EPICS_LIBCOM_MINOR_VERSION = 22
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 0
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
@@ -366,6 +366,7 @@ $(COMMON_DIR)/menu%.h: ../menu%.dbd
|
||||
# DBD files
|
||||
|
||||
$(COMMON_DIR)/bpt%.dbd: bpt%.data
|
||||
$(ECHO) "Converting data from $<"
|
||||
@$(RM) $(notdir $@)
|
||||
$(MAKEBPT) $< $(notdir $@)
|
||||
@$(MV) $(notdir $@) $@
|
||||
@@ -455,7 +456,7 @@ $(COMMON_DIR)/%.html: ../%.pl
|
||||
$(PODTOHTML) -s -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%.html %.html
|
||||
.PRECIOUS: $(COMMON_DIR)/%.html
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# DB files
|
||||
@@ -526,15 +527,15 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file))))
|
||||
#---------------------------------------------------------------
|
||||
# register record,device,driver support
|
||||
|
||||
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
|
||||
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
@$(RM) $@
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
|
||||
|
||||
%_registerRecordDeviceDriver.cpp: %.dbd
|
||||
%_registerRecordDeviceDriver.cpp: %.dbd $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
@$(RM) $@
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
|
||||
|
||||
%_registerRecordDeviceDriver.cpp: ../%.dbd
|
||||
%_registerRecordDeviceDriver.cpp: ../%.dbd $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
@$(RM) $@
|
||||
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ endif
|
||||
checkRelease:
|
||||
+$(CONVERTRELEASE) checkRelease
|
||||
warnRelease:
|
||||
$(CONVERTRELEASE) checkRelease
|
||||
-$(CONVERTRELEASE) checkRelease
|
||||
noCheckRelease:
|
||||
ifeq ($(EPICS_HOST_ARCH),$(T_A))
|
||||
$(info Warning: RELEASE file consistency checks have been disabled)
|
||||
@@ -373,23 +373,25 @@ $(MODNAME): %$(MODEXT): %$(EXE)
|
||||
# Automated testing
|
||||
|
||||
runtests: run-tap-tests
|
||||
run-tap-tests: $(TESTSCRIPTS.t)
|
||||
run-tap-tests: | build
|
||||
ifneq ($(TESTSCRIPTS.t),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(ECHO) "$(PROVE) $^"
|
||||
@$(PROVE) $^ || $(PROVE_FAILURE)
|
||||
$(ECHO) "$(PROVE) $(TESTSCRIPTS.t)"
|
||||
@$(PROVE) $(TESTSCRIPTS.t) || $(PROVE_FAILURE)
|
||||
endif
|
||||
endif
|
||||
|
||||
tapfiles: $(TAPFILES)
|
||||
junitfiles: $(JUNITFILES)
|
||||
# prevent deletion of partial output from failing tests
|
||||
.PRECIOUS: $(TAPFILES) $(JUNITFILES)
|
||||
|
||||
test-results: tap-results
|
||||
tap-results: $(TAPFILES)
|
||||
ifneq ($(strip $(TAPFILES)),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(ECHO) "$(PROVE.tap) $^"
|
||||
@$(PROVE.tap) $^ || $(PROVE_FAILURE)
|
||||
$(ECHO) "$(PROVE.tap) $(TAPFILES)"
|
||||
@$(PROVE.tap) $(TAPFILES) || $(PROVE_FAILURE)
|
||||
endif
|
||||
|
||||
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
|
||||
@@ -405,7 +407,7 @@ ifneq ($(CURRENT_JUNITFILES),)
|
||||
endif
|
||||
|
||||
# A .tap file is the output from running the associated test script
|
||||
$(TAPFILES.t): %.tap: %.t
|
||||
$(TAPFILES.t): %.tap: %.t | build
|
||||
ifdef RUNTESTS_ENABLED
|
||||
$(ECHO) "$(PERL) $< -tap > $@"
|
||||
@$(PERL) $< -tap > $@ || $(TAPFILE_FAILURE)
|
||||
@@ -561,6 +563,10 @@ $(INSTALL_DOC)/%: ../%
|
||||
$(ECHO) "Installing doc $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(INSTALL_DOC)
|
||||
|
||||
$(INSTALL_HTML)/$(HTMLS_DIR)/%: $(COMMON_DIR)/%
|
||||
$(ECHO) "Installing generated html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
$(INSTALL_HTML)/$(HTMLS_DIR)/%: %
|
||||
$(ECHO) "Installing html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
@@ -569,10 +575,6 @@ $(INSTALL_HTML)/$(HTMLS_DIR)/%: ../%
|
||||
$(ECHO) "Installing html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
$(INSTALL_HTML)/$(HTMLS_DIR)/%: $(COMMON_DIR)/%
|
||||
$(ECHO) "Installing generated html $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
$(INSTALL_TEMPLATES_SUBDIR)/%: ../%
|
||||
$(ECHO) "Installing $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
@@ -27,7 +27,7 @@ $(foreach file,$(MAKEFILE_LIST), \
|
||||
|
||||
PRINT_Var = $(@:PRINT.%=%)
|
||||
PRINT.%:
|
||||
@echo $(PRINT_Var) = '$($(PRINT_Var))'
|
||||
@+echo $(PRINT_Var) = '$($(PRINT_Var))'
|
||||
|
||||
.PHONY: PRINT PRINT.%
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
# INC += myVersion.h
|
||||
|
||||
# Default settings
|
||||
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl
|
||||
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl $(QUIET_FLAG)
|
||||
|
||||
EXPANDARCH = -a $(T_A)
|
||||
EXPANDFLAGS += -t $(INSTALL_LOCATION)
|
||||
@@ -55,22 +55,17 @@ EXPANDFLAGS += $(addprefix -D ,$(EXPAND_VARS) $($@_EXPAND_VARS))
|
||||
EXPANDFLAGS += $(foreach var, $(EXPAND_ME) $($@_EXPAND_ME), \
|
||||
-D$(var)="$(strip $($(var)))")
|
||||
|
||||
# The names of files to be expanded must end with '@'
|
||||
# Output files
|
||||
EXPANDED = $(EXPAND:%@=%)
|
||||
EXPANDED_COM = $(EXPAND_COMMON:%@=%)
|
||||
EXPANDED_COMMON = $(EXPANDED_COM:%=$(COMMON_DIR)/%)
|
||||
EXPANDED_COMMON = $(EXPAND_COMMON:%@=$(COMMON_DIR)/%)
|
||||
|
||||
$(EXPANDED): %: %@
|
||||
$(ECHO) "Expanding $< to $@"
|
||||
@$(RM) $@
|
||||
$(EXPAND_TOOL) $(EXPANDARCH) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
|
||||
|
||||
$(EXPANDED_COM): %: %@
|
||||
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %@
|
||||
$(ECHO) "Expanding $< to $(COMMON_DIR)/$@"
|
||||
@$(RM) $@
|
||||
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
|
||||
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %
|
||||
@$(MV) $< $@
|
||||
|
||||
clean: expand_clean
|
||||
|
||||
|
||||
@@ -22,13 +22,14 @@
|
||||
# 7. Submodules must have a configure/CONFIG_SITE file that contains
|
||||
# -include $(TOP)/../CONFIG_SITE.local
|
||||
|
||||
# Add checked-out submodules to DIRS
|
||||
LIVE_SUBMODULES = $(subst /Makefile,,$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
|
||||
DIRS += $(LIVE_SUBMODULES)
|
||||
# Add checked-out submodules to DIRS, unless INSTALL_LOCATION is empty
|
||||
LIVE_SUBMODULES = $(subst /Makefile,, \
|
||||
$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
|
||||
live = $(if $(wildcard $(INSTALL_CONFIG)/RULES_TOP),LIVE,DEAD)
|
||||
DIRS += $($(live)_SUBMODULES)
|
||||
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
|
||||
INSTALL_LOCATION_ABS := $(abspath $(INSTALL_LOCATION))
|
||||
RELEASE_LOCAL := RELEASE.$(EPICS_HOST_ARCH).local
|
||||
|
||||
# Ensure that RELEASE.<host>.local exists before doing anything else
|
||||
@@ -38,14 +39,13 @@ all host $(DIRS) $(ARCHS) $(ACTIONS) $(dirActionTargets) $(dirArchTargets) \
|
||||
# Convenience target
|
||||
RELEASE.host: $(RELEASE_LOCAL)
|
||||
|
||||
$(RELEASE_LOCAL): Makefile CONFIG_SITE.local
|
||||
$(RELEASE_LOCAL): Makefile $(CONFIG)/CONFIG_SITE \
|
||||
$(wildcard $(CONFIG)/CONFIG_SITE.local)
|
||||
$(ECHO) Creating $@ with
|
||||
$(ECHO) " $(PARENT_MODULE) = $(INSTALL_LOCATION_ABS)"
|
||||
@echo $(PARENT_MODULE) = $(INSTALL_LOCATION_ABS)> $@
|
||||
realclean:
|
||||
$(RM) $(wildcard RELEASE.*.local)
|
||||
$(ECHO) " $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)"
|
||||
@echo $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)> $@
|
||||
|
||||
.PHONY: RELEASE.host realclean
|
||||
.PHONY: RELEASE.host
|
||||
|
||||
# Testing: Combine test failure logs from the live submodules
|
||||
TESTS_FAILED_LOGS = $(wildcard $(addsuffix /$(TESTS_FAILED_LOG), \
|
||||
|
||||
@@ -23,35 +23,42 @@ ifndef DISABLE_TOP_RULES
|
||||
# Rules for a regular application top directory
|
||||
#
|
||||
|
||||
distclean: realclean cvsclean realuninstall
|
||||
# When run by 'make distclean' the realuninstall target also
|
||||
# removes any modules/RELEASE.<host>.local files
|
||||
distclean: realclean cvsclean realuninstall
|
||||
|
||||
realuninstall: uninstallDirs
|
||||
realuninstall: uninstallDirs
|
||||
$(RMDIR) $(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB)
|
||||
ifeq (modules,$(filter modules,$(DIRS)))
|
||||
ifeq (distclean,$(filter distclean,$(MAKECMDGOALS)))
|
||||
$(RM) $(wildcard modules/RELEASE.*.local)
|
||||
endif
|
||||
endif
|
||||
|
||||
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
|
||||
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
|
||||
ifneq ($(INSTALL_LOCATION),$(TOP))
|
||||
UNINSTALL_DIRS += $(INSTALL_CONFIG)
|
||||
endif
|
||||
uninstallDirs: | clean
|
||||
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
|
||||
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
|
||||
ifneq ($(INSTALL_LOCATION),$(TOP))
|
||||
UNINSTALL_DIRS += $(INSTALL_CONFIG)
|
||||
endif
|
||||
uninstallDirs:
|
||||
$(RMDIR) $(UNINSTALL_DIRS)
|
||||
|
||||
# Remove the bin and lib directories if they have no sub-directories
|
||||
#
|
||||
EMPTY_INSTALL_DIRS = \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
|
||||
uninstall: archuninstall uninstallDirs | clean
|
||||
EMPTY_INSTALL_DIRS = \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
|
||||
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
|
||||
uninstall: archuninstall uninstallDirs
|
||||
$(RMDIR) $(EMPTY_INSTALL_DIRS)
|
||||
|
||||
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
|
||||
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
|
||||
|
||||
uninstall$(DIVIDER)%: | clean
|
||||
uninstall$(DIVIDER)%:
|
||||
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
|
||||
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))
|
||||
|
||||
# Only run this at the top of the parent
|
||||
runtests test-results:
|
||||
# Only run this at the top of the parent
|
||||
runtests test-results:
|
||||
@$(SHOWTESTFAILURES)
|
||||
|
||||
else
|
||||
@@ -76,7 +83,6 @@ help:
|
||||
@echo " inc - Installs header, dbd and html files"
|
||||
@echo " build - Builds and installs all targets"
|
||||
@echo " install - Builds and installs all targets"
|
||||
@echo " buildInstall - Same as install (deprecated)"
|
||||
@echo " clean - Removes the O.<arch> dirs created by running make"
|
||||
@echo " In O.<arch> dir, clean removes build created files"
|
||||
@echo " realclean - Removes ALL O.<arch> dirs"
|
||||
@@ -101,7 +107,8 @@ ifndef DISABLE_TOP_RULES
|
||||
@echo " uninstall$(DIVIDER)<arch> - Remove bin & lib directories for <arch> only."
|
||||
@echo " uninstall - Remove install directories created by this hostarch."
|
||||
@echo " realuninstall - Removes ALL install dirs"
|
||||
@echo " distclean - Same as realclean cvsclean realuninstall."
|
||||
@echo " distclean - Does realclean cvsclean realuninstall and deletes any"
|
||||
@echo " generated modules/RELEASE.<host>.local files"
|
||||
endif
|
||||
@echo " help - Prints this list of valid make targets "
|
||||
@echo "Object targets are supported by the O.<arch> level Makefile .e.g"
|
||||
|
||||
@@ -77,7 +77,10 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
|
||||
|
||||
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
|
||||
ECHO = @$(if $(make-s),$(NOP),echo)
|
||||
|
||||
# Originally set in os/CONFIG.UnixCommon.Common
|
||||
MKDIR = mkdir -p
|
||||
|
||||
#--------------------------------------------------
|
||||
# Although RTEMS uses gcc, it wants to use gcc its own way
|
||||
|
||||
@@ -11,14 +11,15 @@ MUNCH_SUFFIX = .boot
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
||||
gzip -f9 rtems
|
||||
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@ \
|
||||
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@.elf \
|
||||
$(PROJECT_RELEASE)/lib/bootloader.o \
|
||||
--just-symbols=$< \
|
||||
-b binary rtems.gz \
|
||||
--no-warn-mismatch \
|
||||
--no-warn-mismatch \
|
||||
-T $(PROJECT_RELEASE)/lib/ppcboot.lds \
|
||||
-Map $<.map
|
||||
rm -f rtems.gz
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $@.elf $@
|
||||
rm -f rtems.gz $@.elf
|
||||
endef
|
||||
|
||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||
|
||||
@@ -56,7 +56,7 @@ SHRLIB_LDLIBS = $(addprefix -l, $($*_LDLIBS) $(LIB_LIBS) $(USR_LIBS)) \
|
||||
|
||||
SHRLIB_DEPLIB_DIRS = $(foreach word, \
|
||||
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(SHRLIB_DEPLIBS))), \
|
||||
$(shell $(FULLPATHNAME) $(word)))
|
||||
$(abspath $(word)))
|
||||
|
||||
SHRLIBDIR_LDFLAGS += $(SHRLIB_DEPLIB_DIRS:%=-L%)
|
||||
|
||||
@@ -85,7 +85,7 @@ PROD_LDLIBS += $($(firstword $(LDLIBS_STATIC_$(STATIC_BUILD)) \
|
||||
|
||||
PROD_DEPLIB_DIRS = $(foreach word, \
|
||||
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(PROD_DEPLIBS))), \
|
||||
$(shell $(FULLPATHNAME) $(word)))
|
||||
$(abspath $(word)))
|
||||
|
||||
PRODDIR_LDFLAGS += $(PROD_DEPLIB_DIRS:%=-L%)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ OP_SYS_LDFLAGS += -dynamic -Z -L$(SDK_DIR)/usr/lib -L$(SDK_DIR)/usr/lib/system
|
||||
# Shared libraries
|
||||
SHRLIB_VERSION = $(EPICS_VERSION).$(EPICS_REVISION).$(EPICS_MODIFICATION)
|
||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined suppress \
|
||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||
-install_name $(abspath $(INSTALL_LIB))/$@ \
|
||||
-compatibility_version $(EPICS_VERSION).$(EPICS_REVISION) \
|
||||
-current_version $(SHRLIB_VERSION)
|
||||
SHRLIB_SUFFIX_BASE = .dylib
|
||||
|
||||
21
configure/os/CONFIG.Common.vxWorks-e500v2
Normal file
21
configure/os/CONFIG.Common.vxWorks-e500v2
Normal file
@@ -0,0 +1,21 @@
|
||||
# CONFIG.Common.vxWorks-e500v2
|
||||
#
|
||||
# Definitions for vxWorks-e500v2 target archs (MVME2500)
|
||||
# Sites may override these definitions in CONFIG_SITE.Common.vxWorks-e500v2
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Include definitions common to all vxWorks target archs
|
||||
include $(CONFIG)/os/CONFIG.Common.vxWorksCommon
|
||||
|
||||
# Vx GNU cross compiler suffix
|
||||
CMPLR_SUFFIX = ppc
|
||||
|
||||
ARCH_CLASS = ppc
|
||||
|
||||
# Architecture specific build flags
|
||||
ARCH_DEP_CFLAGS += -te500v2 -mhard-float
|
||||
ARCH_DEP_CPPFLAGS += -DCPU=PPC85XX
|
||||
ARCH_DEP_CFLAGS += -DCPU_VARIANT=_ppc85XX_e500v2
|
||||
ARCH_DEP_CFLAGS += -mlongcall
|
||||
|
||||
GNU_TARGET = powerpc-wrs-vxworks
|
||||
@@ -12,7 +12,7 @@ ARCH_CLASS = x86
|
||||
POSIX = NO
|
||||
|
||||
# Definitions used when COMMANDLINE_LIBRARY is READLINE
|
||||
LDLIBS_READLINE = -lreadline -lcurses
|
||||
LDLIBS_READLINE = -lreadline -ltermcap
|
||||
|
||||
ARCH_DEP_CFLAGS += -m32
|
||||
ARCH_DEP_LDFLAGS += -m32
|
||||
|
||||
@@ -67,7 +67,7 @@ GNU = NO
|
||||
# Darwin shared libraries
|
||||
#
|
||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined dynamic_lookup \
|
||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||
-install_name $(abspath $(INSTALL_LIB))/$@ \
|
||||
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
|
||||
$(addprefix -current_version , $(SHRLIB_VERSION))
|
||||
SHRLIB_SUFFIX_BASE = .dylib
|
||||
|
||||
@@ -6,3 +6,8 @@
|
||||
|
||||
# Include common gnu compiler definitions
|
||||
include $(CONFIG)/CONFIG.gnuCommon
|
||||
|
||||
STATIC_LDFLAGS_YES= -Wl,-Bstatic
|
||||
STATIC_LDFLAGS_NO=
|
||||
STATIC_LDLIBS_YES= -Wl,-Bdynamic
|
||||
STATIC_LDLIBS_NO=
|
||||
|
||||
@@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
|
||||
GNU_LDLIBS_YES =
|
||||
|
||||
# Link with system libraries
|
||||
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
|
||||
@@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
|
||||
GNU_LDLIBS_YES =
|
||||
|
||||
# Link with system libraries
|
||||
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
|
||||
|
||||
@@ -34,5 +34,6 @@
|
||||
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
|
||||
# overridden in this file for native builds, e.g. variables such as
|
||||
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
|
||||
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 instead.
|
||||
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 or for
|
||||
# cross-builds in CONFIG_SITE.<host-arch>.linux-aarch64 instead.
|
||||
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
# to inform the system of the shared library location.
|
||||
|
||||
|
||||
# Use GNU Readline if the header file is installed
|
||||
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
|
||||
$(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \
|
||||
READLINE, EPICS))
|
||||
|
||||
# If libreadline needs additional libraries to be linked with it, try
|
||||
# uncommenting each of the lines below in turn, starting with the top
|
||||
# one and working downwards, until the build succeeds. Do a 'make rebuild'
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
GNU_DIR = /usr/local/vw/microblaze-2.0/microblazeel-unknown-linux-gnu
|
||||
|
||||
|
||||
# Use GNU Readline if the header file is installed
|
||||
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
|
||||
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
|
||||
|
||||
# If libreadline needs additional libraries to be linked with it, try
|
||||
# uncommenting each of the lines below in turn, starting with the top
|
||||
# one and working downwards, until the build succeeds. Do a 'make rebuild'
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
# to inform the system of the shared library location.
|
||||
|
||||
|
||||
# Use GNU Readline if the header file is installed
|
||||
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
|
||||
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
|
||||
|
||||
# If libreadline needs additional libraries to be linked with it, try
|
||||
# uncommenting each of the lines below in turn, starting with the top
|
||||
# one and working downwards, until the build succeeds. Do a 'make rebuild'
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
# to inform the system of the shared library location.
|
||||
|
||||
|
||||
# Use GNU Readline if the header file is installed
|
||||
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
|
||||
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
|
||||
|
||||
# If libreadline needs additional libraries to be linked with it, try
|
||||
# uncommenting each of the lines below in turn, starting with the top
|
||||
# one and working downwards, until the build succeeds. Do a 'make rebuild'
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
# Site-specific settings for the linux-xscale_be target
|
||||
|
||||
|
||||
# Use GNU Readline if the header file is installed
|
||||
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
|
||||
$(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \
|
||||
READLINE, EPICS))
|
||||
|
||||
# If libreadline needs additional libraries to be linked with it, try
|
||||
# uncommenting each of the lines below in turn, starting with the top
|
||||
# one and working downwards, until the build succeeds. Do a 'make rebuild'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CONFIG_SITE.linux-x86.linux-aarch64
|
||||
# CONFIG_SITE.linux-x86_64.linux-aarch64
|
||||
#
|
||||
# Site specific definitions for linux-x86 host - linux-aarch64 target builds
|
||||
# Site specific definitions for linux-x86_64 host - linux-aarch64 target builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Set GNU crosscompiler target name
|
||||
|
||||
@@ -35,3 +35,15 @@ OS_API = posix
|
||||
OS_API = score
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
# if defined(__rtems__) && __RTEMS_MAJOR__<5 && __has_include(<libtecla.h>)
|
||||
COMMANDLINE_LIBRARY ?= LIBTECLA
|
||||
# elif __has_include(<readline/readline.h>)
|
||||
COMMANDLINE_LIBRARY ?= READLINE
|
||||
# else
|
||||
COMMANDLINE_LIBRARY ?= EPICS
|
||||
# endif
|
||||
#else
|
||||
COMMANDLINE_LIBRARY ?= EPICS
|
||||
#endif
|
||||
|
||||
@@ -2300,7 +2300,7 @@ PLANTUML_JAR_PATH =
|
||||
# Minimum value: 0, maximum value: 10000, default value: 50.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
DOT_GRAPH_MAX_NODES = 100
|
||||
|
||||
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
|
||||
# generated by dot. A depth value of 3 means that only nodes reachable from the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Installation Instructions {#install}
|
||||
|
||||
## EPICS Base Release 7.0.5
|
||||
## EPICS Base Release 7.0.x
|
||||
|
||||
-----
|
||||
|
||||
@@ -74,7 +74,7 @@ is older but does still work.
|
||||
|
||||
#### Perl
|
||||
|
||||
You must have Perl version 5.10 or later installed. The EPICS
|
||||
You must have Perl version 5.10.1 or later installed. The EPICS
|
||||
configuration files do not specify the perl full pathname, so the perl
|
||||
executable must be found through your normal search path.
|
||||
|
||||
@@ -387,7 +387,7 @@ install directories.
|
||||
|
||||
EPICS executables and perl scripts are installed into the
|
||||
`$(INSTALL_LOCATION)/bin/<arch>` directories. Libraries are installed
|
||||
into $`(INSTALL_LOCATION)/lib/<arch>`. The default definition for
|
||||
into `$(INSTALL_LOCATION)/lib/<arch>`. The default definition for
|
||||
`$(INSTALL_LOCATION)` is `$(TOP)` which is the root directory in the
|
||||
distribution directory structure, `base`. Intermediate object files
|
||||
are stored in `O.<arch>` source subdirectories during the build
|
||||
|
||||
@@ -2,15 +2,306 @@
|
||||
|
||||
These release notes describe changes that have been made since the previous
|
||||
release of this series of EPICS Base. **Note that changes which were merged up
|
||||
from commits to the 3.15 branch are not described at the top of this file but
|
||||
lower down, under the 3.15 release to which they were originally committed.**
|
||||
Thus it is important to read more than just the first section to understand
|
||||
everything that has changed in each release.
|
||||
from commits to the 3.15 branch are described
|
||||
[further down this file](#changes-incorporated-from-the-315-branch)
|
||||
under the 3.15 release to which they were originally committed.** Thus it is
|
||||
important to read more than just the first section to understand everything that
|
||||
has changed in each release.
|
||||
|
||||
The PVA submodules each have their own individual sets of release notes which
|
||||
should also be read to understand what has changed since earlier releases.
|
||||
|
||||
|
||||
## EPICS Release 7.0.7
|
||||
|
||||
### Doxygen Annotations
|
||||
|
||||
Thanks to several attendees at the 2022 EPICS Codeathon the number of header
|
||||
files with Doxygen annotations in the EPICS Core has again increased.
|
||||
|
||||
### Build System updates
|
||||
|
||||
The top-level make targets `uninstall`, `archuninstall` and similar no
|
||||
longer trigger the `clean` target which empties build directories, this
|
||||
was a bug introduced in 7.0.5.
|
||||
|
||||
The `make distclean` target now properly deletes the generated file(s)
|
||||
`modules/RELEASE.<host>.local` which are essential to build the external
|
||||
submodules under the `modules` directory, and should not crash if the
|
||||
build is configured with `INSTALL_LOCATION` pointing to an empty external directory (i.e. if you run `make distclean` twice in succession). When
|
||||
`INSTALL_LOCATION` is set in the files `configure/CONFIG_SITE` or
|
||||
`configure/CONFIG_SITE.local` the `modules/RELEASE.<host>.local` file
|
||||
will now be regenerated in case the install path has been modified.
|
||||
|
||||
Note that passing `INSTALL_LOCATION=<path>` on the make command-line will
|
||||
only work if you have run `make distclean` immediately beforehand, as the
|
||||
`modules/RELEASE.<host>.local` file must be recreated using the new path.
|
||||
|
||||
### Enhancements to `capr.pl`
|
||||
|
||||
The `capr.pl` script can now display records from older Base versions to
|
||||
which fields have since been added, and shows long strings and array data
|
||||
up to 10 elements, use the new `-n` option to increase that number.
|
||||
The script is fully event-driven and prints all the field data received by
|
||||
the end of the CA wait time (`-w` option which defaults to 2 seconds).
|
||||
The interest level can now be specified using the `-l` option before the
|
||||
PV name, and the new `-D` flag outputs debugging information.
|
||||
|
||||
### Time Synchronization on VxWorks
|
||||
|
||||
VxWorks 6.9 can do its own OS clock time synchronization, if it has been
|
||||
configured by setting `SNTPC_PRIMARY_IPV4_ADDR`. Since EPICS 3.15.3 the
|
||||
IOC time support code has checked for the existence of the VxWorks time
|
||||
synchronization task and avoided starting the EPICS one if the OS task
|
||||
exists and the OS clock gives a "recent" time (i.e. after when EPICS was
|
||||
compiled), unless the environment variable `EPICS_TS_FORCE_NTPTIME` is
|
||||
also set. However a logic error in that code required the environment
|
||||
variable to be set in more cases than it should have.
|
||||
|
||||
This error has been fixed and the IOC should work normally if the VxWorks
|
||||
task is configured and running. The `TIMEZONE` value for the year is also
|
||||
now calculated at initialization in this configuration, previously it was
|
||||
only done when the IOC synchronzation task was used. Setting the above
|
||||
environment variable will now cause the IOC support code to shut down the
|
||||
VxWorks synchronization thread (if running) before starting the EPICS one.
|
||||
|
||||
Running the iocsh command `ClockTime_Report` now shows whether the VxWorks
|
||||
task is running as well as giving the state of the IOC synchronization task.
|
||||
The `ClockTime_Init` command can also be used to stop or restart the IOC
|
||||
time synchronization task while the IOC is running, depending on the `0` or
|
||||
`1` parameter passed to it. This last change also applies to RTEMS IOCs.
|
||||
|
||||
### Incompatible change to `struct db_field_log`
|
||||
|
||||
This change may cause channel filters which manipulate array updates
|
||||
to fail to compile.
|
||||
|
||||
To avoid potential speculation issues arising from overlapping code pointers
|
||||
with data values, `union dbfl_ref` is modified to remove the `dtor` member.
|
||||
`dtor` is moved out into the enclosing `struct db_field_log`.
|
||||
|
||||
So eg. using a `db_field_log* p`, the expression `p->u.r.dtor` must be
|
||||
changed to `(p)->dtor`.
|
||||
|
||||
### Fix undef ts on first camonitor update of NORD from waveformRecord
|
||||
|
||||
The order over operations when processing a waveformRecord is adjusted
|
||||
so that updates to NORD is posted with the correct timestamp.
|
||||
|
||||
### Automatic COMMANDLINE_LIBRARY w/ newer compilers
|
||||
|
||||
When built with a compiler supporting `__has_include<>`, the presence
|
||||
of the `<readline/readline.h>` will be used to automatically determine
|
||||
a default value for `COMMANDLINE_LIBRARY`.
|
||||
|
||||
Mingw builds with readline support now link `-ltermcap` instead of `-lcurses`.
|
||||
|
||||
This should not effect sites which set explicitly set `COMMANDLINE_LIBRARY`
|
||||
as the only definition in Base now has the form `COMMANDLINE_LIBRARY ?= ...`.
|
||||
|
||||
### Perl CA support for empty long strings
|
||||
|
||||
The Perl CA bindings have been fixed to handle zero-length long string data
|
||||
properly.
|
||||
|
||||
### `aao` gains `OMSL` and `DOL`
|
||||
|
||||
The `aao` record types gains the same `DOL` functionality found
|
||||
in other output record types (`ao`, `longout`, etc.)
|
||||
|
||||
### Server exports `RSRV_SERVER_PORT`
|
||||
|
||||
During `iocInit()`, the environment variable `RSRV_SERVER_PORT` is set
|
||||
with the TCP port number selected.
|
||||
|
||||
### `dbdExpand.pl` sorts all items by name
|
||||
|
||||
DBD files generated by the `dbdExpand.pl` script are now sorted within each
|
||||
item type by the primary name of the item. The result should resolve any
|
||||
issues with reproducable builds. No option is provided to prevent the sorting,
|
||||
previously the order was essentially random and varied each time.
|
||||
|
||||
### `dbExpand.pl` sorts records by name
|
||||
|
||||
Records are now output by this program in order, sorted by name. The new flag
|
||||
`-s` can be given to output the records in the same order they were read in,
|
||||
instead of sorting them.
|
||||
|
||||
Note that there are currently no build rules provided with Base which make use
|
||||
of this program.
|
||||
|
||||
### Simulation Mode RAW Support for Output Record Types
|
||||
|
||||
SIMM=RAW support has been added for the relevant output record types
|
||||
(ao, bo, mbbo, mbboDirect).
|
||||
RAW simulation mode will have those records do the appropriate conversion
|
||||
and write RVAL to the location pointed to by SIOL.
|
||||
|
||||
### Fixed leak from a non-EPICS thread
|
||||
|
||||
On some targets, if a thread not created by `epicsThreadCreate*()` directly
|
||||
or indirectly calls an `epicsThread*()` function, a specific tracking struct
|
||||
is allocated.
|
||||
|
||||
Prior to this release, on POSIX and WIN32 targets, this
|
||||
struct would not be `free()`d, resulting in a memory leak.
|
||||
|
||||
This release fixed the leak on POSIX targets.
|
||||
|
||||
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
|
||||
for WIN32 status.
|
||||
|
||||
### Fix `CHECK_RELEASE = WARN`
|
||||
|
||||
This now works again, it was broken in 2019 (7.0.3.1) by an errant commit.
|
||||
|
||||
### Document `DISP` as design-time field
|
||||
|
||||
The DISP field can be set to a non-zero value to prevent records being changed
|
||||
from outside the IOC (this is ancient behavior), but has never been documented
|
||||
as being usable at design-time (DCT=Yes in the Record Reference tables). This
|
||||
has now been changed.
|
||||
|
||||
### Make `epicsInt8` signed on all architectures
|
||||
|
||||
The `epicsInt8` and thus `DBF_CHAR` types have always been unsigned on
|
||||
architectures where `char` is unsigned, for example on many PowerPC CPU
|
||||
architectures. This was counter-intuitive, and resulted in IOC behavior
|
||||
differing between architectures when converting `DBF_CHAR` values into a
|
||||
signed integer or floating point type.
|
||||
|
||||
**WARNING**: This fix may change behavior of existing databases on target
|
||||
architectures with unsigned `char` (mainly PowerPC) when using input links to
|
||||
read from `CHAR` arrays. Architectures with signed `char` (usually x86) should
|
||||
be unaffected, although some compilers might generate new warnings.
|
||||
|
||||
### Allow hexadecimal and octal numbers in hardware links
|
||||
|
||||
[GH:213](https://github.com/epics-base/epics-base/pull/213)
|
||||
|
||||
Several types of hardware links (`VME_IO`, `CAMAC_IO`, etc) now accept
|
||||
hexadecimal and octal numbers. (Hexadecimal numbers had already been valid
|
||||
up to EPICS R3.15.) This change may introduce incompatibilities when using
|
||||
numbers with leading `0` as they will now be parsed as octal.
|
||||
|
||||
### Fix embedded implementations of `epicsEvent`
|
||||
|
||||
[GH:202](https://github.com/epics-base/epics-base/issues/202) and
|
||||
[GH:206](https://github.com/epics-base/epics-base/pull/206)
|
||||
|
||||
Heinz Junkes provided a new implementation of the `epicsEvent` API suitable for
|
||||
RTEMS Posix targets (RTEMS 5.1 and later). In review a few issues related to
|
||||
overflow of timeout values surfaced in this and other embedded implementations,
|
||||
and these were also been fixed in this Pull Request. The API documentation for
|
||||
this and some other routines has also been updated.
|
||||
|
||||
### Breakpoint Table Names
|
||||
|
||||
The names of breakpoint tables were made unnecessarily strict when DBD file
|
||||
processing was moved to Perl for the 3.15 release series. Table names may now
|
||||
contain the special characters `_` `-` `:` `;` `.` `[` `]` `<` `>` in addition
|
||||
to letters and digits.
|
||||
|
||||
### Fix for `undefined` in configure/RELEASE files
|
||||
|
||||
Prevents `Use of uninitialized value` warnings from convertRelease.pl.
|
||||
|
||||
### Colorized Messages for errlog
|
||||
|
||||
Many internal error messages now emit ANSI escape sequences to highlight the
|
||||
words "ERROR" and "WARNING" in an attempt to make occurrences more noticeable
|
||||
during IOC startup.
|
||||
|
||||
The macros `ERL_ERROR` and `ERL_WARNING` are defined for external usage,
|
||||
and expand as string constants. eg.
|
||||
|
||||
```c
|
||||
#include <errlog.h>
|
||||
#ifndef ERL_ERROR
|
||||
# define ERL_ERROR "ERROR"
|
||||
#endif
|
||||
void fn() {
|
||||
...
|
||||
errlogPrintf(ERL_ERROR ": something bad happens :(\n");
|
||||
```
|
||||
|
||||
ANSI escapes are automatically removed from errlog output not destined
|
||||
for a terminal. For example, for logClient, if stderr is redirected,
|
||||
or if unsupported (`$TERM` not set, or Windows < 10).
|
||||
|
||||
### `dbnd` filter pass through `DBE_ALARM|DBE_PROPERTY`
|
||||
|
||||
The `dbnd` server side filter now passes through alarm and property
|
||||
change events, even when not exceeding the deadband.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.6.1
|
||||
|
||||
### `mbboDirectRecord` enhancements
|
||||
|
||||
The bit fields `B0` - `B1F` of this record are now always updated and have a
|
||||
monitor posted when the `VAL` field is set and the record processed. It is now
|
||||
possible to initialize the record's value by setting the bit fields inside a
|
||||
database file as long as no other method was used to initialize it (suc as
|
||||
setting `VAL` directly, using `DOL`, or by an initial readback from device
|
||||
support). A new internal field `OBIT` was added to store information about
|
||||
monitors posted on the bit fields.
|
||||
|
||||
### Minimum Perl Version is now 5.10.1
|
||||
|
||||
Some scripts now make use of features that were introduced to this Perl version
|
||||
that was released in 2009.
|
||||
|
||||
### DB Links to `DBF_MENU` fields fixed
|
||||
|
||||
[GH:183](https://github.com/epics-base/epics-base/issues/183)
|
||||
These were broken in a previous release, but now work again.
|
||||
|
||||
### Long String access to CALC fields fixed
|
||||
|
||||
[GH:194](https://github.com/epics-base/epics-base/issues/194)
|
||||
This was broken in a previous release, but now works again.
|
||||
|
||||
### Minor Changes
|
||||
|
||||
+ Many code comments have been spell-checked and corrected.
|
||||
+ Passing a `-DDEBUG` compiler flag no longer breaks the build.
|
||||
+ Parallel builds of RTEMS-mvme2100 and RTEMS-mvme2700 targets now work.
|
||||
+ Illegal characters seen in JSON strings in a database file should now get a
|
||||
better error message.
|
||||
|
||||
### Other Launchpad Bugs and GitHub Issues Fixed
|
||||
|
||||
+ [lp:1938459](https://bugs.launchpad.net/epics-base/+bug/1938459)
|
||||
[GH:191](https://github.com/epics-base/epics-base/pull/191) int64in only
|
||||
checks lower 32 bits for change
|
||||
+ [lp:1941875](https://bugs.launchpad.net/epics-base/+bug/1941875) Buggy
|
||||
warning message "Record/Alias name '...' should not contain non-printable ...
|
||||
+ [GH:187](https://github.com/epics-base/epics-base/issues/187) waveformRecord
|
||||
missing PACT=true?
|
||||
+ [GH:189](https://github.com/epics-base/epics-base/pull/189) Fix a couple
|
||||
memory leaks and a segfault
|
||||
+ [GH:200](https://github.com/epics-base/epics-base/pull/200) and
|
||||
[GH:201](https://github.com/epics-base/epics-base/pull/201) Fix timers on MS
|
||||
Windows for non-EPICS threads
|
||||
|
||||
### Compiler interface for epicsAtomic tidied up
|
||||
|
||||
[GH:192](https://github.com/epics-base/epics-base/pull/192)
|
||||
Both GCC and CLANG compiler intrisics used for the epicsAtomic APIs have been revised; implementations using CLANG should now run faster as they now use the compiler's built-in atomic functions instead of taking a mutex.
|
||||
|
||||
### The epicsTime code has been reimplemented
|
||||
|
||||
[GH:185](https://github.com/epics-base/epics-base/pull/185)
|
||||
This was done to simplify the code and may have improved performance slightly for some uses. Support for the old NTP-specific `struct l_fp` has been dropped but all other routines and methods of the `class epicsTime` function as before.
|
||||
|
||||
### Updates to Record Reference documentation
|
||||
|
||||
Many of the built-in record types have had improvements to their documentation with additional fields added to the tables, rewrites of descriptions and links to other documents added or fixed.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.6
|
||||
|
||||
### Support for obsolete architectures removed
|
||||
@@ -304,10 +595,10 @@ broken.
|
||||
|
||||
This fixes [lauchpad bug #1896295](https://bugs.launchpad.net/bugs/1896295).
|
||||
|
||||
### Support for Apple M1 (arm64) Processors
|
||||
### Support for Apple M1/M2 (arm64) Processors
|
||||
|
||||
Thanks to Jeong Han Lee this release comes with build support for Apple's new
|
||||
M1 CPUs running macOS, using the target name `darwin-aarch64`.
|
||||
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
|
||||
|
||||
It should also be possible to build universal binaries containing code for
|
||||
both the Intel and arm64 processors under either target name: In the
|
||||
@@ -1323,7 +1614,7 @@ editing and history. This functionality has now been restored, see Launchpad
|
||||
### Constant link types
|
||||
|
||||
Constant links can now hold 64-bit integer values, either as scalars or
|
||||
arrays. Only base 10 is supported by the JSON parser though, the JSON standard
|
||||
arrays. Only base 10 is supported by the JSON parser though, the JSON standard
|
||||
doesn't allow for hexadecimal numbers.
|
||||
|
||||
### Upgraded the YAJL JSON Library
|
||||
@@ -1921,6 +2212,24 @@ header and removed the need for dbScan.c to reach into the internals of its
|
||||
|
||||
## Changes from the 3.15 branch since 3.15.9
|
||||
|
||||
### Support for Apple M1/M2 (arm64) Processors
|
||||
|
||||
Thanks to Jeong Han Lee this release comes with build support for Apple's new
|
||||
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
|
||||
|
||||
### Set thread names on Windows
|
||||
|
||||
On MS Windows, epicsThread names are made available to the OS and debugger
|
||||
using `SetThreadDescription()` if available as well as using the older
|
||||
exception mechanism.
|
||||
|
||||
### Fix timers on MS Windows for non-EPICS threads
|
||||
|
||||
The waitable timer changes in 3.15.9 broke calls to `epicsThreadSleep()` and
|
||||
similar routines that used timers (including `ca_pend_event()`) when made from
|
||||
threads that were not started using the epicsThread APIs.
|
||||
[This problem](https://github.com/epics-base/epics-base/pull/200)
|
||||
[has now been fixed](https://github.com/epics-base/epics-base/pull/201).
|
||||
|
||||
## Changes made between 3.15.8 and 3.15.9
|
||||
|
||||
|
||||
@@ -37,26 +37,11 @@ that should be performed when creating production releases of EPICS Base.</p>
|
||||
|
||||
<h3>The Release Process</h3>
|
||||
|
||||
<h4>Full Process</h4>
|
||||
|
||||
<p>The version released on the Feature Freeze date is designated the first
|
||||
pre-release, <tt>-pre1</tt>. The first release candidate <tt>-rc1</tt> is the
|
||||
first version that has undergone testing by the developers and has shown no
|
||||
problems that must be fixed before release. New versions should be made at about
|
||||
2-weekly intervals after the <tt>-pre1</tt> release, and designated as either
|
||||
pre-release or release candidate versions by the Release Manager. Release
|
||||
candidates are announced to the whole community via the tech-talk mailing list,
|
||||
pre-releases are announced to to the developers via the core-talk list. After a
|
||||
release candidate has been available for 2 weeks without any new problems being
|
||||
reported or major changes having to be committed, the final release can be
|
||||
made.</p>
|
||||
|
||||
<h4>Short Process for Patch Releases</h4>
|
||||
|
||||
<p>The Patch Release date and its scope are agreed upon a few weeks ahead of the
|
||||
release. If no blocking issues are raised, the release is made by the Release
|
||||
Manager on or as soon as possible after that date, following the steps below
|
||||
starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<p>We used to have one written down here, but we weren't following it very
|
||||
closely so now the decision to make a new release is taken during the Core
|
||||
Developers bi-weekly meetings in an informal manner. The steps detailed below
|
||||
were written to remind Andrew (or anyone else who does the release) about
|
||||
everything that has to be done since it's so easy to miss steps.</p>
|
||||
|
||||
<h3>Roles</h3>
|
||||
|
||||
@@ -65,11 +50,11 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<dl>
|
||||
<dt><strong>Release Manager</strong> ()</dt>
|
||||
<dd>Responsible for managing and tagging the release</dd>
|
||||
<dt><strong>Platform Developers</strong> (optional)</dt>
|
||||
<dt><strong>Platform Developers</strong> (informal)</dt>
|
||||
<dd>Responsible for individual operating system platforms</dd>
|
||||
<dt><strong>Application Developers</strong></dt>
|
||||
<dd>Responsible for support modules that depend on EPICS Base.</dd>
|
||||
<dt><strong>Website Manager</strong> (Andrew Johnson)</dt>
|
||||
<dt><strong>Website Editor</strong> (Andrew Johnson)</dt>
|
||||
<dd>Responsible for the EPICS website</dd>
|
||||
</dl>
|
||||
|
||||
@@ -111,9 +96,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
& all developers</td>
|
||||
<td>Ensure that documentation will be updated before the release date:
|
||||
<ul>
|
||||
<li>Application Developers Guide</li>
|
||||
<li>Release Notes</li>
|
||||
<li>Known Problems</li>
|
||||
<li>Other documents</li>
|
||||
</ul>
|
||||
</td>
|
||||
@@ -125,87 +108,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Website Manager</td>
|
||||
<td>Release Manager</td>
|
||||
<td>Create a release milestone on Launchpad. If a target release date is
|
||||
known set "Date Targeted" to the expected release date. Note that
|
||||
pre-release and release-candidate versions should not get Launchpad
|
||||
milestones, only the final release.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Creating pre-release and release-candidate versions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<!-- Submodules... -->
|
||||
<td>Edit and commit changes to the EPICS version number file
|
||||
configure/CONFIG_BASE_VERSION.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Tag the module in Git, using these tag conventions:
|
||||
<ul>
|
||||
<li>
|
||||
<tt>R7.0.5-pre<i>n</i></tt>
|
||||
— pre-release tag
|
||||
</li>
|
||||
<li>
|
||||
<tt>R7.0.5-rc<i>n</i></tt>
|
||||
— release candidate tag
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for 7.0.5-rc1' R7.0.5-rc1
|
||||
</tt></blockquote>
|
||||
Note that submodules must <em>not</em> be tagged with the version used
|
||||
for the top-level, they each have their own separate version numbers
|
||||
that are only tagged at the final release.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Export the tagged version into a tarfile. The <tt>make-tar.sh</tt>
|
||||
script generates a gzipped tarfile directly from the tag, excluding the
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.5-rc1 base-7.0.5-rc1.tar.gz base-7.0.5-rc1/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-7.0.5-rc1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Test the tarfile by extracting its contents and building it on at
|
||||
least one supported platform.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Copy the tarfile and its signature to the Base download area of the
|
||||
website and add the new files to the website Base download index
|
||||
page.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Create or update a website subdirectory to hold the release
|
||||
documentation, and copy in selected files from the base/documentation
|
||||
and base/html directories of the tarfile.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Create or modify the webpage for the new release with links to the
|
||||
release documents and tar file. Pre-release and release-candidate
|
||||
versions should use the page and URL for the final release version
|
||||
number.</td>
|
||||
known set "Date Targeted" to the expected release date.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Testing</th>
|
||||
@@ -250,11 +155,8 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Release Manager</td>
|
||||
<td>Check that documentation has been updated:
|
||||
<ul>
|
||||
<li><a href="https://launchpad.net/epics-appdev">Application
|
||||
Developers Guide</a></li>
|
||||
<li>Release Notes</li>
|
||||
<li>Known Problems (hopefully empty)</li>
|
||||
<li>Other documents (converting...)</li>
|
||||
<li>Other documents</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -266,9 +168,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Obtain a positive <q>Ok to release</q> from all platform developers
|
||||
once a release candidate version has gone for 2 weeks without any major
|
||||
new issues being reported.</td>
|
||||
<td>Obtain a positive <q>Ok to release</q> from developers.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Creating the final release version</th>
|
||||
@@ -277,8 +177,8 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>
|
||||
<p>For each external submodule in turn (assuming it has not been tagged
|
||||
yet):</p>
|
||||
<p><b>For each external submodule</b> in turn (assuming it has not been
|
||||
tagged yet):</p>
|
||||
<ol>
|
||||
<li>Check that the module's Release Notes have been updated to cover
|
||||
all changes; add items as necessary, and set the module version
|
||||
@@ -298,7 +198,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
|
||||
<li>Tag the module:
|
||||
<blockquote><tt>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.5' <module-version>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.6.1' <module-version>
|
||||
</tt></blockquote>
|
||||
</li>
|
||||
|
||||
@@ -326,15 +226,24 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
<p>Commit all the submodule updates to the 7.0 branch.</p>
|
||||
<p><b>After all submodules complete</b> commit the submodule updates
|
||||
which were added for each submodule in step 4 above to the 7.0 branch
|
||||
(don't push). After committing, make sure that the output from
|
||||
<tt>git submodule status --cached</tt> only shows the appropriate
|
||||
version tags in the right-most parenthesized column with no
|
||||
<tt>-<i>n</t>-g<i>xxxxxxx</i></tt> suffix.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
|
||||
<td>Edit the main EPICS Base version file and the built-in module version
|
||||
files:
|
||||
<td>
|
||||
<p><tt>git grep UNRELEASED</tt> and insert the release version to any
|
||||
doxygen annotations that have a <tt>@since UNRELEASED</tt> comment.
|
||||
Commit (don't push).</p>
|
||||
<p>Edit the main EPICS Base version file and the built-in module version
|
||||
files:</p>
|
||||
<ul>
|
||||
<li><tt>configure/CONFIG_BASE_VERSION</tt></li>
|
||||
<li><tt>configure/CONFIG_LIBCOM_VERSION</tt></li>
|
||||
@@ -346,6 +255,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<tt>PATCH_LEVEL</tt> value should have been incremented after the
|
||||
previous release tag was applied. Set all <tt>DEVELOPMENT_FLAG</tt>
|
||||
values to 0 and <tt>EPICS_DEV_SNAPSHOT</tt> to the empty string.</p>
|
||||
<p>Edit the headings in the Release Notes to show the appropriate
|
||||
version number and remove the warning about this being an unreleased
|
||||
version of EPICS.</p>
|
||||
<p>Commit these changes (don't push).</p>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -355,9 +267,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Tag the epics-base module in Git:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.5
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.6.1
|
||||
</tt></blockquote>
|
||||
<p>Don't push these commits or the new tag to the Launchpad repository
|
||||
<p>Don't push anything to the Launchpad repository
|
||||
yet.</p>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -376,6 +288,9 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
release by incrementing the MAINTENANCE_VERSION or PATCH_LEVEL value
|
||||
in each file. Set all <tt>DEVELOPMENT_FLAG</tt> values to 1 and
|
||||
<tt>EPICS_DEV_SNAPSHOT</tt> to "-DEV".</p>
|
||||
<p>Set up the headings in the Release Notes for the next release
|
||||
version number and restore the warning about this being an unreleased
|
||||
version of EPICS.</p>
|
||||
<p>Commit these changes (don't push).</p>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -387,12 +302,12 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.5 ../base-7.0.5.tar.gz base-7.0.5/
|
||||
./.tools/make-tar.sh R7.0.6.1 ../base-7.0.6.1.tar.gz base-7.0.6.1/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
cd ..<br />
|
||||
gpg --armor --sign --detach-sig base-7.0.5.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.6.1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -412,38 +327,38 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Copy the tarfile and its signature to the Base download area of the
|
||||
website.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Update the website subdirectory that holds the release
|
||||
documentation, and copy in the files from the base/documentation
|
||||
directory of the tarfile.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Update the webpage for the new release with links to the release
|
||||
documents and tar file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Add the new release tar file to the website Base download index
|
||||
page.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Link to the release webpage from other relevent areas of the
|
||||
website - update front page and sidebars.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Add an entry to the website News page, linking to the new version
|
||||
webpage.</td>
|
||||
</tr>
|
||||
@@ -453,17 +368,17 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
|
||||
epics-controls web-server.
|
||||
<blockquote><tt>
|
||||
scp base-7.0.5.tar.gz base-7.0.5.tar.gz.asc epics-controls:download/base<br />
|
||||
scp base-7.0.6.1.tar.gz base-7.0.6.1.tar.gz.asc epics-controls:download/base<br />
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Website Editor</td>
|
||||
<td>Follow instructions on
|
||||
<a href="https://epics-controls.org/resources-and-support/documents/epics-website-documentation/adding-a-page-for-a-new-release/">
|
||||
Add a page for a new release</a> to create a new release webpage (not
|
||||
@@ -478,7 +393,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Release Manager</td>
|
||||
<td>Go to the Launchpad milestone for this release. Click the Create
|
||||
release button and add the release date. Put a URL for the release page
|
||||
in the Release notes box, and click the Create release button. Upload
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
# modules/CONFIG_SITE.local
|
||||
#
|
||||
# Despite the .local in its name, this file *is* included in EPICS Base
|
||||
# sources and should *not* be modified by sites. This trick is necessary
|
||||
# to allow external submodules to be placed inside the modules directory
|
||||
# without having to modify them, as long as their configure/CONFIG_SITE
|
||||
# file includes the standard line
|
||||
# -include $(TOP)/../CONFIG_SITE.local
|
||||
# that causes this file to be read in during submodule builds.
|
||||
|
||||
# The name our submodules know us by:
|
||||
PARENT_MODULE = EPICS_BASE
|
||||
|
||||
@@ -88,7 +88,7 @@ const char * ca_message_text []
|
||||
"Bad event subscription (monitor) identifier",
|
||||
"Remote channel has new network address",
|
||||
"New or resumed network connection",
|
||||
"Specified task isnt a member of a CA context",
|
||||
"Specified task isn't a member of a CA context",
|
||||
"Attempt to use defunct CA feature failed",
|
||||
|
||||
"The supplied string is empty",
|
||||
@@ -324,7 +324,7 @@ int epicsStdCall ca_create_channel (
|
||||
*chanptr = pChanNotify;
|
||||
pChanNotify->initiateConnect ( guard );
|
||||
// no need to worry about a connect preempting here because
|
||||
// the connect sequence will not start untill initiateConnect()
|
||||
// the connect sequence will not start until initiateConnect()
|
||||
// is called
|
||||
}
|
||||
catch ( cacChannel::badString & ) {
|
||||
@@ -384,9 +384,9 @@ int epicsStdCall ca_clear_channel ( chid pChan )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( cac.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
@@ -720,7 +720,7 @@ int epicsStdCall ca_context_status ( ca_client_context * pcac, unsigned level )
|
||||
/*
|
||||
* ca_current_context ()
|
||||
*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* used when an auxiliary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
// extern "C"
|
||||
@@ -740,7 +740,7 @@ struct ca_client_context * epicsStdCall ca_current_context ()
|
||||
/*
|
||||
* ca_attach_context ()
|
||||
*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* used when an auxiliary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
// extern "C"
|
||||
|
||||
@@ -494,7 +494,7 @@ void verifyConnectionHandlerConnect ( appChan *pChans, unsigned chanCount,
|
||||
/*
|
||||
* verifyBlockingConnect ()
|
||||
*
|
||||
* 1) verify that we dont print a disconnect message when
|
||||
* 1) verify that we don't print a disconnect message when
|
||||
* we delete the last channel
|
||||
*
|
||||
* 2) verify that we delete the connection to the IOC
|
||||
@@ -645,7 +645,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
status = ca_pend_io ( 1e-16 );
|
||||
if ( status == ECA_TIMEOUT ) {
|
||||
/*
|
||||
* we end up here if the channel isnt on the same host
|
||||
* we end up here if the channel isn't on the same host
|
||||
*/
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll ();
|
||||
@@ -1112,7 +1112,7 @@ void verifyHighThroughputRead ( chid chan, unsigned interestLevel )
|
||||
unsigned i;
|
||||
|
||||
/*
|
||||
* verify we dont jam up on many uninterrupted
|
||||
* verify we don't jam up on many uninterrupted
|
||||
* solicitations
|
||||
*/
|
||||
if ( ca_read_access (chan) ) {
|
||||
@@ -1152,7 +1152,7 @@ void verifyHighThroughputWrite ( chid chan, unsigned interestLevel )
|
||||
}
|
||||
|
||||
/*
|
||||
* verify we dont jam up on many uninterrupted
|
||||
* verify we don't jam up on many uninterrupted
|
||||
* get callback requests
|
||||
*/
|
||||
void verifyHighThroughputReadCallback ( chid chan, unsigned interestLevel )
|
||||
@@ -1181,7 +1181,7 @@ void verifyHighThroughputReadCallback ( chid chan, unsigned interestLevel )
|
||||
}
|
||||
|
||||
/*
|
||||
* verify we dont jam up on many uninterrupted
|
||||
* verify we don't jam up on many uninterrupted
|
||||
* put callback request
|
||||
*/
|
||||
void verifyHighThroughputWriteCallback ( chid chan, unsigned interestLevel )
|
||||
@@ -1239,7 +1239,7 @@ void verifyBadString ( chid chan, unsigned interestLevel )
|
||||
verify ( status == ECA_NORMAL );
|
||||
if ( strcmp ( stimStr, respStr ) ) {
|
||||
printf (
|
||||
"Test fails if stim \"%s\" isnt roughly equiv to resp \"%s\"\n",
|
||||
"Test fails if stim \"%s\" isn't roughly equiv to resp \"%s\"\n",
|
||||
stimStr, respStr);
|
||||
}
|
||||
showProgressEnd ( interestLevel );
|
||||
@@ -1395,7 +1395,7 @@ static void multiSubscrDestroyNoLateCallbackThread ( void * pParm )
|
||||
|
||||
/*
|
||||
* raise the priority of the current thread hoping to improve our
|
||||
* likelyhood of detecting a bug
|
||||
* likelihood of detecting a bug
|
||||
*/
|
||||
priorityOfTestThread = epicsThreadGetPrioritySelf ();
|
||||
epicsThreadSetPriority ( epicsThreadGetIdSelf(), epicsThreadPriorityHigh );
|
||||
@@ -1445,7 +1445,7 @@ static void multiSubscrDestroyNoLateCallbackThread ( void * pParm )
|
||||
}
|
||||
|
||||
/*
|
||||
* verify that, in a preemtive callback mode client, a subscription callback never
|
||||
* verify that, in a preemptive callback mode client, a subscription callback never
|
||||
* comes after the subscription is destroyed
|
||||
*/
|
||||
static void multiSubscrDestroyNoLateCallbackTest ( const char *pName, unsigned interestLevel )
|
||||
@@ -1563,7 +1563,7 @@ void multiSubscriptionDeleteTest ( chid chan, unsigned interestLevel )
|
||||
/*
|
||||
* singleSubscriptionDeleteTest
|
||||
*
|
||||
* verify that we dont fail when we repeatedly create
|
||||
* verify that we don't fail when we repeatedly create
|
||||
* and delete only one subscription with a high level of
|
||||
* traffic on it
|
||||
*/
|
||||
@@ -1617,7 +1617,7 @@ void singleSubscriptionDeleteTest ( chid chan, unsigned interestLevel )
|
||||
/*
|
||||
* channelClearWithEventTrafficTest
|
||||
*
|
||||
* verify that we can delete a channel that has subcriptions
|
||||
* verify that we can delete a channel that has subscriptions
|
||||
* attached with heavy update traffic
|
||||
*/
|
||||
void channelClearWithEventTrafficTest ( const char *pName, unsigned interestLevel )
|
||||
@@ -2481,7 +2481,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
showProgress ( interestLevel );
|
||||
|
||||
/*
|
||||
* attempt to uncover problems where the last event isnt sent
|
||||
* attempt to uncover problems where the last event isn't sent
|
||||
* and hopefully get into a flow control situation
|
||||
*/
|
||||
prevPassCount = 0u;
|
||||
@@ -2522,7 +2522,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
for ( j = 0; j < NELEMENTS ( test ); j++ ) {
|
||||
/*
|
||||
* we shouldnt see old monitors because
|
||||
* we shouldn't see old monitors because
|
||||
* we resubscribed
|
||||
*/
|
||||
verify ( test[j].count <= i + 2 );
|
||||
@@ -3016,7 +3016,7 @@ void testMultithreadSubscr ( void * pParm )
|
||||
}
|
||||
|
||||
/*
|
||||
* test installation of subscriptions similar to usage paterns
|
||||
* test installation of subscriptions similar to usage patterns
|
||||
* employed by modern versions of the sequencer
|
||||
*/
|
||||
void verifyMultithreadSubscr ( const char * pName, unsigned interestLevel )
|
||||
@@ -3111,7 +3111,7 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
|
||||
status = ca_flush_io ();
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
/* look for infinite loop in fd manager schedualing */
|
||||
/* look for infinite loop in fd manager scheduling */
|
||||
epicsTimeGetCurrent ( & begin );
|
||||
eventCount = 0u;
|
||||
while ( 1 ) {
|
||||
@@ -3175,7 +3175,7 @@ void verifyConnectWithDisconnectedChannels (
|
||||
* we should be able to connect to a valid
|
||||
* channel within a reasonable delay even
|
||||
* though there is one permanently
|
||||
* diasconnected channel
|
||||
* disconnected channel
|
||||
*/
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
verify ( status == ECA_NORMAL );
|
||||
@@ -3491,7 +3491,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
|
||||
|
||||
/*
|
||||
* CA pend event delay accuracy test
|
||||
* (CA asssumes that search requests can be sent
|
||||
* (CA assumes that search requests can be sent
|
||||
* at least every 25 mS on all supported os)
|
||||
*/
|
||||
printf ( "\n" );
|
||||
|
||||
@@ -32,7 +32,13 @@ static const iocshArg *acctstArgs[] =
|
||||
&acctstArg3,
|
||||
&acctstArg4
|
||||
};
|
||||
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
|
||||
static const iocshFuncDef acctstFuncDef = {
|
||||
"acctst",
|
||||
5,
|
||||
acctstArgs,
|
||||
"Execute a Channel Access regression test.\n\n"
|
||||
"For more information, see the 'acctst' documentation in the Channel Access reference.\n",
|
||||
};
|
||||
|
||||
|
||||
/* Wrapper called by iocsh, selects the argument types that print needs */
|
||||
|
||||
@@ -130,8 +130,8 @@ bool bhe::updatePeriod (
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
|
||||
//
|
||||
// this block is enetered if the beacon was created as a side effect of
|
||||
// creating a connection and so we dont yet know the first beacon time
|
||||
// this block is entered if the beacon was created as a side effect of
|
||||
// creating a connection and so we don't yet know the first beacon time
|
||||
// and sequence number
|
||||
//
|
||||
if ( this->timeStamp == epicsTime () ) {
|
||||
@@ -154,7 +154,7 @@ bool bhe::updatePeriod (
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1) detect beacon duplications due to redundant routes
|
||||
// 1) detect beacon duplication due to redundant routes
|
||||
// 2) detect lost beacons due to input queue overrun or damage
|
||||
if ( CA_V410 ( protocolRevision ) ) {
|
||||
unsigned beaconSeqAdvance;
|
||||
@@ -175,7 +175,7 @@ bool bhe::updatePeriod (
|
||||
|
||||
// throw out sequence numbers that jump forward by only a few numbers
|
||||
// (this situation is probably caused by a duplicate route
|
||||
// or a beacon due to input queue overun)
|
||||
// or a beacon due to input queue overrun)
|
||||
if ( beaconSeqAdvance > 1 && beaconSeqAdvance < 4 ) {
|
||||
logBeaconDiscard ( beaconSeqAdvance, currentTime );
|
||||
return false;
|
||||
@@ -244,8 +244,8 @@ bool bhe::updatePeriod (
|
||||
/*
|
||||
* Is this an IOC seen because of an IOC reboot
|
||||
* (beacon come at a higher rate just after the
|
||||
* IOC reboots). Lower tolarance here because we
|
||||
* dont have to worry about lost beacons.
|
||||
* IOC reboots). Lower tolerance here because we
|
||||
* don't have to worry about lost beacons.
|
||||
*
|
||||
* It may be possible to get false triggers here
|
||||
* if the client is busy, but this does not cause
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u+1u)
|
||||
|
||||
/*
|
||||
* 1500 (max of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
|
||||
* (the MTU of Ethernet is currently independent of its speed varient)
|
||||
* 1500 (max of Ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
|
||||
* (the MTU of Ethernet is currently independent of its speed variant)
|
||||
*/
|
||||
#define ETHERNET_MAX_UDP ( 1500u - 20u - 8u )
|
||||
#define MAX_UDP_RECV ( 0xffff + 16u ) /* allow large frames to be received in the future */
|
||||
@@ -117,7 +117,7 @@ typedef ca_uint32_t caResId;
|
||||
|
||||
/*
|
||||
* for use with search and not_found (if search fails and
|
||||
* its not a broadcast tell the client to look elesewhere)
|
||||
* its not a broadcast tell the client to look elsewhere)
|
||||
*/
|
||||
#define DOREPLY 10u
|
||||
#define DONTREPLY 5u
|
||||
@@ -176,7 +176,7 @@ typedef struct ca_hdr {
|
||||
struct mon_info {
|
||||
ca_float32_t m_lval; /* low delta */
|
||||
ca_float32_t m_hval; /* high delta */
|
||||
ca_float32_t m_toval; /* period btween samples */
|
||||
ca_float32_t m_toval; /* period between samples */
|
||||
ca_uint16_t m_mask; /* event select mask */
|
||||
ca_uint16_t m_pad; /* extend to 32 bits */
|
||||
};
|
||||
|
||||
@@ -224,7 +224,7 @@ void ca_client_context::changeExceptionEvent (
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->ca_exception_func = pfunc;
|
||||
this->ca_exception_arg = arg;
|
||||
// should block here until releated callback in progress completes
|
||||
// should block here until related callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::replaceErrLogHandler (
|
||||
@@ -237,7 +237,7 @@ void ca_client_context::replaceErrLogHandler (
|
||||
else {
|
||||
this->pVPrintfFunc = epicsVprintf;
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
// should block here until related callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::registerForFileDescriptorCallBack (
|
||||
@@ -252,7 +252,7 @@ void ca_client_context::registerForFileDescriptorCallBack (
|
||||
// w/o having sent the wakeup message
|
||||
this->_sendWakeupMsg ();
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
// should block here until related callback in progress completes
|
||||
}
|
||||
|
||||
int ca_client_context :: printFormated (
|
||||
@@ -392,9 +392,19 @@ void ca_client_context :: vSignal (
|
||||
}
|
||||
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
char date[64];
|
||||
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
|
||||
this->printFormated ( " Current Time: %s\n", date );
|
||||
try {
|
||||
char date[64];
|
||||
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
|
||||
this->printFormated ( " Current Time: %s\n", date );
|
||||
}
|
||||
catch ( std::exception & except ) {
|
||||
errlogPrintf (
|
||||
"CA client library thread \"%s\" caught C++ exception \"%s\"\n",
|
||||
epicsThreadGetNameSelf (), except.what () );
|
||||
epicsTimeStamp now = current;
|
||||
this->printFormated ( " Current Time: %u.%u\n",
|
||||
now.secPastEpoch, now.nsec );
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate execution if unsuccessful
|
||||
@@ -768,9 +778,9 @@ LIBCA_API int epicsStdCall ca_clear_subscription ( evid pMon )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( cac.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
|
||||
@@ -285,7 +285,7 @@ cac::~cac ()
|
||||
// this blocks until the UDP thread exits so that
|
||||
// it will not sneak in any new clients
|
||||
//
|
||||
// lock intentionally not held here so that we dont deadlock
|
||||
// lock intentionally not held here so that we don't deadlock
|
||||
// waiting for the UDP thread to exit while it is waiting to
|
||||
// get the lock.
|
||||
{
|
||||
@@ -312,7 +312,7 @@ cac::~cac ()
|
||||
//
|
||||
// wait for all tcp threads to exit
|
||||
//
|
||||
// this will block for oustanding sends to go out so dont
|
||||
// this will block for outstanding sends to go out so don't
|
||||
// hold a lock while waiting
|
||||
//
|
||||
{
|
||||
@@ -411,7 +411,7 @@ void cac::show (
|
||||
|
||||
::printf ( "Channel Access Client Context at %p for user %s\n",
|
||||
static_cast <const void *> ( this ), this->pUserName );
|
||||
// this also supresses the "defined, but not used"
|
||||
// this also suppresses the "defined, but not used"
|
||||
// warning message
|
||||
::printf ( "\trevision \"%s\"\n", pVersionCAC );
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ typedef unsigned CA_SYNC_GID;
|
||||
#define CA_OP_CONN_UP 6
|
||||
#define CA_OP_CONN_DOWN 7
|
||||
|
||||
/* depricated */
|
||||
/* deprecated */
|
||||
#define CA_OP_SEARCH 2
|
||||
|
||||
/*
|
||||
@@ -464,7 +464,7 @@ LIBCA_API int epicsStdCall ca_array_get_callback
|
||||
/* Specify a function to be executed whenever significant changes */
|
||||
/* occur to a channel. */
|
||||
/* NOTES: */
|
||||
/* 1) Evid may be omited by passing a NULL pointer */
|
||||
/* 1) Evid may be omitted by passing a NULL pointer */
|
||||
/* */
|
||||
/* 2) An array count of zero specifies the native db count */
|
||||
/* */
|
||||
@@ -559,19 +559,19 @@ LIBCA_API chid epicsStdCall ca_evid_to_chid ( evid id );
|
||||
/*
|
||||
* ca_pend_event()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds
|
||||
* timeout R wait for this delay in seconds
|
||||
*/
|
||||
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeOut);
|
||||
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeout);
|
||||
#define ca_poll() ca_pend_event(1e-12)
|
||||
|
||||
/*
|
||||
* ca_pend_io()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds but return early
|
||||
* timeout R wait for this delay in seconds but return early
|
||||
* if all get requests (or search requests with null
|
||||
* connection handler pointer have completed)
|
||||
*/
|
||||
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeOut);
|
||||
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeout);
|
||||
|
||||
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
|
||||
LIBCA_API int epicsStdCall ca_pend (ca_real timeout, int early);
|
||||
@@ -837,7 +837,7 @@ LIBCA_API double epicsStdCall ca_beacon_period (chid chan);
|
||||
LIBCA_API double epicsStdCall ca_receive_watchdog_delay (chid chan);
|
||||
|
||||
/*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* used when an auxiliary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
LIBCA_API struct ca_client_context * epicsStdCall ca_current_context ();
|
||||
|
||||
@@ -188,7 +188,7 @@ int main ( int argc, char ** argv )
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ("casw: error from recv was = \"%s\"\n",
|
||||
errlogPrintf ("casw: " ERL_ERROR " from recv was = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
@@ -224,7 +224,7 @@ int main ( int argc, char ** argv )
|
||||
* always set this field to INADDR_ANY
|
||||
*
|
||||
* clients always assume that if this
|
||||
* field is set to something that isnt INADDR_ANY
|
||||
* field is set to something that isn't INADDR_ANY
|
||||
* then it is the overriding IP address of the server.
|
||||
*/
|
||||
ina.sin_family = AF_INET;
|
||||
@@ -235,7 +235,7 @@ int main ( int argc, char ** argv )
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* old servers dont supply this and the
|
||||
* old servers don't supply this and the
|
||||
* default port must be assumed
|
||||
*/
|
||||
ina.sin_port = htons ( serverPort );
|
||||
|
||||
@@ -45,7 +45,7 @@ bool comBuf::flushToWire ( wireSendAdapter & wire, const epicsTime & currentTime
|
||||
return true;
|
||||
}
|
||||
|
||||
// throwing the exception from a function that isnt inline
|
||||
// throwing the exception from a function that isn't inline
|
||||
// shrinks the GNU compiled object code
|
||||
void comBuf::throwInsufficentBytesException ()
|
||||
{
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
bool push ( const T & value );
|
||||
template < class T >
|
||||
unsigned push ( const T * pValue, unsigned nElem );
|
||||
unsigned push ( const char * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsOldString * pValue, unsigned nElem );
|
||||
@@ -208,6 +209,11 @@ inline unsigned comBuf :: push ( const epicsUInt8 *pValue, unsigned nElem )
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const char *pValue, unsigned nElem )
|
||||
{
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsOldString * pValue, unsigned nElem )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
|
||||
@@ -46,7 +46,7 @@ void comQueRecv::clear ()
|
||||
this->nBytesPending = 0u;
|
||||
}
|
||||
|
||||
unsigned comQueRecv::copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes )
|
||||
unsigned comQueRecv::copyOutBytes ( char *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned totalBytes = 0u;
|
||||
do {
|
||||
@@ -196,7 +196,7 @@ epicsUInt16 comQueRecv::popUInt16 ()
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
// try first for all in one buffer efficient version
|
||||
epicsUInt16 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
@@ -215,7 +215,7 @@ epicsUInt32 comQueRecv::popUInt32 ()
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
// try first for all in one buffer efficient version
|
||||
epicsUInt32 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
@@ -230,7 +230,7 @@ epicsUInt32 comQueRecv::popUInt32 ()
|
||||
|
||||
bool comQueRecv::popOldMsgHeader ( caHdrLargeArray & msg )
|
||||
{
|
||||
// try first for all in one buffer efficent version
|
||||
// try first for all in one buffer efficient version
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
return false;
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
comQueRecv ( comBufMemoryManager & );
|
||||
~comQueRecv ();
|
||||
unsigned occupiedBytes () const;
|
||||
unsigned copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes );
|
||||
unsigned copyOutBytes ( char *pBuf, unsigned nBytes );
|
||||
unsigned removeBytes ( unsigned nBytes );
|
||||
void pushLastComBufReceived ( comBuf & );
|
||||
void clear ();
|
||||
|
||||
@@ -27,17 +27,17 @@
|
||||
// 1) Allow sufficent headroom so that users will be able to perform
|
||||
// a reasonable amount of IO within CA callbacks without experiencing
|
||||
// a push/pull deadlock. If a potential push/pull deadlock situation
|
||||
// occurs then detect and avoid it and provide diagnotic to the user
|
||||
// occurs then detect and avoid it and provide diagnostic to the user
|
||||
// via special status.
|
||||
// 2) Return status to the user when there is insufficent memory to
|
||||
// 2) Return status to the user when there is insufficient memory to
|
||||
// queue a complete message.
|
||||
// 3) return status to the user when a message cant be flushed because
|
||||
// a connection dropped.
|
||||
// 4) Do not allocate too much memory in exception situatons (such as
|
||||
// 4) Do not allocate too much memory in exception situations (such as
|
||||
// after a circuit disconnect).
|
||||
// 5) Avoid allocating more memory than is absolutely necessary to meet
|
||||
// the above requirements.
|
||||
// 6) Message fragments must never be sent to the IOC when there isnt
|
||||
// 6) Message fragments must never be sent to the IOC when there isn't
|
||||
// enough memory to queue part of a message (we also must not force
|
||||
// a disconnect because the client is starved for memory).
|
||||
// 7) avoid the need to check status for each byte pushed into the
|
||||
@@ -45,7 +45,7 @@
|
||||
//
|
||||
// Implementation:
|
||||
// 1) When queuing a complete message, first test to see if a flush is
|
||||
// required. If it is a receive thread scheduals the flush with the
|
||||
// required. If it is a receive thread schedules the flush with the
|
||||
// send thread, and otherwise directly execute the system call. The
|
||||
// send thread must run at a higher priority than the receive thread
|
||||
// if we are to minimize memory consumption.
|
||||
@@ -58,9 +58,9 @@
|
||||
// a) A user is queuing more requests that demand a response from a
|
||||
// callback than are removed by the response that initiated the
|
||||
// callback, and this situation persists for many callbacks until
|
||||
// all buffering in the system is exausted.
|
||||
// all buffering in the system is exhausted.
|
||||
// b) A user is queuing many requests that demand a response from one
|
||||
// callback until all buffering in the system is exausted.
|
||||
// callback until all buffering in the system is exhausted.
|
||||
// c) Some combination of both (a) nad (b).
|
||||
//
|
||||
//
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "caerr.h"
|
||||
|
||||
/*
|
||||
* NOOP if this isnt required
|
||||
* NOOP if this isn't required
|
||||
*/
|
||||
#ifdef EPICS_CONVERSION_REQUIRED
|
||||
|
||||
@@ -326,7 +326,7 @@ arrayElementCount num /* number of values */
|
||||
** int encode; boolean, if true vax to ieee
|
||||
** else ieee to vax
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1022,7 +1022,7 @@ arrayElementCount num /* number of values */
|
||||
** int encode; boolean, if true vax to ieee
|
||||
** else ieee to vax
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1056,7 +1056,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_sts_long(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1118,7 +1118,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_time_short(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1239,7 +1239,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_sts_char(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1274,7 +1274,7 @@ arrayElementCount num /* number of values */
|
||||
/****************************************************************************
|
||||
** cvrt_time_long(s,d)
|
||||
**
|
||||
** converts fields ofstruct in HOST format to ieee format
|
||||
** converts fields of struct in HOST format to ieee format
|
||||
** or
|
||||
** converts fields of struct in NET format to fields with HOST
|
||||
** format
|
||||
@@ -1325,7 +1325,7 @@ arrayElementCount num /* number of values */
|
||||
for(i=0; i<num; i++){
|
||||
*pDest = dbr_ntohs( *pSrc );
|
||||
/*
|
||||
* dont increment these inside the MACRO
|
||||
* don't increment these inside the MACRO
|
||||
*/
|
||||
pDest++;
|
||||
pSrc++;
|
||||
|
||||
@@ -123,7 +123,7 @@ typedef epicsOldString dbr_class_name_t;
|
||||
LIBCA_API extern const int epicsTypeToDBR_XXXX [lastEpicsType+1];
|
||||
|
||||
/*
|
||||
* The DBR_XXXX types are indicies into this array
|
||||
* The DBR_XXXX types are indices into this array
|
||||
*/
|
||||
LIBCA_API extern const epicsType DBR_XXXXToEpicsType [LAST_BUFFER_TYPE+1];
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ void hostNameCache::transactionComplete ( const char * pHostNameIn )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
// a few legacy clients have a direct pointer to this buffer so we
|
||||
// set the entrire string to nill terminators before we start copying
|
||||
// set the entire string to nill terminators before we start copying
|
||||
// in the name (this reduces the chance that another thread will see
|
||||
// garbage characters).
|
||||
size_t newNameLen = strlen ( pHostNameIn );
|
||||
|
||||
@@ -79,7 +79,7 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
|
||||
const char *pStr;
|
||||
const char *pToken;
|
||||
struct sockaddr_in addr;
|
||||
char buf[32u]; /* large enough to hold an IP address */
|
||||
char buf[256u]; /* large enough to hold an IP address or hostname */
|
||||
int status, ret = -1;
|
||||
|
||||
pStr = envGetConfigParamPtr (pEnv);
|
||||
@@ -189,7 +189,7 @@ extern "C" void epicsStdCall configureChannelAccessAddressList
|
||||
int yes;
|
||||
|
||||
/*
|
||||
* dont load the list twice
|
||||
* don't load the list twice
|
||||
*/
|
||||
assert ( ellCount (pList) == 0 );
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request
|
||||
* monitor flow control
|
||||
*
|
||||
* turning this down effects maximum throughput
|
||||
* because we dont get an optimal number of bytes
|
||||
* because we don't get an optimal number of bytes
|
||||
* per network frame
|
||||
*/
|
||||
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
|
||||
|
||||
@@ -57,7 +57,7 @@ void msgForMultiplyDefinedPV::transactionComplete ( const char * pHostNameRej )
|
||||
// calls into cac for the notification
|
||||
// the msg object (= this) is being deleted as part of the notification
|
||||
this->cb.pvMultiplyDefinedNotify ( *this, this->channel, this->acc, pHostNameRej );
|
||||
// !! dont touch 'this' pointer after this point because object has been deleted !!
|
||||
// !! don't touch 'this' pointer after this point because object has been deleted !!
|
||||
}
|
||||
|
||||
void * msgForMultiplyDefinedPV::operator new ( size_t size,
|
||||
|
||||
@@ -147,14 +147,14 @@ void nciu::connect ( unsigned nativeType,
|
||||
guard, this->accessRightState );
|
||||
}
|
||||
|
||||
// channel uninstal routine grabs the callback lock so
|
||||
// channel uninstall routine grabs the callback lock so
|
||||
// a channel will not be deleted while a call back is
|
||||
// in progress
|
||||
//
|
||||
// the callback lock is also taken when a channel
|
||||
// disconnects to prevent a race condition with the
|
||||
// code below - ie we hold the callback lock here
|
||||
// so a chanel cant be destroyed out from under us.
|
||||
// so a channel cant be destroyed out from under us.
|
||||
this->notify().connectNotify ( guard );
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
// destructor is virtual (therefore it is protected).
|
||||
// I assume that SUNPRO will fix this in future versions.
|
||||
// With other compilers we get warnings (and
|
||||
// potential problems) if we dont make the baseNMIU
|
||||
// potential problems) if we don't make the baseNMIU
|
||||
// destructor virtual.
|
||||
#if defined ( __SUNPRO_CC ) && ( __SUNPRO_CC <= 0x540 )
|
||||
# define NETIO_VIRTUAL_DESTRUCTOR
|
||||
|
||||
@@ -591,16 +591,16 @@ void ca_client_context :: whenThereIsAnExceptionDestroySyncGroupIO (
|
||||
io.destroy ( *this->pCallbackGuard.get(), guard );
|
||||
}
|
||||
else {
|
||||
// dont reverse the lock hierarchy
|
||||
// don't reverse the lock hierarchy
|
||||
epicsGuardRelease < epicsMutex > guardRelease ( guard );
|
||||
{
|
||||
//
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( this->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
@@ -571,7 +571,7 @@ int epicsStdCall ca_create_subscription (
|
||||
oldSubscription (
|
||||
guard, *pChan, pChan->io, tmpType, count, mask,
|
||||
pCallBack, pCallBackArg, monixptr );
|
||||
// dont touch object created after above new because
|
||||
// don't touch object created after above new because
|
||||
// the first callback might have canceled, and therefore
|
||||
// destroyed, it
|
||||
return ECA_NORMAL;
|
||||
|
||||
@@ -41,7 +41,7 @@ oldSubscription::oldSubscription (
|
||||
*pEventId = this;
|
||||
}
|
||||
io.subscribe ( guard, type, nElem, mask, *this, &this->id );
|
||||
// Dont touch this pointer after this point because the
|
||||
// Don't touch this pointer after this point because the
|
||||
// 1st update callback might cancel the subscription and
|
||||
// thereby destroy this object.
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
/*
|
||||
* these can be external since there is only one instance
|
||||
* per machine so we dont care about reentrancy
|
||||
* per machine so we don't care about reentrancy
|
||||
*/
|
||||
static tsDLList < repeaterClient > client_list;
|
||||
|
||||
@@ -335,7 +335,7 @@ static void fanOut ( const osiSockAddr & from, const void * pMsg,
|
||||
|
||||
while ( ( pclient = client_list.get () ) ) {
|
||||
theClients.add ( *pclient );
|
||||
/* Dont reflect back to sender */
|
||||
/* Don't reflect back to sender */
|
||||
if ( pclient->identicalAddress ( from ) ) {
|
||||
continue;
|
||||
}
|
||||
@@ -392,7 +392,7 @@ static void register_new_client ( osiSockAddr & from,
|
||||
* repeater would not always allow the loopback address
|
||||
* as a local client address so current clients alternate
|
||||
* between the address of the first non-loopback interface
|
||||
* found and the loopback addresss when subscribing with
|
||||
* found and the loopback address when subscribing with
|
||||
* the CA repeater until all CA repeaters have been updated
|
||||
* to current code.
|
||||
*/
|
||||
@@ -452,7 +452,7 @@ static void register_new_client ( osiSockAddr & from,
|
||||
}
|
||||
|
||||
/*
|
||||
* send a noop message to all other clients so that we dont
|
||||
* send a noop message to all other clients so that we don't
|
||||
* accumulate sockets when there are no beacons
|
||||
*/
|
||||
caHdr noop;
|
||||
|
||||
@@ -279,8 +279,8 @@ epicsTimerNotify::expireStatus searchTimer::expire (
|
||||
if ( this->searchAttempts ) {
|
||||
char buf[64];
|
||||
currentTime.strftime ( buf, sizeof(buf), "%M:%S.%09f");
|
||||
debugPrintf ( ("sent %u delay sec=%f Rts=%s\n",
|
||||
nFrameSent, this->period(), buf ) );
|
||||
debugPrintf ( ("sent %u delay Rts=%s\n",
|
||||
nFrameSent, buf ) );
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -317,7 +317,7 @@ void searchTimer :: show ( unsigned level ) const
|
||||
|
||||
//
|
||||
// Reset the delay to the next search request if we get
|
||||
// at least one response. However, dont reset this delay if we
|
||||
// at least one response. However, don't reset this delay if we
|
||||
// get a delayed response to an old search request.
|
||||
//
|
||||
void searchTimer::uninstallChanDueToSuccessfulSearchResponse (
|
||||
|
||||
@@ -82,8 +82,8 @@ private:
|
||||
double framesPerTry; /* # of UDP frames per search try */
|
||||
double framesPerTryCongestThresh; /* one half N tries w congest */
|
||||
unsigned retry;
|
||||
unsigned searchAttempts; /* num search tries after last timer experation */
|
||||
unsigned searchResponses; /* num search resp after last timer experation */
|
||||
unsigned searchAttempts; /* num search tries after last timer expiration */
|
||||
unsigned searchResponses; /* num search resp after last timer expiration */
|
||||
const unsigned index;
|
||||
ca_uint32_t dgSeqNoAtTimerExpireBegin;
|
||||
ca_uint32_t dgSeqNoAtTimerExpireEnd;
|
||||
|
||||
@@ -82,9 +82,9 @@ extern "C" int epicsStdCall ca_sg_delete ( const CA_SYNC_GID gid )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( pcac->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( pcac->mutex );
|
||||
@@ -106,9 +106,9 @@ void sync_group_reset ( ca_client_context & client, CASG & sg )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( client.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( client.mutex );
|
||||
@@ -219,9 +219,9 @@ extern "C" int epicsStdCall ca_sg_test ( const CA_SYNC_GID gid )
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user creates non-preemptive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
// o user calls this function from an auxiliary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( pcac->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( pcac->mutex );
|
||||
|
||||
@@ -176,7 +176,7 @@ void tcpRecvWatchdog::sendBacklogProgressNotify (
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
|
||||
// We dont set "beaconAnomaly" to be false here because, after we see a
|
||||
// We don't set "beaconAnomaly" to be false here because, after we see a
|
||||
// beacon anomaly (which could be transiently detecting a reboot) we will
|
||||
// not trust the beacon as an indicator of a healthy server until we
|
||||
// receive at least one message from the server.
|
||||
|
||||
@@ -81,7 +81,7 @@ void tcpSendThread::run ()
|
||||
|
||||
while ( true ) {
|
||||
|
||||
// dont wait if there is still labor to be done below
|
||||
// don't wait if there is still labor to be done below
|
||||
if ( ! laborPending ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->iiu.sendThreadFlushEvent.wait ();
|
||||
@@ -124,7 +124,7 @@ void tcpSendThread::run ()
|
||||
}
|
||||
else {
|
||||
// This wakes up the resp thread so that it can call
|
||||
// the connect callback. This isnt maximally efficent
|
||||
// the connect callback. This isn't maximally efficient
|
||||
// but it has the excellent side effect of not requiring
|
||||
// that the UDP thread take the callback lock. There are
|
||||
// almost no V42 servers left at this point.
|
||||
@@ -178,7 +178,7 @@ void tcpSendThread::run ()
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAC TCP clean socket shutdown error was %s\n",
|
||||
errlogPrintf ("CAC TCP clean socket shutdown " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ void tcpSendThread::run ()
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAC TCP clean socket shutdown error was %s\n",
|
||||
errlogPrintf ("CAC TCP clean socket shutdown " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ void tcpSendThread::run ()
|
||||
|
||||
while ( ! this->iiu.recvThread.exitWait ( 30.0 ) ) {
|
||||
// it is possible to get stuck here if the user calls
|
||||
// ca_context_destroy() when a circuit isnt known to
|
||||
// ca_context_destroy() when a circuit isn't known to
|
||||
// be unresponsive, but is. That situation is probably
|
||||
// rare, and the IP kernel might have a timeout for
|
||||
// such situations, nevertheless we will attempt to deal
|
||||
@@ -283,7 +283,7 @@ unsigned tcpiiu::sendBytes ( const void *pBuf,
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAC: unexpected TCP send error: %s\n",
|
||||
errlogPrintf ( "CAC: unexpected TCP send " ERL_ERROR ": %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ void tcpiiu::recvBytes (
|
||||
return;
|
||||
}
|
||||
|
||||
// if the circuit was locally aborted then supress
|
||||
// if the circuit was locally aborted then suppress
|
||||
// warning messages about bad file descriptor etc
|
||||
if ( this->state != iiucs_connected &&
|
||||
this->state != iiucs_clean_shutdown ) {
|
||||
@@ -358,9 +358,9 @@ void tcpiiu::recvBytes (
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
|
||||
// the replacable printf handler isnt called here
|
||||
// because it reqires a callback lock which probably
|
||||
// isnt appropriate here
|
||||
// the replaceable printf handler isn't called here
|
||||
// because it requires a callback lock which probably
|
||||
// isn't appropriate here
|
||||
char name[64];
|
||||
this->hostNameCacheInstance.getName (
|
||||
name, sizeof ( name ) );
|
||||
@@ -535,11 +535,11 @@ void tcpRecvThread::run ()
|
||||
}
|
||||
|
||||
//
|
||||
// we dont feel comfortable calling this with a lock applied
|
||||
// we don't feel comfortable calling this with a lock applied
|
||||
// (it might block for longer than we like)
|
||||
//
|
||||
// we would prefer to improve efficency by trying, first, a
|
||||
// recv with the new MSG_DONTWAIT flag set, but there isnt
|
||||
// we would prefer to improve efficiency by trying, first, a
|
||||
// recv with the new MSG_DONTWAIT flag set, but there isn't
|
||||
// universal support
|
||||
//
|
||||
bool bytesArePending = this->iiu.bytesArePendingInOS ();
|
||||
@@ -957,7 +957,7 @@ void tcpiiu::initiateAbortShutdown (
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAC TCP socket linger set error was %s\n",
|
||||
errlogPrintf ( "CAC TCP socket linger set " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
this->discardingPendingData = true;
|
||||
@@ -988,7 +988,7 @@ void tcpiiu::initiateAbortShutdown (
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAC TCP socket shutdown error was %s\n",
|
||||
errlogPrintf ("CAC TCP socket shutdown " ERL_ERROR " was %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -1002,7 +1002,7 @@ void tcpiiu::initiateAbortShutdown (
|
||||
};
|
||||
|
||||
//
|
||||
// wake up the send thread if it isnt blocking in send()
|
||||
// wake up the send thread if it isn't blocking in send()
|
||||
//
|
||||
this->sendThreadFlushEvent.signal ();
|
||||
this->flushBlockEvent.signal ();
|
||||
@@ -1058,7 +1058,7 @@ void tcpiiu::show ( unsigned level ) const
|
||||
this->_receiveThreadIsBusy );
|
||||
}
|
||||
if ( level > 2u ) {
|
||||
::printf ( "\tvirtual circuit socket identifier %d\n", this->sock );
|
||||
::printf ( "\tvirtual circuit socket identifier %d\n", (int)this->sock );
|
||||
::printf ( "\tsend thread flush signal:\n" );
|
||||
this->sendThreadFlushEvent.show ( level-2u );
|
||||
::printf ( "\tsend thread:\n" );
|
||||
@@ -1580,7 +1580,7 @@ void tcpiiu::subscriptionRequest (
|
||||
maxBytes = MAX_TCP;
|
||||
}
|
||||
unsigned dataType = subscr.getType ( guard );
|
||||
// data type bounds checked when sunscription created
|
||||
// data type bounds checked when subscription created
|
||||
arrayElementCount maxElem = ( maxBytes - dbr_size[dataType] ) / dbr_value_size[dataType];
|
||||
if ( nElem > maxElem ) {
|
||||
throw cacChannel::msgBodyCacheTooSmall ();
|
||||
@@ -1633,7 +1633,7 @@ void tcpiiu::subscriptionUpdateRequest (
|
||||
throw cacChannel::msgBodyCacheTooSmall ();
|
||||
}
|
||||
comQueSendMsgMinder minder ( this->sendQue, guard );
|
||||
// nElem boounds checked above
|
||||
// nElem bounds checked above
|
||||
this->sendQue.insertRequestHeader (
|
||||
CA_PROTO_READ_NOTIFY, 0u,
|
||||
static_cast < ca_uint16_t > ( dataType ),
|
||||
@@ -1712,7 +1712,7 @@ void tcpiiu :: flush ( epicsGuard < epicsMutex > & guard )
|
||||
this->flushRequest ( guard );
|
||||
// the process thread is not permitted to flush as this
|
||||
// can result in a push / pull deadlock on the TCP pipe.
|
||||
// Instead, the process thread scheduals the flush with the
|
||||
// Instead, the process thread schedules the flush with the
|
||||
// send thread which runs at a higher priority than the
|
||||
// receive thread. The same applies to the UDP thread for
|
||||
// locking hierarchy reasons.
|
||||
@@ -1817,7 +1817,7 @@ void tcpiiu::disconnectAllChannels (
|
||||
}
|
||||
|
||||
while ( nciu * pChan = this->createRespPend.get () ) {
|
||||
// we dont yet know the server's id so we cant
|
||||
// we don't yet know the server's id so we cant
|
||||
// send a channel delete request and will instead
|
||||
// trust that the server can do the proper cleanup
|
||||
// when the circuit disconnects
|
||||
@@ -1848,7 +1848,7 @@ void tcpiiu::disconnectAllChannels (
|
||||
|
||||
while ( nciu * pChan = this->unrespCircuit.get () ) {
|
||||
// if we know that the circuit is unresponsive
|
||||
// then we dont send a channel delete request and
|
||||
// then we don't send a channel delete request and
|
||||
// will instead trust that the server can do the
|
||||
// proper cleanup when the circuit disconnects
|
||||
pChan->disconnectAllIO ( cbGuard, guard );
|
||||
@@ -1883,7 +1883,7 @@ void tcpiiu::unlinkAllChannels (
|
||||
while ( nciu * pChan = this->createRespPend.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
// we dont yet know the server's id so we cant
|
||||
// we don't yet know the server's id so we cant
|
||||
// send a channel delete request and will instead
|
||||
// trust that the server can do the proper cleanup
|
||||
// when the circuit disconnects
|
||||
@@ -1921,7 +1921,7 @@ void tcpiiu::unlinkAllChannels (
|
||||
channelNode::cs_none;
|
||||
pChan->disconnectAllIO ( cbGuard, guard );
|
||||
// if we know that the circuit is unresponsive
|
||||
// then we dont send a channel delete request and
|
||||
// then we don't send a channel delete request and
|
||||
// will instead trust that the server can do the
|
||||
// proper cleanup when the circuit disconnects
|
||||
pChan->serviceShutdownNotify ( cbGuard, guard );
|
||||
@@ -1951,7 +1951,7 @@ void tcpiiu::installChannel (
|
||||
this->channelCountTot++;
|
||||
chan.channelNode::listMember = channelNode::cs_createReqPend;
|
||||
chan.searchReplySetUp ( *this, sidIn, typeIn, countIn, guard );
|
||||
// The tcp send thread runs at apriority below the udp thread
|
||||
// The tcp send thread runs at a priority below the udp thread
|
||||
// so that this will not send small packets
|
||||
this->sendThreadFlushEvent.signal ();
|
||||
}
|
||||
@@ -2060,7 +2060,7 @@ bool tcpiiu::bytesArePendingInOS () const
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
osiSockIoctl_t bytesPending = 0; /* shut up purifys yapping */
|
||||
osiSockIoctl_t bytesPending = 0; /* shut up Purify's yapping */
|
||||
int status = socket_ioctl ( this->sock,
|
||||
FIONREAD, & bytesPending );
|
||||
if ( status >= 0 ) {
|
||||
|
||||
@@ -279,7 +279,7 @@ skip_rest:
|
||||
|
||||
/*
|
||||
* wait for the operation to complete
|
||||
* (outstabnding decrements to zero)
|
||||
* (outstanding decrements to zero)
|
||||
*/
|
||||
while(ntries){
|
||||
ca_pend_event(1.0);
|
||||
|
||||
@@ -202,7 +202,7 @@ udpiiu::udpiiu (
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf("CAC: failed to set mcast ttl %d\n", ttl);
|
||||
errlogPrintf("CAC: failed to set mcast ttl %d\n", (int)ttl);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -266,7 +266,7 @@ udpiiu::udpiiu (
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( this->sock );
|
||||
errlogPrintf ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf );
|
||||
errlogPrintf ( "CAC: getsockname () " ERL_ERROR " was \"%s\"\n", sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
if ( tmpAddr.sa.sa_family != AF_INET) {
|
||||
@@ -428,7 +428,7 @@ void udpRecvThread::run ()
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAC: UDP recv error was \"%s\"\n",
|
||||
errlogPrintf ( "CAC: UDP recv " ERL_ERROR " was \"%s\"\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -536,9 +536,9 @@ void epicsStdCall caRepeaterRegistrationMessage (
|
||||
if ( status < 0 ) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
/*
|
||||
* Different OS return different codes when the repeater isnt running.
|
||||
* Its ok to supress these messages because I print another warning message
|
||||
* if we time out registerring with the repeater.
|
||||
* Different OS return different codes when the repeater isn't running.
|
||||
* Its ok to suppress these messages because I print another warning message
|
||||
* if we time out registering with the repeater.
|
||||
*
|
||||
* Linux returns SOCK_ECONNREFUSED
|
||||
* Windows 2000 returns SOCK_ECONNRESET
|
||||
@@ -673,7 +673,7 @@ bool udpiiu :: searchRespAction (
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
/*
|
||||
* we dont currently know what to do with channel's
|
||||
* we don't currently know what to do with channel's
|
||||
* found to be at non-IP type addresses
|
||||
*/
|
||||
if ( addr.sa.sa_family != AF_INET ) {
|
||||
@@ -762,7 +762,7 @@ bool udpiiu::beaconAction (
|
||||
* always set this field to INADDR_ANY
|
||||
*
|
||||
* clients always assume that if this
|
||||
* field is set to something that isnt INADDR_ANY
|
||||
* field is set to something that isn't INADDR_ANY
|
||||
* then it is the overriding IP address of the server.
|
||||
*/
|
||||
ina.sin_family = AF_INET;
|
||||
@@ -772,7 +772,7 @@ bool udpiiu::beaconAction (
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* old servers dont supply this and the
|
||||
* old servers don't supply this and the
|
||||
* default port must be assumed
|
||||
*/
|
||||
ina.sin_port = htons ( this->serverPort );
|
||||
@@ -874,7 +874,7 @@ void udpiiu::postMsg (
|
||||
size = pCurMsg->m_postsize + sizeof ( *pCurMsg );
|
||||
|
||||
/*
|
||||
* dont allow msg body extending beyond frame boundary
|
||||
* don't allow msg body extending beyond frame boundary
|
||||
*/
|
||||
if ( size > blockSize ) {
|
||||
char buf[64];
|
||||
@@ -1044,7 +1044,7 @@ void udpiiu :: SearchRespCallback :: notify (
|
||||
const osiSockAddr & addr, const epicsTime & currentTime )
|
||||
{
|
||||
/*
|
||||
* we dont currently know what to do with channel's
|
||||
* we don't currently know what to do with channel's
|
||||
* found to be at non-IP type addresses
|
||||
*/
|
||||
if ( addr.sa.sa_family != AF_INET ) {
|
||||
@@ -1119,7 +1119,7 @@ bool udpiiu :: datagramFlush (
|
||||
{
|
||||
guard.assertIdenticalMutex ( cacMutex );
|
||||
|
||||
// dont send the version header by itself
|
||||
// don't send the version header by itself
|
||||
if ( this->nBytesInXmitBuf <= sizeof ( caHdr ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
* here and just generates unnecessary compiler warnings. */
|
||||
#define REENTRINC
|
||||
|
||||
/* Clang-12 and later generates many warnings about compound token */
|
||||
#ifdef __has_warning
|
||||
# if __has_warning("-Wcompound-token-split-by-macro")
|
||||
# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "EXTERN.h"
|
||||
#include "perl.h"
|
||||
#include "XSUB.h"
|
||||
@@ -201,6 +208,8 @@ SV * newSVdbr(struct event_handler_args *peha) {
|
||||
if (is_primitive) {
|
||||
if (value_type == DBR_CHAR) {
|
||||
/* Long string => Perl scalar */
|
||||
if (peha->count == 0)
|
||||
return newSVpvn(peha->dbr, 0);
|
||||
((char *)peha->dbr) [peha->count - 1] = 0;
|
||||
return newSVpv(peha->dbr, 0);
|
||||
}
|
||||
@@ -271,8 +280,12 @@ SV * newSVdbr(struct event_handler_args *peha) {
|
||||
char *str = dbr_value_ptr(peha->dbr, peha->type);
|
||||
|
||||
/* Long string => Perl scalar */
|
||||
str[peha->count - 1] = 0;
|
||||
val = newSVpv(str, 0);
|
||||
if (peha->count == 0)
|
||||
val = newSVpvn(str, 0);
|
||||
else {
|
||||
str[peha->count - 1] = 0;
|
||||
val = newSVpv(str, 0);
|
||||
}
|
||||
} else if (peha->count == 1) {
|
||||
/* Single value => Perl scalar */
|
||||
val = newSVdbf(value_type,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env perl
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2005 UChicago Argonne LLC, as Operator of Argonne
|
||||
# Copyright (c) 2022 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# SPDX-License-Identifier: EPICS
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
@@ -14,26 +14,24 @@
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
use 5.10.1;
|
||||
use strict;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib ("$Bin/../../lib/perl");
|
||||
use FindBin qw($RealBin);
|
||||
use lib ("$RealBin/../../lib/perl");
|
||||
|
||||
use Getopt::Std;
|
||||
use EPICS::Path;
|
||||
use Cwd 'abs_path';
|
||||
use CA;
|
||||
|
||||
######### Globals ##########
|
||||
|
||||
our ($opt_h, $opt_f, $opt_r);
|
||||
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} || "$Bin/../../dbd/softIoc.dbd";
|
||||
our $opt_w = 1;
|
||||
our ($opt_h, $opt_f, $opt_l, $opt_r, $opt_D);
|
||||
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} // abs_path("$RealBin/../../dbd/softIoc.dbd");
|
||||
our $opt_w = 2;
|
||||
our $opt_n = 10;
|
||||
|
||||
my %record = (); # Empty hash to put dbd data in
|
||||
my $iIdx = 0; # Array indexes for interest, data type and base
|
||||
my $tIdx = 1;
|
||||
my $bIdx = 2;
|
||||
my %device = (); # Empty hash to record which rec types have device support
|
||||
|
||||
# EPICS field types
|
||||
my %fieldType = (
|
||||
@@ -58,13 +56,14 @@ my %fieldType = (
|
||||
);
|
||||
|
||||
# globals for sub caget
|
||||
my %connected;
|
||||
my $unconnected_count;
|
||||
my %callback_data;
|
||||
my %timed_out;
|
||||
my $callback_incomplete;
|
||||
|
||||
######### Main program ############
|
||||
|
||||
HELP_MESSAGE() unless getopts('hd:f:rw:');
|
||||
HELP_MESSAGE() unless getopts('hDd:f:l:n:rw:');
|
||||
HELP_MESSAGE() if $opt_h;
|
||||
|
||||
die "File $opt_d not found. (\"capr.pl -h\" gives help)\n"
|
||||
@@ -76,7 +75,7 @@ print "Using $opt_d\n\n";
|
||||
# Print a list of record types
|
||||
if ($opt_r) {
|
||||
print ("Record types found:\n");
|
||||
printList(0);
|
||||
printList($opt_l);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -100,7 +99,7 @@ if (@ARGV) {
|
||||
} else {
|
||||
# Drop any ".FIELD" part
|
||||
s/\. \w+ $//x;
|
||||
printRecord($_, 0);
|
||||
printRecord($_, $opt_l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,9 +129,11 @@ sub parseDbd {
|
||||
my $thisRecord;
|
||||
my $thisField;
|
||||
my $thisType;
|
||||
my $thisSize = 0;
|
||||
my $field = {};
|
||||
my $interest = 0;
|
||||
my $thisBase = 'DECIMAL';
|
||||
my $special = '';
|
||||
|
||||
while (@dbd) {
|
||||
$_ = shift @dbd;
|
||||
@@ -155,29 +156,40 @@ sub parseDbd {
|
||||
unless $level == 2 && $isAfield;
|
||||
$interest = $1;
|
||||
}
|
||||
elsif ( m/size \s* \( \s* ([0-9]+) \s* \)/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 2 && $isAfield;
|
||||
$thisSize = $1;
|
||||
}
|
||||
elsif ( m/special \s* \( \s* (\w+) \s* \)/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 2 && $isAfield;
|
||||
$special = $1;
|
||||
}
|
||||
elsif ( m/base \s* \( \s* (\w+) \s* \)/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 2 && $isAfield;
|
||||
$thisBase = $1;
|
||||
}
|
||||
elsif ( m/device \s* \( (\w+) \s* ,/x ) {
|
||||
die "File format error at line $i of file\n $opt_d\n"
|
||||
unless $level == 0;
|
||||
$device{$1}++;
|
||||
}
|
||||
if ( m/\{/ ) {
|
||||
$level++;
|
||||
}
|
||||
if ( m/\}/ ) {
|
||||
if ($level == 2 && $isAfield) {
|
||||
my $params = [];
|
||||
$params->[$iIdx] = $interest;
|
||||
$params->[$tIdx] = $thisType;
|
||||
$params->[$bIdx] = $thisBase;
|
||||
my $params = {};
|
||||
$params->{interest} = $interest;
|
||||
$params->{dbfType} = $thisType;
|
||||
$params->{base} = $thisBase;
|
||||
$params->{special} = $special;
|
||||
$params->{size} = $thisSize;
|
||||
$field->{$thisField} = $params;
|
||||
|
||||
# Reset default values
|
||||
$isAfield = 0;
|
||||
$interest = 0; # reset default
|
||||
$thisBase = 'DECIMAL'; # reset default
|
||||
$interest = 0;
|
||||
$thisBase = 'DECIMAL';
|
||||
$special = '';
|
||||
$thisSize = 0;
|
||||
}
|
||||
elsif ($level == 1 && $isArecord) {
|
||||
$isArecord = 0;
|
||||
@@ -207,21 +219,23 @@ sub getRecType {
|
||||
|
||||
# Given the record type and field, returns the interest level, data type
|
||||
# and number base for the field
|
||||
# Usage: ($dataType, $interest, $base) = getFieldParams($recType, $field);
|
||||
# Usage: ($dataType, $interest, $base, $special, $size) = getFieldParams($recType, $field);
|
||||
sub getFieldParams {
|
||||
my ($recType, $field) = @_;
|
||||
|
||||
my $params = $record{$recType}{$field} or
|
||||
die "Can't find params for $recType.$field";
|
||||
exists($fieldType{$params->[$tIdx]}) ||
|
||||
exists($fieldType{$params->{dbfType}}) ||
|
||||
die "Field data type $field for $recType not found in dbd file --";
|
||||
exists($params->[$iIdx]) ||
|
||||
exists($params->{interest}) ||
|
||||
die "Interest level for $field in $recType not found in dbd file --";
|
||||
|
||||
my $fType = $fieldType{$params->[$tIdx]};
|
||||
my $fInterest = $params->[$iIdx];
|
||||
my $fBase = $params->[$bIdx];
|
||||
return ($fType, $fInterest, $fBase);
|
||||
my $fType = $fieldType{$params->{dbfType}};
|
||||
my $fInterest = $params->{interest};
|
||||
my $fBase = $params->{base};
|
||||
my $fSpecial = $params->{special};
|
||||
my $fSize = $params->{size};
|
||||
return ($fType, $fInterest, $fBase, $fSpecial, $fSize);
|
||||
}
|
||||
|
||||
# Prints field name and data for given field. Formats output so
|
||||
@@ -233,27 +247,37 @@ sub printField {
|
||||
my $screenWidth = 80;
|
||||
my ($outStr, $wide);
|
||||
|
||||
my $field = "$fieldName:";
|
||||
|
||||
if ( $dataType eq 'DBF_STRING' ) {
|
||||
$outStr = sprintf('%-5s %s', $field, $fieldData);
|
||||
} elsif ( $base eq 'HEX' ) {
|
||||
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
|
||||
$outStr = sprintf('%-5s 0x%x', $field, $val);
|
||||
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
|
||||
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
|
||||
} elsif ( $dataType eq 'DBF_CHAR' ) {
|
||||
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
|
||||
} else {
|
||||
# DBF_INT64, DBF_LONG, DBF_SHORT,
|
||||
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
|
||||
$outStr = sprintf('%-5s %d', $field, $fieldData);
|
||||
if (ref $fieldData eq 'ARRAY') {
|
||||
my $elems = scalar @{$fieldData};
|
||||
my $field = "$fieldName\[$elems\]:";
|
||||
my $count = $elems > $opt_n ? $opt_n : $elems;
|
||||
my @show = @{$fieldData}[0 .. $count - 1];
|
||||
$outStr = sprintf('%-5s %s', $field, join(', ', @show));
|
||||
$outStr .= ", ..." if $elems > $count;
|
||||
}
|
||||
else {
|
||||
my $field = "$fieldName:";
|
||||
if ( $dataType eq 'DBF_STRING' ) {
|
||||
$outStr = sprintf('%-5s %s', $field, $fieldData);
|
||||
} elsif ( $base eq 'HEX' ) {
|
||||
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
|
||||
$outStr = sprintf('%-5s 0x%x', $field, $val);
|
||||
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
|
||||
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
|
||||
} elsif ( $dataType eq 'DBF_UCHAR' ) {
|
||||
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
|
||||
} else {
|
||||
# DBF_INT64, DBF_LONG, DBF_SHORT,
|
||||
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
|
||||
$outStr = sprintf('%-5s %d', $field, $fieldData);
|
||||
}
|
||||
}
|
||||
|
||||
my $len = length($outStr);
|
||||
if ($len <= 20) { $wide = 20; }
|
||||
elsif ( $len <= 40 ) { $wide = 40; }
|
||||
elsif ( $len <= 60 ) { $wide = 60; }
|
||||
if ($len < 20) { $wide = 20; }
|
||||
elsif ( $len < 40 ) { $wide = 40; }
|
||||
elsif ( $len < 60 ) { $wide = 60; }
|
||||
else { $wide = 80;}
|
||||
|
||||
my $pad = $wide - $len;
|
||||
@@ -269,49 +293,64 @@ sub printField {
|
||||
return $col;
|
||||
}
|
||||
|
||||
# Query for a list of fields simultaneously.
|
||||
# The results are filled in the the %callback_data global hash
|
||||
# and the result of the operation is the number of read pvs
|
||||
# Query the native values of a list of PVs simultaneously.
|
||||
# The data is returned in the the %callback_data global hash.
|
||||
# The return value is the number of read pvs
|
||||
#
|
||||
# NOTE: Not re-entrant because results are written to global hash
|
||||
# %callback_data
|
||||
#
|
||||
# Usage: $fields_read = caget( @pvlist )
|
||||
sub caget {
|
||||
my @chans = map { CA->new($_); } @_;
|
||||
|
||||
#clear any previous results;
|
||||
%connected = ();
|
||||
$unconnected_count = scalar @_;
|
||||
%callback_data = ();
|
||||
%timed_out = ();
|
||||
$callback_incomplete = 0;
|
||||
|
||||
eval { CA->pend_io($opt_w); };
|
||||
if ($@) {
|
||||
if ($@ =~ m/^ECA_TIMEOUT/) {
|
||||
my $name = $chans[0]->name;
|
||||
my $err = (@chans > 1) ? 'some fields' : "'$name'";
|
||||
print "Channel connect timed out: $err not found.\n";
|
||||
foreach my $chan (@chans) {
|
||||
$timed_out{$chan->name} = !$chan->is_connected;
|
||||
}
|
||||
@chans = grep { $_->is_connected } @chans;
|
||||
} else {
|
||||
die $@;
|
||||
}
|
||||
}
|
||||
my @chans = map {
|
||||
print " Creating channel for $_\n" if $opt_D;
|
||||
CA->new($_, \&canew_callback);
|
||||
} @_;
|
||||
my $channel_count = scalar @chans;
|
||||
return 0 unless $channel_count gt 0;
|
||||
|
||||
map {
|
||||
$_->get_callback(\&caget_callback, $_->field_type);
|
||||
} @chans;
|
||||
print " $channel_count channels created.\n" if $opt_D;
|
||||
|
||||
my $fields_read = $callback_incomplete = @chans;
|
||||
CA->pend_event(0.1)
|
||||
while $callback_incomplete;
|
||||
return $fields_read;
|
||||
my $elapsed = 0;
|
||||
do {
|
||||
print " Waiting for $unconnected_count channels to connect\n"
|
||||
if $unconnected_count && $opt_D;
|
||||
print " Waiting for data from $callback_incomplete channels\n"
|
||||
if $callback_incomplete && $opt_D;
|
||||
CA->pend_event(0.1);
|
||||
$elapsed += 0.1;
|
||||
} until (($elapsed > $opt_w) or
|
||||
(scalar %connected && $callback_incomplete == 0));
|
||||
my $data_count = scalar keys %callback_data;
|
||||
printf " Got data from %d of %d channels\n", $data_count, $channel_count
|
||||
if $opt_D;
|
||||
return $data_count;
|
||||
}
|
||||
|
||||
sub canew_callback {
|
||||
my ($chan, $up) = @_;
|
||||
return unless $up;
|
||||
$connected{$chan->name} = $chan;
|
||||
$unconnected_count--;
|
||||
my $ftype = $chan->field_type;
|
||||
my $count = $chan->element_count;
|
||||
$ftype = 'DBR_LONG' if $ftype eq 'DBR_CHAR' && $count == 1;
|
||||
print " Getting ${\$chan->name} as $ftype\n" if $opt_D;
|
||||
# We have to fetch all elements so we can show how many there are
|
||||
$chan->get_callback(\&caget_callback, $ftype);
|
||||
$callback_incomplete++;
|
||||
}
|
||||
|
||||
sub caget_callback {
|
||||
my ($chan, $status, $data) = @_;
|
||||
die $status if $status;
|
||||
print " Got ${\$chan->name} = '$data'\n" if $opt_D;
|
||||
$callback_data{$chan->name} = $data;
|
||||
$callback_incomplete--;
|
||||
}
|
||||
@@ -333,69 +372,83 @@ sub printRecord {
|
||||
my @ftypes = (); #types, from parser
|
||||
my @bases = (); #bases, from parser
|
||||
foreach my $field (sort keys %{$record{$recType}}) {
|
||||
# Skip DTYP field if this rec type doesn't have device support defined
|
||||
next if $field eq 'DTYP' && !exists($device{$recType});
|
||||
|
||||
my ($fType, $fInterest, $base) = getFieldParams($recType, $field);
|
||||
# FIXME: Support waveform.VAL fields etc.
|
||||
unless( $fType eq 'DBF_NOACCESS' ) {
|
||||
if ($interest >= $fInterest ) {
|
||||
my $fToGet = "$name.$field";
|
||||
push @fields_pr, $field;
|
||||
push @readlist, $fToGet;
|
||||
push @ftypes, $fType;
|
||||
push @bases, $base;
|
||||
}
|
||||
my ($fType, $fInterest, $base, $special, $size) =
|
||||
getFieldParams($recType, $field);
|
||||
next if $fInterest > $interest;
|
||||
my $fToGet = "$name.$field";
|
||||
if ($fType eq 'DBF_NOACCESS') {
|
||||
next unless $special eq 'SPC_DBADDR';
|
||||
$fType = 'DBF_STRING';
|
||||
}
|
||||
elsif ($fType eq 'DBF_STRING' && $size >= 40) {
|
||||
$fToGet .= '$';
|
||||
}
|
||||
push @fields_pr, $field;
|
||||
push @readlist, $fToGet;
|
||||
push @ftypes, $fType;
|
||||
push @bases, $base;
|
||||
}
|
||||
my $fields_read = caget( @readlist );
|
||||
|
||||
my @missing;
|
||||
|
||||
# print while iterating over lists gathered
|
||||
my $col = 0;
|
||||
for (my $i=0; $i < scalar @readlist; $i++) {
|
||||
my $field = $fields_pr[$i];
|
||||
my $fToGet = $readlist[$i];
|
||||
my ($fType, $data, $base);
|
||||
next if $timed_out{$fToGet};
|
||||
push @missing, $field unless exists $callback_data{$fToGet};
|
||||
next unless exists $callback_data{$fToGet};
|
||||
$fType = $ftypes[$i];
|
||||
$base = $bases[$i];
|
||||
$data = $callback_data{$fToGet};
|
||||
$col = printField($field, $data, $fType, $base, $col);
|
||||
}
|
||||
print("\n"); # Final newline
|
||||
|
||||
printf "\nUnreadable fields: %s\n", join(', ', @missing) if @missing && $opt_D;
|
||||
}
|
||||
|
||||
# Prints list of record types found in dbd file. If level > 0
|
||||
# then the fields of that record type, their interest levels and types are
|
||||
# also printed.
|
||||
# Diagnostic routine, usage: void printList(level);
|
||||
# then uses printRecordList to display all fields in each record type.
|
||||
sub printList {
|
||||
my $level = shift;
|
||||
|
||||
foreach my $rkey (sort keys(%record)) {
|
||||
print(" $rkey\n");
|
||||
if ($level > 0) {
|
||||
foreach my $fkey (keys %{$record{$rkey}}) {
|
||||
print("\tField $fkey - interest $record{$rkey}{$fkey}[$iIdx] ");
|
||||
print("- type $record{$rkey}{$fkey}[$tIdx] ");
|
||||
print("- base $record{$rkey}{$fkey}[$bIdx]\n");
|
||||
}
|
||||
printRecordList($rkey);
|
||||
}
|
||||
else {
|
||||
print(" $rkey\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Prints list of fields with interest levels for given record type
|
||||
# Diagnostic routine, usage: void printRecordList("recordType");
|
||||
# Prints list of fields and metadata for given record type
|
||||
sub printRecordList {
|
||||
my $type = shift;
|
||||
|
||||
if (exists($record{$type}) ) {
|
||||
print("Record type - $type\n");
|
||||
foreach my $fkey (sort keys %{$record{$type}}) {
|
||||
printf('%-8s', $fkey);
|
||||
printf(" interest = $record{$type}{$fkey}[$iIdx]");
|
||||
printf(" type = %-12s ",$record{$type}{$fkey}[$tIdx]);
|
||||
print (" base = $record{$type}{$fkey}[$bIdx]\n");
|
||||
my $param = $record{$type}{$fkey};
|
||||
my $dbfType = $param->{dbfType};
|
||||
printf " %-8s", $fkey;
|
||||
printf " interest = %d", $param->{interest};
|
||||
printf " type = %-12s", $dbfType;
|
||||
if ($dbfType eq 'DBF_STRING') {
|
||||
printf " size = %s\n", $param->{size};
|
||||
}
|
||||
elsif ($dbfType =~ m/DBF_U?(CHAR|SHORT|INT|LONG|INT64)/) {
|
||||
printf " base = %s\n", $param->{base};
|
||||
}
|
||||
elsif ($dbfType eq 'DBF_NOACCESS') {
|
||||
printf " special = %s\n", $param->{special};
|
||||
}
|
||||
else {
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -411,16 +464,20 @@ sub HELP_MESSAGE {
|
||||
" capr.pl [options] <record name> [<interest>]\n",
|
||||
"\n",
|
||||
" -h Print this help message.\n",
|
||||
" -D Print debug messages.\n",
|
||||
"Channel Access options:\n",
|
||||
" -w <sec>: Wait time, specifies CA timeout, default is $opt_w second\n",
|
||||
"Database Definitions:\n",
|
||||
" -d <file.dbd>: The file containing record type definitions.\n",
|
||||
" This can be set using the EPICS_CAPR_DBD_FILE environment variable.\n",
|
||||
" Default: ", AbsPath($opt_d), "\n",
|
||||
" Default: ", abs_path($opt_d), "\n",
|
||||
"Output Options:\n",
|
||||
" -r Lists all record types in the selected dbd file.\n",
|
||||
" -f <record type>: Lists all fields with their interest level, data type\n",
|
||||
" and number base for the given record_type.\n",
|
||||
" -f <record type>: Lists all fields with interest level, data type\n",
|
||||
" and other information for the given record_type.\n",
|
||||
" -l <interest>: interest level\n",
|
||||
" -n <elems>: Maximum number of array elements to display\n",
|
||||
" Default: $opt_n\n",
|
||||
"\n",
|
||||
"Base version: ", CA->version, "\n";
|
||||
exit 1;
|
||||
|
||||
@@ -256,7 +256,7 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
|
||||
for (n = 0; n < nPvs; n++) {
|
||||
|
||||
switch (format) {
|
||||
case plain: /* Emulate old caget behaviour */
|
||||
case plain: /* Emulate old caget behavior */
|
||||
if (pvs[n].nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
|
||||
else printf("%s", pvs[n].name);
|
||||
printf("%c", fieldSeparator);
|
||||
|
||||
@@ -192,7 +192,7 @@ int caget (pv *pvs, int nPvs, OutputT format,
|
||||
for (n = 0; n < nPvs; n++) {
|
||||
|
||||
switch (format) {
|
||||
case plain: /* Emulate old caput behaviour */
|
||||
case plain: /* Emulate old caput behavior */
|
||||
if (pvs[n].reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
|
||||
else printf("%s", pvs[n].name);
|
||||
printf("%c", fieldSeparator);
|
||||
|
||||
@@ -241,7 +241,7 @@ void asCaStart(void)
|
||||
epicsThreadGetStackSize(epicsThreadStackBig),
|
||||
(EPICSTHREADFUNC)asCaTask,0);
|
||||
if(threadid==0) {
|
||||
errMessage(0,"asCaStart: taskSpawn Failure\n");
|
||||
errMessage(0,"asCaStart: taskSpawn Failure");
|
||||
}
|
||||
}
|
||||
epicsMutexMustLock(asCaTaskLock);
|
||||
|
||||
@@ -11,5 +11,6 @@
|
||||
|
||||
# This is a Makefile fragment, see src/ioc/Makefile.
|
||||
|
||||
$(patsubst %,$(COMMON_DIR)/%,$(BPT_DBD)) : \
|
||||
$(COMMON_DIR)/bpt%.dbd : $(MAKEBPT)
|
||||
$(addprefix $(COMMON_DIR)/,$(BPT_DBD)) : $(COMMON_DIR)/bpt%.dbd : \
|
||||
$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)
|
||||
# Don't try to use $(MAKEBPT) above
|
||||
|
||||
@@ -85,7 +85,7 @@ static epicsEventId startStopEvent;
|
||||
static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = {
|
||||
"cbLow", "cbMedium", "cbHigh"
|
||||
};
|
||||
#define FULL_MSG(name) "callbackRequest: " name " ring buffer full\n"
|
||||
#define FULL_MSG(name) "callbackRequest: " ERL_ERROR " " name " ring buffer full\n"
|
||||
static char *fullMessage[NUM_CALLBACK_PRIORITIES] = {
|
||||
FULL_MSG("cbLow"), FULL_MSG("cbMedium"), FULL_MSG("cbHigh")
|
||||
};
|
||||
@@ -326,17 +326,17 @@ int callbackRequest(epicsCallback *pcallback)
|
||||
cbQueueSet *mySet;
|
||||
|
||||
if (!pcallback) {
|
||||
epicsInterruptContextMessage("callbackRequest: pcallback was NULL\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback was NULL\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
priority = pcallback->priority;
|
||||
if (priority < 0 || priority >= NUM_CALLBACK_PRIORITIES) {
|
||||
epicsInterruptContextMessage("callbackRequest: Bad priority\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Bad priority\n");
|
||||
return S_db_badChoice;
|
||||
}
|
||||
mySet = &callbackQueue[priority];
|
||||
if (!mySet->queue) {
|
||||
epicsInterruptContextMessage("callbackRequest: Callbacks not initialized\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Callbacks not initialized\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
if (mySet->queueOverflow) return S_db_bufFull;
|
||||
|
||||
@@ -529,7 +529,7 @@ long dbProcess(dbCommon *precord)
|
||||
}
|
||||
}
|
||||
|
||||
/* If already active dont process */
|
||||
/* If already active don't process */
|
||||
if (precord->pact) {
|
||||
unsigned short monitor_mask;
|
||||
|
||||
@@ -931,7 +931,7 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
no_elements = capacity = pfl->no_elements;
|
||||
}
|
||||
|
||||
/* Update field info from record (if neccessary);
|
||||
/* Update field info from record (if necessary);
|
||||
* may modify paddr->pfield.
|
||||
*/
|
||||
if (!dbfl_has_copy(pfl) &&
|
||||
@@ -1104,9 +1104,9 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
if (link_info.ltype == PV_LINK &&
|
||||
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
|
||||
chan = dbChannelCreate(link_info.target);
|
||||
if (chan && dbChannelOpen(chan) != 0) {
|
||||
errlogPrintf("ERROR: dbPutFieldLink %s.%s=%s: dbChannelOpen() failed\n",
|
||||
precord->name, pfldDes->name, link_info.target);
|
||||
if (chan && (status = dbChannelOpen(chan)) != 0) {
|
||||
errlogPrintf(ERL_ERROR ": dbPutFieldLink %s.%s=%s: dbChannelOpen() failed w/ 0x%lx\n",
|
||||
precord->name, pfldDes->name, link_info.target, status);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@@ -1325,7 +1325,6 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
void *pfieldsave = paddr->pfield;
|
||||
rset *prset = dbGetRset(paddr);
|
||||
long status = 0;
|
||||
long offset;
|
||||
dbFldDes *pfldDes;
|
||||
int isValueField;
|
||||
|
||||
@@ -1349,20 +1348,25 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
if (status) return status;
|
||||
}
|
||||
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
if (nRequest>1 || paddr->pfldDes->special == SPC_DBADDR) {
|
||||
long offset = 0;
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
}
|
||||
if (no_elements < nRequest)
|
||||
nRequest = no_elements;
|
||||
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
|
||||
nRequest, no_elements, offset);
|
||||
/* update array info */
|
||||
if (!status && prset->put_array_info)
|
||||
if (!status && paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->put_array_info) {
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
}
|
||||
} else {
|
||||
if (nRequest < 1) {
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
|
||||
@@ -73,7 +73,7 @@ DBCORE_API extern int dbAccessDebugPUTF;
|
||||
* options has a bit set for each option that was accepted
|
||||
* number_elements is actual number of elements obtained
|
||||
*
|
||||
* The individual items can be refered to by the expressions::
|
||||
* The individual items can be referred to by the expressions::
|
||||
*
|
||||
* buffer.status
|
||||
* buffer.severity
|
||||
|
||||
@@ -97,7 +97,7 @@ static long FIND_CONT_NODE(
|
||||
* processing in that lockset to this task. The separate task is
|
||||
* used so that locksets that do not have breakpoints are isolated
|
||||
* from locksets that do. This allows the processing of other
|
||||
* locksets to continue uninterupted, even if they exist on the same
|
||||
* locksets to continue uninterrupted, even if they exist on the same
|
||||
* scan list as a lockset containing a breakpoint.
|
||||
*
|
||||
* An entrypoint is the first record that gets processed in a lockset.
|
||||
@@ -250,7 +250,7 @@ static long FIND_CONT_NODE(
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the breakpoint stack
|
||||
* Initialize the breakpoint stack
|
||||
*/
|
||||
void dbBkptInit(void)
|
||||
{
|
||||
@@ -331,6 +331,7 @@ long dbb(const char *record_name)
|
||||
if (pnode->ex_sem == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
free(pnode);
|
||||
epicsMutexUnlock(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
|
||||
@@ -196,6 +196,73 @@ static void caLinkDec(caLink *pca)
|
||||
if (callback) callback(userPvt);
|
||||
}
|
||||
|
||||
struct waitPvt {
|
||||
caLink *pca;
|
||||
epicsEventId evt;
|
||||
};
|
||||
enum testEvent {
|
||||
testEventConnect,
|
||||
testEventCount,
|
||||
};
|
||||
|
||||
static
|
||||
void testdbCaWaitForEventCB(void *raw)
|
||||
{
|
||||
struct waitPvt *pvt = raw;
|
||||
|
||||
epicsMutexMustLock(pvt->pca->lock);
|
||||
epicsEventMustTrigger(pvt->evt);
|
||||
epicsMutexUnlock(pvt->pca->lock);
|
||||
}
|
||||
|
||||
static
|
||||
void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event)
|
||||
{
|
||||
caLink *pca;
|
||||
epicsEventId evt = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
dbScanLock(plink->precord);
|
||||
|
||||
assert(plink->type==CA_LINK);
|
||||
pca = (caLink *)plink->value.pv_link.pvt;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
assert(!pca->monitor && !pca->connect && !pca->userPvt);
|
||||
|
||||
while(!pca->isConnected || (event==testEventCount && pca->nUpdate < cnt)) {
|
||||
struct waitPvt pvt = {pca, evt};
|
||||
pca->connect = &testdbCaWaitForEventCB;
|
||||
pca->monitor = &testdbCaWaitForEventCB;
|
||||
pca->userPvt = &pvt;
|
||||
|
||||
epicsMutexUnlock(pca->lock);
|
||||
dbScanUnlock(plink->precord);
|
||||
|
||||
epicsEventMustWait(evt);
|
||||
|
||||
dbScanLock(plink->precord);
|
||||
epicsMutexMustLock(pca->lock);
|
||||
|
||||
pca->connect = NULL;
|
||||
pca->monitor = NULL;
|
||||
pca->userPvt = NULL;
|
||||
}
|
||||
|
||||
epicsEventDestroy(evt);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
dbScanUnlock(plink->precord);
|
||||
}
|
||||
|
||||
void testdbCaWaitForConnect(DBLINK *plink)
|
||||
{
|
||||
testdbCaWaitForEvent(plink, 0, testEventConnect);
|
||||
}
|
||||
|
||||
void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt)
|
||||
{
|
||||
testdbCaWaitForEvent(plink, cnt, testEventCount);
|
||||
}
|
||||
|
||||
/* Block until worker thread has processed all previously queued actions.
|
||||
* Does not prevent additional actions from being queued.
|
||||
*/
|
||||
@@ -232,22 +299,6 @@ void dbCaSync(void)
|
||||
epicsEventDestroy(wake);
|
||||
}
|
||||
|
||||
DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink)
|
||||
{
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
unsigned long ret;
|
||||
|
||||
if (!pca) return (unsigned long)-1;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
|
||||
ret = pca->nUpdate;
|
||||
|
||||
epicsMutexUnlock(pca->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dbCaCallbackProcess(void *userPvt)
|
||||
{
|
||||
struct link *plink = (struct link *)userPvt;
|
||||
@@ -785,6 +836,8 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
caLink *pca;
|
||||
short link_action = 0;
|
||||
struct link *plink;
|
||||
dbCaCallback connect = 0;
|
||||
void *userPvt = 0;
|
||||
|
||||
pca = ca_puser(arg.chid);
|
||||
assert(pca);
|
||||
@@ -851,11 +904,16 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
}
|
||||
pca->gotAttributes = 0;
|
||||
if (pca->dbrType != DBR_STRING) {
|
||||
/* will run connect() callback later */
|
||||
link_action |= CA_GET_ATTRIBUTES;
|
||||
} else {
|
||||
connect = pca->connect;
|
||||
userPvt = pca->userPvt;
|
||||
}
|
||||
done:
|
||||
if (link_action) addAction(pca, link_action);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
if (connect) connect(userPvt);
|
||||
}
|
||||
|
||||
static void eventCallback(struct event_handler_args arg)
|
||||
@@ -881,10 +939,10 @@ static void eventCallback(struct event_handler_args arg)
|
||||
if (precord) {
|
||||
if (arg.status != ECA_NORDACCESS &&
|
||||
arg.status != ECA_GETFAIL)
|
||||
errlogPrintf("dbCa: eventCallback record %s error %s\n",
|
||||
errlogPrintf("dbCa: eventCallback record %s " ERL_ERROR " %s\n",
|
||||
precord->name, ca_message(arg.status));
|
||||
} else {
|
||||
errlogPrintf("dbCa: eventCallback error %s\n",
|
||||
errlogPrintf("dbCa: eventCallback " ERL_ERROR " %s\n",
|
||||
ca_message(arg.status));
|
||||
}
|
||||
goto done;
|
||||
@@ -1029,10 +1087,10 @@ static void getAttribEventCallback(struct event_handler_args arg)
|
||||
if (arg.status != ECA_NORMAL) {
|
||||
dbCommon *precord = plink->precord;
|
||||
if (precord) {
|
||||
errlogPrintf("dbCa: getAttribEventCallback record %s error %s\n",
|
||||
errlogPrintf("dbCa: getAttribEventCallback record %s " ERL_ERROR " %s\n",
|
||||
precord->name, ca_message(arg.status));
|
||||
} else {
|
||||
errlogPrintf("dbCa: getAttribEventCallback error %s\n",
|
||||
errlogPrintf("dbCa: getAttribEventCallback " ERL_ERROR " %s\n",
|
||||
ca_message(arg.status));
|
||||
}
|
||||
epicsMutexUnlock(pca->lock);
|
||||
@@ -1058,6 +1116,7 @@ static void getAttribEventCallback(struct event_handler_args arg)
|
||||
|
||||
static void dbCaTask(void *arg)
|
||||
{
|
||||
epicsEventId requestSync = NULL;
|
||||
taskwdInsert(0, NULL, NULL);
|
||||
SEVCHK(ca_context_create(ca_enable_preemptive_callback),
|
||||
"dbCaTask calling ca_context_create");
|
||||
@@ -1078,13 +1137,20 @@ static void dbCaTask(void *arg)
|
||||
|
||||
epicsMutexMustLock(workListLock);
|
||||
if (!(pca = (caLink *)ellGet(&workList))){ /* Take off list head */
|
||||
if(requestSync) {
|
||||
/* dbCaSync() requires workListLock to be held here */
|
||||
epicsEventMustTrigger(requestSync);
|
||||
requestSync = NULL;
|
||||
}
|
||||
epicsMutexUnlock(workListLock);
|
||||
if (dbCaCtl == ctlExit) goto shutdown;
|
||||
break; /* workList is empty */
|
||||
}
|
||||
link_action = pca->link_action;
|
||||
if (link_action&CA_SYNC)
|
||||
epicsEventMustTrigger((epicsEventId)pca->userPvt); /* dbCaSync() requires workListLock to be held here */
|
||||
if (link_action&CA_SYNC) {
|
||||
assert(!requestSync);
|
||||
requestSync = pca->userPvt;
|
||||
}
|
||||
pca->link_action = 0;
|
||||
if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
|
||||
epicsMutexUnlock(workListLock); /* Give back immediately */
|
||||
|
||||
@@ -48,8 +48,12 @@ DBCORE_API long dbCaPutLink(struct link *plink,short dbrType,
|
||||
extern struct ca_client_context * dbCaClientContext;
|
||||
|
||||
#ifdef EPICS_DBCA_PRIVATE_API
|
||||
/* Wait CA link work queue to become empty. eg. after from dbPut() to OUT */
|
||||
DBCORE_API void dbCaSync(void);
|
||||
DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink);
|
||||
/* Wait for the data update counter to reach the specified value. */
|
||||
DBCORE_API void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt);
|
||||
/* Wait for CA link to become connected */
|
||||
DBCORE_API void testdbCaWaitForConnect(DBLINK *plink);
|
||||
#endif
|
||||
|
||||
/* These macros are for backwards compatibility */
|
||||
|
||||
@@ -9,14 +9,22 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Andrew Johnson <anj@aps.anl.gov>
|
||||
* Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#ifndef INC_dbChannel_H
|
||||
#define INC_dbChannel_H
|
||||
|
||||
/** \file dbChannel.h
|
||||
*
|
||||
* \author Andrew Johnson (ANL)
|
||||
* \author Ralph Lange (BESSY)
|
||||
*
|
||||
* \brief The dbChannel API gives access to record fields.
|
||||
*
|
||||
* The dbChannel API is used internally by the IOC and by link types, device
|
||||
* support and IOC servers (RSRV and QSRV) to access record fields, either
|
||||
* directly or through one or more server-side filters as specified in the
|
||||
* channel name used when creating the channel.
|
||||
*/
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "dbAddr.h"
|
||||
#include "ellLib.h"
|
||||
@@ -30,200 +38,531 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
/**
|
||||
* event subscription
|
||||
*/
|
||||
typedef struct evSubscrip {
|
||||
ELLNODE node;
|
||||
struct dbChannel *chan;
|
||||
EVENTFUNC *user_sub;
|
||||
void *user_arg;
|
||||
struct event_que *ev_que;
|
||||
db_field_log **pLastLog;
|
||||
unsigned long npend; /* n times this event is on the queue */
|
||||
unsigned long nreplace; /* n times replacing event on the queue */
|
||||
unsigned char select;
|
||||
char useValque;
|
||||
char callBackInProgress;
|
||||
char enabled;
|
||||
ELLNODE node;
|
||||
struct dbChannel * chan;
|
||||
EVENTFUNC * user_sub;
|
||||
void * user_arg;
|
||||
struct event_que * ev_que;
|
||||
db_field_log ** pLastLog;
|
||||
unsigned long npend; /**< n times this event is on the queue */
|
||||
unsigned long nreplace; /**< n times replacing event on the queue */
|
||||
unsigned char select;
|
||||
char useValque;
|
||||
char callBackInProgress;
|
||||
char enabled;
|
||||
} evSubscrip;
|
||||
|
||||
typedef struct chFilter chFilter;
|
||||
|
||||
/* A dbChannel points to a record field, and can have multiple filters */
|
||||
/** \brief A Database Channel object
|
||||
*
|
||||
* A dbChannel is created from a user-supplied channel name, and holds
|
||||
* pointers to the record & field and information about any filters that
|
||||
* were specified with it. The dbChannel macros defined in this header
|
||||
* file should always be used to read data from a dbChannel object, the
|
||||
* internal implementation may change without notice.
|
||||
*/
|
||||
typedef struct dbChannel {
|
||||
const char *name;
|
||||
dbAddr addr; /* address structure for record/field */
|
||||
long final_no_elements; /* final number of elements (arrays) */
|
||||
short final_field_size; /* final size of element */
|
||||
short final_type; /* final type of database field */
|
||||
ELLLIST filters; /* list of filters as created from JSON */
|
||||
ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
|
||||
ELLLIST post_chain; /* list of filters to be called post-event-queue */
|
||||
const char *name; /**< Channel name */
|
||||
dbAddr addr; /**< Pointers to record & field */
|
||||
long final_no_elements; /**< Final number of array elements */
|
||||
short final_field_size; /**< Final size of each element */
|
||||
short final_type; /**< Final type of database field */
|
||||
ELLLIST filters; /**< Filters used by dbChannel */
|
||||
ELLLIST pre_chain; /**< Filters on pre-event-queue chain */
|
||||
ELLLIST post_chain; /**< Filters on post-event-queue chain */
|
||||
} dbChannel;
|
||||
|
||||
/* Prototype for the channel event function that is called in filter stacks
|
||||
/** \brief Event filter function type
|
||||
*
|
||||
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
|
||||
* Unless dbfl_has_copy(pLog), it must call dbScanLock before accessing the data,
|
||||
* as this indicates the data is still owned by the record.
|
||||
* Prototype for channel event filter functions.
|
||||
*
|
||||
* This function has ownership of the field log pLog, if it wishes to discard
|
||||
* this update it should free the field log with db_delete_field_log() and
|
||||
* then return NULL.
|
||||
* When these functions are called the scan lock for the record associated
|
||||
* with \p chan _may_ already be locked, but they must use dbfl_has_copy()
|
||||
* to determine whether the data in \p pLog belongs to the record. If that
|
||||
* returns 0 the function must call dbScanLock() before accessing the data.
|
||||
*
|
||||
* A filter function owns the field log \p pLog when called. To discard an
|
||||
* update it should free the field log using db_delete_field_log() and
|
||||
* return NULL.
|
||||
*/
|
||||
typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
|
||||
|
||||
/* Return values from chFilterIf->parse_* routines: */
|
||||
/** \brief Result returned by chFilterIf parse routines.
|
||||
*
|
||||
* The parsing functions from a chFilterIf must return either \p parse_stop
|
||||
* (in event of an error) or \p parse_continue.
|
||||
*/
|
||||
typedef enum {
|
||||
parse_stop, parse_continue
|
||||
} parse_result;
|
||||
|
||||
/* These routines must be implemented by each filter plug-in */
|
||||
/** \brief Channel Filter Interface
|
||||
*
|
||||
* Routines to be implemented by each Channel Filter.
|
||||
*/
|
||||
typedef struct chFilterIf {
|
||||
/* cleanup pointer passed to dbRegisterFilter().
|
||||
* Called during DB shutdown
|
||||
/** \brief Release private filter data.
|
||||
*
|
||||
* Called during database shutdown to release resources allocated by
|
||||
* the filter.
|
||||
* \param puser The user-pointer passed into dbRegisterFilter().
|
||||
*/
|
||||
void (* priv_free)(void *puser);
|
||||
/* Parsing event handlers: */
|
||||
parse_result (* parse_start)(chFilter *filter);
|
||||
/* If parse_start() returns parse_continue for a filter, one of
|
||||
|
||||
/** \name Parsing event handlers
|
||||
*
|
||||
* A filter that doesn't accept a particular JSON value type may use a
|
||||
* \p NULL pointer to the parsing handler for that value type, which is
|
||||
* equivalent to a routine that always returns \p parse_stop.
|
||||
*/
|
||||
|
||||
/** \brief Create new filter instance.
|
||||
*
|
||||
* Called when a new filter instance is requested. Filter may allocate
|
||||
* resources for this instance and store in \p filter->puser.
|
||||
* If parse_start() returns \p parse_continue for a filter, one of
|
||||
* parse_abort() or parse_end() will later be called for that same
|
||||
* filter.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_start)(chFilter *filter);
|
||||
|
||||
/** \brief Parsing of filter instance is being cancelled.
|
||||
*
|
||||
* This function should release any memory allocated for the given
|
||||
* \p filter instance; no further parsing handlers will be called for it.
|
||||
* \param filter Pointer to instance data.
|
||||
*/
|
||||
void (* parse_abort)(chFilter *filter);
|
||||
/* If parse_abort() is called it should release any memory allocated
|
||||
* for this filter; no further parse_...() calls will be made;
|
||||
|
||||
/** \brief Parsing of filter instance has completed successfully.
|
||||
*
|
||||
* The parser has reached the end of this instance and no further parsing
|
||||
* handlers will be called for it. The filter must check the instance
|
||||
* data and indicate whether it was complete or not.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_end)(chFilter *filter);
|
||||
/* If parse_end() returns parse_stop it should have released any
|
||||
* memory allocated for this filter; no further parse_...() calls will
|
||||
* be made in this case.
|
||||
|
||||
/** \brief Parser saw \p null value.
|
||||
*
|
||||
* Optional.
|
||||
* Null values are rarely accepted by channel filters.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
|
||||
parse_result (* parse_null)(chFilter *filter);
|
||||
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
|
||||
parse_result (* parse_integer)(chFilter *filter, long integerVal);
|
||||
parse_result (* parse_double)(chFilter *filter, double doubleVal);
|
||||
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
|
||||
size_t stringLen); /* NB: stringVal is not zero-terminated: */
|
||||
|
||||
/** \brief Parser saw boolean value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param boolVal true/false Value.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
|
||||
|
||||
/** \brief Parser saw integer value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param integerVal Value.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_integer)(chFilter *filter, long integerVal);
|
||||
|
||||
/** \brief Parser saw double value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param doubleVal Value.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_double)(chFilter *filter, double doubleVal);
|
||||
|
||||
/** \brief Parser saw string value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param stringVal Value, not zero-terminated.
|
||||
* \param stringLen Number of chars in \p stringVal.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
|
||||
size_t stringLen);
|
||||
|
||||
/** \brief Parser saw start of a JSON map value.
|
||||
*
|
||||
* Optional.
|
||||
* Inside a JSON map all data consists of key/value pairs.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_start_map)(chFilter *filter);
|
||||
|
||||
/** \brief Parser saw a JSON map key.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param key Value not zero-terminated.
|
||||
* \param stringLen Number of chars in \p key
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_map_key)(chFilter *filter, const char *key,
|
||||
size_t stringLen); /* NB: key is not zero-terminated: */
|
||||
size_t stringLen);
|
||||
|
||||
/** \brief Parser saw end of a JSON map value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_end_map)(chFilter *filter);
|
||||
|
||||
/** \brief Parser saw start of a JSON array value.
|
||||
*
|
||||
* Optional.
|
||||
* Data inside a JSON array doesn't have to be all of the same type.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_start_array)(chFilter *filter);
|
||||
|
||||
/** \brief Parser saw end of a JSON array value.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns \p parse_stop on error, or \p parse_continue
|
||||
*/
|
||||
parse_result (* parse_end_array)(chFilter *filter);
|
||||
|
||||
/* Channel operations: */
|
||||
/** \name Channel operations */
|
||||
|
||||
/** \brief Open filter on channel.
|
||||
*
|
||||
* Optional, initialize instance.
|
||||
* \param filter Pointer to instance data.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
long (* channel_open)(chFilter *filter);
|
||||
void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
void (* channel_report)(chFilter *filter, int level, const unsigned short indent);
|
||||
|
||||
/** \brief Get pre-chain filter function.
|
||||
*
|
||||
* Optional.
|
||||
* Returns pre-chain filter function and context.
|
||||
* \param[in] filter Pointer to instance data.
|
||||
* \param[out] cb_out Write filter function pointer here.
|
||||
* \param[out] arg_out Write private data pointer here.
|
||||
* \param[in,out] probe db_field_log with metadata for adjusting.
|
||||
*/
|
||||
void (* channel_register_pre) (chFilter *filter,
|
||||
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
|
||||
/** \brief Get post-chain filter function.
|
||||
*
|
||||
* Optional, return post-chain filter function and context.
|
||||
* \param[in] filter Pointer to instance data.
|
||||
* \param[out] cb_out Write filter function pointer here.
|
||||
* \param[out] arg_out Write private data pointer here.
|
||||
* \param[in,out] probe db_field_log with metadata for adjusting.
|
||||
*/
|
||||
void (* channel_register_post)(chFilter *filter,
|
||||
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
|
||||
|
||||
/** \brief Print information about filter to stdout.
|
||||
*
|
||||
* Optional.
|
||||
* \param filter Pointer to instance data.
|
||||
* \param level Higher levels may provide more detail.
|
||||
* \param indent Indent all lines by this many spaces.
|
||||
*/
|
||||
void (* channel_report)(chFilter *filter,
|
||||
int level, const unsigned short indent);
|
||||
|
||||
/** \brief Close filter.
|
||||
*
|
||||
* Optional, releases resources allocated for this instance.
|
||||
* \param filter Pointer to instance data.
|
||||
*/
|
||||
void (* channel_close)(chFilter *filter);
|
||||
} chFilterIf;
|
||||
|
||||
/* A chFilterPlugin holds data for a filter plugin */
|
||||
/** \brief Filter plugin data
|
||||
*
|
||||
* A chFilterPlugin object holds data about a filter plugin.
|
||||
*/
|
||||
typedef struct chFilterPlugin {
|
||||
ELLNODE node;
|
||||
const char *name;
|
||||
const chFilterIf *fif;
|
||||
void *puser;
|
||||
ELLNODE node; /**< \brief List node (dbBase->filterList) */
|
||||
const char *name; /**< \brief Filter name */
|
||||
const chFilterIf *fif; /**< \brief Filter interface routines */
|
||||
void *puser; /**< \brief For use by the plugin */
|
||||
} chFilterPlugin;
|
||||
|
||||
/* A chFilter holds data for a single filter instance */
|
||||
/** \brief Filter instance data
|
||||
*
|
||||
* A chFilter holds data about a single filter instance.
|
||||
*/
|
||||
struct chFilter {
|
||||
ELLNODE list_node;
|
||||
ELLNODE pre_node;
|
||||
ELLNODE post_node;
|
||||
dbChannel *chan;
|
||||
const chFilterPlugin *plug;
|
||||
chPostEventFunc *pre_func;
|
||||
void *pre_arg;
|
||||
chPostEventFunc *post_func;
|
||||
void *post_arg;
|
||||
void *puser;
|
||||
ELLNODE list_node; /**< \brief List node (dbChannel->filters) */
|
||||
ELLNODE pre_node; /**< \brief List node (dbChannel->pre_chain) */
|
||||
ELLNODE post_node; /**< \brief List node (dbChannel->post_chain) */
|
||||
dbChannel *chan; /**< \brief The dbChannel we belong to */
|
||||
const chFilterPlugin *plug; /**< \brief The plugin that created us */
|
||||
chPostEventFunc *pre_func; /**< \brief pre-chain filter function */
|
||||
void *pre_arg; /**< \brief pre-chain context pointer */
|
||||
chPostEventFunc *post_func; /**< \brief post-chain filter function */
|
||||
void *post_arg; /**< \brief post-chain context pointer */
|
||||
void *puser; /**< \brief For use by the plugin */
|
||||
};
|
||||
|
||||
struct dbCommon;
|
||||
struct dbFldDes;
|
||||
|
||||
DBCORE_API void dbChannelInit (void);
|
||||
/** \brief Initialize the dbChannel subsystem. */
|
||||
DBCORE_API void dbChannelInit(void);
|
||||
|
||||
/** \brief Cleanup the dbChannel subsystem. */
|
||||
DBCORE_API void dbChannelExit(void);
|
||||
|
||||
/** \brief Test the given PV name for existance.
|
||||
*
|
||||
* This routine looks up the given record and field name, but does not check
|
||||
* whether any field modifiers given after the field name are correct.
|
||||
* This is sufficient for the correct server to quickly direct searches to the
|
||||
* IOC that owns that PV name. Field modifiers will be checked when
|
||||
* dbChannelCreate() is later called with the same name.
|
||||
* \param name Channel name.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelTest(const char *name);
|
||||
|
||||
/** \brief Create a dbChannel object for the given PV name.
|
||||
*
|
||||
* \param name Channel name.
|
||||
* \return Pointer to dbChannel object, or NULL if invalid.
|
||||
*/
|
||||
DBCORE_API dbChannel * dbChannelCreate(const char *name);
|
||||
|
||||
/** \brief Open a dbChannel for doing I/O.
|
||||
*
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelOpen(dbChannel *chan);
|
||||
|
||||
/*Following is also defined in db_convert.h*/
|
||||
/** \brief Request (DBR) type conversion array.
|
||||
*
|
||||
* This converter array is declared in db_convert.h but redeclared
|
||||
* here as it is needed by the dbChannel...CAType macros defined here.
|
||||
*/
|
||||
DBCORE_API extern unsigned short dbDBRnewToDBRold[];
|
||||
|
||||
/* In the following macros pChan is dbChannel* */
|
||||
/** \name dbChannel Inspection Macros */
|
||||
|
||||
/* evaluates to const char* */
|
||||
/** \brief Name that defined the channel.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns const char*
|
||||
*/
|
||||
#define dbChannelName(pChan) ((pChan)->name)
|
||||
|
||||
/* evaluates to struct dbCommon* */
|
||||
/** \brief Record the channel connects to.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns struct dbCommon*
|
||||
*/
|
||||
#define dbChannelRecord(pChan) ((pChan)->addr.precord)
|
||||
|
||||
/* evaluates to struct dbFldDes* */
|
||||
/** \brief Field descriptor for the field pointed to.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns struct dbFldDes*
|
||||
*/
|
||||
#define dbChannelFldDes(pChan) ((pChan)->addr.pfldDes)
|
||||
|
||||
/* evaluates to long */
|
||||
/** \brief Number of array elements in the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns long
|
||||
*/
|
||||
#define dbChannelElements(pChan) ((pChan)->addr.no_elements)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Data type (DBF type) of the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFieldType(pChan) ((pChan)->addr.field_type)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Request type (DBR type) of the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelExportType(pChan) ((pChan)->addr.dbr_field_type)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief CA data type of the field.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelExportCAType(pChan) (dbDBRnewToDBRold[dbChannelExportType(pChan)])
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Field (element if array) size in bytes.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFieldSize(pChan) ((pChan)->addr.field_size)
|
||||
|
||||
/* evaluates to long */
|
||||
/** \brief Array length after filtering.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns long
|
||||
*/
|
||||
#define dbChannelFinalElements(pChan) ((pChan)->final_no_elements)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Data type after filtering.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFinalFieldType(pChan) ((pChan)->final_type)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Channel CA data type after filtering.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelFinalCAType(pChan) (dbDBRnewToDBRold[(pChan)->final_type])
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Field/element size after filtering, in bytes.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short */
|
||||
#define dbChannelFinalFieldSize(pChan) ((pChan)->final_field_size)
|
||||
|
||||
/* evaluates to short */
|
||||
/** \brief Field special attribute.
|
||||
*
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns short
|
||||
*/
|
||||
#define dbChannelSpecial(pChan) ((pChan)->addr.special)
|
||||
|
||||
/* Channel filters do not get to interpose here since there are many
|
||||
/** \brief Pointer to the record field.
|
||||
*
|
||||
* Channel filters do not get to interpose here since there are many
|
||||
* places where the field pointer is compared with the address of a
|
||||
* specific record field, so they can't modify the pointer value.
|
||||
* \param pChan Pointer to the dbChannel object.
|
||||
* \returns void *
|
||||
*/
|
||||
/* evaluates to void* */
|
||||
#define dbChannelField(pChan) ((pChan)->addr.pfield)
|
||||
|
||||
|
||||
/** \name dbChannel Operation Functions */
|
||||
|
||||
/** \brief dbGet() through a dbChannel.
|
||||
*
|
||||
* Calls dbGet() for the field that \p chan refers to.
|
||||
* Only call this routine if the record is already locked.
|
||||
* \param[in] chan Pointer to the dbChannel object.
|
||||
* \param[in] type Request type from dbFldTypes.h.
|
||||
* \param[out] pbuffer Pointer to data buffer.
|
||||
* \param[in,out] options Request options from dbAccessDefs.h.
|
||||
* \param[in,out] nRequest Pointer to the element count.
|
||||
* \param[in] pfl Pointer to a db_field_log or NULL.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelGet(dbChannel *chan, short type,
|
||||
void *pbuffer, long *options, long *nRequest, void *pfl);
|
||||
|
||||
/** \brief dbGetField() through a dbChannel.
|
||||
*
|
||||
* Get values from a PV through a channel.
|
||||
* This routine locks the record, calls
|
||||
* dbChannelGet(), then unlocks the record again.
|
||||
* \param[in] chan Pointer to the dbChannel object.
|
||||
* \param[in] type Request type from dbFldTypes.h.
|
||||
* \param[out] pbuffer Pointer to data buffer.
|
||||
* \param[in,out] options Request options from dbAccessDefs.h.
|
||||
* \param[in,out] nRequest Pointer to the element count.
|
||||
* \param[in] pfl Pointer to a db_field_log or NULL.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelGetField(dbChannel *chan, short type,
|
||||
void *pbuffer, long *options, long *nRequest, void *pfl);
|
||||
|
||||
/** \brief dbPut() through a dbChannel.
|
||||
*
|
||||
* Put values to a PV through a channel. Only call this routine if the
|
||||
* record is already locked.
|
||||
* Calls dbPut() for the field that \p chan refers to.
|
||||
* \param chan[in] Pointer to the dbChannel object.
|
||||
* \param type[in] Request type from dbFldTypes.h.
|
||||
* \param pbuffer[in] Pointer to data buffer.
|
||||
* \param nRequest[in] Number of elements in pbuffer.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelPut(dbChannel *chan, short type,
|
||||
const void *pbuffer, long nRequest);
|
||||
|
||||
/** \brief dbPutField() through a dbChannel.
|
||||
*
|
||||
* Put values to a PV through a channel.
|
||||
* This routine calls dbPutField() for the field that \p chan refers to.
|
||||
* \param chan[in] Pointer to the dbChannel object.
|
||||
* \param type[in] Request type from dbFldTypes.h.
|
||||
* \param pbuffer[in] Pointer to data buffer.
|
||||
* \param nRequest[in] Number of elements in pbuffer.
|
||||
* \returns 0, or an error status value.
|
||||
*/
|
||||
DBCORE_API long dbChannelPutField(dbChannel *chan, short type,
|
||||
const void *pbuffer, long nRequest);
|
||||
|
||||
/** \brief Print report on a channel.
|
||||
*
|
||||
* Print information about the channel to stdout.
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
* \param level Higher levels may provide more detail.
|
||||
* \param indent Indent all lines by this many spaces.
|
||||
*/
|
||||
DBCORE_API void dbChannelShow(dbChannel *chan, int level,
|
||||
const unsigned short indent);
|
||||
|
||||
/** \brief Print report on a channel's filters.
|
||||
*
|
||||
* Print information about the channel's filters to stdout.
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
* \param level Higher levels may provide more detail.
|
||||
* \param indent Indent all lines by this many spaces.
|
||||
*/
|
||||
DBCORE_API void dbChannelFilterShow(dbChannel *chan, int level,
|
||||
const unsigned short indent);
|
||||
|
||||
/** \brief Delete a channel.
|
||||
*
|
||||
* Releases resources owned by this channel and its filters.
|
||||
* \param chan Pointer to the dbChannel object.
|
||||
*/
|
||||
DBCORE_API void dbChannelDelete(dbChannel *chan);
|
||||
|
||||
DBCORE_API void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
|
||||
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
|
||||
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
|
||||
|
||||
/** \name Other routines */
|
||||
|
||||
DBCORE_API void dbRegisterFilter(const char *key,
|
||||
const chFilterIf *fif, void *puser);
|
||||
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan,
|
||||
db_field_log *pLogIn);
|
||||
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan,
|
||||
db_field_log *pLogIn);
|
||||
DBCORE_API const chFilterPlugin * dbFindFilter(const char *key, size_t len);
|
||||
DBCORE_API void dbChannelGetArrayInfo(dbChannel *chan,
|
||||
void **pfield, long *no_elements, long *offset);
|
||||
|
||||
@@ -77,12 +77,12 @@ A set of periodic scan intervals
|
||||
=back
|
||||
|
||||
Additional periodic scan rates may be defined for individual IOCs by making a
|
||||
local copy of menuScan.dbd and adding more choices as required. Scan rates
|
||||
should normally be defined in order, with the fastest rates appearing first.
|
||||
Scan periods may now be specified in seconds, minutes, hours or Hertz/Hz, and
|
||||
plural time units will also be accepted (seconds are used if no unit is
|
||||
mentioned in the choice string). For example the rates given below are all
|
||||
valid:
|
||||
local copy of menuScan.dbd and adding more choices as required. Periodic scan
|
||||
rates should normally be defined in order following the other scan types, with
|
||||
the longest periods appearing first. Scan periods can be specified with a unit
|
||||
string of C<second>/C<seconds>, C<minute>/C<minutes>, C<hour>/C<hours> or
|
||||
C<Hertz>/C<Hz>. Seconds are used if no unit is included in the choice string.
|
||||
For example these rates are all valid:
|
||||
|
||||
1 hour
|
||||
0.5 hours
|
||||
@@ -97,7 +97,7 @@ initialization (before the normal scan tasks are started).
|
||||
|
||||
The B<PHAS> field orders the records within a specific SCAN group. This is not
|
||||
meaningful for passive records. All records of a specified phase are processed
|
||||
before those with higher phase number. Whenever possible it is better to use
|
||||
before those with higher phase number. It is generally better practice to use
|
||||
linked passive records to enforce the order of processing rather than a phase
|
||||
number.
|
||||
|
||||
@@ -109,23 +109,23 @@ The call to post_event is: post_event(short event_number).
|
||||
The B<PRIO> field specifies the scheduling priority for processing records
|
||||
with SCAN=C<I/O Event> and asynchronous record completion tasks.
|
||||
|
||||
The B<DISV> field specifies a "disable value". Record processing is
|
||||
immediately terminated if the value of this field is equal to the value of the
|
||||
DISA field, i.e. the record is disabled. Note that field values of a record
|
||||
can be changed by database put or Channel Access, even if a record is
|
||||
The B<DISV> field specifies a "disable value". Record processing cannot
|
||||
begin when the value of this field is equal to the value of the DISA
|
||||
field, meaning the record is disabled. Note that field values of a record
|
||||
can be changed by database or Channel Access puts, even if the record is
|
||||
disabled.
|
||||
|
||||
The B<DISA> field contains the value that is compared with DISV to determine
|
||||
if the record is disabled. The value of the DISA field is obtained via SDIS if
|
||||
SDIS is a database or channel access link. If SDIS is not a database or
|
||||
channel access link, then DISA can be set via dbPutField or dbPutLink.
|
||||
|
||||
If the B<PROC> field of a record is written to, the record is processed.
|
||||
The B<DISA> field contains the value that is compared with DISV to determine if
|
||||
the record is disabled. A value is obtained for the DISA field from the B<SDIS>
|
||||
link field before the IOC tries to process the record. If SDIS is not set, DISA
|
||||
may be set by some other method to enable and disable the record.
|
||||
|
||||
The B<DISS> field defines the record's "disable severity". If this field is
|
||||
not NO_ALARM and the record is disabled, the record will be put into alarm
|
||||
with this severity and a status of DISABLE_ALARM.
|
||||
|
||||
If the B<PROC> field of a record is written to, the record is processed.
|
||||
|
||||
The B<LSET> field contains the lock set to which this record belongs. All
|
||||
records linked in any way via input, output, or forward database links belong
|
||||
to the same lock set. Lock sets are determined at IOC initialization time, and
|
||||
@@ -135,15 +135,18 @@ The B<LCNT> field counts the number of times dbProcess finds the record active
|
||||
during successive scans, i.e. PACT is TRUE. If dbProcess finds the record
|
||||
active MAX_LOCK times (currently set to 10) it raises a SCAN_ALARM.
|
||||
|
||||
The B<PACT> field is TRUE while the record is being processed. For
|
||||
The B<PACT> field is TRUE while the record is active (being processed). For
|
||||
asynchronous records PACT can be TRUE from the time record processing is
|
||||
started until the asynchronous completion occurs. As long as PACT is TRUE,
|
||||
dbProcess will not call the record processing routine. See Application
|
||||
Developers Guide for details on usage of PACT.
|
||||
|
||||
The B<FLNK> field is a database link to another record (the "target" record).
|
||||
Processing a record with a specified FLNK field will force processing of the
|
||||
target record, provided the target record's SCAN field is set to C<Passive>.
|
||||
The B<FLNK> field is a link pointing to another record (the "target" record).
|
||||
Processing a record with the FLNK field set will trigger processing of the
|
||||
target record towards the end of processing the first record (but before PACT is
|
||||
cleared), provided the target record's SCAN field is set to C<Passive>. If the
|
||||
FLNK field is a Channel Access link it must point to the PROC field of the
|
||||
target record.
|
||||
|
||||
The B<SPVT> field is for internal use by the scanning system.
|
||||
|
||||
@@ -227,6 +230,8 @@ The B<SPVT> field is for internal use by the scanning system.
|
||||
}
|
||||
field(DISP,DBF_UCHAR) {
|
||||
prompt("Disable putField")
|
||||
promptgroup("10 - Common")
|
||||
interest(1)
|
||||
}
|
||||
field(PROC,DBF_UCHAR) {
|
||||
prompt("Force Processing")
|
||||
@@ -236,35 +241,46 @@ The B<SPVT> field is for internal use by the scanning system.
|
||||
|
||||
=head3 Alarm Fields
|
||||
|
||||
These fields indicate the status and severity of alarms, or else determine the
|
||||
Alarm fields indicate the status and severity of record alarms, or determine
|
||||
how and when alarms are triggered. Of course, many records have alarm-related
|
||||
fields not common to all records. These fields are listed and explained in the
|
||||
fields not common to all records. Those fields are listed and explained in the
|
||||
appropriate section on each record.
|
||||
|
||||
The B<STAT> field contains the current alarm status.
|
||||
|
||||
The B<SEVR> field contains the current alarm severity.
|
||||
|
||||
These two fields are seen outside database access. The B<NSTA> and B<NSEV>
|
||||
fields are used by the database access, record support, and device support
|
||||
routines to set new alarm status and severity values. Whenever any software
|
||||
component discovers an alarm condition, it uses the following macro function:
|
||||
recGblSetSevr(precord,new_status,new_severity) This ensures that the current
|
||||
alarm severity is set equal to the highest outstanding alarm. The file alarm.h
|
||||
defines all allowed alarm status and severity values.
|
||||
The B<AMSG> string field may contain more detailed information about the alarm.
|
||||
|
||||
The STAT, SEVR and AMSG fields hold alarm information as seen outside of the
|
||||
database. The B<NSTA>, B<NSEV> and B<NAMSG> fields are used during record
|
||||
processing by the database access, record support, and device support routines
|
||||
to set new alarm status and severity values and message text. Whenever any
|
||||
software component discovers an alarm condition, it calls one of these routines
|
||||
to register the alarm:
|
||||
|
||||
recGblSetSevr(precord, new_status, new_severity);
|
||||
recGblSetSevrMsg(precord, new_status, new_severity, "Message", ...);
|
||||
|
||||
These check the current alarm severity and update the NSTA, NSEV and NAMSG
|
||||
fields if appropriate so they always relate to the highest severity alarm seen
|
||||
so far during record processing. The file alarm.h defines the allowed alarm
|
||||
status and severity values. Towards the end of record processing these fields
|
||||
are copied into the STAT, SEVR and AMSG fields and alarm monitors triggered.
|
||||
|
||||
The B<ACKS> field contains the highest unacknowledged alarm severity.
|
||||
|
||||
The B<ACKT> field specifies if it is necessary to acknowledge transient
|
||||
The B<ACKT> field specifies whether it is necessary to acknowledge transient
|
||||
alarms.
|
||||
|
||||
The B<UDF> indicates if the record's value is B<U>nB<D>eB<F>ined. Typically
|
||||
this is caused by a failure in device support, the fact that the record has
|
||||
never been processed, or that the VAL field currently contains a NaN (not a
|
||||
number). UDF is initialized to TRUE at IOC initialization. Record and device
|
||||
support routines which write to the VAL field are responsible for setting UDF.
|
||||
The B<UDF> indicates if the record's value is B<U>nB<D>eB<F>ined. Typically this
|
||||
is caused by a failure in device support, the fact that the record has never
|
||||
been processed, or that the VAL field currently contains a NaN (not a number) or
|
||||
Inf (Infinite) value. UDF defaults to TRUE but can be set in a database file.
|
||||
Record and device support routines which write to the VAL field are generally
|
||||
responsible for setting and clearing UDF.
|
||||
|
||||
=fields STAT, SEVR, NSTA, NSEV, ACKS, ACKT, UDF
|
||||
=fields STAT, SEVR, AMSG, NSTA, NSEV, NAMSG, ACKS, ACKT, UDF
|
||||
|
||||
=cut
|
||||
|
||||
@@ -422,9 +438,11 @@ The B<DPVT> field is is for private use of the device support modules.
|
||||
|
||||
=head3 Debugging Fields
|
||||
|
||||
The B<TPRO> field is used for trace processing. If this field is non-zero a
|
||||
message is printed whenever this record is processed, and when any other
|
||||
record in the same lock-set is processed by a database link from this record.
|
||||
The B<TPRO> field can be used to trace record processing. When this field is
|
||||
non-zero and the record is processed, a trace message will be be printed for
|
||||
this record and any other record in the same lock-set that is triggered by a
|
||||
database link from this record. The trace message includes the name of the
|
||||
thread doing the processing, and the name of the record being processed.
|
||||
|
||||
The B<BKPT> field indicates if there is a breakpoint set at this record. This
|
||||
supports setting a debug breakpoint in the record processing. STEP through
|
||||
@@ -435,32 +453,27 @@ database processing can be supported using this.
|
||||
|
||||
=head3 Miscellaneous Fields
|
||||
|
||||
The B<ASG> field contains a character string value defining the access
|
||||
security group for this record. If left empty, the record is placed in group
|
||||
DEFAULT.
|
||||
The B<ASG> string field sets the name of the access security group used for this
|
||||
record. If left empty, the record is placed in group C<DEFAULT>.
|
||||
|
||||
The B<ASP> field is a field for private use of the access security system.
|
||||
The B<ASP> field is private for use by the access security system.
|
||||
|
||||
The B<DISP> field controls dbPutFields to this record which are normally
|
||||
issued by channel access. If the field is set to TRUE all dbPutFields
|
||||
directed to this record are ignored except to the field DISP itself.
|
||||
The B<DISP> field can be set to a non-zero value to reject puts from outside of
|
||||
the IOC (i.e. via Channel Access or PV Access) to any field of the record other
|
||||
than to the DISP field itself. Field changes and record processing can still be
|
||||
instigated from inside the IOC using DB links and the IOC scan mechanisms.
|
||||
|
||||
The B<DTYP> field specifies the device type for the record. Each record type
|
||||
has its own set of device support routines which are specified in
|
||||
devSup.ASCII. If a record type does not have any associated device support,
|
||||
DTYP and DSET are meaningless.
|
||||
The B<DTYP> field specifies the device type for the record. Most record types
|
||||
have their own set of device types which are specified in the IOC's database
|
||||
definition file. If a record type does not call any device support routines,
|
||||
the DTYP and DSET fields are not used.
|
||||
|
||||
The B<MLOK> field contains the monitor lock. The lock used by the monitor
|
||||
routines when the monitor list is being used. The list is locked whenever
|
||||
monitors are being scheduled, invoked, or when monitors are being added to or
|
||||
removed from the list. This field is accessed only by the dbEvent routines.
|
||||
The B<MLOK> field contains a mutex which is locked by the monitor routines in
|
||||
dbEvent.c whenever the monitor list for this record is accessed.
|
||||
|
||||
The B<MLIS> field is the head of the list of monitors connected to this
|
||||
The B<MLIS> field holds a linked list of client monitors connected to this
|
||||
record. Each record support module is responsible for triggering monitors for
|
||||
any fields that change as a result of record processing. Monitors are present
|
||||
if mlis count is greater than zero. The call to trigger monitors is:
|
||||
db_post_event(precord,&data,mask), where "mask" is some combination of
|
||||
DBE_ALARM, DBE_VALUE, and DBE_LOG.
|
||||
any fields that change as a result of record processing.
|
||||
|
||||
The B<PPN> field contains the address of a putNotify callback.
|
||||
|
||||
@@ -474,23 +487,44 @@ The B<RDES> field contains the address of dbRecordType
|
||||
The B<RPRO> field specifies a reprocessing of the record when current
|
||||
processing completes.
|
||||
|
||||
The B<TIME> field contains the time when this record was last processed in
|
||||
standard format.
|
||||
The B<TIME> field holds the time stamp when this record was last processed.
|
||||
|
||||
The B<TSE> field indicates the mechanism to use to get the time stamp. '0' -
|
||||
call get time as before '-1' - call the time stamp driver and use the best
|
||||
source available. '-2' - the device support provides the time stamp from the
|
||||
hardware. Values between 1-255 request the time of the last occurance of a
|
||||
generalTime event.
|
||||
The B<UTAG> field can be used to hold a site-specific 64-bit User Tag value
|
||||
that is associated with the record's time stamp.
|
||||
|
||||
The B<TSE> field value indicates the mechanism to use to get the time stamp:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
C< 0> E<mdash> Get the current time as normal
|
||||
|
||||
=item *
|
||||
|
||||
C<-1> E<mdash> Ask the time stamp driver for its best source of the current time, if
|
||||
available.
|
||||
|
||||
=item *
|
||||
|
||||
C<-2> E<mdash> Device support sets the time stamp and the optional User Tag from the
|
||||
hardware.
|
||||
|
||||
=item *
|
||||
|
||||
Positive values (normally between 1-255) get the time of the last occurance of
|
||||
the numbered generalTime event.
|
||||
|
||||
=back
|
||||
|
||||
The B<TSEL> field contains an input link for obtaining the time stamp. If this
|
||||
link references the .TIME field of a record then the time stamp of the
|
||||
referenced record becomes the time stamp for this record as well. In this
|
||||
case, an internal flag is set and ".TIME" is then overwritten by ".VAL". If
|
||||
any other field is referenced, the field value is read and stored in the .TSE
|
||||
field which is then used to acquire a timestamp.
|
||||
link points to the TIME field of a record then the time stamp and User Tag of
|
||||
that record are copied directly into this record (Channel Access links can only
|
||||
copy the time stamp, not the User Tag). If the link points to any other field,
|
||||
that field's value is read and stored in the TSE field which is then used to
|
||||
provide the time stamp as described above.
|
||||
|
||||
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, TSE, TSEL
|
||||
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, UTAG, TSE, TSEL
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbLink.h"
|
||||
#include "link.h"
|
||||
#include "errlog.h"
|
||||
|
||||
/**************************** Convert functions ****************************/
|
||||
|
||||
@@ -63,7 +64,7 @@ cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
|
||||
return epicsParse##TYPE(from, to, 0, &end); \
|
||||
}
|
||||
|
||||
/* Instanciate for CHAR, UCHAR, SHORT, USHORT and LONG */
|
||||
/* Instantiate for CHAR, UCHAR, SHORT, USHORT and LONG */
|
||||
cvt_st_int(Int8)
|
||||
cvt_st_int(UInt8)
|
||||
cvt_st_int(Int16)
|
||||
@@ -99,7 +100,7 @@ static long cvt_st_UInt32(const char *from, void *pfield, const dbAddr *paddr)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Instanciate for INT64 and UINT64 */
|
||||
/* Instantiate for INT64 and UINT64 */
|
||||
cvt_st_int(Int64)
|
||||
cvt_st_int(UInt64)
|
||||
|
||||
@@ -117,7 +118,7 @@ cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
|
||||
return epicsParse##TYPE(from, to, &end); \
|
||||
}
|
||||
|
||||
/* Instanciate for FLOAT32 and FLOAT64 */
|
||||
/* Instantiate for FLOAT32 and FLOAT64 */
|
||||
cvt_st_float(Float32)
|
||||
cvt_st_float(Float64)
|
||||
|
||||
@@ -178,17 +179,23 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
const char *pstr = plink->value.constantStr;
|
||||
long status;
|
||||
|
||||
if (!pstr)
|
||||
return S_db_badField;
|
||||
|
||||
return dbLSConvertJSON(pstr, pbuffer, size, plen);
|
||||
status = dbLSConvertJSON(pstr, pbuffer, size, plen);
|
||||
if (status)
|
||||
errlogPrintf("... while parsing link %s.%s\n",
|
||||
plink->precord->name, dbLinkFieldName(plink));
|
||||
return status;
|
||||
}
|
||||
|
||||
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnReq)
|
||||
{
|
||||
const char *pstr = plink->value.constantStr;
|
||||
long status;
|
||||
|
||||
if (!pstr)
|
||||
return S_db_badField;
|
||||
@@ -197,7 +204,11 @@ static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
|
||||
dbrType = DBF_USHORT;
|
||||
|
||||
return dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
|
||||
status = dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
|
||||
if (status)
|
||||
errlogPrintf("... while parsing link %s.%s\n",
|
||||
plink->precord->name, dbLinkFieldName(plink));
|
||||
return status;
|
||||
}
|
||||
|
||||
static long dbConstGetNelements(const struct link *plink, long *nelements)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Auther Jeff Hill
|
||||
* Author Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -30,10 +30,12 @@ typedef struct parseContext {
|
||||
} parseContext;
|
||||
|
||||
static int dbcj_null(void *ctx) {
|
||||
errlogPrintf("dbConvertJSON: Null objects not supported\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_boolean(void *ctx, int val) {
|
||||
errlogPrintf("dbConvertJSON: Boolean not supported\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
@@ -50,10 +52,6 @@ static int dbcj_integer(void *ctx, long long num) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dblsj_integer(void *ctx, long long num) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_double(void *ctx, double num) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
|
||||
@@ -66,7 +64,9 @@ static int dbcj_double(void *ctx, double num) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dblsj_double(void *ctx, double num) {
|
||||
static int dblsj_number(void *ctx, const char *val, size_t len) {
|
||||
errlogPrintf("dbLSConvertJSON: Numeric value %.*s provided, string expected\n",
|
||||
(int)len, val);
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ static int dbcj_string(void *ctx, const unsigned char *val, size_t len) {
|
||||
* metadata about the field than we have available at the moment.
|
||||
*/
|
||||
if (parser->dbrType != DBF_STRING) {
|
||||
errlogPrintf("dbConvertJSON: String provided, numeric value(s) expected\n");
|
||||
errlogPrintf("dbConvertJSON: String \"%.*s\" provided, numeric value expected\n",
|
||||
(int)len, val);
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
@@ -97,11 +98,6 @@ static int dblsj_string(void *ctx, const unsigned char *val, size_t len) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
char *pdest = parser->pdest;
|
||||
|
||||
if (parser->dbrType != DBF_STRING) {
|
||||
errlogPrintf("dbConvertJSON: dblsj_string dbrType error\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
if (parser->elems > 0) {
|
||||
if (len > parser->dbrSize - 1)
|
||||
len = parser->dbrSize - 1;
|
||||
@@ -118,14 +114,6 @@ static int dbcj_start_map(void *ctx) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_map_key(void *ctx, const unsigned char *key, size_t len) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_end_map(void *ctx) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_start_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
|
||||
@@ -135,32 +123,30 @@ static int dbcj_start_array(void *ctx) {
|
||||
return (parser->depth == 1);
|
||||
}
|
||||
|
||||
static int dbcj_end_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
|
||||
parser->depth--;
|
||||
return (parser->depth == 0);
|
||||
}
|
||||
|
||||
|
||||
static yajl_callbacks dbcj_callbacks = {
|
||||
dbcj_null, dbcj_boolean, dbcj_integer, dbcj_double, NULL, dbcj_string,
|
||||
dbcj_start_map, dbcj_map_key, dbcj_end_map,
|
||||
dbcj_start_array, dbcj_end_array
|
||||
dbcj_start_map, NULL, NULL,
|
||||
dbcj_start_array, NULL
|
||||
};
|
||||
|
||||
long dbPutConvertJSON(const char *json, short dbrType,
|
||||
void *pdest, long *pnRequest)
|
||||
{
|
||||
parseContext context, *parser = &context;
|
||||
yajl_alloc_funcs dbcj_alloc;
|
||||
yajl_handle yh;
|
||||
yajl_status ys;
|
||||
size_t jlen = strlen(json);
|
||||
long status;
|
||||
|
||||
if(INVALID_DB_REQ(dbrType))
|
||||
if (INVALID_DB_REQ(dbrType)) {
|
||||
errlogPrintf("dbConvertJSON: Invalid dbrType %d\n", dbrType);
|
||||
return S_db_badDbrtype;
|
||||
}
|
||||
|
||||
if (!jlen) {
|
||||
*pnRequest = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
parser->depth = 0;
|
||||
parser->dbrType = dbrType;
|
||||
@@ -168,10 +154,11 @@ long dbPutConvertJSON(const char *json, short dbrType,
|
||||
parser->pdest = pdest;
|
||||
parser->elems = *pnRequest;
|
||||
|
||||
yajl_set_default_alloc_funcs(&dbcj_alloc);
|
||||
yh = yajl_alloc(&dbcj_callbacks, &dbcj_alloc, parser);
|
||||
if (!yh)
|
||||
yh = yajl_alloc(&dbcj_callbacks, NULL, parser);
|
||||
if (!yh) {
|
||||
errlogPrintf("dbConvertJSON: out of memory\n");
|
||||
return S_db_noMemory;
|
||||
}
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
|
||||
if (ys == yajl_status_ok)
|
||||
@@ -183,15 +170,13 @@ long dbPutConvertJSON(const char *json, short dbrType,
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case yajl_status_error: {
|
||||
unsigned char *err = yajl_get_error(yh, 1,
|
||||
(const unsigned char *) json, jlen);
|
||||
fprintf(stderr, "dbConvertJSON: %s\n", err);
|
||||
yajl_free_error(yh, err);
|
||||
default: {
|
||||
unsigned char *err = yajl_get_error(yh, 1,
|
||||
(const unsigned char *) json, jlen);
|
||||
errlogPrintf("dbConvertJSON: %s", err);
|
||||
yajl_free_error(yh, err);
|
||||
status = S_db_badField;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
status = S_db_badField;
|
||||
}
|
||||
|
||||
yajl_free(yh);
|
||||
@@ -200,16 +185,15 @@ long dbPutConvertJSON(const char *json, short dbrType,
|
||||
|
||||
|
||||
static yajl_callbacks dblsj_callbacks = {
|
||||
dbcj_null, dbcj_boolean, dblsj_integer, dblsj_double, NULL, dblsj_string,
|
||||
dbcj_start_map, dbcj_map_key, dbcj_end_map,
|
||||
dbcj_start_array, dbcj_end_array
|
||||
dbcj_null, dbcj_boolean, NULL, NULL, dblsj_number, dblsj_string,
|
||||
dbcj_start_map, NULL, NULL,
|
||||
dbcj_start_array, NULL
|
||||
};
|
||||
|
||||
long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
parseContext context, *parser = &context;
|
||||
yajl_alloc_funcs dbcj_alloc;
|
||||
yajl_handle yh;
|
||||
yajl_status ys;
|
||||
size_t jlen = strlen(json);
|
||||
@@ -226,10 +210,11 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
|
||||
parser->pdest = pdest;
|
||||
parser->elems = 1;
|
||||
|
||||
yajl_set_default_alloc_funcs(&dbcj_alloc);
|
||||
yh = yajl_alloc(&dblsj_callbacks, &dbcj_alloc, parser);
|
||||
if (!yh)
|
||||
yh = yajl_alloc(&dblsj_callbacks, NULL, parser);
|
||||
if (!yh) {
|
||||
errlogPrintf("dbLSConvertJSON: out of memory\n");
|
||||
return S_db_noMemory;
|
||||
}
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
|
||||
|
||||
@@ -239,15 +224,13 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case yajl_status_error: {
|
||||
unsigned char *err = yajl_get_error(yh, 1,
|
||||
(const unsigned char *) json, jlen);
|
||||
fprintf(stderr, "dbLoadLS_JSON: %s\n", err);
|
||||
yajl_free_error(yh, err);
|
||||
default: {
|
||||
unsigned char *err = yajl_get_error(yh, 1,
|
||||
(const unsigned char *) json, jlen);
|
||||
errlogPrintf("dbLSConvertJSON: %s", err);
|
||||
yajl_free_error(yh, err);
|
||||
status = S_db_badField;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
status = S_db_badField;
|
||||
}
|
||||
|
||||
yajl_free(yh);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This name should probably be changed to inclue "array" */
|
||||
/* This name should probably be changed to include "array" */
|
||||
DBCORE_API long dbPutConvertJSON(const char *json, short dbrType,
|
||||
void *pdest, long *psize);
|
||||
DBCORE_API long dbLSConvertJSON(const char *json, char *pdest,
|
||||
|
||||
@@ -188,8 +188,11 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
&& dbChannelSpecial(chan) != SPC_ATTRIBUTE
|
||||
&& ellCount(&chan->filters) == 0)
|
||||
{
|
||||
/* simple scalar: set up shortcut */
|
||||
unsigned short dbfType = dbChannelFinalFieldType(chan);
|
||||
/* Simple scalar w/o filters, so *Final* type has no additional information.
|
||||
* Needed to correctly handle DBF_MENU fields, which become DBF_ENUM during
|
||||
* probe of dbChannelOpen().
|
||||
*/
|
||||
unsigned short dbfType = dbChannelFieldType(chan);
|
||||
|
||||
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
|
||||
return S_db_badDbrtype;
|
||||
|
||||
@@ -90,7 +90,7 @@ struct event_user {
|
||||
void *extralabor_arg;/* parameter to above */
|
||||
|
||||
epicsThreadId taskid; /* event handler task id */
|
||||
struct evSubscrip *pSuicideEvent; /* event that is deleteing itself */
|
||||
struct evSubscrip *pSuicideEvent; /* event that is deleting itself */
|
||||
unsigned queovr; /* event que overflow count */
|
||||
unsigned char pendexit; /* exit pend task */
|
||||
unsigned char extra_labor; /* if set call extra labor func */
|
||||
@@ -102,7 +102,7 @@ struct event_user {
|
||||
|
||||
/*
|
||||
* Reliable intertask communication requires copying the current value of the
|
||||
* channel for later queing so 3 stepper motor steps of 10 each do not turn
|
||||
* channel for later queuing so 3 stepper motor steps of 10 each do not turn
|
||||
* into only 10 or 20 total steps part of the time.
|
||||
*/
|
||||
|
||||
@@ -585,7 +585,7 @@ void db_cancel_event (dbEventSubscription event)
|
||||
/*
|
||||
* flag the event as canceled by NULLing out the callback handler
|
||||
*
|
||||
* make certain that the event isnt being accessed while
|
||||
* make certain that the event isn't being accessed while
|
||||
* its call back changes
|
||||
*/
|
||||
LOCKEVQUE (pevent->ev_que);
|
||||
@@ -731,7 +731,7 @@ static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
|
||||
/* don't make a copy yet, just reference the field value */
|
||||
pLog->u.r.field = dbChannelField(chan);
|
||||
/* indicate field value still owned by record */
|
||||
pLog->u.r.dtor = NULL;
|
||||
pLog->dtor = NULL;
|
||||
/* no private data yet, may be set by a filter */
|
||||
pLog->u.r.pvt = NULL;
|
||||
}
|
||||
@@ -789,6 +789,18 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
|
||||
|
||||
LOCKEVQUE (ev_que);
|
||||
|
||||
/* if we have an event on the queue and both the last
|
||||
* event on the queue and the current event reference
|
||||
* a record field, simply ignore duplicate events.
|
||||
*/
|
||||
if (pevent->npend > 0u
|
||||
&& !dbfl_has_copy(*pevent->pLastLog)
|
||||
&& !dbfl_has_copy(pLog)) {
|
||||
db_delete_field_log(pLog);
|
||||
UNLOCKEVQUE (ev_que);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* add to task local event que
|
||||
*/
|
||||
@@ -811,7 +823,7 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
|
||||
pevent->nreplace++;
|
||||
/*
|
||||
* the event task has already been notified about
|
||||
* this so we dont need to post the semaphore
|
||||
* this so we don't need to post the semaphore
|
||||
*/
|
||||
firstEventFlag = 0;
|
||||
}
|
||||
@@ -844,7 +856,7 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
|
||||
UNLOCKEVQUE (ev_que);
|
||||
|
||||
/*
|
||||
* its more efficent to notify the event handler
|
||||
* its more efficient to notify the event handler
|
||||
* only after the event is ready and the lock
|
||||
* is off in case it runs at a higher priority
|
||||
* than the caller here.
|
||||
@@ -886,6 +898,8 @@ unsigned int caEventMask
|
||||
if ( (dbChannelField(pevent->chan) == (void *)pField || pField==NULL) &&
|
||||
(caEventMask & pevent->select)) {
|
||||
db_field_log *pLog = db_create_event_log(pevent);
|
||||
if(pLog)
|
||||
pLog->mask = caEventMask & pevent->select;
|
||||
pLog = dbChannelRunPreChain(pevent->chan, pLog);
|
||||
if (pLog) db_queue_event_log(pevent, pLog);
|
||||
}
|
||||
@@ -974,7 +988,7 @@ static int event_read ( struct event_que *ev_que )
|
||||
* Next event pointer can be used by event tasks to determine
|
||||
* if more events are waiting in the queue
|
||||
*
|
||||
* Must remove the lock here so that we dont deadlock if
|
||||
* Must remove the lock here so that we don't deadlock if
|
||||
* this calls dbGetField() and blocks on the record lock,
|
||||
* dbPutField() is in progress in another task, it has the
|
||||
* record lock, and it is calling db_post_events() waiting
|
||||
@@ -1174,9 +1188,6 @@ void db_event_flow_ctrl_mode_on (dbEventCtx ctx)
|
||||
* notify the event handler task
|
||||
*/
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
#ifdef DEBUG
|
||||
printf("fc on %lu\n", tickGet());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1193,9 +1204,6 @@ void db_event_flow_ctrl_mode_off (dbEventCtx ctx)
|
||||
* notify the event handler task
|
||||
*/
|
||||
epicsEventSignal (evUser->ppendsem);
|
||||
#ifdef DEBUG
|
||||
printf("fc off %lu\n", tickGet());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1205,7 +1213,7 @@ void db_delete_field_log (db_field_log *pfl)
|
||||
{
|
||||
if (pfl) {
|
||||
/* Free field if reference type field log and dtor is set */
|
||||
if (pfl->type == dbfl_type_ref && pfl->u.r.dtor) pfl->u.r.dtor(pfl);
|
||||
if (pfl->type == dbfl_type_ref && pfl->dtor) pfl->dtor(pfl);
|
||||
/* Free the field log chunk */
|
||||
freeListFree(dbevFieldLogFreeList, pfl);
|
||||
}
|
||||
|
||||
@@ -1366,10 +1366,17 @@ static long cvt_device_st(
|
||||
char **papChoice;
|
||||
char *pchoice;
|
||||
|
||||
if(!paddr
|
||||
|| !(pdbFldDes = paddr->pfldDes)
|
||||
|| !(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt)
|
||||
|| *from>=pdbDeviceMenu->nChoice
|
||||
if (!paddr
|
||||
|| !(pdbFldDes = paddr->pfldDes)) {
|
||||
recGblDbaddrError(S_db_errArg, paddr, "dbFastLinkConv(cvt_device_st)");
|
||||
return S_db_errArg;
|
||||
}
|
||||
if (!(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt)) {
|
||||
/* Valid, record type has no device support */
|
||||
*to = '\0';
|
||||
return 0;
|
||||
}
|
||||
if (*from >= pdbDeviceMenu->nChoice
|
||||
|| !(papChoice= pdbDeviceMenu->papChoice)
|
||||
|| !(pchoice=papChoice[*from])) {
|
||||
recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_device_st)");
|
||||
|
||||
@@ -35,8 +35,14 @@ static const iocshArg * const dbLoadDatabaseArgs[3] =
|
||||
{
|
||||
&dbLoadDatabaseArg0,&dbLoadDatabaseArg1,&dbLoadDatabaseArg2
|
||||
};
|
||||
static const iocshFuncDef dbLoadDatabaseFuncDef =
|
||||
{"dbLoadDatabase",3,dbLoadDatabaseArgs};
|
||||
static const iocshFuncDef dbLoadDatabaseFuncDef = {
|
||||
"dbLoadDatabase",
|
||||
3,
|
||||
dbLoadDatabaseArgs,
|
||||
"Load the given .dbd file, with 'path' added as a search path, with the given substitutions.\n\n"
|
||||
"Substitutions are usually not needed for .dbd files.\n\n"
|
||||
"Example: dbLoadDatabase dbd/my.dbd\n",
|
||||
};
|
||||
static void dbLoadDatabaseCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocshSetError(dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval));
|
||||
@@ -46,7 +52,14 @@ static void dbLoadDatabaseCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg dbLoadRecordsArg0 = { "file name",iocshArgString};
|
||||
static const iocshArg dbLoadRecordsArg1 = { "substitutions",iocshArgString};
|
||||
static const iocshArg * const dbLoadRecordsArgs[2] = {&dbLoadRecordsArg0,&dbLoadRecordsArg1};
|
||||
static const iocshFuncDef dbLoadRecordsFuncDef = {"dbLoadRecords",2,dbLoadRecordsArgs};
|
||||
static const iocshFuncDef dbLoadRecordsFuncDef = {
|
||||
"dbLoadRecords",
|
||||
2,
|
||||
dbLoadRecordsArgs,
|
||||
"Load the given .db file, with the given substitutions.\n\n"
|
||||
"Substitutions should be given in the format 'var1=value1,var2=value2'.\n\n"
|
||||
"Example: dbLoadRecords db/myRecords.db 'user=myself,host=myhost'\n",
|
||||
};
|
||||
static void dbLoadRecordsCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocshSetError(dbLoadRecords(args[0].sval,args[1].sval));
|
||||
@@ -234,7 +247,7 @@ static const iocshArg dbtgfArg0 = { "record name",iocshArgString};
|
||||
static const iocshArg * const dbtgfArgs[1] = {&dbtgfArg0};
|
||||
static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs,
|
||||
"Database Test Get Field.\n"
|
||||
"Get field with different DBR_* types"};
|
||||
"Get field with different DBR_* types\n"};
|
||||
static void dbtgfCallFunc(const iocshArgBuf *args) { dbtgf(args[0].sval);}
|
||||
|
||||
/* dbtpf */
|
||||
@@ -283,7 +296,7 @@ static const iocshArg * const dbtpnArgs[2] = {&dbtpnArg0,&dbtpnArg1};
|
||||
static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs,
|
||||
"Database Put Notify\n"
|
||||
"Without value, begin async. processing and get\n"
|
||||
"With value, begin put, process, and get"};
|
||||
"With value, begin put, process, and get\n"};
|
||||
static void dbtpnCallFunc(const iocshArgBuf *args)
|
||||
{ dbtpn(args[0].sval,args[1].sval);}
|
||||
|
||||
|
||||
@@ -613,8 +613,10 @@ long dbtpn(char *pname, char *pvalue)
|
||||
ptpnInfo = dbCalloc(1, sizeof(tpnInfo));
|
||||
ptpnInfo->ppn = ppn;
|
||||
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
|
||||
strncpy(ptpnInfo->buffer, pvalue, 80);
|
||||
ptpnInfo->buffer[79] = 0;
|
||||
if (pvalue) {
|
||||
strncpy(ptpnInfo->buffer, pvalue, sizeof(ptpnInfo->buffer));
|
||||
ptpnInfo->buffer[sizeof(ptpnInfo->buffer)-1] = 0;
|
||||
}
|
||||
|
||||
ppn->usrPvt = ptpnInfo;
|
||||
epicsThreadCreate("dbtpn", epicsThreadPriorityHigh,
|
||||
|
||||
@@ -130,7 +130,7 @@ DBCORE_API int dbNotifyDump(void);
|
||||
* if a process request is issued and also calls the client callbacks.
|
||||
*
|
||||
* A process request is issued if any of the following is true.
|
||||
* 1) The requester has issued a processs request and record is passive.
|
||||
* 1) The requester has issued a process request and record is passive.
|
||||
* 2) The requester is doing a put, the record is passive, and either
|
||||
* a) The field description is process passive.
|
||||
* b) The field is PROC.
|
||||
@@ -156,7 +156,7 @@ DBCORE_API int dbNotifyDump(void);
|
||||
* As soon as a record completes processing the field is set NULL
|
||||
* ppnr pointer to processNotifyRecord, which is a private structure
|
||||
* owned by dbNotify.
|
||||
* dbNotify is reponsible for this structure.
|
||||
* dbNotify is responsible for this structure.
|
||||
*
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user