Compare commits
315 Commits
R3.15.5-rc
...
R3.15.6-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b319b4722f | ||
|
|
b4cc5fdf4b | ||
|
|
d35835659c | ||
|
|
cbb13bf6b1 | ||
|
|
150d764d28 | ||
|
|
7dd1ea4cab | ||
|
|
922ed30136 | ||
|
|
9f9f119e7e | ||
|
|
d8214a4531 | ||
|
|
120b100e7e | ||
|
|
949e9d788a | ||
|
|
27c6e6a385 | ||
|
|
4b59476170 | ||
|
|
526b565c6b | ||
|
|
1b7b2bcceb | ||
|
|
49c925d064 | ||
|
|
6a2ed4b333 | ||
|
|
d3bcf5737f | ||
|
|
6c5505ad3e | ||
|
|
4247d98b08 | ||
|
|
13735a8088 | ||
|
|
58d4242b68 | ||
|
|
8e42f516b0 | ||
|
|
9051cdbb34 | ||
|
|
8ffea9de27 | ||
|
|
2548a37267 | ||
|
|
1dc1b25aaa | ||
|
|
fb31dd784b | ||
|
|
fe7260e263 | ||
|
|
67e2b74758 | ||
|
|
c09b6e2f1b | ||
|
|
45be2306bd | ||
|
|
6027f906c3 | ||
|
|
ec351c5e2f | ||
| 89870e2817 | |||
| 4e9cf72d71 | |||
| 80869a0868 | |||
| 998fa984ba | |||
| 31844af88e | |||
| 8f161f9463 | |||
| e0399478ad | |||
|
|
2a2a1e54ac | ||
|
|
20d2cff501 | ||
|
|
860ce156a2 | ||
|
|
0f21196670 | ||
|
|
31fc35fbe8 | ||
|
|
f892731b3f | ||
| ab493264b2 | |||
| 68779943eb | |||
| 7a5ff26984 | |||
| eae59183cc | |||
|
|
8144d2ea01 | ||
|
|
b32629c3bf | ||
|
|
220e404203 | ||
|
|
8f55a1307d | ||
|
|
e459e8bdd4 | ||
|
|
b558bd9b16 | ||
|
|
3c16c3c0da | ||
|
|
a9d7f7be13 | ||
|
|
23c4eb42a3 | ||
|
|
6d7f70f200 | ||
|
|
67844bacc3 | ||
|
|
7e7d230d8c | ||
|
|
c1ece40f41 | ||
|
|
a732539eee | ||
|
|
3bc0805a89 | ||
|
|
c72e35c769 | ||
|
|
2d9c5e99a1 | ||
|
|
ca22d50831 | ||
|
|
4972803ce2 | ||
|
|
3b7e348a8c | ||
|
|
00a974ce52 | ||
|
|
490c504736 | ||
|
|
49371cfe00 | ||
|
|
06ad4a0d70 | ||
|
|
a2ae07dfcd | ||
|
|
b539ced6d5 | ||
|
|
1b332361e7 | ||
|
|
5cb91d9f6d | ||
|
|
116c90c2ea | ||
|
|
3f3696fb91 | ||
|
|
91ce807e8b | ||
|
|
3d88316eab | ||
|
|
b9443f8813 | ||
|
|
d8802c8b24 | ||
|
|
b7d4609e57 | ||
|
|
7b5b23f6d3 | ||
|
|
c8a7e1597d | ||
|
|
8333338f99 | ||
|
|
ceaff61c09 | ||
|
|
2307e94d1c | ||
|
|
05a3699b49 | ||
|
|
be8f35d782 | ||
|
|
6cc623a7b4 | ||
| 2b4a9632b7 | |||
| 396cf4ee3f | |||
|
|
a9764c8f62 | ||
|
|
98d9ea4545 | ||
|
|
8eb4eec7d2 | ||
|
|
98930eebc4 | ||
| e50c468512 | |||
|
|
c18b6f2ccf | ||
|
|
e41f8bf518 | ||
|
|
ae548d3400 | ||
| 428a8f57e9 | |||
| 29795656e6 | |||
| b2d6b67b06 | |||
| 1e9826d187 | |||
| 0691fc5f57 | |||
| 8a3080c16f | |||
| d19afc73af | |||
| adf5375616 | |||
|
|
550beeab9f | ||
|
|
bf91275200 | ||
|
|
ac4d5c95ac | ||
| 7d836d9554 | |||
| 51e492fbb1 | |||
|
|
61296b8cff | ||
|
|
de442e9584 | ||
|
|
ac367398b3 | ||
|
|
713c2d5080 | ||
|
|
af07016464 | ||
|
|
734d16291f | ||
|
|
f1e5e9689b | ||
|
|
1454f42a27 | ||
|
|
ddbdcf9462 | ||
|
|
729e6fda4d | ||
|
|
0315e90e6e | ||
|
|
66c6aaa44f | ||
|
|
c830a3a4ee | ||
|
|
8766ce05aa | ||
|
|
8f62940265 | ||
|
|
8a1477ecab | ||
|
|
89cbb95c2c | ||
|
|
006ce1a240 | ||
|
|
276dee2c3e | ||
|
|
98a2871727 | ||
|
|
5ca1bb3bd5 | ||
|
|
f6be3c7f70 | ||
|
|
00924dcba0 | ||
|
|
3b0f34e0be | ||
|
|
db005ac3fe | ||
|
|
0f0deb8903 | ||
|
|
baf997193e | ||
|
|
5278799575 | ||
|
|
031e755303 | ||
|
|
e794639e31 | ||
|
|
2af98c33c9 | ||
|
|
e38252eecc | ||
|
|
31c7d91884 | ||
|
|
42d37eb19a | ||
|
|
cec4f4e24b | ||
|
|
58460d25b9 | ||
|
|
9e75b8b32d | ||
|
|
32a6f6c4f1 | ||
|
|
169e9f2699 | ||
|
|
22debb3532 | ||
|
|
c441cdd5a4 | ||
|
|
6ee2cc6039 | ||
|
|
13fa1e2722 | ||
|
|
fad89189da | ||
|
|
2e4634853c | ||
|
|
e0757204cc | ||
|
|
78abb25884 | ||
|
|
73f3e76150 | ||
|
|
4ab56518a0 | ||
|
|
80dbc7aeef | ||
|
|
238f6772bd | ||
|
|
dc9859cee9 | ||
|
|
5d5f27a486 | ||
|
|
ad6a16d7c4 | ||
|
|
111cac8e47 | ||
|
|
5c8e5c52ef | ||
|
|
546df1c1f0 | ||
|
|
603331e7a5 | ||
|
|
4b272cc0cf | ||
|
|
619a99bf99 | ||
|
|
1f8cb740f1 | ||
|
|
322f7a97de | ||
|
|
0fc770166c | ||
|
|
f04f17f9bf | ||
|
|
1a70855e25 | ||
|
|
745109e423 | ||
|
|
b9d2712738 | ||
|
|
a69bd833fc | ||
|
|
630b4f375d | ||
|
|
9d4a90ac34 | ||
|
|
83cb50574a | ||
|
|
6b5e7da4fd | ||
|
|
69d530f1db | ||
|
|
411a60c32d | ||
|
|
105e831442 | ||
|
|
a1dc16848c | ||
|
|
2819d7ea3d | ||
|
|
6ef995525a | ||
|
|
18dee384ec | ||
|
|
b369aa67f1 | ||
|
|
085fab4aed | ||
|
|
c853234e01 | ||
|
|
1293747cf3 | ||
|
|
9c859ffdca | ||
|
|
29c069db3d | ||
|
|
12d22e392f | ||
|
|
0dc850f4ec | ||
|
|
98b0f7e48b | ||
|
|
672fd16ec8 | ||
|
|
dcadeac903 | ||
|
|
0b3e44747e | ||
|
|
b7b3dd2b37 | ||
|
|
b14d77dcf2 | ||
|
|
cb89710bbd | ||
|
|
b3bbf67ce8 | ||
|
|
82396ee3ef | ||
|
|
a7c14ec995 | ||
|
|
e430d097b7 | ||
|
|
875e4db3f9 | ||
|
|
8c8604c503 | ||
|
|
9d7c4434ad | ||
|
|
67e12bca9f | ||
|
|
15cb72acbc | ||
|
|
45ed461665 | ||
|
|
3986e43135 | ||
|
|
daad3c6995 | ||
|
|
38be82a154 | ||
|
|
27cd9fd051 | ||
|
|
1ffce72a38 | ||
|
|
dcac64d50f | ||
|
|
0bf789db4c | ||
|
|
57cbe61709 | ||
|
|
a2ab17a782 | ||
|
|
c6910decfc | ||
|
|
b01dd38526 | ||
|
|
d825f87359 | ||
|
|
82ff67a204 | ||
|
|
e751480b06 | ||
|
|
3184371e8d | ||
|
|
f2e54be965 | ||
|
|
c22670cbb0 | ||
|
|
35385bc688 | ||
|
|
c5decfbd12 | ||
|
|
e25a2964bc | ||
|
|
22b10adf29 | ||
|
|
8382367495 | ||
|
|
821fb1302b | ||
|
|
64c16c0f6e | ||
|
|
9f01c47542 | ||
|
|
aca7b44a05 | ||
|
|
b8f542fc0d | ||
|
|
6f9905d060 | ||
|
|
f3841c4767 | ||
|
|
4f8fd545fa | ||
|
|
d4552af39b | ||
|
|
0c02c5cb30 | ||
|
|
1f90e98491 | ||
|
|
352fd32c45 | ||
|
|
b624222a0f | ||
|
|
739a112bec | ||
|
|
5e082bb75d | ||
|
|
8ebfd0821a | ||
|
|
fc8d4c2b5f | ||
|
|
1888253093 | ||
|
|
8edefb9d63 | ||
|
|
0f31e35b87 | ||
|
|
5a73ac59a1 | ||
|
|
e0af3e2af5 | ||
|
|
5726ca6964 | ||
|
|
f164b14ba1 | ||
|
|
4c06cdc660 | ||
|
|
f71102982f | ||
|
|
d6b0c3041e | ||
|
|
214e9534cc | ||
|
|
2a0cd00958 | ||
|
|
d744b06a28 | ||
|
|
048b75304d | ||
|
|
aaafb1a5de | ||
|
|
5783823e25 | ||
|
|
de698f370a | ||
|
|
faf691a5be | ||
|
|
3a0e52fc3f | ||
|
|
a105c6f538 | ||
|
|
73eecbb759 | ||
|
|
3e58c59377 | ||
|
|
b9ae6c3308 | ||
|
|
3fd659e693 | ||
|
|
7310d78057 | ||
|
|
dfc1b8ac23 | ||
|
|
49e0e23f76 | ||
|
|
4a0fd0b954 | ||
|
|
20dda339cc | ||
|
|
7ec6be5d14 | ||
|
|
eff44268e9 | ||
|
|
fd53e175b4 | ||
|
|
85b5551b3b | ||
|
|
260bc64b59 | ||
|
|
5097ac3230 | ||
|
|
8d7bf52e51 | ||
|
|
a13416309c | ||
|
|
1cb75ebb6e | ||
|
|
63b059c35e | ||
|
|
dba6971e07 | ||
|
|
94397b52fc | ||
|
|
7fe152ce1b | ||
|
|
d3568605ce | ||
|
|
666721c7ad | ||
|
|
c3bb2bf2c2 | ||
| 0f7f4710c6 | |||
|
|
2841af7069 | ||
|
|
726d7c6715 | ||
|
|
f1439f8b1c | ||
|
|
aa6e976f92 | ||
|
|
3e0ddbb542 | ||
|
|
67daaaa9b7 | ||
|
|
a36443557b | ||
|
|
428268a71e | ||
|
|
746c739769 |
@@ -1,9 +0,0 @@
|
||||
./bin
|
||||
./lib
|
||||
./db
|
||||
./dbd
|
||||
./html
|
||||
./include
|
||||
./templates
|
||||
**/O.*
|
||||
./QtC-*
|
||||
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/cfg/
|
||||
/bin/
|
||||
/lib/
|
||||
/db/
|
||||
/dbd/
|
||||
/html/
|
||||
/include/
|
||||
/templates/
|
||||
/configure/*.local
|
||||
O.*/
|
||||
/QtC-*
|
||||
*.orig
|
||||
*.log
|
||||
.*.swp
|
||||
32
.travis.yml
Normal file
32
.travis.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
sudo: false
|
||||
dist: trusty
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
env:
|
||||
- CMPLR=gcc
|
||||
- CMPLR=gcc EXTRA=CMD_CXXFLAGS=-std=c++11
|
||||
- CMPLR=gcc STATIC=YES
|
||||
- CMPLR=clang
|
||||
- CMPLR=clang STATIC=YES
|
||||
- WINE=32 TEST=NO STATIC=YES
|
||||
- WINE=32 TEST=NO STATIC=NO
|
||||
- RTEMS=4.10 TEST=NO
|
||||
- RTEMS=4.9 TEST=NO
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libreadline6-dev
|
||||
- libncurses5-dev
|
||||
- perl
|
||||
- clang
|
||||
- g++-mingw-w64-i686
|
||||
- bison
|
||||
- flex
|
||||
- texinfo
|
||||
- install-info
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache
|
||||
install: sh ci/travis-prepare.sh </dev/null
|
||||
script: sh ci/travis-build.sh </dev/null
|
||||
2
README
2
README
@@ -20,5 +20,5 @@ Additional information about EPICS including mailing list
|
||||
archives and subscription instructions, documentation and
|
||||
training materials, additional components, links to other
|
||||
websites etc. is available on the EPICS home page at
|
||||
http://www.aps.anl.gov/epics/
|
||||
https://epics.anl.gov/
|
||||
|
||||
|
||||
85
appveyor.yml
Normal file
85
appveyor.yml
Normal file
@@ -0,0 +1,85 @@
|
||||
# AppVeyor configuration for EPICS Base
|
||||
|
||||
# Ralph Lange <ralph.lange@gmx.de>
|
||||
# Copyright (c) 2016-2017 ITER Organization
|
||||
|
||||
# Version format
|
||||
version: base-{branch}-{build}
|
||||
|
||||
#---------------------------------#
|
||||
# repository cloning #
|
||||
#---------------------------------#
|
||||
|
||||
# Called at very beginning, before repo cloning
|
||||
init:
|
||||
# Set autocrlf to make batch files work
|
||||
- git config --global core.autocrlf true
|
||||
|
||||
# Set clone depth (do not fetch complete history)
|
||||
clone_depth: 2
|
||||
|
||||
# Skipping commits affecting only specific files
|
||||
skip_commits:
|
||||
files:
|
||||
- 'documentation/*'
|
||||
- 'templates/*'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
#---------------------------------#
|
||||
# build matrix configuration #
|
||||
#---------------------------------#
|
||||
|
||||
# Build Configurations: dll/static, regular/debug
|
||||
configuration:
|
||||
- dynamic
|
||||
- static
|
||||
- dynamic-debug
|
||||
- static-debug
|
||||
|
||||
# Environment variables: compiler toolchain
|
||||
environment:
|
||||
matrix:
|
||||
- TOOLCHAIN: 10.0
|
||||
- TOOLCHAIN: 11.0
|
||||
- TOOLCHAIN: 12.0
|
||||
- TOOLCHAIN: 14.0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLCHAIN: 2017
|
||||
- TOOLCHAIN: cygwin
|
||||
- TOOLCHAIN: mingw
|
||||
|
||||
# Platform: architecture
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
|
||||
# Matrix configuration: allow specific failing jobs
|
||||
matrix:
|
||||
exclude:
|
||||
# VS Express installs don't have the 64 bit compiler
|
||||
- platform: x64
|
||||
TOOLCHAIN: 10.0
|
||||
|
||||
#---------------------------------#
|
||||
# building & testing #
|
||||
#---------------------------------#
|
||||
|
||||
install:
|
||||
- cmd: ci/appveyor-prepare.bat
|
||||
|
||||
build_script:
|
||||
- cmd: ci/appveyor-make.bat
|
||||
|
||||
test_script:
|
||||
- cmd: ci/appveyor-make.bat runtests
|
||||
|
||||
#---------------------------------#
|
||||
# notifications #
|
||||
#---------------------------------#
|
||||
|
||||
notifications:
|
||||
|
||||
- provider: Slack
|
||||
incoming_webhook:
|
||||
secure: RYOm3FIUYeZGjWKaeTVKwq+C3fzK54AKwbmAoECED45mex3lN+8HmrC845a6mg9xPUJ/ND51RopWVaKDD9/UzaM0SO195RQLKqUTIUafiuM=
|
||||
137
ci/appveyor-make.bat
Normal file
137
ci/appveyor-make.bat
Normal file
@@ -0,0 +1,137 @@
|
||||
:: Universal build script for AppVeyor (https://ci.appveyor.com/)
|
||||
:: Environment:
|
||||
:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/cygwin/mingw]
|
||||
:: CONFIGURATION - determines EPICS build [dynamic/static]
|
||||
:: PLATFORM - architecture [x86/x64]
|
||||
::
|
||||
:: All command line args are passed to make
|
||||
|
||||
Setlocal EnableDelayedExpansion
|
||||
|
||||
set "ST="
|
||||
if /i "%CONFIGURATION%"=="static" set ST=-static
|
||||
|
||||
set OS=64BIT
|
||||
if "%PLATFORM%"=="x86" set OS=32BIT
|
||||
|
||||
echo [INFO] Platform: %OS%
|
||||
|
||||
:: Use parallel make, except for 3.14
|
||||
set "MAKEARGS=-j2 -Otarget"
|
||||
if "%APPVEYOR_REPO_BRANCH%"=="3.14" set MAKEARGS=
|
||||
|
||||
if "%TOOLCHAIN%"=="cygwin" (
|
||||
set "MAKE=make"
|
||||
if "%OS%"=="64BIT" (
|
||||
set "EPICS_HOST_ARCH=cygwin-x86_64"
|
||||
set "INCLUDE=C:\cygwin64\include;%INCLUDE%"
|
||||
set "PATH=C:\cygwin64\bin;%PATH%"
|
||||
echo [INFO] Cygwin Toolchain 64bit
|
||||
) else (
|
||||
set "EPICS_HOST_ARCH=cygwin-x86"
|
||||
set "INCLUDE=C:\cygwin\include;%INCLUDE%"
|
||||
set "PATH=C:\cygwin\bin;%PATH%"
|
||||
echo [INFO] Cygwin Toolchain 32bit
|
||||
)
|
||||
echo [INFO] Compiler Version
|
||||
gcc -v
|
||||
goto Finish
|
||||
)
|
||||
|
||||
if "%TOOLCHAIN%"=="mingw" (
|
||||
set "MAKE=mingw32-make"
|
||||
if "%OS%"=="64BIT" (
|
||||
set "EPICS_HOST_ARCH=windows-x64-mingw"
|
||||
set "INCLUDE=C:\tools\mingw64\include;%INCLUDE%"
|
||||
set "PATH=C:\tools\mingw64\bin;%PATH%"
|
||||
echo [INFO] MinGW Toolchain 64bit
|
||||
) else (
|
||||
set "EPICS_HOST_ARCH=win32-x86-mingw"
|
||||
set "INCLUDE=C:\tools\mingw32\include;%INCLUDE%"
|
||||
set "PATH=C:\tools\mingw32\bin;%PATH%"
|
||||
echo [INFO] MinGW Toolchain 32bit
|
||||
)
|
||||
echo [INFO] Compiler Version
|
||||
gcc -v
|
||||
goto Finish
|
||||
)
|
||||
|
||||
set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio %TOOLCHAIN%"
|
||||
if not exist "%VSINSTALL%\" set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio\%TOOLCHAIN%\Community"
|
||||
if not exist "%VSINSTALL%\" goto MSMissing
|
||||
|
||||
set "MAKE=C:\tools\make"
|
||||
|
||||
echo [INFO] APPVEYOR_BUILD_WORKER_IMAGE=%APPVEYOR_BUILD_WORKER_IMAGE%
|
||||
|
||||
if "%OS%"=="64BIT" (
|
||||
set EPICS_HOST_ARCH=windows-x64%ST%
|
||||
:: VS 2017
|
||||
if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" (
|
||||
call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat"
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||
goto MSFound
|
||||
)
|
||||
if exist "%VSINSTALL%\VC\vcvarsall.bat" (
|
||||
call "%VSINSTALL%\VC\vcvarsall.bat" amd64
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 (
|
||||
call "%VSINSTALL%\VC\vcvarsall.bat" x86_amd64
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||
)
|
||||
goto MSFound
|
||||
)
|
||||
if exist "%VSINSTALL%\VC\bin\amd64\vcvars64.bat" (
|
||||
call "%VSINSTALL%\VC\bin\amd64\vcvars64.bat"
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||
goto MSFound
|
||||
)
|
||||
) else (
|
||||
set EPICS_HOST_ARCH=win32-x86%ST%
|
||||
:: VS 2017
|
||||
if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat" (
|
||||
call "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat"
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||
goto MSFound
|
||||
)
|
||||
if exist "%VSINSTALL%\VC\vcvarsall.bat" (
|
||||
call "%VSINSTALL%\VC\vcvarsall.bat" x86
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||
goto MSFound
|
||||
)
|
||||
if exist "%VSINSTALL%\VC\bin\vcvars32.bat" (
|
||||
call "%VSINSTALL%\VC\bin\vcvars32.bat"
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||
goto MSFound
|
||||
)
|
||||
if exist "%VSINSTALL%\Common7\Tools\vsvars32.bat" (
|
||||
call "%VSINSTALL%\Common7\Tools\vsvars32.bat"
|
||||
where cl
|
||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||
goto MSFound
|
||||
)
|
||||
)
|
||||
|
||||
:MSMissing
|
||||
echo [INFO] Installation for MSVC Toolchain %TOOLCHAIN% / %OS% seems to be missing
|
||||
exit 1
|
||||
|
||||
:MSFound
|
||||
echo [INFO] Microsoft Visual Studio Toolchain %TOOLCHAIN%
|
||||
echo [INFO] Compiler Version
|
||||
cl
|
||||
|
||||
:Finish
|
||||
echo [INFO] EPICS_HOST_ARCH: %EPICS_HOST_ARCH%
|
||||
echo [INFO] Make version
|
||||
%MAKE% --version
|
||||
echo [INFO] Perl version
|
||||
perl --version
|
||||
|
||||
%MAKE% %MAKEARGS% %*
|
||||
70
ci/appveyor-prepare.bat
Normal file
70
ci/appveyor-prepare.bat
Normal file
@@ -0,0 +1,70 @@
|
||||
:: Build script for AppVeyor (https://ci.appveyor.com/)
|
||||
:: Environment:
|
||||
:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/cygwin/mingw]
|
||||
:: CONFIGURATION - determines EPICS build [dynamic/static, -debug]
|
||||
:: PLATFORM - "x86" -> use 32bit architecture
|
||||
::
|
||||
:: Prepares an Appveyor build by excuting the following steps
|
||||
:: - Set up configure\CONFIG_SITE for static vs. dynamic build
|
||||
:: - Install Cygwin / Mingw (TOOLCHAIN setting) in the in the appropriate flavor
|
||||
:: - Download and install Make-4.1 from EPICS download page
|
||||
|
||||
Setlocal EnableDelayedExpansion
|
||||
|
||||
set OS=64BIT
|
||||
if "%PLATFORM%"=="x86" set OS=32BIT
|
||||
|
||||
echo [INFO] Platform: %OS%
|
||||
|
||||
if "%TOOLCHAIN%"=="cygwin" (
|
||||
echo.%CONFIGURATION% | findstr /C:"static">nul && (
|
||||
echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE
|
||||
echo STATIC_BUILD=YES>> configure\CONFIG_SITE
|
||||
echo [INFO] EPICS set up for static build
|
||||
) || (
|
||||
echo [INFO] EPICS set up for dynamic build
|
||||
)
|
||||
echo.%CONFIGURATION% | findstr /C:"debug">nul && (
|
||||
echo HOST_OPT=NO>> configure\CONFIG_SITE
|
||||
echo [INFO] EPICS set up for debug build
|
||||
) || (
|
||||
echo [INFO] EPICS set up for optimized build
|
||||
)
|
||||
if "%OS%"=="64BIT" (
|
||||
echo [INFO] Installing Cygwin 64bit and dependencies
|
||||
@powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86_64.exe', 'C:\cygwin64\setup-x86_64.exe')"
|
||||
C:\cygwin64\setup-x86_64.exe -q -P "libreadline-devel,libncursesw-devel"
|
||||
) else (
|
||||
echo [INFO] Installing Cygwin 32bit and dependencies
|
||||
@powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86.exe', 'C:\cygwin\setup-x86.exe')"
|
||||
C:\cygwin\setup-x86.exe -q -P "libreadline-devel,libncursesw-devel"
|
||||
)
|
||||
)
|
||||
|
||||
if "%TOOLCHAIN%"=="mingw" (
|
||||
echo.%CONFIGURATION% | findstr /C:"static">nul && (
|
||||
echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE
|
||||
echo STATIC_BUILD=YES>> configure\CONFIG_SITE
|
||||
echo [INFO] EPICS set up for static build
|
||||
) || (
|
||||
echo [INFO] EPICS set up for dynamic build
|
||||
)
|
||||
echo.%CONFIGURATION% | findstr /C:"debug">nul && (
|
||||
echo HOST_OPT=NO>> configure\CONFIG_SITE
|
||||
echo [INFO] EPICS set up for debug build
|
||||
) || (
|
||||
echo [INFO] EPICS set up for optimized build
|
||||
)
|
||||
if "%OS%"=="64BIT" (
|
||||
echo [INFO] Installing MinGW 64bit
|
||||
cinst mingw || cinst mingw
|
||||
) else (
|
||||
echo [INFO] Installing MinGW 32bit
|
||||
cinst mingw --x86 || cinst mingw --x86
|
||||
)
|
||||
)
|
||||
|
||||
echo [INFO] Installing Make 4.1
|
||||
curl -fsS --retry 3 -o C:\tools\make-4.1.zip https://epics.anl.gov/download/tools/make-4.1-win64.zip
|
||||
cd \tools
|
||||
"C:\Program Files\7-Zip\7z" e make-4.1.zip
|
||||
90
ci/travis-build.sh
Normal file
90
ci/travis-build.sh
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
die() {
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
ticker() {
|
||||
while true
|
||||
do
|
||||
sleep 60
|
||||
date -R
|
||||
[ -r "$1" ] && tail -n10 "$1"
|
||||
done
|
||||
}
|
||||
|
||||
CACHEKEY=1
|
||||
|
||||
EPICS_HOST_ARCH=`perl src/tools/EpicsHostArch.pl`
|
||||
|
||||
[ -e configure/os/CONFIG_SITE.Common.linux-x86 ] || die "Wrong location: $PWD"
|
||||
|
||||
case "$CMPLR" in
|
||||
clang)
|
||||
echo "Host compiler is clang"
|
||||
cat << EOF >> configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
|
||||
GNU = NO
|
||||
CMPLR_CLASS = clang
|
||||
CC = clang
|
||||
CCC = clang++
|
||||
EOF
|
||||
;;
|
||||
*) echo "Host compiler is default";;
|
||||
esac
|
||||
|
||||
if [ "$STATIC" = "YES" ]
|
||||
then
|
||||
echo "Build static libraries/executables"
|
||||
cat << EOF >> configure/CONFIG_SITE
|
||||
SHARED_LIBRARIES=NO
|
||||
STATIC_BUILD=YES
|
||||
EOF
|
||||
fi
|
||||
|
||||
# requires wine and g++-mingw-w64-i686
|
||||
if [ "$WINE" = "32" ]
|
||||
then
|
||||
echo "Cross mingw32"
|
||||
sed -i -e '/CMPLR_PREFIX/d' configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
cat << EOF >> configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
CMPLR_PREFIX=i686-w64-mingw32-
|
||||
EOF
|
||||
cat << EOF >> configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
|
||||
EOF
|
||||
fi
|
||||
|
||||
# set RTEMS to eg. "4.9" or "4.10"
|
||||
# requires qemu, bison, flex, texinfo, install-info
|
||||
if [ -n "$RTEMS" ]
|
||||
then
|
||||
echo "Cross RTEMS${RTEMS} for pc386"
|
||||
install -d /home/travis/.cache
|
||||
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \
|
||||
| tar -C /home/travis/.cache -xj
|
||||
|
||||
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS
|
||||
cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS
|
||||
RTEMS_VERSION=$RTEMS
|
||||
RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386
|
||||
EOF
|
||||
cat << EOF >> configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
|
||||
EOF
|
||||
|
||||
# find local qemu-system-i386
|
||||
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
|
||||
echo -n "Using QEMU: "
|
||||
type qemu-system-i386 || echo "Missing qemu"
|
||||
EXTRA=RTEMS_QEMU_FIXUPS=YES
|
||||
fi
|
||||
|
||||
make -j2 $EXTRA
|
||||
|
||||
if [ "$TEST" != "NO" ]
|
||||
then
|
||||
make tapfiles
|
||||
make -s test-results
|
||||
fi
|
||||
40
ci/travis-prepare.sh
Normal file
40
ci/travis-prepare.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
die() {
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
CURDIR="$PWD"
|
||||
|
||||
QDIR="$HOME/.cache/qemu"
|
||||
|
||||
if [ -n "$RTEMS" -a "$TEST" = "YES" ]
|
||||
then
|
||||
git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
|
||||
cd "$HOME/.build/qemu"
|
||||
|
||||
HEAD=`git log -n1 --pretty=format:%H`
|
||||
echo "HEAD revision $HEAD"
|
||||
|
||||
[ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
|
||||
echo "Cached revision $BUILT"
|
||||
|
||||
if [ "$HEAD" != "$BUILT" ]
|
||||
then
|
||||
echo "Building QEMU"
|
||||
git submodule --quiet update --init
|
||||
|
||||
install -d "$HOME/.build/qemu/build"
|
||||
cd "$HOME/.build/qemu/build"
|
||||
|
||||
"$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
|
||||
make -j2
|
||||
make install
|
||||
|
||||
echo "$HEAD" > "$HOME/.cache/qemu/built"
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$CURDIR"
|
||||
@@ -20,11 +20,15 @@ else
|
||||
endif
|
||||
|
||||
# Provide a default if the user hasn't set EPICS_HOST_ARCH
|
||||
ifeq ($(origin EPICS_HOST_ARCH), undefined)
|
||||
# NB: We use a simply expanded variable here for performance:
|
||||
EPICS_HOST_ARCH := $(shell $(CONFIG)/../startup/EpicsHostArch.pl)
|
||||
endif
|
||||
#
|
||||
ifeq ($(origin EPICS_HOST_ARCH), undefined)
|
||||
# Bootstrapping ...
|
||||
EHA := $(firstword $(wildcard $(EPICS_BASE)/lib/perl/EpicsHostArch.pl \
|
||||
$(TOP)/src/tools/EpicsHostArch.pl))
|
||||
# NB: We use a simply expanded variable here for performance:
|
||||
export EPICS_HOST_ARCH := $(shell perl $(EHA))
|
||||
EHA :=
|
||||
endif
|
||||
|
||||
-include $(CONFIG)/RELEASE
|
||||
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH)
|
||||
@@ -73,17 +77,17 @@ ifdef T_A
|
||||
#
|
||||
-include $(CONFIG)/os/CONFIG.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
# Site specific target and host-target definitions and overrides
|
||||
#
|
||||
-include $(CONFIG)/os/CONFIG_SITE.Common.$(T_A)
|
||||
-include $(CONFIG)/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
# RELEASE file specific definitions
|
||||
#
|
||||
ifneq ($(CONFIG),$(TOP)/configure)
|
||||
-include $(CONFIG)/CONFIG_APP_INCLUDE
|
||||
endif
|
||||
|
||||
# Site specific target and host-target definitions
|
||||
#
|
||||
-include $(CONFIG)/os/CONFIG_SITE.Common.$(T_A)
|
||||
-include $(CONFIG)/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
endif # ifdef T_A
|
||||
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@ BUILD_CLASS = CROSS
|
||||
# ifdef CROSS looks better than ifeq ($(BUILD_CLASS),CROSS)
|
||||
CROSS = YES
|
||||
|
||||
GNU_TARGET_INCLUDE_DIR = $(GNU_TARGET:%= $(GNU_DIR)/%/include)
|
||||
GNU_TARGET_LIB_DIR = $(GNU_TARGET:%= $(GNU_DIR)/%/lib)
|
||||
GNU_TARGET_INCLUDE_DIR = $(wildcard $(GNU_TARGET:%=$(GNU_DIR)/%/include))
|
||||
GNU_TARGET_LIB_DIR = $(wildcard $(GNU_TARGET:%=$(GNU_DIR)/%/lib))
|
||||
|
||||
CROSS_INCLUDES = $(addprefix -I,$(GNU_TARGET_INCLUDE_DIR))
|
||||
CROSS_LDFLAGS = $(addprefix -L,$(GNU_TARGET_LIB_DIR))
|
||||
CROSS_INCLUDES = $(GNU_TARGET_INCLUDE_DIR:%=-I%)
|
||||
CROSS_LDFLAGS = $(GNU_TARGET_LIB_DIR:%=-L%)
|
||||
|
||||
CMPLR_PREFIX_CROSS=$(addsuffix -,$(GNU_TARGET))
|
||||
CMPLR_PREFIX=$(CMPLR_PREFIX_$(BUILD_CLASS))
|
||||
CMPLR_PREFIX_CROSS = $(addsuffix -,$(GNU_TARGET))
|
||||
CMPLR_PREFIX = $(CMPLR_PREFIX_$(BUILD_CLASS))
|
||||
|
||||
# Cross builds usually use the gnu compiler
|
||||
include $(CONFIG)/CONFIG.gnuCommon
|
||||
|
||||
@@ -68,6 +68,7 @@ DBTOMENUH = $(PERL) $(TOOLS)/dbdToMenuH.pl
|
||||
REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl
|
||||
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
|
||||
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
|
||||
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
|
||||
|
||||
#-------------------------------------------------------
|
||||
# tools for installing libraries and products
|
||||
|
||||
@@ -27,7 +27,7 @@ EPICS_VERSION = 3
|
||||
EPICS_REVISION = 15
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 5
|
||||
EPICS_MODIFICATION = 6
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included if zero
|
||||
|
||||
@@ -117,11 +117,10 @@ CROSS_COMPILER_TARGET_ARCHS=
|
||||
# configure/os/CONFIG_SITE.<host>.Common files instead.
|
||||
CROSS_COMPILER_HOST_ARCHS=
|
||||
|
||||
# The 'make runtests' and 'make tapfiles' build targets normally only run
|
||||
# The 'runtests', 'tapfiles' and 'junitfiles' make targets normally only run
|
||||
# self-tests for the EPICS_HOST_ARCH architecture. If the host can execute
|
||||
# the self-test programs for any other cross-built architectures such as
|
||||
# a -debug architecture, those architectures can be named here.
|
||||
#
|
||||
# a -debug architecture, those architectures must be named in this variable:
|
||||
CROSS_COMPILER_RUNTEST_ARCHS=
|
||||
|
||||
# Build shared libraries (DLLs on Windows).
|
||||
@@ -175,3 +174,5 @@ GCC_PIPE = NO
|
||||
# run at build-time, e.g. set the LD_LIBRARY_PATH environment variable.
|
||||
LINKER_USE_RPATH = YES
|
||||
|
||||
# Overrides for the settings above may appear in a CONFIG_SITE.local file
|
||||
-include $(CONFIG)/CONFIG_SITE.local
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#
|
||||
# CONFIG_SITE_ENV - EPICS Environment Parameter Site configuration file
|
||||
#
|
||||
# This file is read by the script base/src/libCom/env/bldEnvdata.pl
|
||||
# This file is read by the script base/src/libCom/env/bldEnvData.pl
|
||||
# Variable definitions must take the form
|
||||
# VAR = VALUE
|
||||
# or
|
||||
@@ -26,31 +26,42 @@
|
||||
|
||||
# Time service:
|
||||
# EPICS_TIMEZONE
|
||||
# local timezone info for vxWorks and RTEMS IOCs. The format is
|
||||
# <name>::<minutesWest>:<start daylight>:<end daylight>
|
||||
# where the start and end are mmddhh - that is month,day,hour
|
||||
# e.g. for ANL in 2016: EPICS_TIMEZONE=CST/CDT::360:031302:110602
|
||||
# Local timezone info for vxWorks and RTEMS. The format is
|
||||
# <name>::<minutesWest>:<startDST>:<endDST>
|
||||
# where <name> is only used by strftime() for %Z conversions,
|
||||
# and <startDST> and <endDST> are mmddhh - that is month,day,hour
|
||||
# e.g. for ANL in 2018: EPICS_TIMEZONE=CUS::360:031102:110402
|
||||
# The future dates below assume the rules don't get changed;
|
||||
# see http://www.timeanddate.com/time/dst/2018.html to check.
|
||||
#
|
||||
# DST for 2016 US: Mar 13 - Nov 06
|
||||
# EU: Mar 27 - Oct 30
|
||||
# DST for 2017 US: Mar 12 - Nov 05
|
||||
# EU: Mar 26 - Oct 29
|
||||
# DST for 2018 US: Mar 11 - Nov 04
|
||||
# EU: Mar 25 - Oct 28
|
||||
EPICS_TIMEZONE = CUS::360:031102:110402
|
||||
#EPICS_TIMEZONE = MET::-60:032502:102803
|
||||
#
|
||||
# DST for 2019 US: Mar 10 - Nov 03
|
||||
# EU: Mar 31 - Oct 27
|
||||
#EPICS_TIMEZONE = CUS::360:031002:110302
|
||||
#EPICS_TIMEZONE = MET::-60:033102:102703
|
||||
#
|
||||
# DST for 2020 US: Mar 08 - Nov 01
|
||||
# EU: Mar 29 - Oct 25
|
||||
#EPICS_TIMEZONE = CUS::360:030802:110102
|
||||
#EPICS_TIMEZONE = MET::-60:032902:102503
|
||||
#
|
||||
# DST for 2021 US: Mar 14 - Nov 07
|
||||
# EU: Mar 28 - Oct 31
|
||||
# (see: http://www.timeanddate.com/time/dst/2016.html etc. )
|
||||
#EPICS_TIMEZONE = CUS::360:031402:110702
|
||||
#EPICS_TIMEZONE = MET::-60:032802:103103
|
||||
#
|
||||
# These values are for 2016:
|
||||
EPICS_TIMEZONE=CST/CDT::360:031302:110602
|
||||
#EPICS_TIMEZONE=CET/CEST::-60:032702:103002
|
||||
# DST for 2022 US: Mar 13 - Nov 06
|
||||
# EU: Mar 27 - Oct 30
|
||||
#EPICS_TIMEZONE = CUS::360:031302:110602
|
||||
#EPICS_TIMEZONE = MET::-60:032702:103003
|
||||
|
||||
# EPICS_TS_NTP_INET
|
||||
# NTP time server ip address. Uses boot host if not set.
|
||||
# NTP time server ip address for VxWorks and RTEMS.
|
||||
# IOC will use its boot host if this is not set.
|
||||
EPICS_TS_NTP_INET=
|
||||
|
||||
# IOC Shell:
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE Versions 3.13.7
|
||||
# and higher are distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in the file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
# RELEASE: Define location of external EPICS products
|
||||
|
||||
#
|
||||
# RELEASE: Define the location of external EPICS products
|
||||
#
|
||||
|
||||
# The version of this file in Base should normally be empty.
|
||||
#
|
||||
# Define INSTALL_LOCATION in CONFIG_SITE
|
||||
|
||||
# VX_DIR definition now in os/CONFIG_SITE.Common.vxWorksCommon
|
||||
# RTEMS_BASE (and RTEMS_VERSION) now in os/CONFIG_SITE.Common.RTEMS
|
||||
|
||||
# NB: Settings in RELEASE files can be overridden in files named
|
||||
# RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
# RELEASE.Common.$(T_A)
|
||||
|
||||
@@ -151,7 +151,7 @@ ACTIONS = inc
|
||||
ACTIONS += build
|
||||
ACTIONS += install
|
||||
ACTIONS += buildInstall
|
||||
ACTIONS += runtests tapfiles
|
||||
ACTIONS += runtests tapfiles clean-tests test-results junitfiles
|
||||
|
||||
actionArchTargets = $(foreach x, $(ACTIONS),\ $(foreach arch,$(BUILD_ARCHS), $(x)$(DIVIDER)$(arch)))
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ build$(DIVIDER)$(ARCH) build: buildInstall
|
||||
install$(DIVIDER)$(ARCH) install: buildInstall
|
||||
$(ARCH): buildInstall
|
||||
|
||||
ifeq ($(filter $(ARCH),$(BUILD_ARCHS)),$(ARCH))
|
||||
ifeq ($(filter $(ARCH),$(BUILD_ARCHS)),$(strip $(ARCH)))
|
||||
buildInstall$(DIVIDER)$(ARCH) buildInstall: $(TARGETS)
|
||||
|
||||
clean$(DIVIDER)$(ARCH) clean:
|
||||
@@ -35,4 +35,3 @@ envPaths: $(wildcard $(TOP)/configure/RELEASE*) \
|
||||
|
||||
realclean:
|
||||
$(RM) cdCommands envPaths dllPath.bat relPaths.sh
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ ACTIONS = inc
|
||||
ACTIONS += build
|
||||
ACTIONS += install
|
||||
ACTIONS += buildInstall
|
||||
ACTIONS += runtests tapfiles
|
||||
ACTIONS += runtests tapfiles clean-tests test-results junitfiles
|
||||
|
||||
actionArchTargets = $(foreach action, $(ACTIONS), \
|
||||
$(addprefix $(action)$(DIVIDER), $(BUILD_ARCHS)))
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in the file LICENSE that is included with this distribution.
|
||||
# in the file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
# Rules for making things specified in Makefile
|
||||
@@ -25,7 +25,6 @@ vpath %.html $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
vpath %.skel.static $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
vpath %.y $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
vpath %.l $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
vpath %.pl $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
|
||||
@@ -103,6 +102,7 @@ endif
|
||||
# Products and Object libraries
|
||||
#
|
||||
PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
|
||||
TESTPRODTARGETS += $(TESTPRODNAME) $(TESTMUNCHNAME)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Test specifications and test result files
|
||||
@@ -115,10 +115,11 @@ endif
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
RUNTESTS_ENABLED = YES
|
||||
TAPFILES += $(TESTSCRIPTS:.t=.tap)
|
||||
JUNITFILES += $(TAPFILES:.tap=.xml)
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Libraries
|
||||
# Libraries
|
||||
#
|
||||
|
||||
LIBTARGETS += $(LIBNAME) $(INSTALL_LIBS) $(TESTLIBNAME) \
|
||||
@@ -129,18 +130,18 @@ LIBTARGETS += $(LIBNAME) $(INSTALL_LIBS) $(TESTLIBNAME) \
|
||||
|
||||
# Main targets
|
||||
|
||||
install: buildInstall
|
||||
install: buildInstall
|
||||
|
||||
buildInstall : build
|
||||
buildInstall: build
|
||||
|
||||
# Allows rebuild to work with parallel builds option, -j.
|
||||
install: $(patsubst rebuild,clean,$(filter rebuild,$(MAKECMDGOALS)))
|
||||
|
||||
rebuild: clean install
|
||||
|
||||
build : inc
|
||||
build: inc
|
||||
|
||||
build: $(OBJSNAME) $(LIBTARGETS) $(PRODTARGETS) $(TESTPRODNAME) \
|
||||
build: $(OBJSNAME) $(LIBTARGETS) $(PRODTARGETS) $(TESTPRODTARGETS) \
|
||||
$(TARGETS) $(TESTSCRIPTS) $(INSTALL_LIB_INSTALLS)
|
||||
|
||||
inc : $(COMMON_INC) $(INSTALL_INC) $(INSTALL_CONFIGS)
|
||||
@@ -158,20 +159,21 @@ clean: build_clean
|
||||
|
||||
build_clean:
|
||||
$(ECHO) "Cleaning"
|
||||
@$(RM) *.i *$(OBJ) *.a $(TESTPRODNAME) \
|
||||
@$(RM) *.i *$(OBJ) *.a \
|
||||
$(LIBNAME) $(TESTLIBNAME) $(SHRLIBNAME) $(TESTSHRLIBNAME) \
|
||||
$(DLLSTUB_LIBNAME) $(TESTDLLSTUB_LIBNAME) \
|
||||
$(LOADABLE_SHRLIBNAME) \
|
||||
$(INC) $(TARGETS) $(TDS) $(CLEANS) \
|
||||
*.out MakefileInclude *.manifest *.exp \
|
||||
$(COMMON_INC) $(HDEPENDS_FILES) $(PRODTARGETS) \
|
||||
$(TESTSCRIPTS) $(TAPFILES)
|
||||
$(COMMON_INC) $(HDEPENDS_FILES) $(PRODTARGETS) $(TESTPRODTARGETS) \
|
||||
$(TESTSCRIPTS) $(TAPFILES) $(JUNITFILES)
|
||||
ifdef RES
|
||||
@$(RM) *$(RES)
|
||||
endif
|
||||
|
||||
$(DIRECTORY_TARGETS) :
|
||||
$(MKDIR) -p $@
|
||||
# Sort mkdir targets to remove duplicates & make parents first
|
||||
$(DIRECTORY_TARGETS):
|
||||
$(MKDIR) $(sort $@)
|
||||
|
||||
# Install LIB_INSTALLS libraries before linking executables
|
||||
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS)
|
||||
@@ -188,7 +190,7 @@ warnRelease:
|
||||
-$(CONVERTRELEASE) checkRelease
|
||||
noCheckRelease:
|
||||
ifeq ($(EPICS_HOST_ARCH),$(T_A))
|
||||
@echo "Warning: RELEASE file consistency checks have been disabled"
|
||||
$(info Warning: RELEASE file consistency checks have been disabled)
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------
|
||||
@@ -254,15 +256,13 @@ YACCOPT ?= $($*_YACCOPT)
|
||||
$(MV) $*.tab.c $*.c
|
||||
$(if $(findstring -d, $(YACCOPT)),$(MV) $*.tab.h $*.h,)
|
||||
|
||||
# must be a seperate rule since when not using '-d' the
|
||||
# must be a separate rule since when not using '-d' the
|
||||
# prefix for .h will be different then .c
|
||||
%.h : %.c %.y
|
||||
|
||||
%.c: %.l
|
||||
@$(RM) $*.yy.c
|
||||
$(LEX) $(LEXOPT) -t $< > $*.yy.c
|
||||
@$(RM) $@
|
||||
$(MV) $*.yy.c $@
|
||||
$(LEX) $(LEXOPT) -o$@ $<
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Libraries, shared/DLL and stubs
|
||||
@@ -279,13 +279,17 @@ endif # RANLIB
|
||||
$(SHRLIBNAME) $(DLLSTUB_LIBNAME) $(TESTSHRLIBNAME) $(TESTDLLSTUB_LIBNAME): \
|
||||
$(LIBRARY_OBJS) $(LIBRARY_RESS) $(SHRLIB_DEPLIBS)
|
||||
|
||||
$(DLLSTUB_LIBNAME): $(SHRLIBNAME);
|
||||
# Stub library timestamps may be earlier than the DLL itself.
|
||||
# This order-only prerequisite resolves any related problems.
|
||||
# The $(LINK.shrlib) command must build both library files if
|
||||
# the target requires a separate stub library file.
|
||||
$(DLLSTUB_LIBNAME): | $(SHRLIBNAME);
|
||||
$(SHRLIBNAME): $(SHRLIB_PREFIX)%$(SHRLIB_SUFFIX):
|
||||
@$(RM) $@
|
||||
$(LINK.shrlib)
|
||||
$(MT_DLL_COMMAND)
|
||||
|
||||
$(TESTDLLSTUB_LIBNAME): $(TESTSHRLIBNAME);
|
||||
$(TESTDLLSTUB_LIBNAME): | $(TESTSHRLIBNAME);
|
||||
$(TESTSHRLIBNAME): $(SHRLIB_PREFIX)%$(SHRLIB_SUFFIX):
|
||||
@$(RM) $@
|
||||
$(LINK.shrlib)
|
||||
@@ -317,6 +321,10 @@ $(MUNCHNAME): %$(MUNCH_SUFFIX): $(MUNCH_DEPENDS) %$(EXE)
|
||||
@$(RM) $@
|
||||
$(MUNCH_CMD)
|
||||
|
||||
$(TESTMUNCHNAME): %$(MUNCH_SUFFIX): $(MUNCH_DEPENDS) %$(EXE)
|
||||
@$(RM) $@
|
||||
$(MUNCH_CMD)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# GeSys modules for RTEMS
|
||||
$(MODNAME): %$(MODEXT): %$(EXE)
|
||||
@@ -340,7 +348,23 @@ testspec: $(TESTSCRIPTS)
|
||||
$(if $(TESTFILES), @echo Files: $(TESTFILES) >> $@)
|
||||
$(if $(TESTSPEC_$(OS_CLASS)), @echo "Harness: $(TESTSPEC_$(OS_CLASS))" >> $@)
|
||||
|
||||
test-results: tapfiles
|
||||
ifneq ($(TAPFILES),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES)
|
||||
endif
|
||||
endif
|
||||
|
||||
clean-tests:
|
||||
ifneq ($(TAPFILES),)
|
||||
$(RM) $(TAPFILES)
|
||||
endif
|
||||
ifneq ($(JUNITFILES),)
|
||||
$(RM) $(JUNITFILES)
|
||||
endif
|
||||
|
||||
tapfiles: $(TESTSCRIPTS) $(TAPFILES)
|
||||
junitfiles: $(JUNITFILES)
|
||||
|
||||
# A .tap file is the output from running the associated test script
|
||||
%.tap: %.t
|
||||
@@ -348,6 +372,9 @@ ifdef RUNTESTS_ENABLED
|
||||
-$(PERL) $< -tap > $@
|
||||
endif
|
||||
|
||||
%.xml: %.tap
|
||||
$(TAPTOJUNIT) --puretap --output $@ --input $< $*
|
||||
|
||||
# If there's a perl test script (.plt) available, use it
|
||||
%.t: ../%.plt
|
||||
@$(RM) $@
|
||||
@@ -492,7 +519,8 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
|
||||
.PRECIOUS: $(COMMON_INC)
|
||||
|
||||
.PHONY: all host inc build install clean rebuild buildInstall build_clean
|
||||
.PHONY: runtests tapfiles checkRelease warnRelease noCheckRelease
|
||||
.PHONY: runtests tapfiles clean-tests test-results junitfiles
|
||||
.PHONY: checkRelease warnRelease noCheckRelease
|
||||
|
||||
endif # BASE_RULES_BUILD
|
||||
# EOF RULES_BUILD
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
ARCHS += $(BUILD_ARCHS)
|
||||
ACTIONS += inc build install buildInstall clean realclean archclean
|
||||
ACTIONS += runtests tapfiles
|
||||
ACTIONS += runtests tapfiles clean-tests test-results junitfiles
|
||||
|
||||
dirActionArchTargets = $(foreach dir, $(DIRS), \
|
||||
$(foreach action, $(ACTIONS), \
|
||||
|
||||
@@ -38,6 +38,17 @@ $(foreach target, $(PROD) $(TESTPROD), \
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# These must be done before PROD2_template
|
||||
define TESTLIBRARY_template
|
||||
$(1)_DIR = .
|
||||
TESTBUILD_LIBRARY += $$(if $$(strip $$($(1)_OBJSNAME) $$(LIBRARY_OBJS)),$(1),)
|
||||
endef
|
||||
|
||||
$(foreach target, $(TESTLIBRARY), \
|
||||
$(eval $(call TESTLIBRARY_template,$(strip $(target)))))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
define TARGET2_template
|
||||
$(1)_LDLIBS += $$($(1)_LIBS)
|
||||
$(1)_LDLIBS += $$(if $$(strip $$($(1)_LIBS_$(OS_CLASS))), \
|
||||
@@ -123,16 +134,6 @@ $(foreach target, $(LIBRARY), \
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
define LIBRARY3_template
|
||||
$(1)_DIR = .
|
||||
TESTBUILD_LIBRARY += $$(if $$(strip $$($(1)_OBJSNAME) $$(LIBRARY_OBJS)),$(1),)
|
||||
endef
|
||||
|
||||
$(foreach target, $(TESTLIBRARY), \
|
||||
$(eval $(call LIBRARY3_template,$(strip $(target)))))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
define LOADABLE_LIBRARY_template
|
||||
LOADABLE_BUILD_LIBRARY += $$(if $$(strip $$($(1)_OBJSNAME) $$(LIBRARY_OBJS)),$(1),)
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ help:
|
||||
@echo " Cannot be used within an O.<arch> dir"
|
||||
@echo " rebuild - Same as clean install"
|
||||
@echo " archclean - Removes O.<arch> dirs but not O.Common dir"
|
||||
@echo " runtests - Run self-tests, summarize results"
|
||||
@echo "\"Partial\" build targets supported by Makefiles:"
|
||||
@echo " host - Builds and installs $(EPICS_HOST_ARCH) only."
|
||||
@echo " inc$(DIVIDER)<arch> - Installs <arch> only header files."
|
||||
|
||||
@@ -136,6 +136,13 @@ MOD_LDFLAGS = $(OPT_LDFLAGS) $(TARGET_LDFLAGS) $(USR_LDFLAGS) $(POSIX_LDFLAGS) \
|
||||
LINK.mod = $(CCC) -o $@ $(PRODDIR_LDFLAGS) $(MOD_LDFLAGS)
|
||||
LINK.mod += $(PROD_LDFLAGS) $(PROD_LD_OBJS) $(PROD_LD_RESS) $(MOD_LDLIBS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Here munching means creating a bootable object binary
|
||||
ifdef MUNCH_SUFFIX
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
TESTMUNCHNAME = $(TESTPRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
endif
|
||||
|
||||
#--------------------------------------------------
|
||||
# RTEMS has neither shared libraries nor dynamic loading
|
||||
STATIC_BUILD=YES
|
||||
|
||||
@@ -15,7 +15,6 @@ ARCH_DEP_CFLAGS += -DRTEMS_NETWORK_CONFIG_CLUSTER_SPACE=5120
|
||||
OP_SYS_LDLIBS += -lbspExt
|
||||
|
||||
MUNCH_SUFFIX = .boot
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
||||
endef
|
||||
|
||||
@@ -13,7 +13,6 @@ ARCH_DEP_CFLAGS += -DHAVE_PPCBUG
|
||||
OP_SYS_LDLIBS += -lbspExt
|
||||
|
||||
MUNCH_SUFFIX = .boot
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
||||
gzip -f9 rtems
|
||||
|
||||
@@ -7,7 +7,6 @@ ARCH_DEP_CFLAGS += -DHAVE_PPCBUG
|
||||
ARCH_DEP_CFLAGS += -DNVRAM_INDIRECT
|
||||
|
||||
MUNCH_SUFFIX = .boot
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
||||
gzip -f9 rtems
|
||||
|
||||
@@ -15,7 +15,6 @@ ARCH_DEP_CFLAGS += -DRTEMS_NETWORK_CONFIG_CLUSTER_SPACE=5120
|
||||
OP_SYS_LDLIBS += -lbspExt
|
||||
|
||||
MUNCH_SUFFIX = .boot
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
||||
endef
|
||||
|
||||
@@ -16,7 +16,6 @@ ARCH_DEP_CFLAGS += -DBSP_NVRAM_BASE_ADDR=0xf1110000
|
||||
OP_SYS_LDLIBS += -lbspExt
|
||||
|
||||
MUNCH_SUFFIX = .boot
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
||||
endef
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
RTEMS_TARGET_CPU=i386
|
||||
|
||||
MUNCH_SUFFIX = .boot
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< temp.bin
|
||||
$(BIN2BOOT) $@ 0x00097E00 \
|
||||
|
||||
@@ -9,7 +9,6 @@ RTEMS_TARGET_CPU = m68k
|
||||
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
||||
|
||||
MUNCH_SUFFIX = .boot
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
define MUNCH_CMD
|
||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< $@
|
||||
endef
|
||||
|
||||
@@ -15,5 +15,14 @@ ARCH_CLASS = xscale
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
GNU_TARGET = xscale_be
|
||||
CMPLR_PREFIX = $(addsuffix -,$(GNU_TARGET))
|
||||
CMPLR_PREFIX = $(GNU_TARGET:%=%-)
|
||||
|
||||
# Configure for readline if requested
|
||||
OP_SYS_INCLUDES += $(READLINE_DIR:%=-I%/include)
|
||||
READLINE_LDFLAGS = $(READLINE_DIR:%=-L%/lib)
|
||||
RUNTIME_LDFLAGS_READLINE_YES_NO = $(READLINE_DIR:%=-Wl,-rpath,%/lib)
|
||||
RUNTIME_LDFLAGS += \
|
||||
$(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH)_$(STATIC_BUILD))
|
||||
SHRLIBDIR_LDFLAGS += $(READLINE_LDFLAGS)
|
||||
PRODDIR_LDFLAGS += $(READLINE_LDFLAGS)
|
||||
endif
|
||||
|
||||
@@ -23,13 +23,15 @@ STATIC_LDFLAGS_YES= -Wl,-Bstatic
|
||||
STATIC_LDFLAGS_NO=
|
||||
STATIC_LDLIBS_YES= -Wl,-Bdynamic
|
||||
|
||||
# Set runtime path for shared libraries
|
||||
SHRLIBDIR_RPATH_LDFLAGS_YES += $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
SHRLIBDIR_LDFLAGS += $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
# Set runtime path for shared libraries if USE_RPATH=YES and STATIC_BUILD=NO
|
||||
SHRLIBDIR_RPATH_LDFLAGS_YES_NO = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
SHRLIBDIR_LDFLAGS += \
|
||||
$(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD))
|
||||
|
||||
# Set runtime path for products
|
||||
PRODDIR_RPATH_LDFLAGS_YES += $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
PRODDIR_LDFLAGS += $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
# Set runtime path for products if USE_RPATH=YES and STATIC_BUILD=NO
|
||||
PRODDIR_RPATH_LDFLAGS_YES_NO = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
PRODDIR_LDFLAGS += \
|
||||
$(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD))
|
||||
|
||||
# Link libraries controlled by COMMANDLINE_LIBRARY
|
||||
# The newest Linux versions only need readline, older ones need both
|
||||
|
||||
@@ -106,20 +106,10 @@ GNU_DIR_6 = $(WIND_BASE)/gnu/$(VX_GNU_VERSION)-vxworks-$(VXWORKS_VERSION)/$(WIND
|
||||
GNU_DIR = $(GNU_DIR_$(VXWORKS_MAJOR_VERSION))
|
||||
|
||||
#--------------------------------------------------
|
||||
# Wind River moved nm out of GNU_BIN in some versions
|
||||
# This finds nm on any supported VxWorks version
|
||||
|
||||
WORKBENCH_BIN = $(WIND_BASE)/workbench-$(WORKBENCH_VERSION)/$(WIND_HOST_TYPE)/bin
|
||||
UTILITIES_BIN = $(WIND_BASE)/utilities-$(UTILITIES_VERSION)/$(WIND_HOST_TYPE)/bin
|
||||
|
||||
NM_DIR_6.4 = $(WORKBENCH_BIN)
|
||||
NM_DIR_6.5 = $(WORKBENCH_BIN)
|
||||
NM_DIR_6.6 = $(WORKBENCH_BIN)
|
||||
NM_DIR_6.7 = $(GNU_BIN)
|
||||
NM_DIR_6.8 = $(UTILITIES_BIN)
|
||||
NM_DIR_6.9 = $(UTILITIES_BIN)
|
||||
NM_DIR = $(firstword $(NM_DIR_$(VXWORKS_VERSION)) $(GNU_BIN))
|
||||
|
||||
NM = $(NM_DIR)/$(CMPLR_PREFIX)nm$(CMPLR_SUFFIX)$(HOSTEXE)
|
||||
NMPROG = $(CMPLR_PREFIX)nm$(CMPLR_SUFFIX)$(HOSTEXE)
|
||||
NM = $(firstword $(wildcard $(WIND_BASE)/*/$(WIND_HOST_TYPE)/bin/$(NMPROG)))
|
||||
|
||||
#--------------------------------------------------
|
||||
# A linker script is essential for munching from vxWorks 6.6 onwards
|
||||
@@ -132,6 +122,7 @@ MUNCH_LDFLAGS = $(MUNCH_LDFLAGS_$(VXWORKS_MAJOR_VERSION))
|
||||
#--------------------------------------------------
|
||||
# These are required by some of the Wind River tools
|
||||
export WIND_BASE
|
||||
export WIND_HOME = $(WIND_BASE)
|
||||
export WIND_HOST_TYPE
|
||||
export TOOL_FAMILY = GNU
|
||||
|
||||
@@ -179,6 +170,8 @@ OSITHREAD_USE_DEFAULT_STACK = NO
|
||||
|
||||
#--------------------------------------------------
|
||||
# Link definitions
|
||||
CROSS_LDFLAGS =
|
||||
#
|
||||
LINK.cpp = $(LD) -o $@ $(STATIC_LDFLAGS) $(PRODDIR_LDFLAGS) $(LDFLAGS)
|
||||
LINK.cpp += $(PROD_LDFLAGS) $(PROD_LD_OBJS) $(PROD_LD_RESS) $(PROD_LDLIBS)
|
||||
|
||||
|
||||
@@ -65,14 +65,14 @@ GNU = NO
|
||||
#
|
||||
# Darwin shared libraries
|
||||
#
|
||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined suppress \
|
||||
SHRLIB_LDFLAGS = -dynamiclib -undefined dynamic_lookup \
|
||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
|
||||
$(addprefix -current_version , $(SHRLIB_VERSION))
|
||||
SHRLIB_SUFFIX_BASE = .dylib
|
||||
SHRLIB_SUFFIX = $(addprefix ., $(SHRLIB_VERSION))$(SHRLIB_SUFFIX_BASE)
|
||||
|
||||
LOADABLE_SHRLIB_LDFLAGS = -bundle -flat_namespace -undefined suppress
|
||||
LOADABLE_SHRLIB_LDFLAGS = -bundle -undefined dynamic_lookup
|
||||
|
||||
#
|
||||
# Position-independent code is the default on Darwin.
|
||||
|
||||
@@ -11,19 +11,14 @@ GNU_TARGET = arm-linux
|
||||
CMPLR_SUFFIX =
|
||||
CMPLR_PREFIX = $(addsuffix -,$(GNU_TARGET))
|
||||
|
||||
# Provide a link-time path for shared libraries
|
||||
SHRLIBDIR_RPATH_LDFLAGS_YES += $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath-link,%)
|
||||
SHRLIBDIR_LDFLAGS += $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
# Provide a link-time path for products
|
||||
PRODDIR_RPATH_LDFLAGS_YES += $(PROD_DEPLIB_DIRS:%=-Wl,-rpath-link,%)
|
||||
PRODDIR_LDFLAGS += $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
# Provide a link-time path for readline
|
||||
RUNTIME_LDFLAGS_READLINE_YES = -Wl,-rpath-link,$(GNU_DIR)/lib
|
||||
RUNTIME_LDFLAGS_READLINE = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
|
||||
RUNTIME_LDFLAGS_READLINE_CURSES = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
|
||||
RUNTIME_LDFLAGS_READLINE_NCURSES = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
|
||||
# Provide a link-time path for readline if needed
|
||||
OP_SYS_INCLUDES += $(READLINE_DIR:%=-I%/include)
|
||||
READLINE_LDFLAGS = $(READLINE_DIR:%=-L%/lib)
|
||||
RUNTIME_LDFLAGS_READLINE_YES_NO = $(READLINE_DIR:%=-Wl,-rpath,%/lib)
|
||||
RUNTIME_LDFLAGS += \
|
||||
$(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH)_$(STATIC_BUILD))
|
||||
SHRLIBDIR_LDFLAGS += $(READLINE_LDFLAGS)
|
||||
PRODDIR_LDFLAGS += $(READLINE_LDFLAGS)
|
||||
|
||||
# Library flags
|
||||
STATIC_LDFLAGS_YES= -Wl,-Bstatic
|
||||
|
||||
@@ -79,27 +79,32 @@ CPP = cl -nologo -C -E
|
||||
|
||||
# Configure OS vendor C++ compiler
|
||||
#
|
||||
# __STDC__=0 gives us both:
|
||||
# 1) define STDC for code (pretend ANSI conformance)
|
||||
# 2) set it to 0 to use MS C "extensions" (open for _open etc.)
|
||||
# because MS uses: if __STDC__ ... disable many nice things
|
||||
#
|
||||
# -EHsc - generate code for exceptions
|
||||
# -GR - generate code for run time type identification
|
||||
#
|
||||
CCC = cl -EHsc -GR
|
||||
CODE_CPPFLAGS += -nologo -D__STDC__=0
|
||||
|
||||
# Other compiler flags, used for CPP, C and C++
|
||||
#
|
||||
# -FC - Show absolute path of source file in diagnostics
|
||||
# -D__STDC__=0 gives us both:
|
||||
# 1) define STDC for code (pretend ANSI conformance)
|
||||
# 2) set it to 0 to use MS C "extensions" (open for _open etc.)
|
||||
# because MS uses: if __STDC__ ... disable many nice things
|
||||
#
|
||||
CODE_CPPFLAGS += -nologo -FC -D__STDC__=0
|
||||
CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
|
||||
|
||||
|
||||
# Compiler flags for C++ files
|
||||
|
||||
#
|
||||
# -W<N> use warning level N
|
||||
# (maximum lint level warnings at level 4)
|
||||
# -w44355 set "'this' used in the base initializer list" to be level 4
|
||||
# -W<n> disable warnings from levels > n
|
||||
# -w<n><m> set warning m to level n
|
||||
# -w44355 "'this' used in the base initializer list"
|
||||
# -w44344 "behavior change: use of explicit template arguments results in ..."
|
||||
WARN_CXXFLAGS_YES = -W3 -w44355 -w44344
|
||||
# -w44251 "class needs to have dll-interface to be used by clients of ..."
|
||||
WARN_CXXFLAGS_YES = -W3 -w44355 -w44344 -w44251
|
||||
WARN_CXXFLAGS_NO = -W1
|
||||
|
||||
#
|
||||
@@ -135,6 +140,16 @@ STATIC_LDLIBS_NO=
|
||||
STATIC_LDFLAGS=
|
||||
RANLIB=
|
||||
|
||||
#
|
||||
# option needed for parallel builds with Visual Studio 2015 onward
|
||||
#
|
||||
# -FS Force Synchronous PDB Writes
|
||||
ifneq ($(VisualStudioVersion),)
|
||||
OPT_CXXFLAGS_NO += -FS
|
||||
OPT_CFLAGS_NO += -FS
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# add -profile here to run the ms profiler
|
||||
# -LTCG whole program optimization
|
||||
@@ -165,48 +180,38 @@ EXE=.exe
|
||||
OBJ=.obj
|
||||
RES=.res
|
||||
|
||||
# Problem: MS Visual C++ does not recognize *.cc as C++ source,
|
||||
# so we do C++ compiles using the global flag -TP
|
||||
# MS Visual C++ doesn't recognize *.cc as a C++ source file,
|
||||
# so C++ compiles get the flag -TP
|
||||
COMPILER_CXXFLAGS = -TP
|
||||
|
||||
# Operating system flags
|
||||
# Operating system flags
|
||||
OP_SYS_CFLAGS =
|
||||
OP_SYS_CXXFLAGS = $(COMPILER_CXXFLAGS)
|
||||
|
||||
#
|
||||
# Files and flags needed to link DLLs (used in RULES_BUILD)
|
||||
#
|
||||
WIN32_DLLFLAGS = /subsystem:windows /dll $(OPT_LDFLAGS) \
|
||||
# Files and flags needed to link DLLs (used in RULES_BUILD)
|
||||
WIN32_DLLFLAGS = -subsystem:windows -dll $(OPT_LDFLAGS) \
|
||||
$(USR_LDFLAGS) $(CMD_LDFLAGS) $(TARGET_LDFLAGS) $(LIB_LDFLAGS)
|
||||
|
||||
#
|
||||
# specify dll .def file only if it exists
|
||||
#
|
||||
# Specify dll .def file only if it exists
|
||||
DLL_DEF_FLAG = $(addprefix -def:,$(wildcard ../$(addsuffix .def,$*)))
|
||||
|
||||
#
|
||||
# A WIN32 dll has three parts:
|
||||
# A WIN32 dll has three parts:
|
||||
# x.dll: the real dll (SHRLIBNAME)
|
||||
# x.lib: what you link to progs that use the dll (DLLSTUB_LIBNAME)
|
||||
# x.exp: what you need to build the dll (in no variable)
|
||||
#
|
||||
LINK.shrlib = $(WINLINK) -nologo $(WIN32_DLLFLAGS) -out:$@ \
|
||||
-implib:$(@:%$(SHRLIB_SUFFIX)=%$(LIB_SUFFIX)) \
|
||||
$(DLL_DEF_FLAG) $(LIBRARY_LD_OBJS) $(LIBRARY_LD_RESS) $(SHRLIB_LDLIBS)
|
||||
|
||||
|
||||
# adjust names of libraries to build
|
||||
#
|
||||
# Adjust names of libraries to build
|
||||
SHRLIB_SUFFIX_BASE = .dll
|
||||
SHRLIB_SUFFIX = $(SHRLIB_SUFFIX_BASE)
|
||||
SHRLIBNAME_YES = $(BUILD_LIBRARY:%=%$(SHRLIB_SUFFIX))
|
||||
LOADABLE_SHRLIBNAME = $(LOADABLE_BUILD_LIBRARY:%=%$(SHRLIB_SUFFIX))
|
||||
TESTSHRLIBNAME_YES = $(TESTBUILD_LIBRARY:%=%$(SHRLIB_SUFFIX_BASE))
|
||||
|
||||
#
|
||||
# When SHARED_LIBRARIES is YES we are building a DLL link library
|
||||
# and when SHARED_LIBRARIES is NO we are building an object library
|
||||
#
|
||||
# When SHARED_LIBRARIES is YES we are building a DLL shared library.
|
||||
# When SHARED_LIBRARIES is NO we are building an object library
|
||||
DLLSTUB_SUFFIX = .lib
|
||||
DLLSTUB_LIBNAME_YES = $(BUILD_LIBRARY:%=%.lib)
|
||||
DLLSTUB_LIBNAME = $(DLLSTUB_LIBNAME_$(SHARED_LIBRARIES))
|
||||
@@ -220,7 +225,7 @@ LIBNAME = $(LIBNAME_$(SHARED_LIBRARIES))
|
||||
TESTLIBNAME_NO = $(TESTBUILD_LIBRARY:%=%.lib)
|
||||
TESTLIBNAME = $(TESTLIBNAME_$(SHARED_LIBRARIES))
|
||||
|
||||
# dll install location
|
||||
# dll install location
|
||||
INSTALL_SHRLIB = $(INSTALL_BIN)
|
||||
|
||||
|
||||
@@ -280,7 +285,7 @@ LINK.cpp = $(WINLINK) -nologo $(STATIC_LDFLAGS) $(LDFLAGS) $(PROD_LDFLAGS) \
|
||||
#--------------------------------------------------
|
||||
# UseManifestTool.pl checks MS Visual c++ compiler version number to
|
||||
# decide whether or not to use the Manifest Tool command to embed the
|
||||
# linker created .manifest file into a library or product target.
|
||||
# linker created .manifest file into a library or product target.
|
||||
# useManifestTool.pl returns 0(don't use) or 1(use).
|
||||
#
|
||||
MT.exe = mt.exe -nologo -manifest $@.manifest
|
||||
@@ -290,4 +295,3 @@ MT_EXE_COMMAND_NO = $(MT.exe) "-outputresource:$@;\#1"
|
||||
MT_EXE_COMMAND1 = $(MT_EXE_COMMAND_$(STATIC_BUILD))
|
||||
MT_DLL_COMMAND = $(MT_DLL_COMMAND$(shell $(PERL) $(TOOLS)/useManifestTool.pl))
|
||||
MT_EXE_COMMAND = $(MT_EXE_COMMAND$(shell $(PERL) $(TOOLS)/useManifestTool.pl))
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
include $(CONFIG)/os/CONFIG.win32-x86.win32-x86
|
||||
-include $(CONFIG)/os/CONFIG_SITE.win32-x86.win32-x86
|
||||
|
||||
OPT_LDFLAGS += /MACHINE:X64
|
||||
# /MACHINE:X64
|
||||
# /MACHINE:IA64 (Itanium)
|
||||
# /MACHINE:X86
|
||||
|
||||
OPT_LDFLAGS += -MACHINE:X64
|
||||
# -MACHINE:X64
|
||||
# -MACHINE:IA64 (Itanium)
|
||||
# -MACHINE:X86
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
# CONFIG_SITE.Common.linux-xscale_be
|
||||
#
|
||||
# Site specific definitions for linux-xscale_be target builds.
|
||||
# Site specific definitions for all linux-xscale_be target builds.
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Set GNU_DIR to point to directory containing the tool-chain
|
||||
|
||||
# APS:
|
||||
GNU_DIR = /usr/local/vw/xscale_be
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
# Note: vxWorks 5.4.x (Tornado 2.0.x) is not supported
|
||||
|
||||
VXWORKS_VERSION = 5.5
|
||||
#VXWORKS_VERSION = 5.5
|
||||
#VXWORKS_VERSION = 6.0
|
||||
#VXWORKS_VERSION = 6.1
|
||||
#VXWORKS_VERSION = 6.2
|
||||
@@ -19,7 +19,7 @@ VXWORKS_VERSION = 5.5
|
||||
#VXWORKS_VERSION = 6.6
|
||||
#VXWORKS_VERSION = 6.7
|
||||
#VXWORKS_VERSION = 6.8
|
||||
#VXWORKS_VERSION = 6.9
|
||||
VXWORKS_VERSION = 6.9
|
||||
|
||||
|
||||
# Sites may override the following path for a particular host
|
||||
@@ -29,19 +29,6 @@ VXWORKS_VERSION = 5.5
|
||||
# WIND_BASE is where you installed the Wind River software.
|
||||
# Under vxWorks 6.x this is *not* the same as the old VX_DIR setting
|
||||
|
||||
WIND_BASE = /usr/local/vw/tornado22-$(ARCH_CLASS)
|
||||
#WIND_BASE = /usr/local/vw/vxWorks-$(VXWORKS_VERSION)
|
||||
#WIND_BASE = /usr/local/vw/tornado22-$(ARCH_CLASS)
|
||||
WIND_BASE = /usr/local/vw/vxWorks-$(VXWORKS_VERSION)
|
||||
#WIND_BASE = /ade/vxWorks/$(VXWORKS_VERSION)
|
||||
|
||||
|
||||
# WorkBench Version number, if you're using vxWorks 6.x
|
||||
|
||||
#WORKBENCH_VERSION = 2.6
|
||||
#WORKBENCH_VERSION = 3.0
|
||||
#WORKBENCH_VERSION = 3.2
|
||||
#WORKBENCH_VERSION = 3.3
|
||||
|
||||
|
||||
# Utilities Version number, required from vxWorks 6.8 and later
|
||||
|
||||
#UTILITIES_VERSION = 1.0
|
||||
|
||||
@@ -7,8 +7,25 @@
|
||||
GNU_TARGET = arm-xilinx-linux-gnueabi
|
||||
|
||||
# Set GNU tools install path
|
||||
# This is the install path at APS:
|
||||
# Examples are installations at the APS:
|
||||
GNU_DIR = /usr/local/vw/zynq-2011.09
|
||||
#GNU_DIR = /usr/local/Xilinx/SDK/2016.3/gnu/arm/lin
|
||||
#GNU_DIR = /APSshare/XilinxSDK/2015.4/gnu/arm/lin
|
||||
|
||||
# If cross-building shared libraries and the paths on the target machine are
|
||||
# different than on the build host, you should uncomment the lines below to
|
||||
# disable putting runtime library paths in products and shared libraries.
|
||||
# You will also need to provide another way for programs to find their shared
|
||||
# libraries at runtime, such as by setting LD_LIBRARY_PATH or by using
|
||||
# mechanisms related to /etc/ld.so.conf
|
||||
#SHRLIBDIR_RPATH_LDFLAGS_YES_NO =
|
||||
#PRODDIR_RPATH_LDFLAGS_YES_NO =
|
||||
# Note: It may be simpler to just set STATIC_BUILD=YES here and not
|
||||
# try to use shared libraries at all in these circumstances.
|
||||
|
||||
# To use libreadline, point this to its install prefix
|
||||
#READLINE_DIR = $(GNU_DIR)
|
||||
#READLINE_DIR = /tools/cross/linux-x86.linux-arm/readline
|
||||
# See CONFIG_SITE.Common.linux-arm for other COMMANDLINE_LIBRARY values
|
||||
#COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
# With a Xilinx SDK, it'll be something like
|
||||
#GNU_DIR = /usr/local/zynq/Xilinx/SDK/2015.4/gnu/arm/lin
|
||||
|
||||
11
configure/os/CONFIG_SITE.linux-x86.linux-xscale_be
Normal file
11
configure/os/CONFIG_SITE.linux-x86.linux-xscale_be
Normal file
@@ -0,0 +1,11 @@
|
||||
# CONFIG_SITE.linux-x86.linux-xscale_be
|
||||
#
|
||||
# Site specific definitions for linux-x86 host - linux-xscale_be targets
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Set GNU_DIR to point to directory containing the tool-chain
|
||||
GNU_DIR = /usr/local/vw/xscale_be
|
||||
|
||||
# If readline is available, configure it
|
||||
READLINE_DIR = $(GNU_DIR)/target/usr
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
7
configure/os/CONFIG_SITE.linux-x86_64.linux-xscale_be
Normal file
7
configure/os/CONFIG_SITE.linux-x86_64.linux-xscale_be
Normal file
@@ -0,0 +1,7 @@
|
||||
# CONFIG_SITE.linux-x86_64.linux-xscale_be
|
||||
#
|
||||
# Site specific settings for linux-x86_64 host - linux-xscale_be target
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Inherit setting from linux-x86
|
||||
include $(CONFIG)/os/CONFIG_SITE.linux-x86.linux-xscale_be
|
||||
@@ -4,18 +4,18 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<title>Known Problems in R3.15.5</title>
|
||||
<title>Known Problems in R3.15.6</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 style="text-align: center">EPICS Base R3.15.5: Known Problems</h1>
|
||||
<h1 style="text-align: center">EPICS Base R3.15.6: Known Problems</h1>
|
||||
|
||||
<p>Any patch files linked below should be applied at the root of the
|
||||
base-3.15.5 tree. Download them, then use the GNU Patch program as
|
||||
base-3.15.6 tree. Download them, then use the GNU Patch program as
|
||||
follows:</p>
|
||||
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.5</b>
|
||||
% <b>patch -p0 < <i>/path/to/</i>file.patch</b></pre></blockquote>
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.6</b>
|
||||
% <b>patch -p1 < <i>/path/to/</i>file.patch</b></pre></blockquote>
|
||||
|
||||
<p>The following significant problems have been reported with this
|
||||
version of EPICS Base:</p>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
Installation Instructions
|
||||
|
||||
EPICS Base Release 3.15.5
|
||||
EPICS Base Release 3.15.6
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Table of Contents
|
||||
|
||||
* What is EPICS base?
|
||||
* What is new in this release?
|
||||
* Copyright
|
||||
* Supported platforms
|
||||
* Supported compilers
|
||||
* Software requirements
|
||||
* Host system storage requirements
|
||||
* Documentation
|
||||
* Directory Structure
|
||||
* Build related components
|
||||
* Building EPICS base (Unix and Win32)
|
||||
* Example application and extension
|
||||
* Multiple host platforms
|
||||
* What is EPICS base?
|
||||
* What is new in this release?
|
||||
* Copyright
|
||||
* Supported platforms
|
||||
* Supported compilers
|
||||
* Software requirements
|
||||
* Host system storage requirements
|
||||
* Documentation
|
||||
* Directory Structure
|
||||
* Build related components
|
||||
* Building EPICS base (Unix and Win32)
|
||||
* Example application and extension
|
||||
* Multiple host platforms
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
@@ -166,12 +166,11 @@
|
||||
|
||||
base/startup directory - contains scripts to set environment and path
|
||||
|
||||
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable
|
||||
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable
|
||||
Site.profile bourne shell script to set path and env variables
|
||||
Site.cshrc c shell script to set path and env variables
|
||||
cygwin.bat WIN32 bat file to set cygwin path and env variables
|
||||
win32.bat WIN32 bat file to set path and env variables
|
||||
EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
|
||||
unix.csh C shell script to set path and env variables
|
||||
unix.sh Bourne shell script to set path and env variables
|
||||
win32.bat Bat file example to configure win32-x86 target
|
||||
windows.bat Bat file example to configure windows-x64 target
|
||||
|
||||
base/configure directory - contains build definitions and rules
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ of my Bash login script (~/.bash_login):
|
||||
#
|
||||
EPICS_BASE="${HOME}/src/EPICS/base"
|
||||
EPICS_EXTENSIONS="${HOME}/src/EPICS/extensions"
|
||||
<strong>.</strong> "${EPICS_BASE}"/startup/Site.profile
|
||||
<strong>.</strong> "${EPICS_BASE}"/startup/unix.sh
|
||||
</pre>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<BODY>
|
||||
<CENTER>
|
||||
<H1>Installation Instructions</H1>
|
||||
<H2>EPICS Base Release 3.15.5</H2><BR>
|
||||
<H2>EPICS Base Release 3.15.6</H2><BR>
|
||||
</CENTER>
|
||||
<HR>
|
||||
<H3> Table of Contents</H3>
|
||||
@@ -98,8 +98,8 @@
|
||||
base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its
|
||||
target-specific overrides.</P>
|
||||
|
||||
<P>Consult the <a href="http://www.aps.anl.gov/epics/base/tornado.php">vxWorks
|
||||
5.x</a> or <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
|
||||
<P>Consult the <a href="https://epics.anl.gov/base/tornado.php">vxWorks
|
||||
5.x</a> or <a href="https://epics.anl.gov/base/vxWorks6.php">vxWorks
|
||||
6.x</a> EPICS web pages about and the vxWorks documentation for information
|
||||
about configuring your vxWorks operating system for use with EPICS.</P>
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
|
||||
<H3><A NAME="0_0_8"> Documentation</A></H3>
|
||||
<BLOCKQUOTE>EPICS documentation is available through the
|
||||
<a href="http://www.aps.anl.gov/epics/">EPICS website</a> at Argonne.
|
||||
<a href="https://epics.anl.gov/">EPICS website</a> at Argonne.
|
||||
<P>Release specific documentation can also be found in the base/documentation
|
||||
directory of the distribution.</BLOCKQUOTE>
|
||||
|
||||
@@ -177,12 +177,11 @@
|
||||
|
||||
<H4>base/startup directory - contains scripts to set environment and path</H4>
|
||||
<PRE>
|
||||
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable
|
||||
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable
|
||||
Site.profile bourne shell script to set path and env variables
|
||||
Site.cshrc c shell script to set path and env variables
|
||||
cygwin.bat WIN32 bat file to set cygwin path and env variables
|
||||
win32.bat WIN32 bat file to set path and env variables
|
||||
EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
|
||||
unix.csh C shell script to set path and env variables
|
||||
unix.sh Bourne shell script to set path and env variables
|
||||
win32.bat Bat file example to configure win32-x86 target
|
||||
windows.bat Bat file example to configure windows-x64 target
|
||||
</PRE>
|
||||
|
||||
<H4>base/configure directory - contains build definitions and rules</H4>
|
||||
|
||||
@@ -3,18 +3,262 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
<title>EPICS Base R3.15.5 Release Notes</title>
|
||||
<title>EPICS Base R3.15.6 Release Notes</title>
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1 align="center">EPICS Base Release 3.15.5</h1>
|
||||
<h1 align="center">EPICS Base Release 3.15.6</h1>
|
||||
|
||||
<p style="color:red">This version of EPICS Base has not been released yet.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes made on the 3.15 branch since 3.15.4</h2>
|
||||
<h2 align="center">Changes made on the 3.15 branch since 3.15.5</h2>
|
||||
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h3>Warning indicators in msi (and macLib) output</h3>
|
||||
|
||||
<p>The libCom macro expansion library has been modified so that when the
|
||||
SUPPRESS_WARNINGS flag is set it will no longer include any <tt>,undefined</tt>
|
||||
or <tt>,recursive</tt> indicators in its output when undefined or recursive
|
||||
macros are encountered. These indicators were harmless when the output was fed
|
||||
into an IOC along with a definition for the macro, but when the <tt>msi</tt>
|
||||
tool was used to generate other kinds of files they caused problems. If the
|
||||
<tt>msi -V</tt> flag is used the markers will still be present in the output
|
||||
whenever the appropriate condition is seen.</p>
|
||||
|
||||
<h3>Improvements to msi</h3>
|
||||
|
||||
<p>In addition to fixing its response to discovering parsing errors in its
|
||||
substitution input file (reported as Launchpad
|
||||
<a href="https://bugs.launchpad.net/epics-base/+bug/1503661">bug #1503661</a>)
|
||||
so it now deletes the incomplete output file, the msi program has been cleaned
|
||||
up a little bit internally.</p>
|
||||
|
||||
<h3>All array records now post monitors on their array-length fields</h3>
|
||||
|
||||
<p>The waveform record has been posting monitors on its NORD field since Base
|
||||
3.15.0.1; we finally got around to doing the equivalent in all the other
|
||||
built-in record types, which even required modifying device support in some
|
||||
cases. This fixes <a href="https://bugs.launchpad.net/epics-base/+bug/1730727">
|
||||
Launchpad bug #1730727</a>.</p>
|
||||
|
||||
<h3>HOWTO: Converting Wiki Record Reference to POD</h3>
|
||||
|
||||
<p>Some documentation has been added to the <tt>dbdToHtml.pl</tt> script
|
||||
explaining how Perl POD (Plain Old Documentation) markup can be added to
|
||||
<tt>.dbd</tt> files to generate HTML documentation for the record types. To see
|
||||
these instructions, run <tt>perl bin/<host>/dbdToHtml.pl -H</tt>
|
||||
or <tt>perldoc bin/<host>/dbdToHtml.pl</tt>.</p>
|
||||
|
||||
<h3>Fix problem with numeric soft events</h3>
|
||||
|
||||
<p>Changing from numeric to named soft events introduced an incompatibility
|
||||
when a numeric event 1-255 is converted from a DOUBLE, e.g. from a calc record.
|
||||
The <tt>post_event()</tt> API is not marked deprecated any more.
|
||||
|
||||
<p>Also <code>scanpel</code> has been modified to accept a glob pattern for
|
||||
event name filtering and to show events with no connected records as well.</p>
|
||||
|
||||
<h3>Add osiSockOptMcastLoop_t and osiSockTest</h3>
|
||||
|
||||
<p>Added a new OS-independent typedef for multicast socket options, and a test
|
||||
file to check their correct operation.<p>
|
||||
|
||||
<h3>Support for CONFIG_SITE.local in Base</h3>
|
||||
|
||||
<p>This feature is mostly meant for use by developers; configuration
|
||||
settings that would normally appear in Base/configure/CONFIG_SITE can now
|
||||
be put in a locally created base/configure/CONFIG_SITE.local file instead
|
||||
of having go modify or replace the original. A new .gitignore pattern
|
||||
tells git to ignore all configure/*.local files.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes from the 3.14 branch since 3.15.5</h2>
|
||||
|
||||
<!-- Insert inherited items immediately below here ... -->
|
||||
|
||||
<h3>Fix broken <tt>EPICS_IOC_LOG_FILE_LIMIT=0</tt> setting</h3>
|
||||
|
||||
<p>The Application Developers' Guide says this is allowed and disables the
|
||||
limit on the log-file, but it hasn't actually worked for some time (if ever).
|
||||
Note that the iocLogServer will be removed from newer Base release sometime
|
||||
soon as its functionality can be implemented by other dedicated log servers
|
||||
such as logstash or syslog-ng.</p>
|
||||
|
||||
<p>Fixes <a href="https://bugs.launchpad.net/bugs/1786858">lp:1786858</a>
|
||||
and part of <a href="https://bugs.launchpad.net/bugs/1786966">lp:1786966</a>.
|
||||
</p>
|
||||
|
||||
<h3>Cleanup of startup directory</h3>
|
||||
|
||||
<p>The files in the startup directory have not been maintained in recent years
|
||||
and have grown crufty (technical term). This release includes the following
|
||||
updates to these files:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>The Perl <tt>EpicsHostArch.pl</tt> script has been rewritten, and support
|
||||
for a few previously missing host architectures has been added to it.</li>
|
||||
|
||||
<li>The <tt>EpicsHostArch.pl</tt> script has also been moved into the standard
|
||||
<tt>src/tools</tt> directory, from where it will be installed into
|
||||
<tt>lib/perl</tt>. In this new location it is no longer executable, so it must
|
||||
be run by the <tt>perl</tt> executable.</li>
|
||||
|
||||
<li>The build system has been adjusted to look for <tt>EpicsHostArch.pl</tt> in
|
||||
both places if the <tt>EPICS_HOST_ARCH</tt> environment variable has not been
|
||||
set at build-time.</li>
|
||||
|
||||
<li>Sites that used the original Perl script to set <tt>EPICS_HOST_ARCH</tt> as
|
||||
part of their standard environment will need to adjust their scripts when they
|
||||
upgrade to this release.</li>
|
||||
|
||||
<li>The <tt>EpicsHostArch</tt> shell script has been replaced with a wrapper
|
||||
routine that calls the Perl <tt>EpicsHostArch.pl</tt> script. Sites that rely on
|
||||
this script to set <tt>EPICS_HOST_ARCH</tt> should consider switching to the
|
||||
Perl script instead.</li>
|
||||
|
||||
<li>The <tt>Site.cshrc</tt> and <tt>Site.profile</tt> files have been renamed to
|
||||
<tt>unix.csh</tt> and <tt>unix.sh</tt>, respectively.</li>
|
||||
|
||||
<li>The existing <tt>win32.bat</tt> file has been cleaned up and a new
|
||||
<tt>windows.bat</tt> file added for 64-bit targets. The contents of these files
|
||||
should be seen as examples, don't uncomment or install parts for software that
|
||||
you don't explicitly know that you need.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h3>Recent Apple XCode Build Issues</h3>
|
||||
|
||||
<p>The latest version of XCode will not compile calls to <tt>system()</tt> or
|
||||
<tt>clock_settime()</tt> for iOS targets. There were several places in Base
|
||||
where these were being compiled, although there were probably never called. The
|
||||
code has now been modified to permit iOS builds to complete again.</p>
|
||||
|
||||
<h3>Prevent illegal alarm severities</h3>
|
||||
|
||||
<p>A check has been added to <tt>recGblResetAlarms()</tt> that prevents records
|
||||
from getting an alarm severity higher than INVALID_ALARM. It is still possible
|
||||
for a field like HSV to get set to a value that is not a legal alarm severity,
|
||||
but the core IOC code should never copy such a value into a record's SEVR or
|
||||
ACKS fields. With this fix the record's alarm severity will be limited to
|
||||
INVALID_ALARM.</p>
|
||||
|
||||
<h3>Fixes for Launchpad bugs</h3>
|
||||
|
||||
<p>The following launchpad bugs have fixes included:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1786320">
|
||||
lp: #1786320</a>, dbCa subscribes twice to ENUM</li>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/541221">
|
||||
lp: #541221</a>, 'assert (pca->pgetNative)' failed in ../dbCa.c</li>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1747091">
|
||||
lp: #1747091</a>, epicsTimeGetEvent() / generalTime bug</li>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1743076">
|
||||
lp: #1743076</a>, Segfault in ca_attach_context() during exits</li>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1751380">
|
||||
lp: #1751380</a>, Deadlock in ca_clear_subscription()</li>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1597809">
|
||||
lp: #1597809</a>, Setting NAME field in DB file may break IOC</li>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1770292">
|
||||
lp: #1770292</a>, get_alarm_double() inconsistent across record types</li>
|
||||
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1771298">
|
||||
lp: #1771298</a>, Conversion of NaN to integer relies on undefined
|
||||
behavior</li>
|
||||
</ul>
|
||||
|
||||
<h3>Updated VxWorks Timezone settings</h3>
|
||||
|
||||
<p>Removed the settings for 2017; fixed the hour of the change for MET.</p>
|
||||
|
||||
<h3>Fixed camonitor server side relative timestamps bug</h3>
|
||||
|
||||
<p>Initialize the first time-stamp from the first monitor, not the client-side
|
||||
current time in this configuration.</p>
|
||||
|
||||
<h3>Build changes for MSVC</h3>
|
||||
|
||||
<p>Windows builds using Visual Studio 2015 and later now use the <tt>-FS</tt>
|
||||
compiler option to allow parallel builds to work properly.</p>
|
||||
|
||||
<p>We now give the <tt>-FC</tt> option to tell the compiler to print absolute
|
||||
paths for source files in diagnostic messages.</p>
|
||||
|
||||
<h3>Extend maximum Posix epicsEventWaitWithTimeout() delay</h3>
|
||||
|
||||
<p>The Posix implementation of epicsEventWaitWithTimeout() was limiting the
|
||||
timeout delay to at most 60 minutes (3600.0 seconds). This has been changed to
|
||||
10 years; significantly longer maximum delays cause problems on systems where
|
||||
<tt>time_t</tt> is still a signed 32-bit integer so cannot represent absolute
|
||||
time-stamps after 2038-01-19. Our assumption is that such 32-bit systems will
|
||||
have been retired before the year 2028, but some additional tests have been
|
||||
added to the epicsTimeTest program to detect and fail if this assumption is
|
||||
violated.</p>
|
||||
|
||||
<h3>New test-related make targets</h3>
|
||||
|
||||
<p>This release adds several new make targets intended for use by developers
|
||||
and Continuous Integration systems which simplify the task of running the
|
||||
built-in self-test programs and viewing the results. Since these targets are
|
||||
intended for limited use they can have requirements for the build host which
|
||||
go beyond the standard minimum set needed to build and run Base.</p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<h4><tt>test-results</tt> — Summarize test results</h4>
|
||||
|
||||
<p>The new make target <tt>test-results</tt> will run the self-tests if
|
||||
necessary to generate a TAP file for each test, then summarizes the TAP output
|
||||
files in each test directory in turn, displaying the details of any failures.
|
||||
This step uses the program <q>prove</q> which comes with Perl, but also needs
|
||||
<q>cat</q> to be provided in the default search path so will not work on most
|
||||
Windows systems.</p>
|
||||
|
||||
<h4><tt>junitfiles</tt> — Convert test results to JUnit XML Format</h4>
|
||||
|
||||
<p>The new make target <tt>junitfiles</tt> will run the self-tests if necessary
|
||||
and then convert the TAP output files into the more commonly-supported JUnit
|
||||
XML format. The program that performs this conversion needs the Perl module
|
||||
<q><tt>XML::Generator</tt></q> to have been installed.</p>
|
||||
|
||||
<h4><tt>clean-tests</tt> — Delete test result files</h4>
|
||||
|
||||
<p>The new make target <tt>clean-tests</tt> removes any test result files from
|
||||
previous test runs. It cleans both TAP and JUnit XML files.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h3>Fix DNS related crash on exit</h3>
|
||||
|
||||
<p>The attempt to fix DNS related delays for short lived CLI programs (eg. caget)
|
||||
in lp:1527636 introduced a bug which cased these short lived clients to crash on exit.
|
||||
This bug should now be fixed.</p>
|
||||
|
||||
<h3>Server bind issue on Windows</h3>
|
||||
|
||||
<p>When a National Instruments network variables CA server is already running on
|
||||
a Windows system and an IOC or PCAS server is started, the IOC's attempt to
|
||||
bind a TCP socket to the CA server port number fails, but Windows returns a
|
||||
different error status value than the IOC is expecting in that circumstance
|
||||
(because the National Instruments code requests exclusive use of that port,
|
||||
unlike the EPICS code) so the IOC fails to start properly. The relevent EPICS
|
||||
bind() checks have now been updated so the IOC will request that a dynamic port
|
||||
number be allocated for this TCP socket instead when this happens.</p>
|
||||
|
||||
<h3>Checking Periodic Scan Rates</h3>
|
||||
|
||||
<p>Code has been added to the IOC startup to better protect it against bad
|
||||
periodic scan rates, including against locales where <q><tt>.</tt></q> is not
|
||||
accepted as a decimal separator character. If the scan period in a menuScan
|
||||
choice string cannot be parsed, the associated periodic scan thread will no
|
||||
longer be started by the IOC and a warning message will be displayed at iocInit
|
||||
time. The <tt>scanppl</tt> command will also flag the faulty menuScan value.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes made between 3.15.4 and 3.15.5</h2>
|
||||
|
||||
<h3>dbStatic Library Speedup and Cleanup</h3>
|
||||
|
||||
<p>Loading of database files has been optimized to avoid overproportionally
|
||||
@@ -28,10 +272,6 @@ old behavior.</p>
|
||||
to be used by database configuration tools linked against a host side version
|
||||
of the dbStatic library that is not being built anymore.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes from the 3.14 branch since 3.15.4</h2>
|
||||
<!-- Insert inherited items immediately below here ... -->
|
||||
|
||||
<h3>Launchpad Bug-fixes</h3>
|
||||
|
||||
<p>In addition to the more detailed change descriptions below, the following
|
||||
@@ -1519,7 +1759,7 @@ The iocLogServer was moved into the same directory (src/libCom/log) as
|
||||
the log client code.</p>
|
||||
|
||||
<p><a name="as">3</a>
|
||||
The Access Security code has been divided, with the parts not related to the
|
||||
The Access Security code has been divided, with the parts not related to the
|
||||
database (lexer/parser and trap registration) becoming part of libCom.
|
||||
The remaining components are included in the dbCore library</p>
|
||||
|
||||
|
||||
@@ -41,11 +41,12 @@ that should be performed when creating new releases of EPICS Base.</p>
|
||||
pre-release, <tt>-pre1</tt>. The first Release Candidate <tt>-rc1</tt> is the
|
||||
first version that has undergone widespread testing and which has no known
|
||||
problems in it that are slated to be fixed in this release. New versions should
|
||||
be made at about weekly intervals during the testing and debugging period, and
|
||||
will be designated as either pre-release versions or Release Candidates by the
|
||||
Release Manager. A Release Candidate that has received widespread testing for a
|
||||
week without any additional problems being discovered or significant changes
|
||||
being committed can be designated as the final release version.</p>
|
||||
be made at 2-weekly intervals during the testing and debugging period, and will
|
||||
be designated as either pre-release versions or Release Candidates by the
|
||||
Release Manager. After a Release Candidate has been available to the whole
|
||||
community for testing for at least a week without any additional problems being
|
||||
reported or significant changes being committed, the branch can be designated as
|
||||
the final release version.</p>
|
||||
|
||||
<h3>Roles</h3>
|
||||
|
||||
@@ -56,7 +57,7 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<dl>
|
||||
<dt><strong>Release Manager</strong> (Ralph Lange)</dt>
|
||||
<dd>Responsible for managing and tagging the release</dd>
|
||||
<dt><strong>Platform Developers</strong></dt>
|
||||
<dt><strong>Platform Developers</strong> (optional)</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>
|
||||
@@ -90,7 +91,7 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Set the Feature Freeze date, by which time all Bazaar commits for
|
||||
<td>Set the Feature Freeze date, by which time all Git commits for
|
||||
enhancements and new functionality should have been completed. After
|
||||
this date, commits should only be made to fix problems that show up
|
||||
during testing.</td>
|
||||
@@ -132,39 +133,36 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Tag the module in Bazaar, using these tag conventions:
|
||||
<td>Tag the module in Git, using these tag conventions:
|
||||
<ul>
|
||||
<li>
|
||||
<tt>R3.15.5-pre<i>n</i></tt>
|
||||
<tt>R3.15.6-pre1</tt>
|
||||
— pre-release tag
|
||||
</li>
|
||||
<li>
|
||||
<tt>R3.15.5-rc<i>n</i></tt>
|
||||
— release candidate tag, note the <tt>rc</tt> is now
|
||||
lower-case</li>
|
||||
<tt>R3.15.6-rc1</tt>
|
||||
— release candidate tag
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote><tt>
|
||||
cd ~/base/mirror-3.15<br />
|
||||
bzr tag R3.15.5-rc<i>n</i>
|
||||
cd base-3.15<br />
|
||||
git tag -m 'RL: Tagged for 3.15.6-rc1' R3.15.6-rc1
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Export the tagged version into a tarfile. Note that this command
|
||||
generates a gzipped tarfile directly from the repository:
|
||||
<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<br />
|
||||
bzr export
|
||||
--root=base-3.15.5-rc<i>n</i>
|
||||
-r tag:R3.15.5-rc<i>n</i>
|
||||
base-3.15.5-rc<i>n</i>.tar.gz
|
||||
mirror-3.15
|
||||
cd base-3.15<br />
|
||||
git archive --prefix=base-3.15.6-rc1/ R3.15.6-rc1 --output=base-3.15.6-rc1.tar.gz
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-3.15.5-rc<i>n</i>.tar.gz
|
||||
gpg --armor --sign --detach-sig base-3.15.6-rc1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -273,10 +271,10 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Tag the module in Bazaar:
|
||||
<td>Tag the module in Git:
|
||||
<blockquote><tt>
|
||||
cd ~/base/mirror-3.15<br />
|
||||
bzr tag R3.15.5</i>
|
||||
cd base-3.15<br />
|
||||
git tag -m 'RL: Tagged for 3.15.6' R3.15.6
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -286,16 +284,12 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<td>Export the tagged version into a tarfile. Note that this command
|
||||
generates a gzipped tarfile directly from the repository:
|
||||
<blockquote><tt>
|
||||
cd ~/base<br />
|
||||
bzr export
|
||||
--root=base-3.15.5
|
||||
-r tag:R3.15.5
|
||||
base-3.15.5.tar.gz
|
||||
mirror-3.15
|
||||
cd base-3.15<br />
|
||||
git archive --prefix=base-3.15.6/ R3.15.6 --output=base-3.15.6.tar.gz
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-3.15.5.tar.gz
|
||||
gpg --armor --sign --detach-sig base-3.15.6.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -305,14 +299,24 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<td>Test the tar file by extracting its contents and building it on at
|
||||
least one supported platform</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Upload the release tar file to the Launchpad download area.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Find all Launchpad bug reports with the status Fix Committed which
|
||||
have been fixed in this release and mark them Fix Released.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Publish and Announce it</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Website Manager</td>
|
||||
<td>If necessary recreate the tarfile following the instructions above.
|
||||
Copy the tar file and its <tt>.asc</tt> signature file to the Base
|
||||
<td>Copy the tar file and its <tt>.asc</tt> signature file to the Base
|
||||
download area of the website.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -343,24 +347,13 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Website Manager</td>
|
||||
<td>Upload the release tar file to the Launchpad download area.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Website Manager</td>
|
||||
<td>Find all Launchpad bug reports with the status Fix Committed which
|
||||
have been fixed in this release and mark them Fix Released.</td>
|
||||
<td>Add an entry to the website News page, linking to the new version
|
||||
webpage.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Email tech-talk</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Website Manager</td>
|
||||
<td>Add an entry to the website News page, linking to the new version
|
||||
webpage.</td>
|
||||
<td>Announce the release on the tech-talk mailing list.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1009,7 +1009,7 @@ d:/user/epics/base-3.15/lib/win32-x86/Com.lib</code></p>
|
||||
<h2><a name="CommandUtils">Command Line Utilities</a></h2>
|
||||
|
||||
<h3><a name="acctst">acctst</a></h3>
|
||||
<pre>acctst <PV name> [progress logging level] [channel duplication count]
|
||||
<pre>acctst <PV name> [progress logging level] [channel duplication count]
|
||||
[test repetition count] [enable preemptive callback]</pre>
|
||||
|
||||
<h4>Description</h4>
|
||||
@@ -1146,16 +1146,10 @@ the output.</p>
|
||||
<td>Wide mode "name timestamp value stat sevr" (read PVs as
|
||||
DBR_TIME_xxx)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-n</td>
|
||||
<td>Print DBF_ENUM values as number (default are enum strings)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-d <type></td>
|
||||
<td>Request specific dbr type; use string (DBR_ prefix may be omitted)
|
||||
|
||||
<p>or number of one of the following types:</p>
|
||||
|
||||
<td>Request specific dbr type; use string (DBR_ prefix may be omitted)<br>
|
||||
or number of one of the following types:<br>
|
||||
<table border="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
@@ -1272,6 +1266,14 @@ the output.</p>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><strong>Enum format:</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-n</td>
|
||||
<td>Print DBF_ENUM value as number (default is enum string)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><strong>Arrays:</strong></td>
|
||||
@@ -1303,15 +1305,15 @@ the output.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-e <nr></td>
|
||||
<td>Use %e format, with <nr> digits after the decimal point</td>
|
||||
<td>Use %e format, with a precision of <nr> digits</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-f <nr></td>
|
||||
<td>Use %f format, with <nr> digits after the decimal point</td>
|
||||
<td>Use %f format, with a precision of <nr> digits</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-g <nr></td>
|
||||
<td>Use %g format, with <nr> digits after the decimal point</td>
|
||||
<td>Use %g format, with a precision of <nr> digits</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-s</td>
|
||||
@@ -1349,6 +1351,14 @@ the output.</p>
|
||||
<td>-0b</td>
|
||||
<td>Print as binary number</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><strong>Alternate output field separator:</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-F <ofs></td>
|
||||
<td>Use <ofs> as an alternate output field separator</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1381,9 +1391,10 @@ the output.</p>
|
||||
<td>Wait time, specifies longer CA timeout, default is 1.0 second</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-m <mask></td>
|
||||
<td>Specify CA event mask to use, with <mask> being any combination
|
||||
of 'v' (value), 'a' (alarm), 'l' (log), 'p' (property). Default: va</td>
|
||||
<td>-m <msk></td>
|
||||
<td>Specify CA event mask to use. <msk> is any combination of<br>
|
||||
'v' (value), 'a' (alarm), 'l' (log/archive), 'p' (property).<br>
|
||||
Default event mask is 'va'</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-p <prio></td>
|
||||
@@ -1405,8 +1416,8 @@ the output.</p>
|
||||
'n' = no timestamps<br>
|
||||
'r' = relative timestamps (time elapsed since start of program)<br>
|
||||
'i' = incremental timestamps (time elapsed since last update)<br>
|
||||
'I' = incremental timestamps (time elapsed since last update, by
|
||||
channel)</td>
|
||||
'I' = incremental timestamps (time since last update, by channel)<br>
|
||||
'r', 'i' or 'I' require 's' or 'c' to select the time source</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
@@ -1414,7 +1425,7 @@ the output.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-n</td>
|
||||
<td>Print DBF_ENUM values as number (default are enum strings)</td>
|
||||
<td>Print DBF_ENUM values as number (default is enum string)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
@@ -1422,16 +1433,15 @@ the output.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Value format: Print number of requested values, then list of
|
||||
values</td>
|
||||
<td>Array values: Print number of elements, then list of values</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Default:</td>
|
||||
<td>Print all values</td>
|
||||
<td>Default: Request and print all elements (dynamic arrays supported)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-# <count></td>
|
||||
<td>Print first <count> elements of an array</td>
|
||||
<td>-# <num></td>
|
||||
<td>Request and print up to <num> elements</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-S</td>
|
||||
@@ -1439,23 +1449,23 @@ the output.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><strong>Floating point type format:</strong></td>
|
||||
<td><strong>Floating point format:</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Default:</td>
|
||||
<td>Use %g format</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-e <nr></td>
|
||||
<td>Use %e format, with <nr> digits after the decimal point</td>
|
||||
<td>-e <num></td>
|
||||
<td>Use %e format, with a precision of <num> digits</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-f <nr></td>
|
||||
<td>Use %f format, with <nr> digits after the decimal point</td>
|
||||
<td>-f <num></td>
|
||||
<td>Use %f format, with a precision of <num> digits</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-g <nr></td>
|
||||
<td>Use %g format, with <nr> digits after the decimal point</td>
|
||||
<td>-g <num></td>
|
||||
<td>Use %g format, with a precision of <num> digits</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-s</td>
|
||||
@@ -1497,21 +1507,27 @@ the output.</p>
|
||||
</table>
|
||||
|
||||
<h3><a name="caput">caput</a></h3>
|
||||
<pre>caput [options] <PV name> <value>
|
||||
<pre>caput [options] <PV name> <value> ...
|
||||
caput -a [options] <PV name> <no of elements> <value> ...</pre>
|
||||
|
||||
<h4>Description</h4>
|
||||
|
||||
<p>Put value to a PV.</p>
|
||||
|
||||
<p>The specified value is written to the PV (as a string). The PV value is read
|
||||
before and after the write operation and printed as "Old" and "new" values on
|
||||
stdout.</p>
|
||||
<p>The specified value is written to the PV (as a string). The PV's value is
|
||||
read before and after the write operation and printed as "Old" and "New" values
|
||||
on stdout.</p>
|
||||
|
||||
<p>The array variant writes an array to the specified PV. The first numeric
|
||||
argument specifying the number of array elements is kept for compatibility with
|
||||
the array data format of caget - the actual number of values specified on the
|
||||
command line is used.</p>
|
||||
<p>There are two variants to the arguments for this command. For the scalar
|
||||
variant without the <code>-a</code> flag, all the value arguments provided after
|
||||
the PV name are concatenated with a single space character between them, and the
|
||||
resulting string (up to 40 characters long unless the <code>-S</code> flag is
|
||||
given) is written to the specified PV.</p>
|
||||
|
||||
<p>The array variant with the <code>-a</code> flag writes an array of string
|
||||
values to the specified PV. The numeric argument giving the number of array
|
||||
elements is actually ignored, the array length to be written is actually
|
||||
controlled by the number of values provided on the command line.</p>
|
||||
|
||||
<table border="1">
|
||||
<caption></caption>
|
||||
@@ -1550,12 +1566,16 @@ command line is used.</p>
|
||||
<td>-t</td>
|
||||
<td>Terse mode - print only successfully written value, without name</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-l</td>
|
||||
<td>Long mode "name timestamp value stat sevr" (read PVs as DBR_TIME_xxx)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><strong>Enum Format:</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Default:</td>
|
||||
<td>Auto - try value as ENUM string, then as index number</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -1571,17 +1591,24 @@ command line is used.</p>
|
||||
<td><strong>Arrays:</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-a</td>
|
||||
<td>Put array data</td>
|
||||
<td>Default:</td>
|
||||
<td>Put scalar</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Value format: Print number of requested values, then list of
|
||||
values</td>
|
||||
<td>Value format: all value arguments concatenated with spaces</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-S</td>
|
||||
<td>Put string as an array of char (long string)</td>
|
||||
<td>Put string as an array of chars (long string)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-a</td>
|
||||
<td>Put array</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Value format: number of values, then list of values</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -2052,7 +2079,7 @@ example, be beneficial when tuning an archiver installation.</p>
|
||||
<p>Significant performance gains can be realized when the CA client library
|
||||
doesn't wait for a response to return from the server after each request. All
|
||||
requests which require interaction with a CA server are accumulated (buffered)
|
||||
and not forwarded to the IOC until one of <code>ca_flush_io()</code>,
|
||||
and not forwarded to the IOC until one of <code>ca_flush_io()</code>,
|
||||
<code>ca_pend_io()</code>, <code>ca_pend_event()</code>, or
|
||||
<code>ca_sg_block()</code> are called allowing several operations to be
|
||||
efficiently sent over the network together. Any process variable values written
|
||||
@@ -2076,16 +2103,16 @@ shouldn't test the success of a CA function call by checking to see if the
|
||||
returned value is zero as is the UNIX convention. Below are several methods to
|
||||
test CA function returns. See <a href="#ca_signal"><code>ca_signal()</code> and
|
||||
<code>SEVCHK()</code></a> for more information on this topic.</p>
|
||||
<pre>status = ca_XXXX();
|
||||
SEVCHK( status, "ca_XXXX() returned failure status");
|
||||
<pre>status = ca_XXXX();
|
||||
SEVCHK( status, "ca_XXXX() returned failure status");
|
||||
|
||||
if ( status & CA_M_SUCCESS ) {
|
||||
printf ( "The requested ca_XXXX() operation didn't complete successfully");
|
||||
}
|
||||
if ( status & CA_M_SUCCESS ) {
|
||||
printf ( "The requested ca_XXXX() operation didn't complete successfully");
|
||||
}
|
||||
|
||||
if ( status != ECA_NORMAL ) {
|
||||
if ( status != ECA_NORMAL ) {
|
||||
printf("The requested ca_XXXX() operation didn't complete successfully because \"%s\"\n",
|
||||
ca_message ( status ) );
|
||||
ca_message ( status ) );
|
||||
}</pre>
|
||||
|
||||
<h3><a name="Channel">Channel Access Data Types</a></h3>
|
||||
@@ -2258,7 +2285,7 @@ int main ( int argc, char ** argv )
|
||||
unsigned nBytes;
|
||||
unsigned elementCount;
|
||||
char timeString[32];
|
||||
unsigned i;
|
||||
unsigned i;
|
||||
chid chan;
|
||||
double sum;
|
||||
int status;
|
||||
@@ -2301,7 +2328,7 @@ int main ( int argc, char ** argv )
|
||||
epicsTimeToStrftime ( timeString, sizeof ( timeString ),
|
||||
"%a %b %d %Y %H:%M:%S.%f", & pTD->stamp );
|
||||
|
||||
printf ( "The sum of elements in %s at %s was %f\n",
|
||||
printf ( "The sum of elements in %s at %s was %f\n",
|
||||
argv[1], timeString, sum );
|
||||
|
||||
ca_clear_channel ( chan );
|
||||
@@ -2332,7 +2359,7 @@ executing within the user's callback function.</p>
|
||||
<pre>typedef struct event_handler_args {
|
||||
void *usr; /* user argument supplied with request */
|
||||
chanId chid; /* channel id */
|
||||
long type; /* the type of the item returned */
|
||||
long type; /* the type of the item returned */
|
||||
long count; /* the element count of the item returned */
|
||||
const void *dbr; /* a pointer to the item returned */
|
||||
int status; /* ECA_XXX status of the requested op from the server */
|
||||
@@ -2355,7 +2382,7 @@ attached to the request, an exception handler is executed in the client. The
|
||||
default exception handler prints a message on the console and exits if the
|
||||
exception condition is severe. Certain internal exceptions within the CA client
|
||||
library, and failures detected by the SEVCHK macro may also cause the exception
|
||||
handler to be invoked. To modify this behavior see
|
||||
handler to be invoked. To modify this behavior see
|
||||
<code><a href="#ca_add_exception_event">ca_add_exception_event</a>()</code>.</p>
|
||||
|
||||
<h3><a name="Server">Server and Client Share the Same Address Space on The Same
|
||||
@@ -2647,6 +2674,14 @@ automatically released by the system when the process exits and
|
||||
vxWorks or RTEMS no cleanup occurs unless the application calls
|
||||
<code>ca_context_destroy()</code>.</p>
|
||||
|
||||
<p>Note: This operation blocks until any user callbacks for any channel
|
||||
created in the current context have run to completion. If callbacks take a
|
||||
lock (mutex) then it is the user's responsibility to ensure that this lock
|
||||
is not held when <code>ca_clear_context()</code> is called, otherwise a
|
||||
deadlock may ensue. (See also
|
||||
<code><a href="#ca_clear_channel">ca_clear_channel</a>()</code> and
|
||||
<code><a href="#ca_clear_event">ca_clear_subscription</a>()</code>.)</p>
|
||||
|
||||
<h4>Returns</h4>
|
||||
|
||||
<p>ECA_NORMAL - Normal successful completion</p>
|
||||
@@ -2719,7 +2754,7 @@ time.</p>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt><code>USERFUNC</code></dt>
|
||||
<dd>Optional address of the user's callback function to be run when the
|
||||
<dd>Optional pointer to the user's callback function to be run when the
|
||||
connection state changes. Casual users of channel access may decide to
|
||||
set this field to null or 0 if they do not need to have a callback
|
||||
function run in response to each connection state change event.
|
||||
@@ -2792,6 +2827,12 @@ efficiently sent over the network in one message.</p>
|
||||
clearing a channel does shutdown and reclaim any channel state change event
|
||||
subscriptions (monitors) registered with the channel.</p>
|
||||
|
||||
<p>Note: This operation blocks until any user callbacks for this channel
|
||||
have run to completion. If callbacks take a lock (mutex) then it is the
|
||||
user's responsibility to ensure that this lock is not held when
|
||||
<code>ca_clear_channel()</code> is called, otherwise a deadlock may ensue.
|
||||
(See also <code><a href="#ca_clear_event">ca_clear_subscription</a>()</code>.)</p>
|
||||
|
||||
<h4>Arguments</h4>
|
||||
<dl>
|
||||
<dt><code>CHID</code></dt>
|
||||
@@ -2806,16 +2847,16 @@ subscriptions (monitors) registered with the channel.</p>
|
||||
|
||||
<h3><code><a name="ca_put">ca_put()</a></code></h3>
|
||||
<pre>#include <cadef.h>
|
||||
int ca_put ( chtype TYPE,
|
||||
chid CHID, void *PVALUE );
|
||||
int ca_array_put ( chtype TYPE, unsigned long COUNT,
|
||||
int ca_put ( chtype TYPE,
|
||||
chid CHID, void *PVALUE );
|
||||
int ca_array_put ( chtype TYPE, unsigned long COUNT,
|
||||
chid CHID, const void *PVALUE);
|
||||
typedef void ( caEventCallBackFunc ) (struct event_handler_args);
|
||||
int ca_put_callback ( chtype TYPE,
|
||||
chid CHID, const void *PVALUE,
|
||||
caEventCallBackFunc PFUNC, void *USERARG );
|
||||
int ca_array_put_callback ( chtype TYPE, unsigned long COUNT,
|
||||
chid CHID, const void *PVALUE,
|
||||
int ca_put_callback ( chtype TYPE,
|
||||
chid CHID, const void *PVALUE,
|
||||
caEventCallBackFunc PFUNC, void *USERARG );
|
||||
int ca_array_put_callback ( chtype TYPE, unsigned long COUNT,
|
||||
chid CHID, const void *PVALUE,
|
||||
caEventCallBackFunc PFUNC, void *USERARG );</pre>
|
||||
|
||||
<h4>Description</h4>
|
||||
@@ -2894,7 +2935,7 @@ but they do not cause the record to be processed.</p>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt><code>PFUNC</code></dt>
|
||||
<dd>address of <a href="#User">user supplied callback function</a> to be
|
||||
<dd>Pointer to a <a href="#User">user supplied callback function</a> to be
|
||||
run when the requested operation completes</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
@@ -3002,7 +3043,7 @@ when a CA get request is initiated.</p>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt><code>USERFUNC</code></dt>
|
||||
<dd>Address of <a href="#User">user supplied callback function</a> to be
|
||||
<dd>Pointer to a <a href="#User">user supplied callback function</a> to be
|
||||
run when the requested operation completes.</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
@@ -3042,7 +3083,7 @@ when a CA get request is initiated.</p>
|
||||
typedef void ( caEventCallBackFunc ) (struct event_handler_args);
|
||||
int ca_create_subscription ( chtype TYPE, unsigned long COUNT,
|
||||
chid CHID, unsigned long MASK,
|
||||
caEventCallBackFunc USERFUNC, void *USERARG,
|
||||
caEventCallBackFunc USERFUNC, void *USERARG,
|
||||
evid *PEVID );</pre>
|
||||
|
||||
<h4>Description</h4>
|
||||
@@ -3103,8 +3144,8 @@ indicating the current state of the channel.</p>
|
||||
<dd>channel identifier</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt><code>USRERFUNC</code></dt>
|
||||
<dd>The address of <a href="#User">user supplied callback function</a> to
|
||||
<dt><code>USERFUNC</code></dt>
|
||||
<dd>Pointer to a <a href="#User">user supplied callback function</a> to
|
||||
be invoked with each subscription update.</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
@@ -3126,7 +3167,7 @@ indicating the current state of the channel.</p>
|
||||
<dt><code>MASK</code></dt>
|
||||
<dd>A mask with bits set for each of the event trigger types requested. The
|
||||
event trigger mask must be a <em>bitwise or</em> of one or more of the
|
||||
following constants.
|
||||
following constants.
|
||||
<ul>
|
||||
<li>DBE_VALUE - Trigger events when the channel value exceeds the
|
||||
monitor dead band</li>
|
||||
@@ -3173,6 +3214,13 @@ and not forwarded to the server until one of <code>ca_flush_io()</code>, <code>c
|
||||
<code>ca_pend_event()</code>, or <code>ca_sg_block()</code> are called. This allows several requests to be
|
||||
efficiently sent together in one message.</p>
|
||||
|
||||
<p>Note: This operation blocks until any user callbacks for this channel
|
||||
have run to completion. If callbacks take a lock (mutex) then it is the
|
||||
user's responsibility to ensure that this lock is not held when
|
||||
<code>ca_clear_subscription()</code> is called, otherwise a deadlock may
|
||||
ensue. (See also <code><a
|
||||
href="#ca_clear_channel">ca_clear_channel</a>()</code>.)</p>
|
||||
|
||||
<h4>Arguments</h4>
|
||||
<dl>
|
||||
<dt>EVID</dt>
|
||||
@@ -3337,7 +3385,7 @@ becomes full.</p>
|
||||
|
||||
<h3><code><a name="ca_signal">ca_signal()</a></code></h3>
|
||||
<pre>#include <cadef.h>
|
||||
int ca_signal ( long CA_STATUS, const char * CONTEXT_STRING );
|
||||
int ca_signal ( long CA_STATUS, const char * CONTEXT_STRING );
|
||||
void SEVCHK( CA_STATUS, CONTEXT_STRING );</pre>
|
||||
|
||||
<h4>Description</h4>
|
||||
@@ -3354,7 +3402,7 @@ recommended error handler for simple applications which do not wish to write
|
||||
code testing the status returned from each channel access call.</p>
|
||||
|
||||
<h4>Examples</h4>
|
||||
<pre>status = ca_context_create (...);
|
||||
<pre>status = ca_context_create (...);
|
||||
SEVCHK ( status, "Unable to create a CA client context" );</pre>
|
||||
|
||||
<p>If the application only wishes to print the message associated with an error
|
||||
@@ -3378,7 +3426,7 @@ this purpose.</p>
|
||||
|
||||
<h3><code><a
|
||||
name="ca_add_exception_event">ca_add_exception_event()</a></code></h3>
|
||||
<pre>#include <cadef.h>
|
||||
<pre>#include <cadef.h>
|
||||
typedef void (*pCallback) ( struct exception_handler_args HANDLERARGS );
|
||||
int ca_add_exception_event ( pCallback USERFUNC, void *USERARG );</pre>
|
||||
|
||||
@@ -3402,7 +3450,7 @@ field should not be used.</p>
|
||||
<h4>Arguments</h4>
|
||||
<dl>
|
||||
<dt><code>USERFUNC</code></dt>
|
||||
<dd>Address of user callback function to be executed when an exceptions
|
||||
<dd>Pointer to a user callback function to be executed when exceptions
|
||||
occur. Passing a null value causes the default exception handler to be
|
||||
reinstalled. The following structure is passed by value to the user's
|
||||
callback function. Currently, the <code>op</code> field can be one of
|
||||
@@ -3537,7 +3585,7 @@ default handler uses fprintf to send messages to 'stderr'.</p>
|
||||
<h4>Arguments</h4>
|
||||
<dl>
|
||||
<dt><code>PFUNC</code></dt>
|
||||
<dd>The address of a user supplied callback handler to be invoked when CA
|
||||
<dd>A pointer to a user supplied callback handler to be invoked when CA
|
||||
prints diagnostic messages. Installing a null pointer will cause the
|
||||
default callback handler to be reinstalled.</dd>
|
||||
</dl>
|
||||
@@ -3585,9 +3633,9 @@ specified channel.</p>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt><code>PFUNC</code></dt>
|
||||
<dd>Address of user supplied callback function. A null pointer uninstalls
|
||||
<dd>Pointer to a user supplied callback function. A null pointer uninstalls
|
||||
the current handler. The following arguments are passed <em>by value</em>
|
||||
to the supplied callback handler.
|
||||
to the supplied callback handler.
|
||||
<pre>typedef struct ca_access_rights {
|
||||
unsigned read_access:1;
|
||||
unsigned write_access:1;
|
||||
@@ -3927,8 +3975,8 @@ type.</p>
|
||||
prints diagnostics to standard out.</p>
|
||||
|
||||
<h4>Examples</h4>
|
||||
<pre>void ca_test_event ();
|
||||
status = ca_create_subscription ( type, chid, ca_test_event, NULL, NULL );
|
||||
<pre>void ca_test_event ();
|
||||
status = ca_create_subscription ( type, chid, ca_test_event, NULL, NULL );
|
||||
SEVCHK ( status, .... );</pre>
|
||||
|
||||
<h4>See Also</h4>
|
||||
@@ -3962,8 +4010,8 @@ outstanding within them at any given time.</p>
|
||||
</dl>
|
||||
|
||||
<h4>Examples</h4>
|
||||
<pre>CA_SYNC_GID gid;
|
||||
status = ca_sg_create ( &gid );
|
||||
<pre>CA_SYNC_GID gid;
|
||||
status = ca_sg_create ( &gid );
|
||||
SEVCHK ( status, Sync group create failed );</pre>
|
||||
|
||||
<h4>Returns</h4>
|
||||
@@ -4001,8 +4049,8 @@ int ca_sg_delete ( CA_SYNC_GID GID );</pre>
|
||||
</dl>
|
||||
|
||||
<h4>Examples</h4>
|
||||
<pre>CA_SYNC_GID gid;
|
||||
status = ca_sg_delete ( gid );
|
||||
<pre>CA_SYNC_GID gid;
|
||||
status = ca_sg_delete ( gid );
|
||||
SEVCHK ( status, Sync group delete failed );</pre>
|
||||
|
||||
<h4>Returns</h4>
|
||||
@@ -4113,7 +4161,7 @@ will not block unless additional subsequent requests are made.</p>
|
||||
</dl>
|
||||
|
||||
<h4>Examples</h4>
|
||||
<pre>CA_SYNC_GID gid;
|
||||
<pre>CA_SYNC_GID gid;
|
||||
status = ca_sg_reset(gid);</pre>
|
||||
|
||||
<h4>Returns</h4>
|
||||
@@ -4126,7 +4174,7 @@ status = ca_sg_reset(gid);</pre>
|
||||
<pre>#include <cadef.h>
|
||||
int ca_sg_put ( CA_SYNC_GID GID, chtype TYPE,
|
||||
chid CHID, void *PVALUE );
|
||||
int ca_sg_array_put ( CA_SYNC_GID GID, chtype TYPE,
|
||||
int ca_sg_array_put ( CA_SYNC_GID GID, chtype TYPE,
|
||||
unsigned long COUNT, chid CHID, void *PVALUE );</pre>
|
||||
|
||||
<p>Write a value, or array of values, to a channel and increment the outstanding
|
||||
@@ -4267,7 +4315,7 @@ reissued.</p>
|
||||
|
||||
<h3><code><a name="ca_client_status">ca_client_status()</a></code></h3>
|
||||
<pre>int ca_client_status ( unsigned level );
|
||||
int ca_context_status ( struct ca_client_context *CONTEXT,
|
||||
int ca_context_status ( struct ca_client_context *CONTEXT,
|
||||
unsigned LEVEL );</pre>
|
||||
|
||||
<h4>Description</h4>
|
||||
|
||||
@@ -127,21 +127,10 @@ const char * ca_message_text []
|
||||
|
||||
static epicsThreadOnceId caClientContextIdOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
extern "C" void ca_client_exit_handler (void *)
|
||||
{
|
||||
if ( caClientContextId ) {
|
||||
epicsThreadPrivateDelete ( caClientContextId );
|
||||
caClientContextId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// runs once only for each process
|
||||
extern "C" void ca_init_client_context ( void * )
|
||||
{
|
||||
caClientContextId = epicsThreadPrivateCreate ();
|
||||
if ( caClientContextId ) {
|
||||
epicsAtExit ( ca_client_exit_handler,0 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -635,11 +635,13 @@ void cac::transferChanToVirtCircuit (
|
||||
// must occur before moving to new iiu
|
||||
pChan->getPIIU(guard)->uninstallChanDueToSuccessfulSearchResponse (
|
||||
guard, *pChan, currentTime );
|
||||
piiu->installChannel (
|
||||
guard, *pChan, sid, typeCode, count );
|
||||
if ( piiu ) {
|
||||
piiu->installChannel (
|
||||
guard, *pChan, sid, typeCode, count );
|
||||
|
||||
if ( newIIU ) {
|
||||
piiu->start ( guard );
|
||||
if ( newIIU ) {
|
||||
piiu->start ( guard );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1304,9 +1306,11 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
|
||||
callbackManager mgr ( this->notify, this->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->exception ( mgr.cbGuard, guard, ECA_DBLCHNL, buf, __FILE__, __LINE__ );
|
||||
|
||||
// remove from the list under lock
|
||||
this->msgMultiPVList.remove ( mfmdpv );
|
||||
}
|
||||
// remove from the list and delete msg object
|
||||
this->msgMultiPVList.remove ( mfmdpv );
|
||||
// delete msg object
|
||||
mfmdpv.~msgForMultiplyDefinedPV ();
|
||||
this->mdpvFreeList.release ( & mfmdpv );
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
DBE_ARCHIVE (DBE_LOG)
|
||||
Trigger an event when an archive significant change in the channel's
|
||||
valuue occurs. Relies on the archiver monitor deadband field under DCT.
|
||||
value occurs. Relies on the archiver monitor deadband field under DCT.
|
||||
|
||||
DBE_ALARM
|
||||
Trigger an event when the alarm state changes
|
||||
|
||||
@@ -390,7 +390,7 @@ int epicsShareAPI ca_array_get_callback ( chtype type,
|
||||
{
|
||||
caStatus = ECA_ALLOCMEM;
|
||||
}
|
||||
catch ( cacChannel::msgBodyCacheTooSmall ) {
|
||||
catch ( cacChannel::msgBodyCacheTooSmall & ) {
|
||||
caStatus = ECA_TOLARGE;
|
||||
}
|
||||
catch ( ... )
|
||||
|
||||
@@ -652,7 +652,7 @@ not follow this pattern, but are still printable strings.
|
||||
|
||||
=item [1] R3.15 Channel Access Reference Manual by Jeffrey O. Hill
|
||||
|
||||
L<http://www.aps.anl.gov/epics/base/R3-15/2-docs/CAref.html>
|
||||
L<https://epics.anl.gov/base/R3-15/5-docs/CAref.html>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ Cap5_LIBS = ca Com
|
||||
Cap5_INCLUDES = -I$(shell $(PERL) ../perlConfig.pl archlib)/CORE
|
||||
Cap5_CFLAGS = $(shell $(PERL) ../perlConfig.pl ccflags)
|
||||
|
||||
CLEANS += Cap5.c pod2htmd.tmp pod2htmi.tmp
|
||||
CLEANS += Cap5.c
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
@@ -20,13 +20,16 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
|
||||
HELP_MESSAGE() unless getopts('0:ac:d:e:f:F:g:hnsStw:');
|
||||
HELP_MESSAGE() if $opt_h;
|
||||
|
||||
die "caget: -c option takes a positive number\n"
|
||||
die "caget.pl: -c option takes a positive number\n"
|
||||
unless looks_like_number($opt_c) && $opt_c >= 0;
|
||||
|
||||
die "No pv name specified. ('caget -h' gives help.)\n"
|
||||
die "No pv name specified. ('caget.pl -h' gives help.)\n"
|
||||
unless @ARGV;
|
||||
|
||||
my @chans = map { CA->new($_); } @ARGV;
|
||||
my @chans = map { CA->new($_); } grep { $_ ne '' } @ARGV;
|
||||
|
||||
die "caget.pl: Please provide at least one non-empty pv name\n"
|
||||
unless @chans;
|
||||
|
||||
eval { CA->pend_io($opt_w); };
|
||||
if ($@) {
|
||||
@@ -137,6 +140,10 @@ sub display {
|
||||
printf " Lo ctrl limit: %g\n", $data->{lower_ctrl_limit};
|
||||
printf " Hi ctrl limit: %g\n", $data->{upper_ctrl_limit};
|
||||
}
|
||||
if (exists $data->{ackt}) {
|
||||
printf " Ack transients: %s\n", $data->{ackt} ? 'YES' : 'NO';
|
||||
printf " Ack severity: %s\n", $data->{acks};
|
||||
}
|
||||
} else {
|
||||
my $value = format_number($data, $type);
|
||||
if ($opt_t) {
|
||||
|
||||
@@ -16,10 +16,13 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
|
||||
HELP_MESSAGE() unless getopts('hw:');
|
||||
HELP_MESSAGE() if $opt_h;
|
||||
|
||||
die "No pv name specified. ('cainfo -h' gives help.)\n"
|
||||
die "No pv name specified. ('cainfo.pl -h' gives help.)\n"
|
||||
unless @ARGV;
|
||||
|
||||
my @chans = map { CA->new($_); } @ARGV;
|
||||
my @chans = map { CA->new($_); } grep { $_ ne '' } @ARGV;
|
||||
|
||||
die "cainfo.pl: Please provide at least one non-empty pv name\n"
|
||||
unless @chans;
|
||||
|
||||
eval {
|
||||
CA->pend_io($opt_w);
|
||||
|
||||
@@ -20,14 +20,17 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
|
||||
HELP_MESSAGE() unless getopts('0:c:e:f:F:g:hm:nsSw:');
|
||||
HELP_MESSAGE() if $opt_h;
|
||||
|
||||
die "caget: -c option takes a positive number\n"
|
||||
die "camonitor.pl: -c option takes a positive number\n"
|
||||
unless looks_like_number($opt_c) && $opt_c >= 0;
|
||||
|
||||
die "No pv name specified. ('camonitor -h' gives help.)\n"
|
||||
die "No pv name specified. ('camonitor.pl -h' gives help.)\n"
|
||||
unless @ARGV;
|
||||
|
||||
my %monitors;
|
||||
my @chans = map { CA->new($_, \&conn_callback); } @ARGV;
|
||||
my @chans = map { CA->new($_, \&conn_callback); } grep { $_ ne '' } @ARGV;
|
||||
|
||||
die "camonitor.pl: Please provide at least one non-empty pv name\n"
|
||||
unless @chans;
|
||||
|
||||
my $fmt = ($opt_F eq ' ') ? "%-30s %s\n" : "%s$opt_F%s\n";
|
||||
|
||||
|
||||
@@ -17,11 +17,13 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
|
||||
HELP_MESSAGE() unless getopts('achlnsStw:');
|
||||
HELP_MESSAGE() if $opt_h;
|
||||
|
||||
die "No pv name specified. ('caput -h' gives help.)\n"
|
||||
die "No pv name specified. ('caput.pl -h' gives help.)\n"
|
||||
unless @ARGV;
|
||||
my $pv = shift;
|
||||
die "caput.pl: Empty pv name given.\n"
|
||||
unless $pv ne '';
|
||||
|
||||
die "No value specified. ('caput -h' gives help.)\n"
|
||||
die "No value specified. ('caput.pl -h' gives help.)\n"
|
||||
unless @ARGV;
|
||||
|
||||
my $chan = CA->new($pv);
|
||||
|
||||
@@ -504,6 +504,7 @@ void ca_repeater ()
|
||||
if ( sockerrno == SOCK_EADDRINUSE ) {
|
||||
osiSockRelease ();
|
||||
debugPrintf ( ( "CA Repeater: exiting because a repeater is already running\n" ) );
|
||||
delete [] pBuf;
|
||||
return;
|
||||
}
|
||||
char sockErrBuf[64];
|
||||
|
||||
@@ -541,11 +541,11 @@ int main (int argc, char *argv[])
|
||||
for (n = 0; optind < argc; n++, optind++)
|
||||
pvs[n].name = argv[optind] ; /* Copy PV names from command line */
|
||||
|
||||
connect_pvs(pvs, nPvs);
|
||||
result = connect_pvs(pvs, nPvs);
|
||||
|
||||
/* Read and print data */
|
||||
|
||||
result = caget(pvs, nPvs, request, format, type, count);
|
||||
if (!result)
|
||||
result = caget(pvs, nPvs, request, format, type, count);
|
||||
|
||||
/* Shut down Channel Access */
|
||||
ca_context_destroy();
|
||||
|
||||
@@ -211,10 +211,11 @@ int main (int argc, char *argv[])
|
||||
for (n = 0; optind < argc; n++, optind++)
|
||||
pvs[n].name = argv[optind] ; /* Copy PV names from command line */
|
||||
|
||||
connect_pvs(pvs, nPvs);
|
||||
result = connect_pvs(pvs, nPvs);
|
||||
|
||||
/* Print data */
|
||||
result = cainfo(pvs, nPvs);
|
||||
if (!result)
|
||||
result = cainfo(pvs, nPvs);
|
||||
|
||||
/* Shut down Channel Access */
|
||||
ca_context_destroy();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Copyright (c) 2002 Berliner Elektronenspeicherringgesellschaft fuer
|
||||
* Synchrotronstrahlung.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
@@ -56,7 +56,7 @@ static epicsEventId epId;
|
||||
|
||||
void usage (void)
|
||||
{
|
||||
fprintf (stderr, "\nUsage: caput [options] <PV name> <PV value>\n"
|
||||
fprintf (stderr, "\nUsage: caput [options] <PV name> <PV value> ...\n"
|
||||
" caput -a [options] <PV name> <no of values> <PV value> ...\n\n"
|
||||
" -h: Help: Print this message\n"
|
||||
"Channel Access options:\n"
|
||||
@@ -71,9 +71,11 @@ void usage (void)
|
||||
" -n: Force interpretation of values as numbers\n"
|
||||
" -s: Force interpretation of values as strings\n"
|
||||
"Arrays:\n"
|
||||
" Default: Put scalar\n"
|
||||
" Value format: all value arguments concatenated with spaces\n"
|
||||
" -S: Put string as an array of chars (long string)\n"
|
||||
" -a: Put array\n"
|
||||
" Value format: number of requested values, then list of values\n"
|
||||
" -S: Put string as an array of char (long string)\n"
|
||||
" Value format: number of values, then list of values\n"
|
||||
"Alternate output field separator:\n"
|
||||
" -F <ofs>: Use <ofs> as an alternate output field separator\n"
|
||||
"\nExample: caput my_channel 1.2\n"
|
||||
@@ -417,7 +419,7 @@ int main (int argc, char *argv[])
|
||||
if (argc > optind+1) {
|
||||
for (i = optind + 1; i < argc; i++) {
|
||||
strcat(cbuf, " ");
|
||||
strcat(cbuf, argv[i]);
|
||||
strcat(cbuf, argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,6 +530,11 @@ int main (int argc, char *argv[])
|
||||
/* Use standard put with defined timeout */
|
||||
result = ca_array_put (dbrType, count, pvs[0].chid, pbuf);
|
||||
}
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "Error from put operation: %s\n", ca_message(result));
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = ca_pend_io(caTimeout);
|
||||
if (result == ECA_TIMEOUT) {
|
||||
fprintf(stderr, "Write operation timed out: Data was not written.\n");
|
||||
@@ -543,7 +550,7 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "Error occured writing data.\n");
|
||||
fprintf(stderr, "Error occured writing data: %s\n", ca_message(result));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,14 +79,14 @@ static void sprint_long (char *ret, dbr_long_t val, IntFormatT outType)
|
||||
}
|
||||
else {
|
||||
const char *fmt[4] = { /* Order must match the enum IntFormatT */
|
||||
"%ld" /* dec */,
|
||||
"0" /* bin, val is 0 */,
|
||||
"0o%lo" /* oct */,
|
||||
"0x%lX" /* hex */
|
||||
"%d" /* dec */,
|
||||
"0" /* bin and val is 0 */,
|
||||
"0o%o" /* oct */,
|
||||
"0x%X" /* hex */
|
||||
};
|
||||
|
||||
/* Formats have long modifier, pass value as a long */
|
||||
sprintf(ret, fmt[outType], (long) val);
|
||||
/* dbr_long_t is actually an int on all supported platforms */
|
||||
sprintf(ret, fmt[outType], (int) val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,6 +414,12 @@ char *dbr2str (const void *value, unsigned type)
|
||||
ptsNewS = &((struct TYPE *)value)->stamp; \
|
||||
ptsNewC = &tsNow; \
|
||||
\
|
||||
if (!tsInitS) \
|
||||
{ \
|
||||
tsFirst = *ptsNewS; \
|
||||
tsInitS = 1; \
|
||||
} \
|
||||
\
|
||||
switch (tsType) { \
|
||||
case relative: \
|
||||
ptsRefC = &tsStart; \
|
||||
@@ -506,12 +512,6 @@ void print_time_val_sts (pv* pv, unsigned long reqElems)
|
||||
epicsTimeGetCurrent(&tsNow);
|
||||
epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, &tsNow);
|
||||
|
||||
if (!tsInitS)
|
||||
{
|
||||
tsFirst = tsNow;
|
||||
tsInitS = 1;
|
||||
}
|
||||
|
||||
if (pv->nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
|
||||
else printf("%s", pv->name);
|
||||
printf("%c", fieldSeparator);
|
||||
|
||||
@@ -165,7 +165,7 @@ udpiiu::udpiiu (
|
||||
|
||||
#ifdef IP_ADD_MEMBERSHIP
|
||||
{
|
||||
int flag = 1;
|
||||
osiSockOptMcastLoop_t flag = 1;
|
||||
if ( setsockopt ( this->sock, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
(char *) &flag, sizeof ( flag ) ) == -1 ) {
|
||||
char sockErrBuf[64];
|
||||
@@ -915,10 +915,12 @@ bool udpiiu::pushDatagramMsg ( epicsGuard < epicsMutex > & guard,
|
||||
|
||||
caHdr * pbufmsg = ( caHdr * ) &this->xmitBuf[this->nBytesInXmitBuf];
|
||||
*pbufmsg = msg;
|
||||
memcpy ( pbufmsg + 1, pExt, extsize );
|
||||
if ( extsize != alignedExtSize ) {
|
||||
char *pDest = (char *) ( pbufmsg + 1 );
|
||||
memset ( pDest + extsize, '\0', alignedExtSize - extsize );
|
||||
if ( extsize ) {
|
||||
memcpy ( pbufmsg + 1, pExt, extsize );
|
||||
if ( extsize != alignedExtSize ) {
|
||||
char *pDest = (char *) ( pbufmsg + 1 );
|
||||
memset ( pDest + extsize, '\0', alignedExtSize - extsize );
|
||||
}
|
||||
}
|
||||
AlignedWireRef < epicsUInt16 > ( pbufmsg->m_postsize ) = alignedExtSize;
|
||||
this->nBytesInXmitBuf += msgsize;
|
||||
|
||||
@@ -308,7 +308,7 @@ void gdd::test()
|
||||
pdd->convertOffsetsToAddress();
|
||||
pdd->dump();
|
||||
pdd->unreference();
|
||||
delete buf;
|
||||
delete [] buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -510,7 +510,7 @@ void gddContainer::test(void)
|
||||
fprintf(stderr,"=====RE-DUMP OF ORIGINAL CONTAINER:\n");
|
||||
dump();
|
||||
cdd1->unreference();
|
||||
delete buf;
|
||||
delete [] buf;
|
||||
|
||||
// test copy(), Dup(), copyInfo()
|
||||
fprintf(stderr,"=======CREATING TEST CONTAINER FOR *COPY* TEST:\n");
|
||||
|
||||
@@ -74,10 +74,9 @@ LIBSRCS += casStreamIO.cc
|
||||
LIBSRCS += ipIgnoreEntry.cc
|
||||
|
||||
# There is a bug in some vxWorks compilers that these work around:
|
||||
ifeq ($(VX_GNU_VERSION), 4.1.2)
|
||||
casStreamOS_CXXFLAGS_vxWorks-ppc604_altivec = -O0
|
||||
casStreamOS_CXXFLAGS_vxWorks-ppc604_long = -O0
|
||||
casStreamOS_CXXFLAGS_vxWorks-ppc604 = -O0
|
||||
ifeq ($(VXWORKS_VERSION)$(filter -mcpu=604,$(ARCH_DEP_CFLAGS)), 6.6-mcpu=604)
|
||||
casDGIntfOS_CXXFLAGS = -fno-inline
|
||||
casStreamOS_CXXFLAGS = -fno-inline
|
||||
endif
|
||||
|
||||
LIBSRCS_vxWorks += templateInstances.cpp
|
||||
|
||||
@@ -170,7 +170,7 @@ static int parseDirectoryFP (FILE *pf, const char *pFileName)
|
||||
|
||||
status = aToIPAddr (hostNameStr, 0u, &ipa);
|
||||
if (status) {
|
||||
fprintf (pf, "Unknown host name=\"%s\" (or bad dotted ip addr) in \"%s\" with PV=\"%s\"?\n",
|
||||
fprintf (stderr, "Unknown host name=\"%s\" (or bad dotted ip addr) in \"%s\" with PV=\"%s\"?\n",
|
||||
hostNameStr, pFileName, pvNameStr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ casChannelI::casChannelI ( casCoreClient & clientIn,
|
||||
casChannel & chanIn, casPVI & pvIn, ca_uint32_t cidIn ) :
|
||||
privateForPV ( clientIn, *this ),
|
||||
pv ( pvIn ),
|
||||
maxElem( pvIn.nativeCount() ),
|
||||
chan ( chanIn ),
|
||||
cid ( cidIn ),
|
||||
serverDeletePending ( false ),
|
||||
@@ -29,7 +30,7 @@ casChannelI::casChannelI ( casCoreClient & clientIn,
|
||||
}
|
||||
|
||||
casChannelI::~casChannelI ()
|
||||
{
|
||||
{
|
||||
this->privateForPV.client().removeFromEventQueue (
|
||||
*this, this->accessRightsEvPending );
|
||||
|
||||
@@ -48,7 +49,7 @@ void casChannelI::uninstallFromPV ( casEventSys & eventSys )
|
||||
this->privateForPV.removeSelfFromPV ( this->pv, dest );
|
||||
while ( casMonitor * pMon = dest.get () ) {
|
||||
eventSys.prepareMonitorForDestroy ( *pMon );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void casChannelI::show ( unsigned level ) const
|
||||
@@ -68,13 +69,13 @@ caStatus casChannelI::cbFunc (
|
||||
{
|
||||
caStatus stat = S_cas_success;
|
||||
{
|
||||
stat = this->privateForPV.client().accessRightsResponse (
|
||||
stat = this->privateForPV.client().accessRightsResponse (
|
||||
clientGuard, this );
|
||||
}
|
||||
if ( stat == S_cas_success ) {
|
||||
this->accessRightsEvPending = false;
|
||||
}
|
||||
return stat;
|
||||
if ( stat == S_cas_success ) {
|
||||
this->accessRightsEvPending = false;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
caStatus casChannelI::read ( const casCtx & ctx, gdd & prototype )
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
@@ -31,55 +30,62 @@ class casChannelI : public tsDLNode < casChannelI >,
|
||||
public:
|
||||
casChannelI ( casCoreClient & clientIn, casChannel & chanIn,
|
||||
casPVI & pvIn, ca_uint32_t cidIn );
|
||||
~casChannelI ();
|
||||
~casChannelI ();
|
||||
void casChannelDestroyFromInterfaceNotify ();
|
||||
const caResId getCID ();
|
||||
const caResId getSID ();
|
||||
const caResId getCID ();
|
||||
const caResId getSID ();
|
||||
void uninstallFromPV ( casEventSys & eventSys );
|
||||
void installIntoPV ();
|
||||
void installIO ( casAsyncIOI & );
|
||||
void uninstallIO ( casAsyncIOI & );
|
||||
void installMonitor ( casMonitor & mon );
|
||||
casMonitor * removeMonitor ( ca_uint32_t clientIdIn );
|
||||
casPVI & getPVI () const;
|
||||
void clearOutstandingReads ();
|
||||
void postAccessRightsEvent ();
|
||||
casPVI & getPVI () const;
|
||||
void clearOutstandingReads ();
|
||||
void postAccessRightsEvent ();
|
||||
const gddEnumStringTable & enumStringTable () const;
|
||||
void setOwner ( const char * const pUserName,
|
||||
const char * const pHostName );
|
||||
bool readAccess () const;
|
||||
ca_uint32_t getMaxElem () const;
|
||||
void setOwner ( const char * const pUserName,
|
||||
const char * const pHostName );
|
||||
bool readAccess () const;
|
||||
bool writeAccess () const;
|
||||
bool confirmationRequested () const;
|
||||
bool confirmationRequested () const;
|
||||
caStatus read ( const casCtx & ctx, gdd & prototype );
|
||||
caStatus write ( const casCtx & ctx, const gdd & value );
|
||||
caStatus writeNotify ( const casCtx & ctx, const gdd & value );
|
||||
void show ( unsigned level ) const;
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
chanIntfForPV privateForPV;
|
||||
tsDLList < casAsyncIOI > ioList;
|
||||
casPVI & pv;
|
||||
tsDLList < casAsyncIOI > ioList;
|
||||
casPVI & pv;
|
||||
ca_uint32_t maxElem;
|
||||
casChannel & chan;
|
||||
caResId cid; // client id
|
||||
caResId cid; // client id
|
||||
bool serverDeletePending;
|
||||
bool accessRightsEvPending;
|
||||
//epicsShareFunc virtual void destroy ();
|
||||
caStatus cbFunc (
|
||||
bool accessRightsEvPending;
|
||||
//epicsShareFunc virtual void destroy ();
|
||||
caStatus cbFunc (
|
||||
casCoreClient &,
|
||||
epicsGuard < casClientMutex > &,
|
||||
epicsGuard < evSysMutex > & );
|
||||
void postDestroyEvent ();
|
||||
casChannelI ( const casChannelI & );
|
||||
casChannelI & operator = ( const casChannelI & );
|
||||
casChannelI ( const casChannelI & );
|
||||
casChannelI & operator = ( const casChannelI & );
|
||||
};
|
||||
|
||||
inline casPVI & casChannelI::getPVI () const
|
||||
{
|
||||
return this->pv;
|
||||
return this->pv;
|
||||
}
|
||||
|
||||
inline ca_uint32_t casChannelI::getMaxElem () const
|
||||
{
|
||||
return this->maxElem;
|
||||
}
|
||||
|
||||
inline const caResId casChannelI::getCID ()
|
||||
{
|
||||
return this->cid;
|
||||
return this->cid;
|
||||
}
|
||||
|
||||
inline const caResId casChannelI::getSID ()
|
||||
@@ -89,7 +95,7 @@ inline const caResId casChannelI::getSID ()
|
||||
|
||||
inline void casChannelI::postAccessRightsEvent ()
|
||||
{
|
||||
this->privateForPV.client().addToEventQueue ( *this, this->accessRightsEvPending );
|
||||
this->privateForPV.client().addToEventQueue ( *this, this->accessRightsEvPending );
|
||||
}
|
||||
|
||||
inline const gddEnumStringTable & casChannelI::enumStringTable () const
|
||||
@@ -108,7 +114,7 @@ inline void casChannelI::clearOutstandingReads ()
|
||||
}
|
||||
|
||||
inline void casChannelI::setOwner ( const char * const pUserName,
|
||||
const char * const pHostName )
|
||||
const char * const pHostName )
|
||||
{
|
||||
this->chan.setOwner ( pUserName, pHostName );
|
||||
}
|
||||
|
||||
@@ -24,39 +24,39 @@
|
||||
|
||||
casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
|
||||
{
|
||||
& casDGClient::versionAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::versionAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::searchAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::echoAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::echoAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction
|
||||
};
|
||||
|
||||
//
|
||||
@@ -84,7 +84,7 @@ casDGClient::~casDGClient()
|
||||
//
|
||||
void casDGClient::destroy()
|
||||
{
|
||||
printf("Attempt to destroy the DG client was ignored\n");
|
||||
printf("Attempt to destroy the DG client was ignored\n");
|
||||
}
|
||||
|
||||
//
|
||||
@@ -92,16 +92,16 @@ void casDGClient::destroy()
|
||||
//
|
||||
void casDGClient::show (unsigned level) const
|
||||
{
|
||||
printf ( "casDGClient at %p\n",
|
||||
printf ( "casDGClient at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
if (level>=1u) {
|
||||
char buf[64];
|
||||
this->hostName (buf, sizeof(buf));
|
||||
printf ("Client Host=%s\n", buf);
|
||||
if (level>=1u) {
|
||||
char buf[64];
|
||||
this->hostName (buf, sizeof(buf));
|
||||
printf ("Client Host=%s\n", buf);
|
||||
this->casCoreClient::show ( level - 1u );
|
||||
this->in.show ( level - 1u );
|
||||
this->out.show ( level - 1u );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -109,7 +109,7 @@ void casDGClient::show (unsigned level) const
|
||||
//
|
||||
caStatus casDGClient::uknownMessageAction ()
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
@@ -117,7 +117,7 @@ caStatus casDGClient::uknownMessageAction ()
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"bad request code=%u in DG\n", mp->m_cmmd );
|
||||
|
||||
return S_cas_badProtocol;
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -125,9 +125,9 @@ caStatus casDGClient::uknownMessageAction ()
|
||||
//
|
||||
caStatus casDGClient::searchAction()
|
||||
{
|
||||
const caHdrLargeArray *mp = this->ctx.getMsg();
|
||||
const caHdrLargeArray *mp = this->ctx.getMsg();
|
||||
const char *pChanName = static_cast <char * > ( this->ctx.getData() );
|
||||
caStatus status;
|
||||
caStatus status;
|
||||
|
||||
//
|
||||
// check the sanity of the message
|
||||
@@ -135,7 +135,7 @@ caStatus casDGClient::searchAction()
|
||||
if ( mp->m_postsize <= 1 ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"empty PV name extension in UDP search request?\n" );
|
||||
return S_cas_success;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ caStatus casDGClient::searchAction()
|
||||
if ( pChanName[0] == '\0' ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"zero length PV name in UDP search request?\n" );
|
||||
return S_cas_success;
|
||||
}
|
||||
@@ -155,56 +155,56 @@ caStatus casDGClient::searchAction()
|
||||
if ( i <= 1 ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"unterminated PV name in UDP search request?\n" );
|
||||
return S_cas_success;
|
||||
}
|
||||
}
|
||||
|
||||
if ( this->getCAS().getDebugLevel() > 6u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is searching for \"%s\"\n",
|
||||
if ( this->getCAS().getDebugLevel() > 6u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is searching for \"%s\"\n",
|
||||
pHostName, pChanName );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// verify that we have sufficent memory for a PV and a
|
||||
// monitor prior to calling PV exist test so that when
|
||||
// the server runs out of memory we dont reply to
|
||||
// search requests, and therefore dont thrash through
|
||||
// caServer::pvExistTest() and casCreatePV::pvAttach()
|
||||
//
|
||||
//
|
||||
// verify that we have sufficent memory for a PV and a
|
||||
// monitor prior to calling PV exist test so that when
|
||||
// the server runs out of memory we dont reply to
|
||||
// search requests, and therefore dont thrash through
|
||||
// caServer::pvExistTest() and casCreatePV::pvAttach()
|
||||
//
|
||||
if ( ! osiSufficentSpaceInPool ( 0 ) ) {
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
//
|
||||
// ask the server tool if this PV exists
|
||||
//
|
||||
this->userStartedAsyncIO = false;
|
||||
pvExistReturn pver =
|
||||
this->getCAS()->pvExistTest ( this->ctx, this->lastRecvAddr, pChanName );
|
||||
//
|
||||
// ask the server tool if this PV exists
|
||||
//
|
||||
this->userStartedAsyncIO = false;
|
||||
pvExistReturn pver =
|
||||
this->getCAS()->pvExistTest ( this->ctx, this->lastRecvAddr, pChanName );
|
||||
|
||||
//
|
||||
// prevent problems when they initiate
|
||||
// async IO but dont return status
|
||||
// indicating so (and vise versa)
|
||||
//
|
||||
if ( this->userStartedAsyncIO ) {
|
||||
//
|
||||
// prevent problems when they initiate
|
||||
// async IO but dont return status
|
||||
// indicating so (and vise versa)
|
||||
//
|
||||
if ( this->userStartedAsyncIO ) {
|
||||
if ( pver.getStatus() != pverAsyncCompletion ) {
|
||||
errMessage (S_cas_badParameter,
|
||||
"- assuming asynch IO status from caServer::pvExistTest()");
|
||||
errMessage (S_cas_badParameter,
|
||||
"- assuming asynch IO status from caServer::pvExistTest()");
|
||||
}
|
||||
status = S_cas_success;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// otherwise we assume sync IO operation was initiated
|
||||
//
|
||||
}
|
||||
else {
|
||||
//
|
||||
// otherwise we assume sync IO operation was initiated
|
||||
//
|
||||
switch ( pver.getStatus() ) {
|
||||
case pverExistsHere:
|
||||
status = this->searchResponse (*mp, pver);
|
||||
status = this->searchResponse (*mp, pver);
|
||||
break;
|
||||
|
||||
case pverDoesNotExistHere:
|
||||
@@ -212,18 +212,18 @@ caStatus casDGClient::searchAction()
|
||||
break;
|
||||
|
||||
case pverAsyncCompletion:
|
||||
errMessage (S_cas_badParameter,
|
||||
"- unexpected asynch IO status from caServer::pvExistTest() ignored");
|
||||
errMessage (S_cas_badParameter,
|
||||
"- unexpected asynch IO status from caServer::pvExistTest() ignored");
|
||||
status = S_cas_success;
|
||||
break;
|
||||
|
||||
default:
|
||||
errMessage (S_cas_badParameter,
|
||||
"- invalid return from caServer::pvExistTest() ignored");
|
||||
errMessage (S_cas_badParameter,
|
||||
"- invalid return from caServer::pvExistTest() ignored");
|
||||
status = S_cas_success;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -340,9 +340,9 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
}
|
||||
|
||||
//
|
||||
// casDGClient::searchFailResponse()
|
||||
// (only when requested by the client
|
||||
// - when it isnt a reply to a broadcast)
|
||||
// casDGClient::searchFailResponse()
|
||||
// (only when requested by the client
|
||||
// - when it isnt a reply to a broadcast)
|
||||
//
|
||||
caStatus casDGClient::searchFailResponse ( const caHdrLargeArray * mp )
|
||||
{
|
||||
@@ -350,9 +350,9 @@ caStatus casDGClient::searchFailResponse ( const caHdrLargeArray * mp )
|
||||
this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
|
||||
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available, 0 );
|
||||
|
||||
this->out.commitMsg ();
|
||||
this->out.commitMsg ();
|
||||
|
||||
return S_cas_success;
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -360,7 +360,7 @@ caStatus casDGClient::searchFailResponse ( const caHdrLargeArray * mp )
|
||||
*/
|
||||
caStatus casDGClient::versionAction ()
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
|
||||
if ( mp->m_count != 0 ) {
|
||||
this->minor_version_number = static_cast <ca_uint16_t> ( mp->m_count );
|
||||
@@ -371,7 +371,7 @@ caStatus casDGClient::versionAction ()
|
||||
this->seqNoOfReq = 0;
|
||||
}
|
||||
}
|
||||
return S_cas_success;
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -380,25 +380,25 @@ caStatus casDGClient::versionAction ()
|
||||
//
|
||||
void casDGClient::sendBeacon ( ca_uint32_t beaconNumber )
|
||||
{
|
||||
union {
|
||||
caHdr msg;
|
||||
char buf;
|
||||
};
|
||||
union {
|
||||
caHdr msg;
|
||||
char buf;
|
||||
};
|
||||
|
||||
//
|
||||
// create the message
|
||||
//
|
||||
memset ( & buf, 0, sizeof ( msg ) );
|
||||
//
|
||||
// create the message
|
||||
//
|
||||
memset ( & buf, 0, sizeof ( msg ) );
|
||||
AlignedWireRef < epicsUInt16 > ( msg.m_cmmd ) = CA_PROTO_RSRV_IS_UP;
|
||||
AlignedWireRef < epicsUInt16 > ( msg.m_dataType ) = CA_MINOR_PROTOCOL_REVISION;
|
||||
AlignedWireRef < epicsUInt32 > ( msg.m_cid ) = beaconNumber;
|
||||
|
||||
//
|
||||
// send it to all addresses on the beacon list,
|
||||
//
|
||||
// send it to all addresses on the beacon list,
|
||||
// but let the IO specific code set the address
|
||||
// field and the port field
|
||||
//
|
||||
this->sendBeaconIO ( buf, sizeof (msg), msg.m_count, msg.m_available );
|
||||
//
|
||||
this->sendBeaconIO ( buf, sizeof (msg), msg.m_count, msg.m_available );
|
||||
}
|
||||
|
||||
//
|
||||
@@ -419,8 +419,8 @@ outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
|
||||
|
||||
if ( pHdr->cadg_addr.isValid() ) {
|
||||
outBufClient::flushCondition stat =
|
||||
this->osdSend ( pDG, sizeDG, pHdr->cadg_addr );
|
||||
if ( stat != outBufClient::flushProgress ) {
|
||||
this->osdSend ( pDG, sizeDG, pHdr->cadg_addr );
|
||||
if ( stat != outBufClient::flushProgress ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -429,10 +429,10 @@ outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
|
||||
}
|
||||
|
||||
if ( totalBytes ) {
|
||||
//
|
||||
// !! this time fetch may be slowing things down !!
|
||||
//
|
||||
//this->lastSendTS = epicsTime::getCurrent();
|
||||
//
|
||||
// !! this time fetch may be slowing things down !!
|
||||
//
|
||||
//this->lastSendTS = epicsTime::getCurrent();
|
||||
nBytesSent = totalBytes;
|
||||
return outBufClient::flushProgress;
|
||||
}
|
||||
@@ -455,16 +455,16 @@ inBufClient::fillCondition casDGClient::xRecv (char *pBufIn, bufSizeT nBytesToRe
|
||||
|
||||
while (pAfter-pCurBuf >= static_cast<int>(MAX_UDP_RECV+sizeof(cadg))) {
|
||||
pHdr = reinterpret_cast < cadg * > ( pCurBuf );
|
||||
stat = this->osdRecv ( reinterpret_cast < char * > ( pHdr + 1 ),
|
||||
stat = this->osdRecv ( reinterpret_cast < char * > ( pHdr + 1 ),
|
||||
MAX_UDP_RECV, parm, nDGBytesRecv, pHdr->cadg_addr);
|
||||
if (stat==casFillProgress) {
|
||||
if (stat==casFillProgress) {
|
||||
pHdr->cadg_nBytes = nDGBytesRecv + sizeof(*pHdr);
|
||||
pCurBuf += pHdr->cadg_nBytes;
|
||||
//
|
||||
// !! this time fetch may be slowing things down !!
|
||||
//
|
||||
//this->lastRecvTS = epicsTime::getCurrent();
|
||||
}
|
||||
//
|
||||
// !! this time fetch may be slowing things down !!
|
||||
//
|
||||
//this->lastRecvTS = epicsTime::getCurrent();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
@@ -515,7 +515,7 @@ caStatus casDGClient::asyncSearchResponse (
|
||||
pMsg->m_dataType = htons ( sequenceNoIsValid );
|
||||
}
|
||||
|
||||
caStatus stat = this->searchResponse ( msg, retVal );
|
||||
caStatus stat = this->searchResponse ( msg, retVal );
|
||||
|
||||
pRespHdr->cadg_nBytes = this->out.popCtx (outctx) + sizeof ( *pRespHdr );
|
||||
if ( pRespHdr->cadg_nBytes > sizeof ( *pRespHdr ) + sizeof (caHdr) ) {
|
||||
@@ -523,7 +523,7 @@ caStatus casDGClient::asyncSearchResponse (
|
||||
this->out.commitRawMsg ( pRespHdr->cadg_nBytes );
|
||||
}
|
||||
|
||||
return stat;
|
||||
return stat;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -644,6 +644,11 @@ caStatus casDGClient::processDG ()
|
||||
if ( status != S_cas_success ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( this->in.bytesPresent () > 0 && dgInBytesConsumed == 0 && status == S_cas_success ) {
|
||||
this->in.removeMsg ( this->in.bytesPresent() );
|
||||
}
|
||||
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -653,7 +658,7 @@ caStatus casDGClient::processDG ()
|
||||
//
|
||||
unsigned casDGClient::getDebugLevel() const
|
||||
{
|
||||
return this->getCAS().getDebugLevel();
|
||||
return this->getCAS().getDebugLevel();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -661,7 +666,7 @@ unsigned casDGClient::getDebugLevel() const
|
||||
//
|
||||
caNetAddr casDGClient::fetchLastRecvAddr () const
|
||||
{
|
||||
return this->lastRecvAddr;
|
||||
return this->lastRecvAddr;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -669,7 +674,7 @@ caNetAddr casDGClient::fetchLastRecvAddr () const
|
||||
//
|
||||
ca_uint32_t casDGClient::datagramSequenceNumber () const
|
||||
{
|
||||
return this->seqNoOfReq;
|
||||
return this->seqNoOfReq;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -729,27 +734,27 @@ outBufClient::flushCondition casDGClient::flush ()
|
||||
//
|
||||
caStatus casDGClient::processMsg ()
|
||||
{
|
||||
int status = S_cas_success;
|
||||
int status = S_cas_success;
|
||||
|
||||
try {
|
||||
unsigned bytesLeft;
|
||||
while ( ( bytesLeft = this->in.bytesPresent() ) ) {
|
||||
unsigned bytesLeft;
|
||||
while ( ( bytesLeft = this->in.bytesPresent() ) ) {
|
||||
caHdrLargeArray msgTmp;
|
||||
unsigned msgSize;
|
||||
ca_uint32_t hdrSize;
|
||||
char * rawMP;
|
||||
{
|
||||
//
|
||||
// copy as raw bytes in order to avoid
|
||||
// alignment problems
|
||||
//
|
||||
//
|
||||
// copy as raw bytes in order to avoid
|
||||
// alignment problems
|
||||
//
|
||||
caHdr smallHdr;
|
||||
if ( bytesLeft < sizeof ( smallHdr ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
rawMP = this->in.msgPtr ();
|
||||
memcpy ( & smallHdr, rawMP, sizeof ( smallHdr ) );
|
||||
memcpy ( & smallHdr, rawMP, sizeof ( smallHdr ) );
|
||||
|
||||
ca_uint32_t payloadSize = AlignedWireRef < epicsUInt16 > ( smallHdr.m_postsize );
|
||||
ca_uint32_t nElem = AlignedWireRef < epicsUInt16 > ( smallHdr.m_count );
|
||||
@@ -798,45 +803,45 @@ caStatus casDGClient::processMsg ()
|
||||
|
||||
this->ctx.setMsg ( msgTmp, rawMP + hdrSize );
|
||||
|
||||
if ( this->getCAS().getDebugLevel() > 5u ) {
|
||||
if ( this->getCAS().getDebugLevel() > 5u ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?",
|
||||
caServerI::dumpMsg ( pHostName, "?",
|
||||
& msgTmp, rawMP + hdrSize, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the context to the default
|
||||
// (guarantees that previous message does not get mixed
|
||||
// up with the current message)
|
||||
//
|
||||
this->ctx.setChannel ( NULL );
|
||||
this->ctx.setPV ( NULL );
|
||||
//
|
||||
// Reset the context to the default
|
||||
// (guarantees that previous message does not get mixed
|
||||
// up with the current message)
|
||||
//
|
||||
this->ctx.setChannel ( NULL );
|
||||
this->ctx.setPV ( NULL );
|
||||
|
||||
//
|
||||
// Call protocol stub
|
||||
//
|
||||
//
|
||||
// Call protocol stub
|
||||
//
|
||||
casDGClient::pCASMsgHandler pHandler;
|
||||
if ( msgTmp.m_cmmd < NELEMENTS ( casDGClient::msgHandlers ) ) {
|
||||
if ( msgTmp.m_cmmd < NELEMENTS ( casDGClient::msgHandlers ) ) {
|
||||
pHandler = this->casDGClient::msgHandlers[msgTmp.m_cmmd];
|
||||
}
|
||||
}
|
||||
else {
|
||||
pHandler = & casDGClient::uknownMessageAction;
|
||||
}
|
||||
status = ( this->*pHandler ) ();
|
||||
if ( status ) {
|
||||
status = ( this->*pHandler ) ();
|
||||
if ( status ) {
|
||||
this->in.removeMsg ( this->in.bytesPresent() );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this->in.removeMsg ( msgSize );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( std::exception & except ) {
|
||||
this->in.removeMsg ( this->in.bytesPresent() );
|
||||
status = this->sendErr (
|
||||
this->sendErr (
|
||||
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
|
||||
"C++ exception \"%s\" in CA circuit server",
|
||||
except.what () );
|
||||
@@ -844,13 +849,13 @@ caStatus casDGClient::processMsg ()
|
||||
}
|
||||
catch (...) {
|
||||
this->in.removeMsg ( this->in.bytesPresent() );
|
||||
status = this->sendErr (
|
||||
this->sendErr (
|
||||
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
|
||||
"unexpected C++ exception in CA datagram server" );
|
||||
status = S_cas_internal;
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -859,24 +864,25 @@ caStatus casDGClient::processMsg ()
|
||||
caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
|
||||
ca_uint32_t cid, const int reportedStatus, const char *pformat, ... )
|
||||
{
|
||||
unsigned stringSize;
|
||||
char msgBuf[1024]; /* allocate plenty of space for the message string */
|
||||
if ( pformat ) {
|
||||
va_list args;
|
||||
va_start ( args, pformat );
|
||||
int status = vsprintf ( msgBuf, pformat, args );
|
||||
if ( status < 0 ) {
|
||||
errPrintf (S_cas_internal, __FILE__, __LINE__,
|
||||
"bad sendErr(%s)", pformat);
|
||||
stringSize = 0u;
|
||||
}
|
||||
else {
|
||||
stringSize = 1u + (unsigned) status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
stringSize = 0u;
|
||||
}
|
||||
unsigned stringSize;
|
||||
char msgBuf[1024]; /* allocate plenty of space for the message string */
|
||||
if ( pformat ) {
|
||||
va_list args;
|
||||
va_start ( args, pformat );
|
||||
int status = vsprintf ( msgBuf, pformat, args );
|
||||
if ( status < 0 ) {
|
||||
errPrintf (S_cas_internal, __FILE__, __LINE__,
|
||||
"bad sendErr(%s)", pformat);
|
||||
stringSize = 0u;
|
||||
}
|
||||
else {
|
||||
stringSize = 1u + (unsigned) status;
|
||||
}
|
||||
va_end ( args );
|
||||
}
|
||||
else {
|
||||
stringSize = 0u;
|
||||
}
|
||||
|
||||
unsigned hdrSize = sizeof ( caHdr );
|
||||
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
|
||||
@@ -927,7 +933,7 @@ caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
|
||||
this->out.commitMsg ();
|
||||
}
|
||||
|
||||
return S_cas_success;
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
|
||||
@@ -936,8 +942,8 @@ caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
|
||||
//
|
||||
caStatus casDGClient::echoAction ()
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
const void * dp = this->ctx.getData();
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
const void * dp = this->ctx.getData();
|
||||
void * pPayloadOut;
|
||||
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
@@ -948,5 +954,5 @@ caStatus casDGClient::echoAction ()
|
||||
memcpy ( pPayloadOut, dp, mp->m_postsize );
|
||||
this->out.commitMsg ();
|
||||
}
|
||||
return S_cas_success;
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
@@ -26,33 +26,39 @@
|
||||
#include "casAsyncIOI.h"
|
||||
#include "casMonitor.h"
|
||||
|
||||
casPVI::casPVI ( casPV & intf ) :
|
||||
pCAS ( NULL ), pPV ( & intf ), nMonAttached ( 0u ),
|
||||
|
||||
// Use casErrMessage instead of errMessage to show PV name
|
||||
#define casErrMessage(S, PM) \
|
||||
errPrintf(S, __FILE__, __LINE__, ", %s, %s", getName(), PM)
|
||||
|
||||
casPVI::casPVI ( casPV & intf ) :
|
||||
pCAS ( NULL ), pPV ( & intf ), nMonAttached ( 0u ),
|
||||
nIOAttached ( 0u ), deletePending ( false ) {}
|
||||
|
||||
casPVI::~casPVI ()
|
||||
{
|
||||
//
|
||||
// all channels should have been destroyed
|
||||
// (otherwise the server tool is yanking the
|
||||
//
|
||||
// all channels should have been destroyed
|
||||
// (otherwise the server tool is yanking the
|
||||
// PV out from under the server)
|
||||
//
|
||||
casVerify ( this->chanList.count() == 0u );
|
||||
//
|
||||
casVerify ( this->chanList.count() == 0u );
|
||||
|
||||
//
|
||||
// all outstanding IO should have been deleted
|
||||
// when we destroyed the channels
|
||||
//
|
||||
casVerify ( this->nIOAttached == 0u );
|
||||
//
|
||||
// all outstanding IO should have been deleted
|
||||
// when we destroyed the channels
|
||||
//
|
||||
casVerify ( this->nIOAttached == 0u );
|
||||
if ( this->nIOAttached ) {
|
||||
errlogPrintf ( "The number of IO objected attached is %u\n", this->nIOAttached );
|
||||
errlogPrintf ( "%u IO objects still attached in destructor\n",
|
||||
this->nIOAttached );
|
||||
}
|
||||
|
||||
//
|
||||
// all monitors should have been deleted
|
||||
// when we destroyed the channels
|
||||
//
|
||||
casVerify ( this->nMonAttached == 0u );
|
||||
//
|
||||
// all monitors should have been deleted
|
||||
// when we destroyed the channels
|
||||
//
|
||||
casVerify ( this->nMonAttached == 0u );
|
||||
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
@@ -139,26 +145,26 @@ caStatus casPVI::attachToServer ( caServerI & cas )
|
||||
caStatus casPVI::updateEnumStringTable ( casCtx & ctxIn )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
|
||||
//
|
||||
// create a gdd with the "enum string table" application type
|
||||
//
|
||||
// gddArray(int app, aitEnum prim, int dimen, ...);
|
||||
gdd * pTmp = new gddScalar ( gddAppType_enums );
|
||||
if ( pTmp == NULL ) {
|
||||
errMessage ( S_cas_noMemory,
|
||||
casErrMessage ( S_cas_noMemory,
|
||||
"unable to create gdd for read of application type \"enums\" string"
|
||||
" conversion table for enumerated PV" );
|
||||
return S_cas_noMemory;
|
||||
}
|
||||
|
||||
caStatus status = convertContainerMemberToAtomic ( *pTmp,
|
||||
caStatus status = convertContainerMemberToAtomic ( *pTmp,
|
||||
gddAppType_enums, MAX_ENUM_STATES );
|
||||
if ( status != S_cas_success ) {
|
||||
pTmp->unreference ();
|
||||
errMessage ( status,
|
||||
"unable to to config gdd for read of application type \"enums\" string"
|
||||
" conversion table for enumerated PV");
|
||||
casErrMessage ( status,
|
||||
"unable to config gdd for read of application type \"enums\" string"
|
||||
" conversion table for enumerated PV" );
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -169,12 +175,11 @@ caStatus casPVI::updateEnumStringTable ( casCtx & ctxIn )
|
||||
if ( status == S_cas_success ) {
|
||||
updateEnumStringTableAsyncCompletion ( *pTmp );
|
||||
}
|
||||
else if ( status != S_casApp_asyncCompletion &&
|
||||
else if ( status != S_casApp_asyncCompletion &&
|
||||
status != S_casApp_postponeAsyncIO ) {
|
||||
errPrintf ( status, __FILE__, __LINE__,
|
||||
"- unable to read application type \"enums\" "
|
||||
" (string conversion table) from enumerated native type PV \"%s\"",
|
||||
this->getName() );
|
||||
casErrMessage ( status,
|
||||
"unable to read application type \"enums\" "
|
||||
" (string conversion table) from enumerated native type PV" );
|
||||
}
|
||||
|
||||
pTmp->unreference ();
|
||||
@@ -185,40 +190,39 @@ caStatus casPVI::updateEnumStringTable ( casCtx & ctxIn )
|
||||
void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
|
||||
if ( resp.isContainer() ) {
|
||||
errMessage ( S_cas_badType,
|
||||
"application type \"enums\" string conversion table for"
|
||||
" enumerated PV was a container (expected vector of strings)" );
|
||||
casErrMessage ( S_cas_badType,
|
||||
"Invalid \"enums\" string conversion table for"
|
||||
" enumerated PV (container instead of vector of strings)" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( resp.dimension() == 0 ) {
|
||||
if ( resp.primitiveType() == aitEnumString ) {
|
||||
aitString *pStr = (aitString *) resp.dataVoid ();
|
||||
if ( ! this->enumStrTbl.setString ( 0, pStr->string() ) ) {
|
||||
errMessage ( S_cas_noMemory,
|
||||
casErrMessage ( S_cas_noMemory,
|
||||
"no memory to set enumerated PV string cache" );
|
||||
}
|
||||
}
|
||||
else if ( resp.primitiveType() == aitEnumFixedString ) {
|
||||
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
|
||||
if ( ! this->enumStrTbl.setString ( 0, pStr->fixed_string ) ) {
|
||||
errMessage ( S_cas_noMemory,
|
||||
casErrMessage ( S_cas_noMemory,
|
||||
"no memory to set enumerated PV string cache" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
errPrintf ( S_cas_badType, __FILE__, __LINE__,
|
||||
casErrMessage ( S_cas_badType,
|
||||
"application type \"enums\" string conversion"
|
||||
" table for enumerated PV \"%s\" isnt a string type?",
|
||||
getName() );
|
||||
" table for enumerated PV isnt a string type?" );
|
||||
}
|
||||
}
|
||||
else if ( resp.dimension() == 1 ) {
|
||||
gddStatus gdd_status;
|
||||
aitIndex index, first, count;
|
||||
|
||||
|
||||
gdd_status = resp.getBound ( 0, first, count );
|
||||
assert ( gdd_status == 0 );
|
||||
|
||||
@@ -232,7 +236,7 @@ void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
||||
aitString *pStr = (aitString *) resp.dataVoid ();
|
||||
for ( index = 0; index<count; index++ ) {
|
||||
if ( ! this->enumStrTbl.setString ( index, pStr[index].string() ) ) {
|
||||
errMessage ( S_cas_noMemory,
|
||||
casErrMessage ( S_cas_noMemory,
|
||||
"no memory to set enumerated PV string cache" );
|
||||
}
|
||||
}
|
||||
@@ -241,19 +245,18 @@ void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
||||
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
|
||||
for ( index = 0; index < count; index++ ) {
|
||||
if ( ! this->enumStrTbl.setString ( index, pStr[index].fixed_string ) ) {
|
||||
errMessage ( S_cas_noMemory,
|
||||
casErrMessage ( S_cas_noMemory,
|
||||
"no memory to set enumerated PV string cache" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMessage ( S_cas_badType,
|
||||
"application type \"enums\" string conversion"
|
||||
" table for enumerated PV isnt a string type?" );
|
||||
casErrMessage( S_cas_badType,
|
||||
"bad \"enums\" string conversion table for enumerated PV" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMessage ( S_cas_badType,
|
||||
casErrMessage ( S_cas_badType,
|
||||
"application type \"enums\" string conversion table"
|
||||
" for enumerated PV was multi-dimensional"
|
||||
" (expected vector of strings)" );
|
||||
@@ -287,7 +290,7 @@ void casPVI::postEvent ( const casEventMask & select, const gdd & event )
|
||||
}
|
||||
}
|
||||
|
||||
caStatus casPVI::installMonitor (
|
||||
caStatus casPVI::installMonitor (
|
||||
casMonitor & mon, tsDLList < casMonitor > & monitorList )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
@@ -303,14 +306,14 @@ caStatus casPVI::installMonitor (
|
||||
}
|
||||
}
|
||||
|
||||
casMonitor * casPVI::removeMonitor (
|
||||
casMonitor * casPVI::removeMonitor (
|
||||
tsDLList < casMonitor > & list, ca_uint32_t clientIdIn )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
casMonitor * pMon = 0;
|
||||
//
|
||||
// (it is reasonable to do a linear search here because
|
||||
// sane clients will require only one or two monitors
|
||||
// sane clients will require only one or two monitors
|
||||
// per channel)
|
||||
//
|
||||
tsDLIter < casMonitor > iter = list.firstIter ();
|
||||
@@ -359,9 +362,9 @@ void casPVI::installChannel ( chanIntfForPV & chan )
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->chanList.add ( chan );
|
||||
}
|
||||
|
||||
void casPVI::removeChannel (
|
||||
chanIntfForPV & chan, tsDLList < casMonitor > & src,
|
||||
|
||||
void casPVI::removeChannel (
|
||||
chanIntfForPV & chan, tsDLList < casMonitor > & src,
|
||||
tsDLList < casMonitor > & dest )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
@@ -380,8 +383,8 @@ void casPVI::clearOutstandingReads ( tsDLList < casAsyncIOI > & ioList )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
// cancel any pending asynchronous IO
|
||||
tsDLIter < casAsyncIOI > iterIO =
|
||||
// cancel any pending asynchronous IO
|
||||
tsDLIter < casAsyncIOI > iterIO =
|
||||
ioList.firstIter ();
|
||||
while ( iterIO.valid () ) {
|
||||
tsDLIter < casAsyncIOI > tmp = iterIO;
|
||||
@@ -407,7 +410,7 @@ void casPVI::destroyAllIO ( tsDLList < casAsyncIOI > & ioList )
|
||||
}
|
||||
}
|
||||
|
||||
void casPVI::installIO (
|
||||
void casPVI::installIO (
|
||||
tsDLList < casAsyncIOI > & ioList, casAsyncIOI & io )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
@@ -416,7 +419,7 @@ void casPVI::installIO (
|
||||
this->nIOAttached++;
|
||||
}
|
||||
|
||||
void casPVI::uninstallIO (
|
||||
void casPVI::uninstallIO (
|
||||
tsDLList < casAsyncIOI > & ioList, casAsyncIOI & io )
|
||||
{
|
||||
{
|
||||
@@ -517,8 +520,8 @@ aitEnum casPVI::bestExternalType () const
|
||||
}
|
||||
}
|
||||
|
||||
// CA only does 1D arrays for now
|
||||
aitIndex casPVI::nativeCount ()
|
||||
// CA only does 1D arrays for now
|
||||
aitIndex casPVI::nativeCount ()
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( this->pPV ) {
|
||||
@@ -542,4 +545,3 @@ const char * casPVI::getName () const
|
||||
return "<disconnected>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn)
|
||||
//
|
||||
// element count out of range ?
|
||||
//
|
||||
if ( ctx.msg.m_count > pChan->getPVI().nativeCount() ||
|
||||
if ( ctx.msg.m_count > pChan->getMaxElem() ||
|
||||
( !allowdyn && ctx.msg.m_count == 0u ) ) {
|
||||
return ECA_BADCOUNT;
|
||||
}
|
||||
@@ -530,8 +530,20 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
|
||||
pChan->getCID(), status, ECA_GETFAIL );
|
||||
}
|
||||
|
||||
aitUint32 elementCount = 0;
|
||||
if (desc.isContainer()) {
|
||||
aitUint32 index;
|
||||
int gdds = gddApplicationTypeTable::app_table.mapAppToIndex
|
||||
( desc.applicationType(), gddAppType_value, index );
|
||||
if ( gdds ) {
|
||||
return S_cas_badType;
|
||||
}
|
||||
elementCount = desc.getDD(index)->getDataSizeElements();
|
||||
} else {
|
||||
elementCount = desc.getDataSizeElements();
|
||||
}
|
||||
ca_uint32_t count = (msg.m_count == 0) ?
|
||||
(ca_uint32_t)desc.getDataSizeElements() :
|
||||
(ca_uint32_t)elementCount :
|
||||
msg.m_count;
|
||||
|
||||
void * pPayload;
|
||||
@@ -659,8 +671,20 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
|
||||
return ecaStatus;
|
||||
}
|
||||
|
||||
aitUint32 elementCount = 0;
|
||||
if (desc.isContainer()) {
|
||||
aitUint32 index;
|
||||
int gdds = gddApplicationTypeTable::app_table.mapAppToIndex
|
||||
( desc.applicationType(), gddAppType_value, index );
|
||||
if ( gdds ) {
|
||||
return S_cas_badType;
|
||||
}
|
||||
elementCount = desc.getDD(index)->getDataSizeElements();
|
||||
} else {
|
||||
elementCount = desc.getDataSizeElements();
|
||||
}
|
||||
ca_uint32_t count = (msg.m_count == 0) ?
|
||||
(ca_uint32_t)desc.getDataSizeElements() :
|
||||
(ca_uint32_t)elementCount :
|
||||
msg.m_count;
|
||||
|
||||
void *pPayload;
|
||||
@@ -856,8 +880,20 @@ caStatus casStrmClient::monitorResponse (
|
||||
casChannelI & chan, const caHdrLargeArray & msg,
|
||||
const gdd & desc, const caStatus completionStatus )
|
||||
{
|
||||
aitUint32 elementCount = 0;
|
||||
if (desc.isContainer()) {
|
||||
aitUint32 index;
|
||||
int gdds = gddApplicationTypeTable::app_table.mapAppToIndex
|
||||
( desc.applicationType(), gddAppType_value, index );
|
||||
if ( gdds ) {
|
||||
return S_cas_badType;
|
||||
}
|
||||
elementCount = desc.getDD(index)->getDataSizeElements();
|
||||
} else {
|
||||
elementCount = desc.getDataSizeElements();
|
||||
}
|
||||
ca_uint32_t count = (msg.m_count == 0) ?
|
||||
(ca_uint32_t)desc.getDataSizeElements() :
|
||||
(ca_uint32_t)elementCount :
|
||||
msg.m_count;
|
||||
|
||||
void * pPayload = 0;
|
||||
@@ -883,7 +919,7 @@ caStatus casStrmClient::monitorResponse (
|
||||
gdd * pDBRDD = 0;
|
||||
if ( completionStatus == S_cas_success ) {
|
||||
caStatus status = createDBRDD ( msg.m_dataType, count,
|
||||
chan.getPVI().nativeCount(), pDBRDD );
|
||||
chan.getMaxElem(), pDBRDD );
|
||||
if ( status != S_cas_success ) {
|
||||
caStatus ecaStatus;
|
||||
if ( status == S_cas_badType ) {
|
||||
@@ -1854,7 +1890,7 @@ caStatus casStrmClient::privateCreateChanResponse (
|
||||
// the protocol buffer.
|
||||
//
|
||||
assert ( nativeTypeDBR <= 0xffff );
|
||||
aitIndex nativeCount = chan.getPVI().nativeCount();
|
||||
aitIndex nativeCount = chan.getMaxElem();
|
||||
assert ( nativeCount <= 0xffffffff );
|
||||
assert ( hdr.m_cid == chan.getCID() );
|
||||
status = this->out.copyInHeader ( CA_PROTO_CREATE_CHAN, 0,
|
||||
@@ -2614,7 +2650,7 @@ caStatus casStrmClient::read ()
|
||||
{
|
||||
gdd * pDD = 0;
|
||||
caStatus status = createDBRDD ( pHdr->m_dataType, pHdr->m_count,
|
||||
this->ctx.getChannel()->getPVI().nativeCount(), pDD );
|
||||
this->ctx.getChannel()->getMaxElem(), pDD );
|
||||
if ( status != S_cas_success ) {
|
||||
return status;
|
||||
}
|
||||
@@ -2761,6 +2797,7 @@ caStatus casStrmClient::sendErr ( epicsGuard <casClientMutex> &,
|
||||
else {
|
||||
stringSize = 1u + (unsigned) status;
|
||||
}
|
||||
va_end ( args );
|
||||
}
|
||||
else {
|
||||
stringSize = 0u;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
//
|
||||
@@ -32,7 +32,7 @@ const unsigned caServerConnectPendQueueSize = 5u;
|
||||
//
|
||||
// casIntfIO::casIntfIO()
|
||||
//
|
||||
casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
|
||||
casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
|
||||
sock ( INVALID_SOCKET ),
|
||||
addr ( addrIn.getSockIP() )
|
||||
{
|
||||
@@ -40,80 +40,79 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
|
||||
osiSocklen_t addrSize;
|
||||
bool portChange;
|
||||
|
||||
if ( ! osiSockAttach () ) {
|
||||
throw S_cas_internal;
|
||||
}
|
||||
if ( ! osiSockAttach () ) {
|
||||
throw S_cas_internal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the server socket
|
||||
*/
|
||||
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if (this->sock==INVALID_SOCKET) {
|
||||
/*
|
||||
* Setup the server socket
|
||||
*/
|
||||
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if (this->sock == INVALID_SOCKET) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
printf ( "No socket error was %s\n", sockErrBuf );
|
||||
throw S_cas_noFD;
|
||||
}
|
||||
printf ( "No socket error was %s\n", sockErrBuf );
|
||||
throw S_cas_noFD;
|
||||
}
|
||||
|
||||
epicsSocketEnableAddressReuseDuringTimeWaitState ( this->sock );
|
||||
|
||||
status = bind ( this->sock,
|
||||
reinterpret_cast <sockaddr *> (&this->addr),
|
||||
sizeof(this->addr) );
|
||||
if (status<0) {
|
||||
if (SOCKERRNO == SOCK_EADDRINUSE) {
|
||||
//
|
||||
// enable assignment of a default port
|
||||
// (so the getsockname() call below will
|
||||
// work correctly)
|
||||
//
|
||||
this->addr.sin_port = ntohs (0);
|
||||
status = bind(
|
||||
status = bind ( this->sock,
|
||||
reinterpret_cast <sockaddr *> (&this->addr),
|
||||
sizeof(this->addr) );
|
||||
if (status < 0) {
|
||||
if (SOCKERRNO == SOCK_EADDRINUSE ||
|
||||
SOCKERRNO == SOCK_EACCES) {
|
||||
//
|
||||
// enable assignment of a default port
|
||||
// (so the getsockname() call below will
|
||||
// work correctly)
|
||||
//
|
||||
this->addr.sin_port = ntohs (0);
|
||||
status = bind(
|
||||
this->sock,
|
||||
reinterpret_cast <sockaddr *> (&this->addr),
|
||||
sizeof(this->addr) );
|
||||
}
|
||||
if (status<0) {
|
||||
}
|
||||
if (status < 0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
char buf[64];
|
||||
ipAddrToA (&this->addr, buf, sizeof(buf));
|
||||
errPrintf ( S_cas_bindFail,
|
||||
__FILE__, __LINE__,
|
||||
"- bind TCP IP addr=%s failed because %s",
|
||||
buf, sockErrBuf );
|
||||
char buf[64];
|
||||
ipAddrToA (&this->addr, buf, sizeof(buf));
|
||||
errlogPrintf ( "CAS: Socket bind TCP to %s failed with %s",
|
||||
buf, sockErrBuf );
|
||||
epicsSocketDestroy (this->sock);
|
||||
throw S_cas_bindFail;
|
||||
}
|
||||
throw S_cas_bindFail;
|
||||
}
|
||||
portChange = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
portChange = false;
|
||||
}
|
||||
|
||||
addrSize = ( osiSocklen_t ) sizeof (this->addr);
|
||||
status = getsockname (
|
||||
this->sock,
|
||||
reinterpret_cast <sockaddr *> ( &this->addr ),
|
||||
addrSize = ( osiSocklen_t ) sizeof (this->addr);
|
||||
status = getsockname (
|
||||
this->sock,
|
||||
reinterpret_cast <sockaddr *> ( &this->addr ),
|
||||
&addrSize );
|
||||
if (status) {
|
||||
if (status) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAS: getsockname() error %s\n",
|
||||
sockErrBuf );
|
||||
errlogPrintf ( "CAS: getsockname() error %s\n",
|
||||
sockErrBuf );
|
||||
epicsSocketDestroy (this->sock);
|
||||
throw S_cas_internal;
|
||||
}
|
||||
throw S_cas_internal;
|
||||
}
|
||||
|
||||
//
|
||||
// be sure of this now so that we can fetch the IP
|
||||
// address and port number later
|
||||
//
|
||||
//
|
||||
// be sure of this now so that we can fetch the IP
|
||||
// address and port number later
|
||||
//
|
||||
assert (this->addr.sin_family == AF_INET);
|
||||
|
||||
if ( portChange ) {
|
||||
errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
|
||||
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
|
||||
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
|
||||
ntohs (this->addr.sin_port) );
|
||||
errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
|
||||
errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
|
||||
@@ -121,12 +120,12 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
|
||||
}
|
||||
|
||||
status = listen(this->sock, caServerConnectPendQueueSize);
|
||||
if(status < 0) {
|
||||
if (status < 0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAS: listen() error %s\n", sockErrBuf );
|
||||
errlogPrintf ( "CAS: listen() error %s\n", sockErrBuf );
|
||||
epicsSocketDestroy (this->sock);
|
||||
throw S_cas_internal;
|
||||
throw S_cas_internal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,17 +134,17 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
|
||||
//
|
||||
casIntfIO::~casIntfIO()
|
||||
{
|
||||
if (this->sock != INVALID_SOCKET) {
|
||||
epicsSocketDestroy (this->sock);
|
||||
}
|
||||
if (this->sock != INVALID_SOCKET) {
|
||||
epicsSocketDestroy (this->sock);
|
||||
}
|
||||
|
||||
osiSockRelease ();
|
||||
osiSockRelease ();
|
||||
}
|
||||
|
||||
//
|
||||
// newStreamIO::newStreamClient()
|
||||
//
|
||||
casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
|
||||
casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
|
||||
clientBufMemoryManager & bufMgr ) const
|
||||
{
|
||||
static bool oneMsgFlag = false;
|
||||
@@ -175,14 +174,14 @@ casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
|
||||
args.sock = newSock;
|
||||
casStreamOS * pOS = new casStreamOS ( cas, bufMgr, args );
|
||||
if ( ! pOS ) {
|
||||
errMessage ( S_cas_noMemory,
|
||||
errMessage ( S_cas_noMemory,
|
||||
"unable to create data structures for a new client" );
|
||||
epicsSocketDestroy ( newSock );
|
||||
}
|
||||
else {
|
||||
if ( cas.getDebugLevel() > 0u ) {
|
||||
char pName[64u];
|
||||
|
||||
|
||||
pOS->hostName ( pName, sizeof ( pName ) );
|
||||
errlogPrintf ( "CAS: allocated client object for \"%s\"\n", pName );
|
||||
}
|
||||
@@ -197,7 +196,7 @@ void casIntfIO::setNonBlocking()
|
||||
{
|
||||
int status;
|
||||
osiSockIoctl_t yes = true;
|
||||
|
||||
|
||||
status = socket_ioctl(this->sock, FIONBIO, &yes);
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
|
||||
@@ -23,5 +23,5 @@ dbCore_SRCS += asIocRegister.c
|
||||
|
||||
PROD_HOST += ascheck
|
||||
ascheck_SRCS = ascheck.c
|
||||
ascheck_LIBS = dbCore
|
||||
ascheck_LIBS = dbCore ca Com
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "epicsExport.h"
|
||||
#include "link.h"
|
||||
#include "recSup.h"
|
||||
#include "dbUnitTest.h" /* for testSyncCallback() */
|
||||
|
||||
|
||||
static int callbackQueueSize = 2000;
|
||||
@@ -81,6 +82,10 @@ static int callbackIsInit;
|
||||
static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = {
|
||||
"cbLow", "cbMedium", "cbHigh"
|
||||
};
|
||||
#define FULL_MSG(name) "callbackRequest: " name " ring buffer full\n"
|
||||
static char *fullMessage[NUM_CALLBACK_PRIORITIES] = {
|
||||
FULL_MSG("cbLow"), FULL_MSG("cbMedium"), FULL_MSG("cbHigh")
|
||||
};
|
||||
static unsigned int threadPriority[NUM_CALLBACK_PRIORITIES] = {
|
||||
epicsThreadPriorityScanLow - 1,
|
||||
epicsThreadPriorityScanLow + 4,
|
||||
@@ -284,11 +289,7 @@ int callbackRequest(CALLBACK *pcallback)
|
||||
pushOK = epicsRingPointerPush(mySet->queue, pcallback);
|
||||
|
||||
if (!pushOK) {
|
||||
char msg[48] = "callbackRequest: ";
|
||||
|
||||
strcat(msg, threadNamePrefix[priority]);
|
||||
strcat(msg, " ring buffer full\n");
|
||||
epicsInterruptContextMessage(msg);
|
||||
epicsInterruptContextMessage(fullMessage[priority]);
|
||||
mySet->queueOverflow = TRUE;
|
||||
return S_db_bufFull;
|
||||
}
|
||||
@@ -353,3 +354,86 @@ void callbackRequestProcessCallbackDelayed(CALLBACK *pcallback,
|
||||
callbackSetProcess(pcallback, Priority, pRec);
|
||||
callbackRequestDelayed(pcallback, seconds);
|
||||
}
|
||||
|
||||
/* Sync. process of testSyncCallback()
|
||||
*
|
||||
* 1. For each priority, make a call to callbackRequest() for each worker.
|
||||
* 2. Wait until all callbacks are concurrently being executed
|
||||
* 3. Last worker to begin executing signals success and begins waking up other workers
|
||||
* 4. Last worker to wake signals testSyncCallback() to complete
|
||||
*/
|
||||
typedef struct {
|
||||
epicsEventId wait_phase2, wait_phase4;
|
||||
int nphase2, nphase3;
|
||||
epicsCallback cb;
|
||||
} sync_helper;
|
||||
|
||||
static void sync_callback(epicsCallback *cb)
|
||||
{
|
||||
sync_helper *helper;
|
||||
callbackGetUser(helper, cb);
|
||||
|
||||
testGlobalLock();
|
||||
|
||||
assert(helper->nphase2 > 0);
|
||||
if(--helper->nphase2!=0) {
|
||||
/* we are _not_ the last to start. */
|
||||
testGlobalUnlock();
|
||||
epicsEventMustWait(helper->wait_phase2);
|
||||
testGlobalLock();
|
||||
}
|
||||
|
||||
/* we are either the last to start, or have been
|
||||
* woken by the same and must pass the wakeup along
|
||||
*/
|
||||
epicsEventMustTrigger(helper->wait_phase2);
|
||||
|
||||
assert(helper->nphase2 == 0);
|
||||
assert(helper->nphase3 > 0);
|
||||
|
||||
if(--helper->nphase3==0) {
|
||||
/* we are the last to wake up. wake up testSyncCallback() */
|
||||
epicsEventMustTrigger(helper->wait_phase4);
|
||||
}
|
||||
|
||||
testGlobalUnlock();
|
||||
}
|
||||
|
||||
void testSyncCallback(void)
|
||||
{
|
||||
sync_helper helper[NUM_CALLBACK_PRIORITIES];
|
||||
unsigned i;
|
||||
|
||||
testDiag("Begin testSyncCallback()");
|
||||
|
||||
for(i=0; i<NUM_CALLBACK_PRIORITIES; i++) {
|
||||
helper[i].wait_phase2 = epicsEventMustCreate(epicsEventEmpty);
|
||||
helper[i].wait_phase4 = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
/* no real need to lock here, but do so anyway so that valgrind can establish
|
||||
* the locking requirements for sync_helper.
|
||||
*/
|
||||
testGlobalLock();
|
||||
helper[i].nphase2 = helper[i].nphase3 = callbackQueue[i].threadsRunning;
|
||||
testGlobalUnlock();
|
||||
|
||||
callbackSetUser(&helper[i], &helper[i].cb);
|
||||
callbackSetPriority(i, &helper[i].cb);
|
||||
callbackSetCallback(sync_callback, &helper[i].cb);
|
||||
|
||||
callbackRequest(&helper[i].cb);
|
||||
}
|
||||
|
||||
for(i=0; i<NUM_CALLBACK_PRIORITIES; i++) {
|
||||
epicsEventMustWait(helper[i].wait_phase4);
|
||||
}
|
||||
|
||||
for(i=0; i<NUM_CALLBACK_PRIORITIES; i++) {
|
||||
testGlobalLock();
|
||||
epicsEventDestroy(helper[i].wait_phase2);
|
||||
epicsEventDestroy(helper[i].wait_phase4);
|
||||
testGlobalUnlock();
|
||||
}
|
||||
|
||||
testDiag("Complete testSyncCallback()");
|
||||
}
|
||||
|
||||
@@ -42,7 +42,9 @@ typedef struct callbackPvt {
|
||||
int priority;
|
||||
void *user; /*for use by callback user*/
|
||||
void *timer; /*for use by callback itself*/
|
||||
}CALLBACK;
|
||||
}epicsCallback;
|
||||
|
||||
typedef epicsCallback CALLBACK;
|
||||
|
||||
typedef void (*CALLBACKFUNC)(struct callbackPvt*);
|
||||
|
||||
|
||||
@@ -291,10 +291,14 @@ static void get_alarm(DBADDR *paddr, char **ppbuffer,
|
||||
if (*options & DBR_AL_LONG) {
|
||||
struct dbr_alLong *pal = (struct dbr_alLong*) pbuffer;
|
||||
|
||||
pal->upper_alarm_limit = (epicsInt32) ald.upper_alarm_limit;
|
||||
pal->upper_warning_limit = (epicsInt32) ald.upper_warning_limit;
|
||||
pal->lower_warning_limit = (epicsInt32) ald.lower_warning_limit;
|
||||
pal->lower_alarm_limit = (epicsInt32) ald.lower_alarm_limit;
|
||||
pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ?
|
||||
(epicsInt32) ald.upper_alarm_limit : 0;
|
||||
pal->upper_warning_limit = finite(ald.upper_warning_limit) ?
|
||||
(epicsInt32) ald.upper_warning_limit : 0;
|
||||
pal->lower_warning_limit = finite(ald.lower_warning_limit) ?
|
||||
(epicsInt32) ald.lower_warning_limit : 0;
|
||||
pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ?
|
||||
(epicsInt32) ald.lower_alarm_limit : 0;
|
||||
|
||||
if (no_data)
|
||||
*options ^= DBR_AL_LONG; /*Turn off option*/
|
||||
@@ -738,28 +742,34 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
|
||||
{
|
||||
dbCommon *precord = paddr->precord;
|
||||
dbFldDes *pfldDes = paddr->pfldDes;
|
||||
/* size of pbuf storage in bytes, including space for trailing nil */
|
||||
int maxlen;
|
||||
DBENTRY dbEntry;
|
||||
long status;
|
||||
long nReq = nRequest ? *nRequest : 1;
|
||||
|
||||
/* dbFindRecord() below will always succeed as we have a
|
||||
* valid DBADDR, so no point to check again.
|
||||
* Request for zero elements always succeeds
|
||||
*/
|
||||
if(!nReq)
|
||||
return 0;
|
||||
|
||||
switch (dbrType) {
|
||||
case DBR_STRING:
|
||||
maxlen = MAX_STRING_SIZE - 1;
|
||||
if (nRequest && *nRequest > 1) *nRequest = 1;
|
||||
maxlen = MAX_STRING_SIZE;
|
||||
nReq = 1;
|
||||
break;
|
||||
|
||||
case DBR_DOUBLE: /* Needed for dbCa links */
|
||||
if (nRequest && *nRequest) *nRequest = 1;
|
||||
if (nRequest) *nRequest = 1;
|
||||
*(double *)pbuf = epicsNAN;
|
||||
return 0;
|
||||
|
||||
case DBR_CHAR:
|
||||
case DBR_UCHAR:
|
||||
if (nRequest && *nRequest > 0) {
|
||||
maxlen = *nRequest - 1;
|
||||
break;
|
||||
}
|
||||
/* else fall through ... */
|
||||
maxlen = nReq;
|
||||
break;
|
||||
default:
|
||||
return S_db_badDbrtype;
|
||||
}
|
||||
@@ -768,10 +778,13 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
|
||||
status = dbFindRecord(&dbEntry, precord->name);
|
||||
if (!status) status = dbFindField(&dbEntry, pfldDes->name);
|
||||
if (!status) {
|
||||
char *rtnString = dbGetString(&dbEntry);
|
||||
const char *rtnString = dbGetString(&dbEntry);
|
||||
|
||||
strncpy(pbuf, rtnString, --maxlen);
|
||||
pbuf[maxlen] = 0;
|
||||
strncpy(pbuf, rtnString, maxlen-1);
|
||||
pbuf[maxlen-1] = 0;
|
||||
if(dbrType!=DBR_STRING)
|
||||
nReq = strlen(pbuf)+1;
|
||||
if(nRequest) *nRequest = nReq;
|
||||
}
|
||||
dbFinishEntry(&dbEntry);
|
||||
return status;
|
||||
@@ -781,28 +794,31 @@ static long getAttrValue(DBADDR *paddr, short dbrType,
|
||||
char *pbuf, long *nRequest)
|
||||
{
|
||||
int maxlen;
|
||||
long nReq = nRequest ? *nRequest : 1;
|
||||
|
||||
if (!paddr->pfield) return S_db_badField;
|
||||
|
||||
switch (dbrType) {
|
||||
case DBR_STRING:
|
||||
maxlen = MAX_STRING_SIZE - 1;
|
||||
if (nRequest && *nRequest > 1) *nRequest = 1;
|
||||
maxlen = MAX_STRING_SIZE;
|
||||
nReq = 1;
|
||||
break;
|
||||
|
||||
case DBR_CHAR:
|
||||
case DBR_UCHAR:
|
||||
if (nRequest && *nRequest > 0) {
|
||||
maxlen = *nRequest - 1;
|
||||
break;
|
||||
}
|
||||
maxlen = nReq;
|
||||
break;
|
||||
|
||||
/* else fall through ... */
|
||||
default:
|
||||
return S_db_badDbrtype;
|
||||
}
|
||||
|
||||
strncpy(pbuf, paddr->pfield, --maxlen);
|
||||
pbuf[maxlen] = 0;
|
||||
strncpy(pbuf, paddr->pfield, maxlen-1);
|
||||
pbuf[maxlen-1] = 0;
|
||||
if(dbrType!=DBR_STRING)
|
||||
nReq = strlen(pbuf)+1;
|
||||
if(nRequest) *nRequest = nReq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -930,6 +946,15 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
localAddr.pfield = (char *) pfl->u.r.field;
|
||||
status = convert(&localAddr, pbuf, n, capacity, offset);
|
||||
}
|
||||
|
||||
if(!status && dbrType==DBF_CHAR && nRequest &&
|
||||
paddr->pfldDes && paddr->pfldDes->field_type==DBF_STRING)
|
||||
{
|
||||
/* long string ensure nil and truncate to actual length */
|
||||
long nReq = *nRequest;
|
||||
pbuf[nReq-1] = '\0';
|
||||
*nRequest = strlen(pbuf)+1;
|
||||
}
|
||||
}
|
||||
done:
|
||||
paddr->pfield = pfieldsave;
|
||||
|
||||
@@ -410,7 +410,7 @@ long dbd(const char *record_name)
|
||||
|
||||
precord = addr.precord;
|
||||
|
||||
if (! precord->bkpt & BKPT_ON_MASK) {
|
||||
if (!(precord->bkpt & BKPT_ON_MASK)) {
|
||||
printf(" BKPT> No breakpoint set in this record\n");
|
||||
return(S_db_bkptNotSet);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,6 @@ static void addAction(caLink *pca, short link_action)
|
||||
if (++removesOutstanding >= removesOutstandingWarning) {
|
||||
errlogPrintf("dbCa::addAction pausing, %d channels to clear\n",
|
||||
removesOutstanding);
|
||||
printLinks(pca);
|
||||
}
|
||||
while (removesOutstanding >= removesOutstandingWarning) {
|
||||
epicsMutexUnlock(workListLock);
|
||||
@@ -650,11 +649,16 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
if (pca->gotFirstConnection) {
|
||||
if (pca->nelements != ca_element_count(arg.chid) ||
|
||||
pca->dbrType != ca_field_type(arg.chid)) {
|
||||
/* BUG: We have no way to clear any old subscription with the
|
||||
* originally chosen data type/size. That will continue
|
||||
* to send us data and will result in an assert() fail.
|
||||
*/
|
||||
/* Let next dbCaGetLink and/or dbCaPutLink determine options */
|
||||
/* Size or type changed, clear everything and let the next call
|
||||
to dbCaGetLink() and/or dbCaPutLink() reset everything */
|
||||
if (pca->evidNative) {
|
||||
ca_clear_event(pca->evidNative);
|
||||
pca->evidNative = 0;
|
||||
}
|
||||
if (pca->evidString) {
|
||||
ca_clear_event(pca->evidString);
|
||||
pca->evidString = 0;
|
||||
}
|
||||
plink->value.pv_link.pvlMask &=
|
||||
~(pvlOptInpNative | pvlOptInpString |
|
||||
pvlOptOutNative | pvlOptOutString);
|
||||
@@ -702,6 +706,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
struct dbr_time_double *pdbr_time_double;
|
||||
dbCaCallback monitor = 0;
|
||||
void *userPvt = 0;
|
||||
int doScan = 1;
|
||||
|
||||
assert(pca);
|
||||
epicsMutexMustLock(pca->lock);
|
||||
@@ -730,10 +735,13 @@ static void eventCallback(struct event_handler_args arg)
|
||||
memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size);
|
||||
pca->gotInString = TRUE;
|
||||
} else switch (arg.type){
|
||||
case DBR_TIME_ENUM:
|
||||
/* Disable the record scan if we also have a string monitor */
|
||||
doScan = !(plink->value.pv_link.pvlMask & pvlOptInpString);
|
||||
/* fall through */
|
||||
case DBR_TIME_STRING:
|
||||
case DBR_TIME_SHORT:
|
||||
case DBR_TIME_FLOAT:
|
||||
case DBR_TIME_ENUM:
|
||||
case DBR_TIME_CHAR:
|
||||
case DBR_TIME_LONG:
|
||||
case DBR_TIME_DOUBLE:
|
||||
@@ -749,7 +757,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
pca->sevr = pdbr_time_double->severity;
|
||||
pca->stat = pdbr_time_double->status;
|
||||
memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp));
|
||||
if (precord) {
|
||||
if (doScan && precord) {
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
|
||||
if ((ppv_link->pvlMask & pvlOptCP) ||
|
||||
@@ -1006,7 +1014,8 @@ static void dbCaTask(void *arg)
|
||||
status = ca_add_array_event(
|
||||
ca_field_type(pca->chid)+DBR_TIME_STRING,
|
||||
ca_element_count(pca->chid),
|
||||
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
|
||||
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0,
|
||||
&pca->evidNative);
|
||||
if (status != ECA_NORMAL) {
|
||||
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
||||
ca_message(status));
|
||||
@@ -1018,7 +1027,8 @@ static void dbCaTask(void *arg)
|
||||
pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
status = ca_add_array_event(DBR_TIME_STRING, 1,
|
||||
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
|
||||
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0,
|
||||
&pca->evidString);
|
||||
if (status != ECA_NORMAL) {
|
||||
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
||||
ca_message(status));
|
||||
|
||||
@@ -78,6 +78,8 @@ typedef struct caLink
|
||||
char *pgetString;
|
||||
void *pputNative;
|
||||
char *pputString;
|
||||
evid evidNative;
|
||||
evid evidString;
|
||||
char gotInNative;
|
||||
char gotInString;
|
||||
char gotOutNative;
|
||||
|
||||
@@ -130,8 +130,8 @@ long dbcar(char *precordname, int level)
|
||||
precord->name,
|
||||
pdbFldDes->name,
|
||||
plink->value.pv_link.pvname,
|
||||
pca->nDisconnect,
|
||||
pca->nNoWrite);
|
||||
pca ? pca->nDisconnect : 0,
|
||||
pca ? pca->nNoWrite : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbConvert.c */
|
||||
/*
|
||||
@@ -582,7 +582,7 @@ static long getCharFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getCharDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -783,7 +783,7 @@ static long getUcharFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getUcharDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -984,7 +984,7 @@ static long getShortFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getShortDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -1184,7 +1184,7 @@ static long getUshortFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getUshortDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -1385,7 +1385,7 @@ static long getLongFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getLongDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -1586,7 +1586,7 @@ static long getUlongFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getUlongDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -1636,7 +1636,7 @@ static long getFloatString(
|
||||
char *pbuffer = (char *) pto;
|
||||
float *psrc = (float *) paddr->pfield;
|
||||
long status = 0;
|
||||
int precision = 6;
|
||||
long precision = 6;
|
||||
struct rset *prset = 0;
|
||||
|
||||
if (paddr) prset = dbGetRset(paddr);
|
||||
@@ -1799,7 +1799,7 @@ static long getFloatFloat(
|
||||
COPYNOCONVERT(sizeof(float), paddr->pfield, pto, nRequest, no_elements, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getFloatDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -1848,8 +1848,8 @@ static long getDoubleString(
|
||||
{
|
||||
char *pbuffer = (char *) pto;
|
||||
double *psrc = (double *) paddr->pfield;
|
||||
long status = 0;
|
||||
int precision = 6;
|
||||
long status = 0;
|
||||
long precision = 6;
|
||||
struct rset *prset = 0;
|
||||
|
||||
if (paddr) prset = dbGetRset(paddr);
|
||||
@@ -2019,7 +2019,7 @@ static long getDoubleFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getDoubleDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -2217,7 +2217,7 @@ static long getEnumFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long getEnumDouble(
|
||||
const dbAddr *paddr,
|
||||
void *pto, long nRequest, long no_elements, long offset)
|
||||
@@ -2874,7 +2874,7 @@ static long putCharFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putCharDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -3077,7 +3077,7 @@ static long putUcharFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putUcharDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -3280,7 +3280,7 @@ static long putShortFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putShortDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -3483,7 +3483,7 @@ static long putUshortFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putUshortDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -3686,7 +3686,7 @@ static long putLongFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putLongDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -3889,7 +3889,7 @@ static long putUlongFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putUlongDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -3937,13 +3937,12 @@ static long putFloatString(
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
{
|
||||
const float *pbuffer = (const float *) pfrom;
|
||||
char *pdest = (char *) paddr->pfield;
|
||||
long status = 0;
|
||||
int precision = 6;
|
||||
struct rset *prset = 0;
|
||||
char *pdest = (char *) paddr->pfield;
|
||||
long status = 0;
|
||||
long precision = 6;
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
short size = paddr->field_size;
|
||||
|
||||
if (paddr) prset = dbGetRset(paddr);
|
||||
if (prset && (prset->get_precision))
|
||||
status = (*prset->get_precision)(paddr,&precision);
|
||||
if (nRequest==1 && offset==0) {
|
||||
@@ -4103,7 +4102,7 @@ static long putFloatFloat(
|
||||
COPYNOCONVERT(sizeof(float), pfrom, paddr->pfield, nRequest, no_elements, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putFloatDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -4151,13 +4150,12 @@ static long putDoubleString(
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
{
|
||||
const double *pbuffer = (const double *) pfrom;
|
||||
char *pdest = (char *) paddr->pfield;
|
||||
long status = 0;
|
||||
int precision = 6;
|
||||
struct rset *prset = 0;
|
||||
char *pdest = (char *) paddr->pfield;
|
||||
long status = 0;
|
||||
long precision = 6;
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
short size = paddr->field_size;
|
||||
|
||||
if (paddr) prset = dbGetRset(paddr);
|
||||
if (prset && (prset->get_precision))
|
||||
status = (*prset->get_precision)(paddr,&precision);
|
||||
if (nRequest==1 && offset==0) {
|
||||
@@ -4324,7 +4322,7 @@ static long putDoubleFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putDoubleDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
@@ -4533,7 +4531,7 @@ static long putEnumFloat(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long putEnumDouble(
|
||||
dbAddr *paddr,
|
||||
const void *pfrom, long nRequest, long no_elements, long offset)
|
||||
|
||||
@@ -117,6 +117,8 @@ static char *EVENT_PEND_NAME = "eventTask";
|
||||
|
||||
static struct evSubscrip canceledEvent;
|
||||
|
||||
static epicsMutexId stopSync;
|
||||
|
||||
static unsigned short ringSpace ( const struct event_que *pevq )
|
||||
{
|
||||
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
|
||||
@@ -258,6 +260,10 @@ dbEventCtx db_init_events (void)
|
||||
{
|
||||
struct event_user * evUser;
|
||||
|
||||
if (!stopSync) {
|
||||
stopSync = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
if (!dbevEventUserFreeList) {
|
||||
freeListInitPvt(&dbevEventUserFreeList,
|
||||
sizeof(struct event_user),8);
|
||||
@@ -321,6 +327,8 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* intentionally leak stopSync to avoid possible shutdown races */
|
||||
/*
|
||||
* DB_CLOSE_EVENTS()
|
||||
*
|
||||
@@ -356,11 +364,15 @@ void db_close_events (dbEventCtx ctx)
|
||||
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
epicsMutexMustLock (stopSync);
|
||||
|
||||
epicsEventDestroy(evUser->pexitsem);
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
epicsMutexUnlock (stopSync);
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
}
|
||||
|
||||
@@ -1043,8 +1055,15 @@ static void event_task (void *pParm)
|
||||
|
||||
taskwdRemove(epicsThreadGetIdSelf());
|
||||
|
||||
/* use stopSync to ensure pexitsem is not destroy'd
|
||||
* until epicsEventSignal() has returned.
|
||||
*/
|
||||
epicsMutexMustLock (stopSync);
|
||||
|
||||
epicsEventSignal(evUser->pexitsem);
|
||||
|
||||
epicsMutexUnlock(stopSync);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "cvtFast.h"
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsStdlib.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
@@ -96,6 +97,103 @@ static const char * link_field_name(const struct link *plink)
|
||||
|
||||
/***************************** Constant Links *****************************/
|
||||
|
||||
/* Convert functions */
|
||||
|
||||
/* The difference between these and dbFastConvert is that constants
|
||||
* may contain hex numbers, whereas database conversions can't.
|
||||
*/
|
||||
|
||||
/* Copy to STRING */
|
||||
static long cvt_st_st(const char *from, void *pfield, const dbAddr *paddr)
|
||||
{
|
||||
char *to = pfield;
|
||||
size_t size;
|
||||
|
||||
if (paddr && paddr->field_size < MAX_STRING_SIZE) {
|
||||
size = paddr->field_size - 1;
|
||||
} else {
|
||||
size = MAX_STRING_SIZE - 1;
|
||||
}
|
||||
strncpy(to, from, size);
|
||||
to[size] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Most integer conversions are identical */
|
||||
#define cvt_st_int(TYPE) static long \
|
||||
cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
|
||||
epics##TYPE *to = pfield; \
|
||||
char *end; \
|
||||
\
|
||||
if (*from == 0) { \
|
||||
*to = 0; \
|
||||
return 0; \
|
||||
} \
|
||||
return epicsParse##TYPE(from, to, 0, &end); \
|
||||
}
|
||||
|
||||
/* Instanciate for CHAR, UCHAR, SHORT, USHORT and LONG */
|
||||
cvt_st_int(Int8)
|
||||
cvt_st_int(UInt8)
|
||||
cvt_st_int(Int16)
|
||||
cvt_st_int(UInt16)
|
||||
cvt_st_int(Int32)
|
||||
|
||||
/* Conversion for ULONG is different... */
|
||||
static long cvt_st_UInt32(const char *from, void *pfield, const dbAddr *paddr)
|
||||
{
|
||||
epicsUInt32 *to = pfield;
|
||||
char *end;
|
||||
long status;
|
||||
|
||||
if (*from == 0) {
|
||||
*to = 0;
|
||||
return 0;
|
||||
}
|
||||
status = epicsParseUInt32(from, to, 0, &end);
|
||||
if (status == S_stdlib_noConversion ||
|
||||
(!status && (*end == '.' || *end == 'e' || *end == 'E'))) {
|
||||
/*
|
||||
* Convert via double so numbers like 1.0e3 convert properly.
|
||||
* db_access pretends ULONG fields are DOUBLE.
|
||||
*/
|
||||
double dval;
|
||||
|
||||
status = epicsParseFloat64(from, &dval, &end);
|
||||
if (!status &&
|
||||
dval >=0 &&
|
||||
dval <= ULONG_MAX)
|
||||
*to = dval;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Float conversions are identical */
|
||||
#define cvt_st_float(TYPE) static long \
|
||||
cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
|
||||
epics##TYPE *to = pfield; \
|
||||
char *end; \
|
||||
\
|
||||
if (*from == 0) { \
|
||||
*to = 0; \
|
||||
return 0; \
|
||||
} \
|
||||
return epicsParse##TYPE(from, to, &end); \
|
||||
}
|
||||
|
||||
/* Instanciate for FLOAT32 and FLOAT64 */
|
||||
cvt_st_float(Float32)
|
||||
cvt_st_float(Float64)
|
||||
|
||||
|
||||
static long (*convert[DBF_DOUBLE+1])(const char *, void *, const dbAddr *) = {
|
||||
cvt_st_st,
|
||||
cvt_st_Int8, cvt_st_UInt8,
|
||||
cvt_st_Int16, cvt_st_UInt16,
|
||||
cvt_st_Int32, cvt_st_UInt32,
|
||||
cvt_st_Float32, cvt_st_Float64
|
||||
};
|
||||
|
||||
static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
|
||||
{
|
||||
if (!plink->value.constantStr)
|
||||
@@ -105,8 +203,7 @@ static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
|
||||
if (dbrType== DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
|
||||
dbrType = DBF_USHORT;
|
||||
|
||||
return dbFastPutConvertRoutine[DBR_STRING][dbrType]
|
||||
(plink->value.constantStr, pbuffer, NULL);
|
||||
return convert[dbrType](plink->value.constantStr, pbuffer, NULL);
|
||||
}
|
||||
|
||||
static long dbConstGetNelements(const struct link *plink, long *nelements)
|
||||
@@ -116,7 +213,7 @@ static long dbConstGetNelements(const struct link *plink, long *nelements)
|
||||
}
|
||||
|
||||
static long dbConstGetLink(struct link *plink, short dbrType, void *pbuffer,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
|
||||
long *pnRequest)
|
||||
{
|
||||
if (pnRequest)
|
||||
*pnRequest = 0;
|
||||
@@ -194,7 +291,7 @@ static long dbDbGetElements(const struct link *plink, long *nelements)
|
||||
}
|
||||
|
||||
static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
|
||||
long *pnRequest)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
DBADDR *paddr = ppv_link->pvt;
|
||||
@@ -211,8 +308,6 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
*pstat = paddr->precord->stat;
|
||||
*psevr = paddr->precord->sevr;
|
||||
|
||||
if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
@@ -233,6 +328,9 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
}
|
||||
ppv_link->lastGetdbrType = dbrType;
|
||||
}
|
||||
if (!status && precord != paddr->precord)
|
||||
inherit_severity(ppv_link, precord,
|
||||
paddr->precord->stat, paddr->precord->sevr);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -542,23 +640,22 @@ long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
|
||||
|
||||
switch (plink->type) {
|
||||
case CONSTANT:
|
||||
status = dbConstGetLink(plink, dbrType, pbuffer, &stat, &sevr,
|
||||
pnRequest);
|
||||
status = dbConstGetLink(plink, dbrType, pbuffer, pnRequest);
|
||||
break;
|
||||
case DB_LINK:
|
||||
status = dbDbGetValue(plink, dbrType, pbuffer, &stat, &sevr, pnRequest);
|
||||
status = dbDbGetValue(plink, dbrType, pbuffer, pnRequest);
|
||||
break;
|
||||
case CA_LINK:
|
||||
status = dbCaGetLink(plink, dbrType, pbuffer, &stat, &sevr, pnRequest);
|
||||
if (!status)
|
||||
inherit_severity(&plink->value.pv_link, precord, stat, sevr);
|
||||
break;
|
||||
default:
|
||||
cantProceed("dbGetLinkValue: Illegal link type %d\n", plink->type);
|
||||
printf("dbGetLinkValue: Illegal link type %d\n", plink->type);
|
||||
status = -1;
|
||||
}
|
||||
if (status) {
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
} else {
|
||||
inherit_severity(&plink->value.pv_link, precord, stat, sevr);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -658,7 +755,7 @@ long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
|
||||
status = dbCaPutLink(plink, dbrType, pbuffer, nRequest);
|
||||
break;
|
||||
default:
|
||||
cantProceed("dbPutLinkValue: Illegal link type %d\n", plink->type);
|
||||
printf("dbPutLinkValue: Illegal link type %d\n", plink->type);
|
||||
status = -1;
|
||||
}
|
||||
if (status) {
|
||||
@@ -739,4 +836,3 @@ long dbPutLinkLS(struct link *plink, char *pbuffer, epicsUInt32 len)
|
||||
|
||||
return dbPutLink(plink, DBR_STRING, pbuffer, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ typedef struct lset {
|
||||
int (*getDBFtype)(const struct link *plink);
|
||||
long (*getElements)(const struct link *plink, long *nelements);
|
||||
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest);
|
||||
long *pnRequest);
|
||||
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
|
||||
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
|
||||
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
|
||||
|
||||
@@ -552,10 +552,10 @@ long dblsr(char *recordname,int level)
|
||||
printf(" Not Locked\n");
|
||||
} else {
|
||||
printf(" thread %p",plockSet->thread_id);
|
||||
if(! plockSet->precord || !plockSet->precord->name)
|
||||
printf(" NULL record or record name\n");
|
||||
if(! plockSet->precord)
|
||||
printf(" NULL record\n");
|
||||
else
|
||||
printf(" record %s\n",plockSet->precord->name);
|
||||
printf(" record %s\n",plockSet->precord->name);
|
||||
}
|
||||
if(level==0) { if(recordname) break; continue; }
|
||||
for(plockRecord = (lockRecord *)ellFirst(&plockSet->lockRecordList);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Copyright (c) 2013 Helmholtz-Zentrum Berlin
|
||||
* für Materialien und Energie GmbH.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbScan.c */
|
||||
/* tasks and subroutines to scan the database */
|
||||
@@ -111,8 +111,8 @@ static char *priorityName[NUM_CALLBACK_PRIORITIES] = {
|
||||
typedef struct event_list {
|
||||
CALLBACK callback[NUM_CALLBACK_PRIORITIES];
|
||||
scan_list scan_list[NUM_CALLBACK_PRIORITIES];
|
||||
struct event_list *next;
|
||||
char event_name[MAX_STRING_SIZE];
|
||||
struct event_list *next;
|
||||
char eventname[1]; /* actually arbitrary size */
|
||||
} event_list;
|
||||
static event_list * volatile pevent_list[256];
|
||||
static epicsMutexId event_lock;
|
||||
@@ -161,8 +161,11 @@ void scanStop(void)
|
||||
interruptAccept = FALSE;
|
||||
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
papPeriodic[i]->scanCtl = ctlExit;
|
||||
epicsEventSignal(papPeriodic[i]->loopEvent);
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) continue;
|
||||
ppsl->scanCtl = ctlExit;
|
||||
epicsEventSignal(ppsl->loopEvent);
|
||||
epicsEventWait(startStopEvent);
|
||||
}
|
||||
|
||||
@@ -207,16 +210,24 @@ void scanRun(void)
|
||||
interruptAccept = TRUE;
|
||||
scanCtl = ctlRun;
|
||||
|
||||
for (i = 0; i < nPeriodic; i++)
|
||||
papPeriodic[i]->scanCtl = ctlRun;
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) continue;
|
||||
ppsl->scanCtl = ctlRun;
|
||||
}
|
||||
}
|
||||
|
||||
void scanPause(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = nPeriodic - 1; i >= 0; --i)
|
||||
papPeriodic[i]->scanCtl = ctlPause;
|
||||
for (i = nPeriodic - 1; i >= 0; --i) {
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) continue;
|
||||
ppsl->scanCtl = ctlPause;
|
||||
}
|
||||
|
||||
scanCtl = ctlPause;
|
||||
interruptAccept = FALSE;
|
||||
@@ -238,11 +249,6 @@ void scanAdd(struct dbCommon *precord)
|
||||
event_list *pel;
|
||||
|
||||
eventname = precord->evnt;
|
||||
if (strlen(eventname) >= MAX_STRING_SIZE) {
|
||||
recGblRecordError(S_db_badField, (void *)precord,
|
||||
"scanAdd: too long EVNT value");
|
||||
return;
|
||||
}
|
||||
prio = precord->prio;
|
||||
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
|
||||
recGblRecordError(-1, (void *)precord,
|
||||
@@ -288,9 +294,11 @@ void scanAdd(struct dbCommon *precord)
|
||||
}
|
||||
addToList(precord, &piosh->iosl[prio].scan_list);
|
||||
} else if (scan >= SCAN_1ST_PERIODIC) {
|
||||
addToList(precord, &papPeriodic[scan - SCAN_1ST_PERIODIC]->scan_list);
|
||||
periodic_scan_list *ppsl = papPeriodic[scan - SCAN_1ST_PERIODIC];
|
||||
|
||||
if (ppsl)
|
||||
addToList(precord, &ppsl->scan_list);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void scanDelete(struct dbCommon *precord)
|
||||
@@ -304,24 +312,17 @@ void scanDelete(struct dbCommon *precord)
|
||||
recGblRecordError(-1, (void *)precord,
|
||||
"scanDelete detected illegal SCAN value");
|
||||
} else if (scan == menuScanEvent) {
|
||||
char* eventname;
|
||||
int prio;
|
||||
event_list *pel;
|
||||
scan_list *psl = 0;
|
||||
|
||||
eventname = precord->evnt;
|
||||
prio = precord->prio;
|
||||
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
|
||||
recGblRecordError(-1, (void *)precord,
|
||||
"scanDelete detected illegal PRIO field");
|
||||
return;
|
||||
}
|
||||
do /* multithreading: make sure pel is consistent */
|
||||
pel = pevent_list[0];
|
||||
while (pel != pevent_list[0]);
|
||||
for (; pel; pel=pel->next) {
|
||||
if (strcmp(pel->event_name, eventname) == 0) break;
|
||||
}
|
||||
pel = eventNameToHandle(precord->evnt);
|
||||
if (pel && (psl = &pel->scan_list[prio]))
|
||||
deleteFromList(precord, psl);
|
||||
} else if (scan == menuScanI_O_Intr) {
|
||||
@@ -354,28 +355,48 @@ void scanDelete(struct dbCommon *precord)
|
||||
}
|
||||
deleteFromList(precord, &piosh->iosl[prio].scan_list);
|
||||
} else if (scan >= SCAN_1ST_PERIODIC) {
|
||||
deleteFromList(precord, &papPeriodic[scan - SCAN_1ST_PERIODIC]->scan_list);
|
||||
periodic_scan_list *ppsl = papPeriodic[scan - SCAN_1ST_PERIODIC];
|
||||
|
||||
if (ppsl)
|
||||
deleteFromList(precord, &ppsl->scan_list);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double scanPeriod(int scan) {
|
||||
periodic_scan_list *ppsl;
|
||||
|
||||
scan -= SCAN_1ST_PERIODIC;
|
||||
if (scan < 0 || scan >= nPeriodic)
|
||||
return 0.0;
|
||||
return papPeriodic[scan]->period;
|
||||
ppsl = papPeriodic[scan];
|
||||
return ppsl ? ppsl->period : 0.0;
|
||||
}
|
||||
|
||||
int scanppl(double period) /* print periodic list */
|
||||
|
||||
int scanppl(double period) /* print periodic scan list(s) */
|
||||
{
|
||||
periodic_scan_list *ppsl;
|
||||
dbMenu *pmenu = dbFindMenu(pdbbase, "menuScan");
|
||||
char message[80];
|
||||
int i;
|
||||
|
||||
if (!pmenu || !papPeriodic) {
|
||||
printf("scanppl: dbScan subsystem not initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
ppsl = papPeriodic[i];
|
||||
if (ppsl == NULL) continue;
|
||||
if (period > 0.0 && (fabs(period - ppsl->period) >.05)) continue;
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) {
|
||||
const char *choice = pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC];
|
||||
|
||||
printf("Periodic scan list for SCAN = '%s' not initialized\n",
|
||||
choice);
|
||||
continue;
|
||||
}
|
||||
if (period > 0.0 &&
|
||||
(fabs(period - ppsl->period) > 0.05))
|
||||
continue;
|
||||
|
||||
sprintf(message, "Records with SCAN = '%s' (%lu over-runs):",
|
||||
ppsl->name, ppsl->overruns);
|
||||
printList(&ppsl->scan_list, message);
|
||||
@@ -389,14 +410,12 @@ int scanpel(const char* eventname) /* print event list */
|
||||
int prio;
|
||||
event_list *pel;
|
||||
|
||||
do /* multithreading: make sure pel is consistent */
|
||||
pel = pevent_list[0];
|
||||
while (pel != pevent_list[0]);
|
||||
for (; pel; pel = pel->next) {
|
||||
if (!eventname || strcmp(pel->event_name, eventname) == 0) {
|
||||
for (pel = pevent_list[0]; pel; pel = pel->next) {
|
||||
if (!eventname || epicsStrGlobMatch(pel->eventname, eventname)) {
|
||||
printf("Event \"%s\"\n", pel->eventname);
|
||||
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||
if (ellCount(&pel->scan_list[prio].list) == 0) continue;
|
||||
sprintf(message, "Event \"%s\" Priority %s", pel->event_name, priorityName[prio]);
|
||||
sprintf(message, " Priority %s", priorityName[prio]);
|
||||
printList(&pel->scan_list[prio], message);
|
||||
}
|
||||
}
|
||||
@@ -447,18 +466,52 @@ event_list *eventNameToHandle(const char *eventname)
|
||||
int prio;
|
||||
event_list *pel;
|
||||
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
||||
double eventnumber = 0;
|
||||
size_t namelength;
|
||||
|
||||
if (!eventname || eventname[0] == 0)
|
||||
return NULL;
|
||||
if (!eventname) return NULL;
|
||||
while (isspace((unsigned char)eventname[0])) eventname++;
|
||||
if (!eventname[0]) return NULL;
|
||||
namelength = strlen(eventname);
|
||||
while (isspace((unsigned char)eventname[namelength-1])) namelength--;
|
||||
|
||||
/* Backward compatibility with numeric events:
|
||||
Treat any string that represents a double with an
|
||||
integer part between 0 and 255 the same as the integer
|
||||
because it is most probably a conversion from double
|
||||
like from a calc record.
|
||||
*/
|
||||
if (epicsParseDouble(eventname, &eventnumber, NULL) == 0)
|
||||
{
|
||||
if (eventnumber >= 0 && eventnumber < 256)
|
||||
{
|
||||
if (eventnumber < 1)
|
||||
return NULL; /* 0 is no event */
|
||||
if ((pel = pevent_list[(int)eventnumber]) != NULL)
|
||||
return pel;
|
||||
}
|
||||
else
|
||||
eventnumber = 0; /* not a numeric event between 1 and 255 */
|
||||
}
|
||||
|
||||
epicsThreadOnce(&onceId, eventOnce, NULL);
|
||||
epicsMutexMustLock(event_lock);
|
||||
for (pel = pevent_list[0]; pel; pel=pel->next) {
|
||||
if (strcmp(pel->event_name, eventname) == 0) break;
|
||||
if (strncmp(pel->eventname, eventname, namelength) == 0
|
||||
&& pel->eventname[namelength] == 0)
|
||||
break;
|
||||
}
|
||||
if (pel == NULL) {
|
||||
pel = dbCalloc(1, sizeof(event_list));
|
||||
strcpy(pel->event_name, eventname);
|
||||
pel = calloc(1, sizeof(event_list) + namelength);
|
||||
if (!pel)
|
||||
goto done;
|
||||
if (eventnumber > 0) {
|
||||
/* backward compatibility: make all numeric events look like integers */
|
||||
sprintf(pel->eventname, "%i", (int)eventnumber);
|
||||
pevent_list[(int)eventnumber] = pel;
|
||||
}
|
||||
else
|
||||
strncpy(pel->eventname, eventname, namelength);
|
||||
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||
callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]);
|
||||
callbackSetPriority(prio, &pel->callback[prio]);
|
||||
@@ -468,13 +521,8 @@ event_list *eventNameToHandle(const char *eventname)
|
||||
}
|
||||
pel->next=pevent_list[0];
|
||||
pevent_list[0]=pel;
|
||||
{ /* backward compatibility */
|
||||
char* p;
|
||||
long e = strtol(eventname, &p, 0);
|
||||
if (*p == 0 && e > 0 && e <= 255)
|
||||
pevent_list[e] = pel;
|
||||
}
|
||||
}
|
||||
done:
|
||||
epicsMutexUnlock(event_lock);
|
||||
return pel;
|
||||
}
|
||||
@@ -494,13 +542,8 @@ void postEvent(event_list *pel)
|
||||
/* backward compatibility */
|
||||
void post_event(int event)
|
||||
{
|
||||
event_list* pel;
|
||||
|
||||
if (event <= 0 || event > 255) return;
|
||||
do { /* multithreading: make sure pel is consistent */
|
||||
pel = pevent_list[event];
|
||||
} while (pel != pevent_list[event]);
|
||||
postEvent(pel);
|
||||
postEvent(pevent_list[event]);
|
||||
}
|
||||
|
||||
static void ioscanOnce(void *arg)
|
||||
@@ -694,7 +737,7 @@ static void periodicTask(void *arg)
|
||||
if (++overruns >= 10 &&
|
||||
epicsTimeDiffInSeconds(&now, &reported) > report_delay) {
|
||||
errlogPrintf("\ndbScan warning from '%s' scan thread:\n"
|
||||
"\tScan processing averages %.2f seconds (%.2f .. %.2f).\n"
|
||||
"\tScan processing averages %.3f seconds (%.3f .. %.3f).\n"
|
||||
"\tOver-runs have now happened %u times in a row.\n"
|
||||
"\tTo fix this, move some records to a slower scan rate.\n",
|
||||
ppsl->name, ppsl->period + overtime / overruns,
|
||||
@@ -741,12 +784,8 @@ static void initPeriodic(void)
|
||||
char *unit;
|
||||
int status = epicsParseDouble(choice, &number, &unit);
|
||||
|
||||
ppsl->scan_list.lock = epicsMutexMustCreate();
|
||||
ellInit(&ppsl->scan_list.list);
|
||||
ppsl->name = choice;
|
||||
if (status || number == 0) {
|
||||
if (status || number <= 0) {
|
||||
errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice);
|
||||
ppsl->period = i;
|
||||
}
|
||||
else if (!*unit ||
|
||||
!epicsStrCaseCmp(unit, "second") ||
|
||||
@@ -767,16 +806,24 @@ static void initPeriodic(void)
|
||||
}
|
||||
else {
|
||||
errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice);
|
||||
ppsl->period = i;
|
||||
}
|
||||
if (ppsl->period == 0) {
|
||||
free(ppsl);
|
||||
continue;
|
||||
}
|
||||
|
||||
ppsl->scan_list.lock = epicsMutexMustCreate();
|
||||
ellInit(&ppsl->scan_list.list);
|
||||
ppsl->name = choice;
|
||||
ppsl->scanCtl = ctlPause;
|
||||
ppsl->loopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
number = ppsl->period / quantum;
|
||||
if ((ppsl->period < 2 * quantum) ||
|
||||
(number / floor(number) > 1.1)) {
|
||||
errlogPrintf("initPeriodic: Scan rate '%s' is not achievable.\n",
|
||||
choice);
|
||||
}
|
||||
ppsl->scanCtl = ctlPause;
|
||||
ppsl->loopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
papPeriodic[i] = ppsl;
|
||||
}
|
||||
@@ -788,6 +835,8 @@ static void deletePeriodic(void)
|
||||
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) continue;
|
||||
ellFree(&ppsl->scan_list.list);
|
||||
epicsEventDestroy(ppsl->loopEvent);
|
||||
epicsMutexDestroy(ppsl->scan_list.lock);
|
||||
@@ -800,10 +849,11 @@ static void deletePeriodic(void)
|
||||
|
||||
static void spawnPeriodic(int ind)
|
||||
{
|
||||
periodic_scan_list *ppsl;
|
||||
periodic_scan_list *ppsl = papPeriodic[ind];
|
||||
char taskName[20];
|
||||
|
||||
ppsl = papPeriodic[ind];
|
||||
if (!ppsl) return;
|
||||
|
||||
sprintf(taskName, "scan-%g", ppsl->period);
|
||||
periodicTaskId[ind] = epicsThreadCreate(
|
||||
taskName, epicsThreadPriorityScanLow + ind,
|
||||
|
||||
@@ -50,7 +50,7 @@ epicsShareFunc void scanCleanup(void);
|
||||
|
||||
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
|
||||
epicsShareFunc void postEvent(EVENTPVT epvt);
|
||||
epicsShareFunc void post_event(int event) EPICS_DEPRECATED;
|
||||
epicsShareFunc void post_event(int event);
|
||||
epicsShareFunc void scanAdd(struct dbCommon *);
|
||||
epicsShareFunc void scanDelete(struct dbCommon *);
|
||||
epicsShareFunc double scanPeriod(int scan);
|
||||
|
||||
@@ -308,6 +308,11 @@ long dbgf(const char *pname)
|
||||
if (nameToAddr(pname, &addr))
|
||||
return -1;
|
||||
|
||||
if (addr.precord->lset == NULL) {
|
||||
printf("dbgf only works after iocInit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size);
|
||||
if (addr.dbr_field_type == DBR_ENUM) {
|
||||
long status = dbGetField(&addr, DBR_STRING, pbuffer,
|
||||
@@ -344,6 +349,11 @@ long dbpf(const char *pname,const char *pvalue)
|
||||
if (nameToAddr(pname, &addr))
|
||||
return -1;
|
||||
|
||||
if (addr.precord->lset == NULL) {
|
||||
printf("dbpf only works after iocInit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr.no_elements > 1 &&
|
||||
(addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR)) {
|
||||
dbrType = addr.dbr_field_type;
|
||||
@@ -398,6 +408,11 @@ long dbtr(const char *pname)
|
||||
if (nameToAddr(pname, &addr))
|
||||
return -1;
|
||||
|
||||
if (addr.precord->lset == NULL) {
|
||||
printf("dbtr only works after iocInit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
precord = (struct dbCommon*)addr.precord;
|
||||
if (precord->pact) {
|
||||
printf("record active\n");
|
||||
@@ -437,6 +452,11 @@ long dbtgf(const char *pname)
|
||||
if (nameToAddr(pname, &addr))
|
||||
return -1;
|
||||
|
||||
if (addr.precord->lset == NULL) {
|
||||
printf("dbtgf only works after iocInit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* try all options first */
|
||||
req_options = 0xffffffff;
|
||||
ret_options = req_options;
|
||||
@@ -534,6 +554,11 @@ long dbtpf(const char *pname, const char *pvalue)
|
||||
if (nameToAddr(pname, &addr))
|
||||
return -1;
|
||||
|
||||
if (addr.precord->lset == NULL) {
|
||||
printf("dbtpf only works after iocInit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
val_long = strtol(pvalue, &pend, 10);
|
||||
validLong = (*pend == 0);
|
||||
|
||||
@@ -797,7 +822,7 @@ static void printBuffer(
|
||||
|
||||
printf("no_strs = %u:\n",
|
||||
pdbr_enumStrs->no_str);
|
||||
for (i = 0; i < pdbr_enumStrs->no_str; i++)
|
||||
for (i = 0; i < pdbr_enumStrs->no_str; i++)
|
||||
printf("\t\"%s\"\n", pdbr_enumStrs->strs[i]);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "epicsUnitTest.h"
|
||||
#include "osiFileName.h"
|
||||
#include "registry.h"
|
||||
#include "epicsThread.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbAccess.h"
|
||||
@@ -111,7 +112,7 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap)
|
||||
return dbPutField(&addr, dbrType, pod.bytes, 1);
|
||||
}
|
||||
|
||||
void testdbPutFieldOk(const char* pv, short dbrType, ...)
|
||||
void testdbPutFieldOk(const char* pv, int dbrType, ...)
|
||||
{
|
||||
long ret;
|
||||
va_list ap;
|
||||
@@ -123,7 +124,7 @@ void testdbPutFieldOk(const char* pv, short dbrType, ...)
|
||||
testOk(ret==0, "dbPutField(%s, %d, ...) == %ld", pv, dbrType, ret);
|
||||
}
|
||||
|
||||
void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
|
||||
void testdbPutFieldFail(long status, const char* pv, int dbrType, ...)
|
||||
{
|
||||
long ret;
|
||||
va_list ap;
|
||||
@@ -138,7 +139,7 @@ void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
|
||||
testFail("dbPutField(\"%s\", %d, ...) != %ld (%ld)", pv, dbrType, status, ret);
|
||||
}
|
||||
|
||||
void testdbGetFieldEqual(const char* pv, short dbrType, ...)
|
||||
void testdbGetFieldEqual(const char* pv, int dbrType, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@@ -163,6 +164,9 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
|
||||
if(status) {
|
||||
testFail("dbGetField(\"%s\",%d,...) returns %ld", pv, dbrType, status);
|
||||
return;
|
||||
} else if(nReq==0) {
|
||||
testFail("dbGetField(\"%s\", %d, ...) -> zero length", pv, dbrType);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(dbrType) {
|
||||
@@ -190,6 +194,72 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
|
||||
}
|
||||
}
|
||||
|
||||
void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long cnt, const void *pbufraw)
|
||||
{
|
||||
DBADDR addr;
|
||||
const long vSize = dbValueSize(dbfType);
|
||||
const long nStore = vSize * nRequest;
|
||||
long status;
|
||||
char *gbuf, *gstore;
|
||||
const char *pbuf = pbufraw;
|
||||
|
||||
if(dbNameToAddr(pv, &addr)) {
|
||||
testFail("Missing PV \"%s\"", pv);
|
||||
return;
|
||||
}
|
||||
|
||||
gbuf = gstore = malloc(nStore);
|
||||
if(!gbuf && nStore!=0) { /* note that malloc(0) is allowed to return NULL on success */
|
||||
testFail("Allocation failed esize=%ld total=%ld", vSize, nStore);
|
||||
return;
|
||||
}
|
||||
|
||||
status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL);
|
||||
if (status) {
|
||||
testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status);
|
||||
|
||||
} else {
|
||||
unsigned match = nRequest==cnt;
|
||||
long n, N = nRequest < cnt ? nRequest : cnt;
|
||||
|
||||
if(!match)
|
||||
testDiag("Length mis-match. expected=%lu actual=%lu", cnt, nRequest);
|
||||
|
||||
for(n=0; n<N; n++, gbuf+=vSize, pbuf+=vSize) {
|
||||
|
||||
switch(dbfType) {
|
||||
case DBR_STRING: {
|
||||
const char *expect = (const char*)pbuf,
|
||||
*actual = (const char*)gbuf;
|
||||
/* expected (pbuf) is allowed to omit storage for trailing nils for last element */
|
||||
unsigned int eq = strncmp(expect, actual, MAX_STRING_SIZE)==0 && actual[MAX_STRING_SIZE-1]=='\0';
|
||||
match &= eq;
|
||||
if(!eq)
|
||||
testDiag("[%lu] = expected=\"%s\" actual=\"%s\"", n, expect, actual);
|
||||
break;
|
||||
}
|
||||
#define OP(DBR,Type,pat) case DBR: {Type expect = *(Type*)pbuf, actual = *(Type*)gbuf; assert(vSize==sizeof(Type)); match &= expect==actual; \
|
||||
if(expect!=actual) testDiag("[%lu] expected=" pat " actual=" pat, n, expect, actual); break;}
|
||||
|
||||
OP(DBR_CHAR, char, "%c");
|
||||
OP(DBR_UCHAR, unsigned char, "%u");
|
||||
OP(DBR_SHORT, short, "%d");
|
||||
OP(DBR_USHORT, unsigned short, "%u");
|
||||
OP(DBR_LONG, int, "%d");
|
||||
OP(DBR_ULONG, unsigned int, "%u");
|
||||
OP(DBR_FLOAT, float, "%e");
|
||||
OP(DBR_DOUBLE, double, "%e");
|
||||
OP(DBR_ENUM, int, "%d");
|
||||
#undef OP
|
||||
}
|
||||
}
|
||||
|
||||
testOk(match, "dbGetField(\"%s\", dbrType=%d, nRequest=%ld ...) match", pv, dbfType, nRequest);
|
||||
}
|
||||
|
||||
free(gstore);
|
||||
}
|
||||
|
||||
dbCommon* testdbRecordPtr(const char* pv)
|
||||
{
|
||||
DBADDR addr;
|
||||
@@ -199,3 +269,26 @@ dbCommon* testdbRecordPtr(const char* pv)
|
||||
|
||||
return addr.precord;
|
||||
}
|
||||
|
||||
static
|
||||
epicsMutexId test_global;
|
||||
|
||||
static
|
||||
epicsThreadOnceId test_global_once = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
static
|
||||
void test_global_init(void* ignored)
|
||||
{
|
||||
test_global = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
void testGlobalLock(void)
|
||||
{
|
||||
epicsThreadOnce(&test_global_once, &test_global_init, NULL);
|
||||
epicsMutexMustLock(test_global);
|
||||
}
|
||||
|
||||
void testGlobalUnlock(void)
|
||||
{
|
||||
epicsMutexUnlock(test_global);
|
||||
}
|
||||
|
||||
@@ -46,17 +46,93 @@ epicsShareFunc void testdbCleanup(void);
|
||||
* testdbPutFieldOk("pvname", DBF_FLOAT, (double)4.1);
|
||||
* testdbPutFieldOk("pvname", DBF_STRING, "hello world");
|
||||
*/
|
||||
epicsShareFunc void testdbPutFieldOk(const char* pv, short dbrType, ...);
|
||||
epicsShareFunc void testdbPutFieldOk(const char* pv, int dbrType, ...);
|
||||
/* Tests for put failure */
|
||||
epicsShareFunc void testdbPutFieldFail(long status, const char* pv, short dbrType, ...);
|
||||
epicsShareFunc void testdbPutFieldFail(long status, const char* pv, int dbrType, ...);
|
||||
|
||||
epicsShareFunc long testdbVPutField(const char* pv, short dbrType, va_list ap);
|
||||
|
||||
epicsShareFunc void testdbGetFieldEqual(const char* pv, short dbrType, ...);
|
||||
epicsShareFunc void testdbGetFieldEqual(const char* pv, int dbrType, ...);
|
||||
epicsShareFunc void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap);
|
||||
|
||||
/**
|
||||
* @param pv PV name string
|
||||
* @param dbfType One of the DBF_* macros from dbAccess.h
|
||||
* @param nRequest Number of elements to request from pv
|
||||
* @param pbufcnt Number of elements pointed to be pbuf
|
||||
* @param pbuf Expected value buffer
|
||||
*
|
||||
* Execute dbGet() of nRequest elements and compare the result with
|
||||
* pbuf (pbufcnt is an element count).
|
||||
* Element size is derived from dbfType.
|
||||
*
|
||||
* nRequest > pbufcnt will detect truncation.
|
||||
* nRequest < pbufcnt always fails.
|
||||
* nRequest ==pbufcnt checks prefix (actual may be longer than expected)
|
||||
*/
|
||||
epicsShareFunc void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long pbufcnt, const void *pbuf);
|
||||
|
||||
epicsShareFunc dbCommon* testdbRecordPtr(const char* pv);
|
||||
|
||||
/** Synchronize the shared callback queues.
|
||||
*
|
||||
* Block until all callback queue jobs which were queued, or running,
|
||||
* have completed.
|
||||
*/
|
||||
epicsShareFunc void testSyncCallback(void);
|
||||
|
||||
/** Global mutex for use by test code.
|
||||
*
|
||||
* This utility mutex is intended to be used to avoid races in situations
|
||||
* where some other syncronization primitive is being destroyed (epicsEvent,
|
||||
* epicsMutex, ...).
|
||||
*
|
||||
* For example. The following has a subtle race where the event may be
|
||||
* destroyed (free()'d) before the call to epicsEventMustSignal() has
|
||||
* returned. On some targets this leads to a use after free() error.
|
||||
*
|
||||
@code
|
||||
epicsEventId evt;
|
||||
void thread1() {
|
||||
evt = epicsEventMustCreate(...);
|
||||
// spawn thread2()
|
||||
epicsEventMustWait(evt);
|
||||
epicsEventDestroy(evt);
|
||||
}
|
||||
// ...
|
||||
void thread2() {
|
||||
epicsEventMustSignal(evt);
|
||||
}
|
||||
@endcode
|
||||
*
|
||||
* One way to avoid this race is to use a global mutex to ensure
|
||||
* that epicsEventMustSignal() has returned before destroying
|
||||
* the event.
|
||||
*
|
||||
@code
|
||||
epicsEventId evt;
|
||||
void thread1() {
|
||||
evt = epicsEventMustCreate(...);
|
||||
// spawn thread2()
|
||||
epicsEventMustWait(evt);
|
||||
testGlobalLock(); // <-- added
|
||||
epicsEventDestroy(evt);
|
||||
testGlobalUnlock(); // <-- added
|
||||
}
|
||||
// ...
|
||||
void thread2() {
|
||||
testGlobalLock(); // <-- added
|
||||
epicsEventMustSignal(evt);
|
||||
testGlobalUnlock(); // <-- added
|
||||
}
|
||||
@endcode
|
||||
*
|
||||
* This must be a global mutex to avoid simply shifting the race
|
||||
* from the event to a locally allocated mutex.
|
||||
*/
|
||||
epicsShareFunc void testGlobalLock(void);
|
||||
epicsShareFunc void testGlobalUnlock(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -172,6 +172,7 @@ int pft(const char *pname, const char *pvalue)
|
||||
ca_dump_dbr(DBR_ENUM,1, buffer);
|
||||
}
|
||||
printf("\n");
|
||||
dbChannelDelete(chan);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -231,6 +232,7 @@ int tpn(const char *pname, const char *pvalue)
|
||||
ppn = calloc(1, sizeof(processNotify));
|
||||
if (!ppn) {
|
||||
printf("calloc failed\n");
|
||||
dbChannelDelete(chan);
|
||||
return -1;
|
||||
}
|
||||
ppn->requestType = putProcessRequest;
|
||||
@@ -241,6 +243,8 @@ int tpn(const char *pname, const char *pvalue)
|
||||
ptpnInfo = calloc(1, sizeof(tpnInfo));
|
||||
if (!ptpnInfo) {
|
||||
printf("calloc failed\n");
|
||||
free(ppn);
|
||||
dbChannelDelete(chan);
|
||||
return -1;
|
||||
}
|
||||
ptpnInfo->ppn = ppn;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "alarm.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "epicsStdlib.h"
|
||||
@@ -181,6 +182,9 @@ unsigned short recGblResetAlarms(void *precord)
|
||||
epicsEnum16 val_mask = 0;
|
||||
epicsEnum16 stat_mask = 0;
|
||||
|
||||
if (new_sevr > INVALID_ALARM)
|
||||
new_sevr = INVALID_ALARM;
|
||||
|
||||
pdbc->stat = new_stat;
|
||||
pdbc->sevr = new_sevr;
|
||||
pdbc->nsta = 0;
|
||||
|
||||
@@ -131,7 +131,14 @@ recGblCheckDeadbandTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += recGblCheckDeadbandTest.c
|
||||
TESTS += recGblCheckDeadbandTest
|
||||
|
||||
# The testHarness runs all the test programs in a known working order.
|
||||
TESTPROD_HOST += testPutGetTest
|
||||
testPutGetTest_SRCS += dbPutGetTest.c
|
||||
testPutGetTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbPutGetTest.db
|
||||
TESTFILES += ../dbPutGetTest.db
|
||||
TESTS += testPutGetTest
|
||||
|
||||
# This runs all the test programs in a known working order:
|
||||
testHarness_SRCS += epicsRunDbTests.c
|
||||
|
||||
dbTestHarness_SRCS += $(testHarness_SRCS)
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
*
|
||||
* Two time intervals are measured. The time to queue and run each of
|
||||
* the immediate callbacks, and the actual delay of the delayed callback.
|
||||
*
|
||||
* Slow callbacks no longer fail the test, they just emit a diagnostic.
|
||||
*/
|
||||
|
||||
#define NCALLBACKS 169
|
||||
@@ -108,7 +110,7 @@ MAIN(callbackParallelTest)
|
||||
for (j = 0; j < 5; j++)
|
||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||
|
||||
testPlan(4);
|
||||
testPlan(2);
|
||||
|
||||
testDiag("Starting %d parallel callback threads", noCpus);
|
||||
|
||||
@@ -165,7 +167,8 @@ MAIN(callbackParallelTest)
|
||||
}
|
||||
}
|
||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
||||
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
|
||||
if (slowups)
|
||||
testDiag("%d slowups during callback setup", slowups);
|
||||
|
||||
slowups = 0;
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
@@ -182,7 +185,8 @@ MAIN(callbackParallelTest)
|
||||
}
|
||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
||||
}
|
||||
testOk(slowups < 5, "%d slowups during callbacks", slowups);
|
||||
if (slowups)
|
||||
testDiag("%d slowups during callback setup", slowups);
|
||||
|
||||
testDiag("Setup time statistics");
|
||||
printStats(setupError[0], "LOW");
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
*
|
||||
* Two time intervals are measured. The time to queue and run each of
|
||||
* the immediate callbacks, and the actual delay of the delayed callback.
|
||||
*
|
||||
* Slow callbacks no longer fail the test, they just emit a diagnostic.
|
||||
*/
|
||||
|
||||
#define NCALLBACKS 169
|
||||
@@ -108,7 +110,7 @@ MAIN(callbackTest)
|
||||
for (j = 0; j < 5; j++)
|
||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||
|
||||
testPlan(4);
|
||||
testPlan(2);
|
||||
|
||||
callbackInit();
|
||||
epicsThreadSleep(1.0);
|
||||
@@ -162,7 +164,8 @@ MAIN(callbackTest)
|
||||
}
|
||||
}
|
||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
||||
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
|
||||
if (slowups)
|
||||
testDiag("%d slowups during callback setup", slowups);
|
||||
|
||||
slowups = 0;
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
@@ -179,7 +182,8 @@ MAIN(callbackTest)
|
||||
}
|
||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
||||
}
|
||||
testOk(slowups < 5, "%d slowups during callbacks", slowups);
|
||||
if (slowups)
|
||||
testDiag("%d slowups during callback setup", slowups);
|
||||
|
||||
testDiag("Setup time statistics");
|
||||
printStats(setupError[0], "LOW");
|
||||
|
||||
@@ -541,8 +541,11 @@ MAIN(chfPluginTest)
|
||||
dbChannel *pch;
|
||||
db_field_log *pfl;
|
||||
|
||||
#if defined(WIN32) && (!defined(_MINGW) || __MSVCRT_VERSION__ >= 0x0800)
|
||||
#ifdef _WIN32
|
||||
#if (defined(_MSC_VER) && _MSC_VER < 1900) || \
|
||||
(defined(_MINGW) && defined(_TWO_DIGIT_EXPONENT))
|
||||
_set_output_format(_TWO_DIGIT_EXPONENT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
testPlan(1433);
|
||||
|
||||
150
src/ioc/db/test/dbPutGetTest.c
Normal file
150
src/ioc/db/test/dbPutGetTest.c
Normal file
@@ -0,0 +1,150 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <errlog.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbStaticLib.h>
|
||||
#include <dbStaticPvt.h>
|
||||
#include <dbUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
static
|
||||
void testdbGetStringEqual(const char *pv, const char *expected)
|
||||
{
|
||||
const char *actual;
|
||||
int ok;
|
||||
DBENTRY ent;
|
||||
|
||||
dbInitEntry(pdbbase, &ent);
|
||||
|
||||
if(dbFindRecord(&ent, pv)) {
|
||||
testFail("Failed to find record '%s'", pv);
|
||||
return;
|
||||
}
|
||||
|
||||
actual = dbGetString(&ent);
|
||||
ok = (!actual && !expected)
|
||||
|| (actual && expected && strcmp(actual, expected)==0);
|
||||
|
||||
testOk(ok, "dbGetString(\"%s\") -> \"%s\" == \"%s\"", pv, actual, expected);
|
||||
|
||||
dbFinishEntry(&ent);
|
||||
}
|
||||
|
||||
static
|
||||
void testGetString(void)
|
||||
{
|
||||
testDiag("testGetString()");
|
||||
|
||||
testdbGetStringEqual("recempty.DTYP", "Soft Channel");
|
||||
testdbGetStringEqual("recempty.DESC", "");
|
||||
testdbGetStringEqual("recempty.PHAS", "0");
|
||||
testdbGetStringEqual("recempty.TSE" , "0");
|
||||
testdbGetStringEqual("recempty.DISA", "0");
|
||||
testdbGetStringEqual("recempty.DISV", "0");
|
||||
|
||||
testdbGetStringEqual("recoverwrite.DTYP", "Soft Channel");
|
||||
testdbGetStringEqual("recoverwrite.DESC", "");
|
||||
testdbGetStringEqual("recoverwrite.PHAS", "0");
|
||||
testdbGetStringEqual("recoverwrite.TSE" , "0");
|
||||
testdbGetStringEqual("recoverwrite.DISA", "0");
|
||||
testdbGetStringEqual("recoverwrite.DISV", "0");
|
||||
}
|
||||
|
||||
static
|
||||
void testStringMax(void)
|
||||
{
|
||||
testDiag("testStringMax()");
|
||||
|
||||
testdbGetStringEqual("recmax.DISA", "-1");
|
||||
}
|
||||
|
||||
static
|
||||
void testLongLink(void)
|
||||
{
|
||||
testDiag("testLonkLink()");
|
||||
|
||||
testdbGetFieldEqual("lnktest.INP", DBR_STRING, "lnktarget NPP NMS");
|
||||
testdbGetFieldEqual("lnktest.INP$", DBR_STRING, "lnktarget NPP NMS");
|
||||
testDiag("dbGet() w/ nRequest==1 gets only trailing nil");
|
||||
testdbGetFieldEqual("lnktest.INP$", DBR_CHAR, '\0');
|
||||
testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 19, 18, "lnktarget NPP NMS");
|
||||
|
||||
testDiag("get w/ truncation");
|
||||
testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 0, 0, NULL);
|
||||
testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 1, 1, "");
|
||||
testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 2, 2, "l");
|
||||
testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 3, 3, "ln");
|
||||
testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 17, 17, "lnktarget NPP NM");
|
||||
testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 18, 18, "lnktarget NPP NMS");
|
||||
|
||||
testdbGetArrFieldEqual("lnktest.INP", DBR_STRING, 2, 1, "lnktarget NPP NMS");
|
||||
}
|
||||
|
||||
static
|
||||
void testLongAttr(void)
|
||||
{
|
||||
testDiag("testLongAttr()");
|
||||
|
||||
testdbGetFieldEqual("lnktest.RTYP", DBR_STRING, "x");
|
||||
testdbGetFieldEqual("lnktest.RTYP$", DBR_STRING, "x");
|
||||
testDiag("dbGet() w/ nRequest==1 gets only trailing nil");
|
||||
testdbGetFieldEqual("lnktest.RTYP$", DBR_CHAR, '\0');
|
||||
|
||||
testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 4, 2, "x");
|
||||
|
||||
testDiag("get w/ truncation");
|
||||
testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 0, 0, NULL);
|
||||
testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 1, 1, "");
|
||||
testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 2, 2, "x");
|
||||
}
|
||||
|
||||
static
|
||||
void testLongField(void)
|
||||
{
|
||||
testDiag("testLongField()");
|
||||
|
||||
testdbGetFieldEqual("lnktest.NAME", DBR_STRING, "lnktest");
|
||||
testdbGetFieldEqual("lnktest.NAME$", DBR_STRING, "108");
|
||||
testDiag("dbGet() w/ nRequest==1 gets only trailing nil");
|
||||
testdbGetFieldEqual("lnktest.NAME$", DBR_CHAR, '\0');
|
||||
testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 10, 8, "lnktest");
|
||||
|
||||
testDiag("get w/ truncation");
|
||||
testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 0, 0, NULL);
|
||||
testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 1, 1, "");
|
||||
testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 2, 2, "l");
|
||||
testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 3, 3, "ln");
|
||||
testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 7, 7, "lnktes");
|
||||
testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 8, 8, "lnktest");
|
||||
}
|
||||
|
||||
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(dbPutGet)
|
||||
{
|
||||
testPlan(41);
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
|
||||
dbTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
testdbReadDatabase("dbPutGetTest.db", NULL, NULL);
|
||||
|
||||
testGetString();
|
||||
|
||||
testStringMax();
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
testLongLink();
|
||||
testLongAttr();
|
||||
testLongField();
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user