Compare commits
360 Commits
libcom-3.1
...
R3.16.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5fd621337 | ||
|
|
ea409e79be | ||
|
|
c59a18600a | ||
|
|
68f6f361e1 | ||
|
|
84b7612036 | ||
|
|
f3cf1df503 | ||
|
|
9b385480d0 | ||
|
|
ec036cb26d | ||
|
|
64d9d1a4c9 | ||
|
|
e53244df1f | ||
|
|
fe3d68b5f7 | ||
|
|
49f5527cd7 | ||
|
|
ee90dffd40 | ||
|
|
6664ccfc64 | ||
|
|
444cac337c | ||
|
|
313afc4a4c | ||
|
|
0fae0fcc17 | ||
|
|
aab5693b45 | ||
|
|
6f919c3991 | ||
|
|
87761ebf29 | ||
|
|
10d951e2d7 | ||
|
|
d436561cb2 | ||
|
|
a43b805b65 | ||
|
|
9e999d2bef | ||
|
|
040f9013f4 | ||
|
|
0f16977caf | ||
|
|
694f045332 | ||
|
|
daad9b1ba1 | ||
|
|
937878e0a9 | ||
|
|
6e536e1ee0 | ||
|
|
6ea6c6ff66 | ||
|
|
168d430921 | ||
|
|
9a8860b771 | ||
|
|
693c1020f2 | ||
|
|
63ddb2d4fc | ||
|
|
3d8e2d933d | ||
|
|
5f3f87a365 | ||
|
|
072dbd53e7 | ||
|
|
43322335df | ||
|
|
fcb5675040 | ||
|
|
3d88c8495b | ||
|
|
215c5d954b | ||
|
|
59ec8d897d | ||
|
|
94ebd0fe48 | ||
|
|
8a7442e878 | ||
|
|
31870b4c41 | ||
|
|
ae38fb2c1c | ||
|
|
a3ace1f260 | ||
|
|
728bb556cf | ||
|
|
b7afb287d5 | ||
|
|
275d36b09d | ||
|
|
a81c3503d2 | ||
|
|
03b8257d71 | ||
|
|
46370302f6 | ||
|
|
ab59c97f4b | ||
|
|
77bdea22f8 | ||
|
|
00ee7bf7d3 | ||
|
|
3c607d9034 | ||
|
|
06f522b253 | ||
|
|
c6476fbbdc | ||
|
|
b336545853 | ||
|
|
63994839d0 | ||
|
|
1564f87bd6 | ||
|
|
6eb88b16a0 | ||
|
|
27ee078bc8 | ||
|
|
a62c357e99 | ||
|
|
ea0556e471 | ||
|
|
891caa5933 | ||
|
|
b18478077a | ||
|
|
dd78ab0888 | ||
|
|
f1e55ef240 | ||
|
|
2c07e5fbb9 | ||
|
|
11ba48232c | ||
|
|
531ab6fc36 | ||
|
|
e7e9e66651 | ||
|
|
453ad41c48 | ||
|
|
eed208afaa | ||
|
|
ae63854dff | ||
|
|
ce7943fb44 | ||
|
|
4e865a03d8 | ||
|
|
9a4febd3bc | ||
|
|
dc5d373b57 | ||
|
|
47c361f135 | ||
|
|
9943796f7f | ||
| 3cb72ec209 | |||
| 701ef5b936 | |||
| c3995a9d63 | |||
| ce3eadde34 | |||
|
|
62929fcbd1 | ||
|
|
456a68eb96 | ||
|
|
b319b4722f | ||
|
|
b4cc5fdf4b | ||
|
|
d35835659c | ||
| 65714033ea | |||
| 7151fbe498 | |||
|
|
cbb13bf6b1 | ||
|
|
150d764d28 | ||
|
|
7dd1ea4cab | ||
|
|
922ed30136 | ||
|
|
9f9f119e7e | ||
|
|
d8214a4531 | ||
|
|
120b100e7e | ||
|
|
949e9d788a | ||
|
|
27c6e6a385 | ||
|
|
4b59476170 | ||
|
|
526b565c6b | ||
|
|
1b7b2bcceb | ||
|
|
49c925d064 | ||
|
|
46b5d6006e | ||
|
|
6a2ed4b333 | ||
|
|
73b81ad139 | ||
|
|
7c00cc8045 | ||
|
|
b2bb14c654 | ||
|
|
ae5122759d | ||
|
|
d3bcf5737f | ||
|
|
6c5505ad3e | ||
|
|
4247d98b08 | ||
|
|
13735a8088 | ||
|
|
58d4242b68 | ||
|
|
8e42f516b0 | ||
|
|
9051cdbb34 | ||
|
|
8ffea9de27 | ||
|
|
2548a37267 | ||
|
|
592a83385d | ||
|
|
1ffd30c6d4 | ||
|
|
6e85a407da | ||
|
|
76a4a20698 | ||
|
|
7626856a20 | ||
|
|
1dc1b25aaa | ||
|
|
fb31dd784b | ||
|
|
fe7260e263 | ||
|
|
67e2b74758 | ||
|
|
c09b6e2f1b | ||
|
|
45be2306bd | ||
|
|
6027f906c3 | ||
|
|
ec351c5e2f | ||
| 89870e2817 | |||
| 4e9cf72d71 | |||
| 80869a0868 | |||
| 998fa984ba | |||
| 31844af88e | |||
| 8f161f9463 | |||
| e0399478ad | |||
|
|
2a2a1e54ac | ||
|
|
20d2cff501 | ||
|
|
860ce156a2 | ||
|
|
27431facb8 | ||
|
|
fe4b5d7d72 | ||
|
|
a447ed8bd0 | ||
|
|
7ef9ea7193 | ||
|
|
0f21196670 | ||
|
|
31fc35fbe8 | ||
|
|
f892731b3f | ||
|
|
d20ce9e6bc | ||
|
|
e82f59a2d7 | ||
|
|
6761726e95 | ||
|
|
4e24acebfe | ||
| ab493264b2 | |||
| 68779943eb | |||
| 7a5ff26984 | |||
| eae59183cc | |||
|
|
8144d2ea01 | ||
|
|
b32629c3bf | ||
|
|
220e404203 | ||
|
|
83b17d5061 | ||
|
|
65dec97f9e | ||
|
|
dcb494b494 | ||
|
|
8f55a1307d | ||
|
|
e459e8bdd4 | ||
|
|
b558bd9b16 | ||
|
|
3c16c3c0da | ||
|
|
7d28ae3732 | ||
|
|
a9d7f7be13 | ||
|
|
c0a7ab976c | ||
|
|
b029448059 | ||
|
|
3b77d9be8c | ||
|
|
6e3aa77c42 | ||
|
|
2fb46fc541 | ||
|
|
36f23f3aec | ||
|
|
ffe6fceffa | ||
|
|
bcfdc8d368 | ||
|
|
c6c25ab43d | ||
|
|
5796f717ef | ||
|
|
89b9e240b0 | ||
|
|
8cdcaf5a87 | ||
|
|
f2ceb3bbbf | ||
|
|
fd30989f63 | ||
|
|
55db6525ee | ||
|
|
fe1ec6ed31 | ||
|
|
8fb6c6d610 | ||
|
|
23c4eb42a3 | ||
|
|
6d7f70f200 | ||
|
|
67844bacc3 | ||
|
|
7e7d230d8c | ||
|
|
c0cbf8e985 | ||
|
|
498b248811 | ||
|
|
c1ece40f41 | ||
|
|
a732539eee | ||
|
|
3bc0805a89 | ||
|
|
c72e35c769 | ||
|
|
7e293e60a6 | ||
|
|
c80783dfa9 | ||
|
|
3b6a4ad5a6 | ||
| ccc8f75ec7 | |||
| d9742d5240 | |||
| 7aa2ae2094 | |||
| ab517a9392 | |||
| 4df39bb425 | |||
| 6ff271527b | |||
|
|
2d9c5e99a1 | ||
|
|
ca22d50831 | ||
|
|
3b89515664 | ||
|
|
1893cb4f54 | ||
|
|
2b1d5ae4e3 | ||
|
|
1ca8535266 | ||
|
|
c0cbbd8bee | ||
|
|
fef15d6c91 | ||
|
|
805e62b29c | ||
|
|
d94c8d1e37 | ||
|
|
a4fcd2296a | ||
|
|
4972803ce2 | ||
|
|
3b7e348a8c | ||
|
|
00a974ce52 | ||
|
|
490c504736 | ||
|
|
35ad28dde1 | ||
|
|
ba4c609506 | ||
|
|
49371cfe00 | ||
|
|
06ad4a0d70 | ||
|
|
a2ae07dfcd | ||
|
|
b539ced6d5 | ||
|
|
1b332361e7 | ||
|
|
5cb91d9f6d | ||
|
|
116c90c2ea | ||
|
|
3f3696fb91 | ||
|
|
57eea6a153 | ||
|
|
877d38e79a | ||
|
|
92f0f65d2c | ||
|
|
7cef334b64 | ||
|
|
b84ee89d87 | ||
|
|
b8a0792fae | ||
|
|
91ce807e8b | ||
|
|
c2c32e5876 | ||
|
|
ca2003bb63 | ||
|
|
3d88316eab | ||
|
|
b9443f8813 | ||
|
|
086bc961a4 | ||
|
|
58dc1ced9b | ||
|
|
d8802c8b24 | ||
|
|
b7d4609e57 | ||
|
|
7b5b23f6d3 | ||
|
|
c8a7e1597d | ||
|
|
0f7a7902e4 | ||
|
|
42403232e9 | ||
|
|
8333338f99 | ||
|
|
ceaff61c09 | ||
|
|
12bb8969ad | ||
|
|
ea408578e0 | ||
|
|
2307e94d1c | ||
|
|
05a3699b49 | ||
|
|
97ea68d40c | ||
|
|
f44da65942 | ||
|
|
be8f35d782 | ||
|
|
6cc623a7b4 | ||
| 2b4a9632b7 | |||
| 396cf4ee3f | |||
|
|
d7e416e76a | ||
|
|
c05101bb3f | ||
|
|
958c81db89 | ||
|
|
9020c2ce1a | ||
|
|
8f64af96fd | ||
|
|
54c47f02de | ||
|
|
d87ac0319b | ||
|
|
20404003bf | ||
|
|
1fa5d9d3b6 | ||
|
|
5e394e4928 | ||
|
|
c0d4835e66 | ||
|
|
8ae34ba01d | ||
|
|
98f656fc96 | ||
|
|
1458f8640e | ||
|
|
a9764c8f62 | ||
|
|
98d9ea4545 | ||
|
|
8eb4eec7d2 | ||
|
|
98930eebc4 | ||
| e50c468512 | |||
|
|
292141458c | ||
|
|
c18b6f2ccf | ||
|
|
e41f8bf518 | ||
|
|
ae548d3400 | ||
| 428a8f57e9 | |||
| 29795656e6 | |||
| b2d6b67b06 | |||
| 1e9826d187 | |||
| 0691fc5f57 | |||
| 8a3080c16f | |||
| d19afc73af | |||
| adf5375616 | |||
|
|
85c6e9bdfb | ||
|
|
550beeab9f | ||
|
|
bf91275200 | ||
|
|
ac4d5c95ac | ||
| 7d836d9554 | |||
| 51e492fbb1 | |||
|
|
cd8fd8a08f | ||
|
|
61296b8cff | ||
|
|
de442e9584 | ||
|
|
ac367398b3 | ||
|
|
713c2d5080 | ||
|
|
eef6f3afbb | ||
|
|
af07016464 | ||
|
|
734d16291f | ||
|
|
f1e5e9689b | ||
|
|
1454f42a27 | ||
|
|
506be838af | ||
|
|
ddbdcf9462 | ||
|
|
729e6fda4d | ||
|
|
0315e90e6e | ||
|
|
00f30ac53a | ||
|
|
66c6aaa44f | ||
|
|
c830a3a4ee | ||
|
|
1daab5fb35 | ||
|
|
f5cd555383 | ||
|
|
f527e5939e | ||
|
|
d41f2e6806 | ||
|
|
692b971e06 | ||
|
|
8766ce05aa | ||
|
|
84e0220852 | ||
|
|
8f62940265 | ||
|
|
8a1477ecab | ||
|
|
5c97e54cf7 | ||
|
|
3646493014 | ||
|
|
89cbb95c2c | ||
|
|
006ce1a240 | ||
|
|
276dee2c3e | ||
|
|
98a2871727 | ||
|
|
5ca1bb3bd5 | ||
|
|
f6be3c7f70 | ||
|
|
00924dcba0 | ||
|
|
8e2b782b7c | ||
|
|
3b0f34e0be | ||
|
|
2d1f1ed2fa | ||
|
|
db005ac3fe | ||
|
|
c28a360357 | ||
|
|
0f0deb8903 | ||
|
|
baf997193e | ||
|
|
5278799575 | ||
|
|
aebfe587d8 | ||
|
|
031e755303 | ||
|
|
e794639e31 | ||
|
|
2af98c33c9 | ||
|
|
e8b4f448ea | ||
|
|
d5f74fe006 | ||
|
|
6923ca9fda | ||
|
|
aace975de1 | ||
|
|
c8b60e0f1b | ||
|
|
1255cdc9ee | ||
|
|
12da38a7ca | ||
|
|
f78e1f39d7 | ||
|
|
684fe10d8c | ||
|
|
15b97f65cb | ||
|
|
c1b0c1bac1 |
@@ -11,8 +11,8 @@ env:
|
|||||||
- CMPLR=clang STATIC=YES
|
- CMPLR=clang STATIC=YES
|
||||||
- WINE=32 TEST=NO STATIC=YES
|
- WINE=32 TEST=NO STATIC=YES
|
||||||
- WINE=32 TEST=NO STATIC=NO
|
- WINE=32 TEST=NO STATIC=NO
|
||||||
- RTEMS=4.10 TEST=NO
|
- RTEMS=4.10 TEST=YES
|
||||||
- RTEMS=4.9 TEST=NO
|
- RTEMS=4.9 TEST=YES
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
@@ -25,8 +25,8 @@ addons:
|
|||||||
- flex
|
- flex
|
||||||
- texinfo
|
- texinfo
|
||||||
- install-info
|
- install-info
|
||||||
|
- qemu-system-x86
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.cache
|
- $HOME/.cache
|
||||||
install: sh ci/travis-prepare.sh </dev/null
|
|
||||||
script: sh ci/travis-build.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
|
archives and subscription instructions, documentation and
|
||||||
training materials, additional components, links to other
|
training materials, additional components, links to other
|
||||||
websites etc. is available on the EPICS home page at
|
websites etc. is available on the EPICS home page at
|
||||||
http://www.aps.anl.gov/epics/
|
https://epics.anl.gov/
|
||||||
|
|
||||||
|
|||||||
@@ -40,11 +40,12 @@ configuration:
|
|||||||
# Environment variables: compiler toolchain
|
# Environment variables: compiler toolchain
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- TOOLCHAIN: 9.0
|
|
||||||
- TOOLCHAIN: 10.0
|
- TOOLCHAIN: 10.0
|
||||||
- TOOLCHAIN: 11.0
|
- TOOLCHAIN: 11.0
|
||||||
- TOOLCHAIN: 12.0
|
- TOOLCHAIN: 12.0
|
||||||
- TOOLCHAIN: 14.0
|
- TOOLCHAIN: 14.0
|
||||||
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
TOOLCHAIN: 2017
|
||||||
- TOOLCHAIN: cygwin
|
- TOOLCHAIN: cygwin
|
||||||
- TOOLCHAIN: mingw
|
- TOOLCHAIN: mingw
|
||||||
|
|
||||||
@@ -57,8 +58,6 @@ platform:
|
|||||||
matrix:
|
matrix:
|
||||||
exclude:
|
exclude:
|
||||||
# VS Express installs don't have the 64 bit compiler
|
# VS Express installs don't have the 64 bit compiler
|
||||||
- platform: x64
|
|
||||||
TOOLCHAIN: 9.0
|
|
||||||
- platform: x64
|
- platform: x64
|
||||||
TOOLCHAIN: 10.0
|
TOOLCHAIN: 10.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
:: Universal build script for AppVeyor (https://ci.appveyor.com/)
|
:: Universal build script for AppVeyor (https://ci.appveyor.com/)
|
||||||
:: Environment:
|
:: Environment:
|
||||||
:: TOOLCHAIN - toolchain version [9.0/10.0/11.0/12.0/14.0/cygwin/mingw]
|
:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/cygwin/mingw]
|
||||||
:: CONFIGURATION - determines EPICS build [dynamic/static]
|
:: CONFIGURATION - determines EPICS build [dynamic/static]
|
||||||
:: PLATFORM - architecture [x86/x64]
|
:: PLATFORM - architecture [x86/x64]
|
||||||
::
|
::
|
||||||
@@ -57,10 +57,22 @@ if "%TOOLCHAIN%"=="mingw" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio %TOOLCHAIN%"
|
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"
|
set "MAKE=C:\tools\make"
|
||||||
|
|
||||||
|
echo [INFO] APPVEYOR_BUILD_WORKER_IMAGE=%APPVEYOR_BUILD_WORKER_IMAGE%
|
||||||
|
|
||||||
if "%OS%"=="64BIT" (
|
if "%OS%"=="64BIT" (
|
||||||
set EPICS_HOST_ARCH=windows-x64%ST%
|
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" (
|
if exist "%VSINSTALL%\VC\vcvarsall.bat" (
|
||||||
call "%VSINSTALL%\VC\vcvarsall.bat" amd64
|
call "%VSINSTALL%\VC\vcvarsall.bat" amd64
|
||||||
where cl
|
where cl
|
||||||
@@ -79,12 +91,19 @@ if "%OS%"=="64BIT" (
|
|||||||
)
|
)
|
||||||
) else (
|
) else (
|
||||||
set EPICS_HOST_ARCH=win32-x86%ST%
|
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" (
|
if exist "%VSINSTALL%\VC\vcvarsall.bat" (
|
||||||
call "%VSINSTALL%\VC\vcvarsall.bat" x86
|
call "%VSINSTALL%\VC\vcvarsall.bat" x86
|
||||||
where cl
|
where cl
|
||||||
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
if !ERRORLEVEL! NEQ 0 goto MSMissing
|
||||||
goto MSFound
|
goto MSFound
|
||||||
)
|
)
|
||||||
if exist "%VSINSTALL%\VC\bin\vcvars32.bat" (
|
if exist "%VSINSTALL%\VC\bin\vcvars32.bat" (
|
||||||
call "%VSINSTALL%\VC\bin\vcvars32.bat"
|
call "%VSINSTALL%\VC\bin\vcvars32.bat"
|
||||||
where cl
|
where cl
|
||||||
|
|||||||
@@ -65,6 +65,6 @@ if "%TOOLCHAIN%"=="mingw" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
echo [INFO] Installing Make 4.1
|
echo [INFO] Installing Make 4.1
|
||||||
@powershell -Command "(new-object net.webclient).DownloadFile('https://www.aps.anl.gov/epics/download/tools/make-4.1-win64.zip', 'C:\tools\make-4.1.zip')"
|
curl -fsS --retry 3 -o C:\tools\make-4.1.zip https://epics.anl.gov/download/tools/make-4.1-win64.zip
|
||||||
cd \tools
|
cd \tools
|
||||||
"C:\Program Files\7-Zip\7z" e make-4.1.zip
|
"C:\Program Files\7-Zip\7z" e make-4.1.zip
|
||||||
|
|||||||
@@ -6,18 +6,9 @@ die() {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker() {
|
|
||||||
while true
|
|
||||||
do
|
|
||||||
sleep 60
|
|
||||||
date -R
|
|
||||||
[ -r "$1" ] && tail -n10 "$1"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
CACHEKEY=1
|
CACHEKEY=1
|
||||||
|
|
||||||
EPICS_HOST_ARCH=`sh startup/EpicsHostArch`
|
EPICS_HOST_ARCH=`perl src/tools/EpicsHostArch.pl`
|
||||||
|
|
||||||
[ -e configure/os/CONFIG_SITE.Common.linux-x86 ] || die "Wrong location: $PWD"
|
[ -e configure/os/CONFIG_SITE.Common.linux-x86 ] || die "Wrong location: $PWD"
|
||||||
|
|
||||||
@@ -62,23 +53,22 @@ if [ -n "$RTEMS" ]
|
|||||||
then
|
then
|
||||||
echo "Cross RTEMS${RTEMS} for pc386"
|
echo "Cross RTEMS${RTEMS} for pc386"
|
||||||
install -d /home/travis/.cache
|
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" \
|
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
|
||||||
| tar -C /home/travis/.cache -xj
|
| tar -C / -xmj
|
||||||
|
|
||||||
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS
|
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS
|
||||||
cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS
|
cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS
|
||||||
RTEMS_VERSION=$RTEMS
|
RTEMS_VERSION=$RTEMS
|
||||||
RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386
|
RTEMS_BASE=/home/travis/.rtems
|
||||||
EOF
|
EOF
|
||||||
cat << EOF >> configure/CONFIG_SITE
|
cat << EOF >> configure/CONFIG_SITE
|
||||||
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
|
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
|
||||||
|
CROSS_COMPILER_RUNTEST_ARCHS += RTEMS-pc386-qemu
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# find local qemu-system-i386
|
# find local qemu-system-i386
|
||||||
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
|
|
||||||
echo -n "Using QEMU: "
|
echo -n "Using QEMU: "
|
||||||
type qemu-system-i386 || echo "Missing qemu"
|
type qemu-system-i386 || echo "Missing qemu"
|
||||||
EXTRA=RTEMS_QEMU_FIXUPS=YES
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
make -j2 $EXTRA
|
make -j2 $EXTRA
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/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
|
endif
|
||||||
|
|
||||||
# Provide a default if the user hasn't set EPICS_HOST_ARCH
|
# 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
|
||||||
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH)
|
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl
|
|||||||
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
|
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
|
||||||
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
|
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
|
||||||
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
|
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
|
||||||
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG)
|
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG)
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# tools for installing libraries and products
|
# tools for installing libraries and products
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ EPICS_VERSION = 3
|
|||||||
EPICS_REVISION = 16
|
EPICS_REVISION = 16
|
||||||
|
|
||||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||||
EPICS_MODIFICATION = 1
|
EPICS_MODIFICATION = 2
|
||||||
|
|
||||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||||
# Not included if zero
|
# Not included if zero
|
||||||
EPICS_PATCH_LEVEL = 0
|
EPICS_PATCH_LEVEL = 0
|
||||||
|
|
||||||
# This will end in -DEV between official releases
|
# This will end in -DEV between official releases
|
||||||
EPICS_DEV_SNAPSHOT=-DEV
|
#EPICS_DEV_SNAPSHOT=-DEV
|
||||||
#EPICS_DEV_SNAPSHOT=-pre1
|
#EPICS_DEV_SNAPSHOT=-pre1
|
||||||
#EPICS_DEV_SNAPSHOT=-pre1-DEV
|
#EPICS_DEV_SNAPSHOT=-pre1-DEV
|
||||||
#EPICS_DEV_SNAPSHOT=-pre2
|
#EPICS_DEV_SNAPSHOT=-pre2
|
||||||
@@ -54,7 +54,7 @@ EPICS_DEV_SNAPSHOT=-DEV
|
|||||||
#EPICS_DEV_SNAPSHOT=-rc1-DEV
|
#EPICS_DEV_SNAPSHOT=-rc1-DEV
|
||||||
#EPICS_DEV_SNAPSHOT=-rc2
|
#EPICS_DEV_SNAPSHOT=-rc2
|
||||||
#EPICS_DEV_SNAPSHOT=-rc2-DEV
|
#EPICS_DEV_SNAPSHOT=-rc2-DEV
|
||||||
#EPICS_DEV_SNAPSHOT=
|
EPICS_DEV_SNAPSHOT=
|
||||||
|
|
||||||
# No changes should be needed below here
|
# No changes should be needed below here
|
||||||
|
|
||||||
|
|||||||
@@ -76,10 +76,14 @@ COMMON_DIR = ../O.Common
|
|||||||
IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
|
IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
|
||||||
|
|
||||||
#-------------------------------------------------------
|
#-------------------------------------------------------
|
||||||
# Make echo output - suppress echoing if make's '-s' flag is set
|
# Silencing the build - suppress messages during 'make -s'
|
||||||
NOP = :
|
NOP = :
|
||||||
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
|
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
|
||||||
QUIET_FLAG := $(if $(findstring s,$(MAKEFLAGS)),-q,)
|
QUIET_FLAG := $(if $(findstring s,$(MFLAGS)),-q,)
|
||||||
|
|
||||||
|
#-------------------------------------------------------
|
||||||
|
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
|
||||||
|
QUESTION_FLAG := $(if $(findstring q,$(MFLAGS)),-i,)
|
||||||
|
|
||||||
#-------------------------------------------------------
|
#-------------------------------------------------------
|
||||||
ifdef T_A
|
ifdef T_A
|
||||||
@@ -89,7 +93,7 @@ INSTALL_SHRLIB = $(INSTALL_LOCATION_LIB)/$(T_A)
|
|||||||
INSTALL_TCLLIB = $(INSTALL_LOCATION_LIB)/$(T_A)
|
INSTALL_TCLLIB = $(INSTALL_LOCATION_LIB)/$(T_A)
|
||||||
INSTALL_BIN = $(INSTALL_LOCATION_BIN)/$(T_A)
|
INSTALL_BIN = $(INSTALL_LOCATION_BIN)/$(T_A)
|
||||||
|
|
||||||
#Directories for libraries
|
# Directories for libraries
|
||||||
SHRLIB_SEARCH_DIRS = $(INSTALL_LIB)
|
SHRLIB_SEARCH_DIRS = $(INSTALL_LIB)
|
||||||
|
|
||||||
#-------------------------------------------------------
|
#-------------------------------------------------------
|
||||||
|
|||||||
@@ -34,35 +34,30 @@
|
|||||||
# The future dates below assume the rules don't get changed;
|
# The future dates below assume the rules don't get changed;
|
||||||
# see http://www.timeanddate.com/time/dst/2018.html to check.
|
# see http://www.timeanddate.com/time/dst/2018.html to check.
|
||||||
#
|
#
|
||||||
# DST for 2017 US: Mar 12 - Nov 05
|
|
||||||
# EU: Mar 26 - Oct 29
|
|
||||||
EPICS_TIMEZONE = CUS::360:031202:110502
|
|
||||||
#EPICS_TIMEZONE = MET::-60:032602:102902
|
|
||||||
#
|
|
||||||
# DST for 2018 US: Mar 11 - Nov 04
|
# DST for 2018 US: Mar 11 - Nov 04
|
||||||
# EU: Mar 25 - Oct 28
|
# EU: Mar 25 - Oct 28
|
||||||
#EPICS_TIMEZONE = CUS::360:031102:110402
|
EPICS_TIMEZONE = CUS::360:031102:110402
|
||||||
#EPICS_TIMEZONE = MET::-60:032502:102802
|
#EPICS_TIMEZONE = MET::-60:032502:102803
|
||||||
#
|
#
|
||||||
# DST for 2019 US: Mar 10 - Nov 03
|
# DST for 2019 US: Mar 10 - Nov 03
|
||||||
# EU: Mar 31 - Oct 27
|
# EU: Mar 31 - Oct 27
|
||||||
#EPICS_TIMEZONE = CUS::360:031002:110302
|
#EPICS_TIMEZONE = CUS::360:031002:110302
|
||||||
#EPICS_TIMEZONE = MET::-60:033102:102702
|
#EPICS_TIMEZONE = MET::-60:033102:102703
|
||||||
#
|
#
|
||||||
# DST for 2020 US: Mar 08 - Nov 01
|
# DST for 2020 US: Mar 08 - Nov 01
|
||||||
# EU: Mar 29 - Oct 25
|
# EU: Mar 29 - Oct 25
|
||||||
#EPICS_TIMEZONE = CUS::360:030802:110102
|
#EPICS_TIMEZONE = CUS::360:030802:110102
|
||||||
#EPICS_TIMEZONE = MET::-60:032902:102502
|
#EPICS_TIMEZONE = MET::-60:032902:102503
|
||||||
#
|
#
|
||||||
# DST for 2021 US: Mar 14 - Nov 07
|
# DST for 2021 US: Mar 14 - Nov 07
|
||||||
# EU: Mar 28 - Oct 31
|
# EU: Mar 28 - Oct 31
|
||||||
#EPICS_TIMEZONE = CUS::360:031402:110702
|
#EPICS_TIMEZONE = CUS::360:031402:110702
|
||||||
#EPICS_TIMEZONE = MET::-60:032802:103102
|
#EPICS_TIMEZONE = MET::-60:032802:103103
|
||||||
#
|
#
|
||||||
# DST for 2022 US: Mar 13 - Nov 06
|
# DST for 2022 US: Mar 13 - Nov 06
|
||||||
# EU: Mar 27 - Oct 30
|
# EU: Mar 27 - Oct 30
|
||||||
#EPICS_TIMEZONE = CUS::360:031302:110602
|
#EPICS_TIMEZONE = CUS::360:031302:110602
|
||||||
#EPICS_TIMEZONE = MET::-60:032702:103002
|
#EPICS_TIMEZONE = MET::-60:032702:103003
|
||||||
|
|
||||||
# EPICS_TS_NTP_INET
|
# EPICS_TS_NTP_INET
|
||||||
# NTP time server ip address for VxWorks and RTEMS.
|
# NTP time server ip address for VxWorks and RTEMS.
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
|
||||||
# National Laboratory.
|
# National Laboratory.
|
||||||
# Copyright (c) 2002 The Regents of the University of California, as
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
# Operator of Los Alamos National Laboratory.
|
# Operator of Los Alamos National Laboratory.
|
||||||
# EPICS BASE Versions 3.13.7
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||||
# and higher are distributed subject to a Software License Agreement found
|
# in the file LICENSE that is included with this distribution.
|
||||||
# in file LICENSE that is included with this distribution.
|
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
|
|
||||||
ifndef T_A
|
ifndef T_A
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
# Copyright (c) 2002 The Regents of the University of California, as
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
# Operator of Los Alamos National Laboratory.
|
# Operator of Los Alamos National Laboratory.
|
||||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||||
# in file LICENSE that is included with this distribution.
|
# in the file LICENSE that is included with this distribution.
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
#RULES.Db
|
|
||||||
|
# RULES.Db
|
||||||
|
|
||||||
# Set db substitutions and template file suffixes
|
# Set db substitutions and template file suffixes
|
||||||
SUBST_SUFFIX ?= .substitutions
|
SUBST_SUFFIX ?= .substitutions
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
# Copyright (c) 2002 The Regents of the University of California, as
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
# Operator of Los Alamos National Laboratory.
|
# Operator of Los Alamos National Laboratory.
|
||||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||||
# in file LICENSE that is included with this distribution.
|
# in the file LICENSE that is included with this distribution.
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
#RULES.ioc
|
|
||||||
|
# RULES.ioc
|
||||||
|
|
||||||
include $(CONFIG)/RULES_DIRS
|
include $(CONFIG)/RULES_DIRS
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,4 @@ realclean:
|
|||||||
.PHONY : $(BUILD_ARCHS) rebuild archsCommonClean
|
.PHONY : $(BUILD_ARCHS) rebuild archsCommonClean
|
||||||
.PHONY : $(ACTIONS) clean realclean archclean host all
|
.PHONY : $(ACTIONS) clean realclean archclean host all
|
||||||
|
|
||||||
# User specific rules
|
include $(CONFIG)/RULES_COMMON
|
||||||
#
|
|
||||||
-include $(HOME)/configure/RULES_USER
|
|
||||||
|
|||||||
@@ -6,11 +6,12 @@
|
|||||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
# 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_BUILD
|
||||||
|
|
||||||
|
# Rules for making things specified in a Makefile
|
||||||
#
|
#
|
||||||
# Rules for making things specified in Makefile
|
# CWD is O.$(T_A), but most sources are elsewhere
|
||||||
#
|
|
||||||
# we are in O.$(T_A), but most sources are elsewhere
|
|
||||||
#
|
|
||||||
|
|
||||||
ifndef BASE_RULES_BUILD
|
ifndef BASE_RULES_BUILD
|
||||||
BASE_RULES_BUILD=1
|
BASE_RULES_BUILD=1
|
||||||
@@ -42,6 +43,7 @@ LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_HOST)
|
|||||||
OBJS += $(OBJS_HOST)
|
OBJS += $(OBJS_HOST)
|
||||||
PROD += $(PROD_HOST)
|
PROD += $(PROD_HOST)
|
||||||
SCRIPTS += $(SCRIPTS_HOST)
|
SCRIPTS += $(SCRIPTS_HOST)
|
||||||
|
TARGETS += $(TARGETS_HOST)
|
||||||
TESTLIBRARY += $(TESTLIBRARY_HOST)
|
TESTLIBRARY += $(TESTLIBRARY_HOST)
|
||||||
TESTSCRIPTS += $(TESTSCRIPTS_HOST)
|
TESTSCRIPTS += $(TESTSCRIPTS_HOST)
|
||||||
TESTPROD += $(TESTPROD_HOST)
|
TESTPROD += $(TESTPROD_HOST)
|
||||||
@@ -53,6 +55,7 @@ LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_IOC)
|
|||||||
OBJS += $(OBJS_IOC)
|
OBJS += $(OBJS_IOC)
|
||||||
PROD += $(PROD_IOC)
|
PROD += $(PROD_IOC)
|
||||||
SCRIPTS += $(SCRIPTS_IOC)
|
SCRIPTS += $(SCRIPTS_IOC)
|
||||||
|
TARGETS += $(TARGETS_IOC)
|
||||||
TESTLIBRARY += $(TESTLIBRARY_IOC)
|
TESTLIBRARY += $(TESTLIBRARY_IOC)
|
||||||
TESTSCRIPTS += $(TESTSCRIPTS_IOC)
|
TESTSCRIPTS += $(TESTSCRIPTS_IOC)
|
||||||
TESTPROD += $(TESTPROD_IOC)
|
TESTPROD += $(TESTPROD_IOC)
|
||||||
@@ -79,9 +82,9 @@ else
|
|||||||
host:
|
host:
|
||||||
endif
|
endif
|
||||||
|
|
||||||
-include $(CONFIG)/RULES_FILE_TYPE
|
include $(CONFIG)/RULES_FILE_TYPE
|
||||||
|
|
||||||
-include $(CONFIG)/RULES.Db
|
include $(CONFIG)/RULES.Db
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Include defines and rules for prod, library and test* targets
|
# Include defines and rules for prod, library and test* targets
|
||||||
@@ -102,6 +105,7 @@ endif
|
|||||||
# Products and Object libraries
|
# Products and Object libraries
|
||||||
#
|
#
|
||||||
PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
|
PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
|
||||||
|
TESTPRODTARGETS += $(TESTPRODNAME) $(TESTMUNCHNAME)
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Test specifications and test result files
|
# Test specifications and test result files
|
||||||
@@ -140,7 +144,7 @@ rebuild: clean install
|
|||||||
|
|
||||||
build: inc
|
build: inc
|
||||||
|
|
||||||
build: $(OBJSNAME) $(LIBTARGETS) $(PRODTARGETS) $(TESTPRODNAME) \
|
build: $(OBJSNAME) $(LIBTARGETS) $(PRODTARGETS) $(TESTPRODTARGETS) \
|
||||||
$(TARGETS) $(TESTSCRIPTS) $(INSTALL_LIB_INSTALLS)
|
$(TARGETS) $(TESTSCRIPTS) $(INSTALL_LIB_INSTALLS)
|
||||||
|
|
||||||
inc : $(COMMON_INC) $(INSTALL_INC) $(INSTALL_CONFIGS)
|
inc : $(COMMON_INC) $(INSTALL_INC) $(INSTALL_CONFIGS)
|
||||||
@@ -158,20 +162,21 @@ clean: build_clean
|
|||||||
|
|
||||||
build_clean:
|
build_clean:
|
||||||
$(ECHO) "Cleaning"
|
$(ECHO) "Cleaning"
|
||||||
@$(RM) *.i *$(OBJ) *.a $(TESTPRODNAME) \
|
@$(RM) *.i *$(OBJ) *.a \
|
||||||
$(LIBNAME) $(TESTLIBNAME) $(SHRLIBNAME) $(TESTSHRLIBNAME) \
|
$(LIBNAME) $(TESTLIBNAME) $(SHRLIBNAME) $(TESTSHRLIBNAME) \
|
||||||
$(DLLSTUB_LIBNAME) $(TESTDLLSTUB_LIBNAME) \
|
$(DLLSTUB_LIBNAME) $(TESTDLLSTUB_LIBNAME) \
|
||||||
$(LOADABLE_SHRLIBNAME) \
|
$(LOADABLE_SHRLIBNAME) \
|
||||||
$(INC) $(TARGETS) $(TDS) $(CLEANS) \
|
$(INC) $(TARGETS) $(TDS) $(CLEANS) \
|
||||||
*.out MakefileInclude *.manifest *.exp \
|
*.out MakefileInclude *.manifest *.exp \
|
||||||
$(COMMON_INC) $(HDEPENDS_FILES) $(PRODTARGETS) \
|
$(COMMON_INC) $(HDEPENDS_FILES) $(PRODTARGETS) $(TESTPRODTARGETS) \
|
||||||
$(TESTSCRIPTS) $(TAPFILES) $(JUNITFILES)
|
$(TESTSCRIPTS) $(TAPFILES) $(JUNITFILES)
|
||||||
ifdef RES
|
ifdef RES
|
||||||
@$(RM) *$(RES)
|
@$(RM) *$(RES)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(DIRECTORY_TARGETS) :
|
# Sort mkdir targets to remove duplicates & make parents first
|
||||||
$(MKDIR) $@
|
$(DIRECTORY_TARGETS):
|
||||||
|
$(MKDIR) $(sort $@)
|
||||||
|
|
||||||
# Install LIB_INSTALLS libraries before linking executables
|
# Install LIB_INSTALLS libraries before linking executables
|
||||||
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS)
|
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS)
|
||||||
@@ -183,7 +188,7 @@ endif
|
|||||||
|
|
||||||
# RELEASE file consistency checking
|
# RELEASE file consistency checking
|
||||||
checkRelease:
|
checkRelease:
|
||||||
$(CONVERTRELEASE) checkRelease
|
+$(CONVERTRELEASE) checkRelease
|
||||||
warnRelease:
|
warnRelease:
|
||||||
-$(CONVERTRELEASE) checkRelease
|
-$(CONVERTRELEASE) checkRelease
|
||||||
noCheckRelease:
|
noCheckRelease:
|
||||||
@@ -254,15 +259,13 @@ YACCOPT ?= $($*_YACCOPT)
|
|||||||
$(MV) $*.tab.c $*.c
|
$(MV) $*.tab.c $*.c
|
||||||
$(if $(findstring -d, $(YACCOPT)),$(MV) $*.tab.h $*.h,)
|
$(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
|
# prefix for .h will be different then .c
|
||||||
%.h : %.c %.y
|
%.h : %.c %.y
|
||||||
|
|
||||||
%.c: %.l
|
%.c: %.l
|
||||||
@$(RM) $*.yy.c
|
|
||||||
$(LEX) $(LEXOPT) -t $< > $*.yy.c
|
|
||||||
@$(RM) $@
|
@$(RM) $@
|
||||||
$(MV) $*.yy.c $@
|
$(LEX) $(LEXOPT) -o$@ $<
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Libraries, shared/DLL and stubs
|
# Libraries, shared/DLL and stubs
|
||||||
@@ -321,6 +324,10 @@ $(MUNCHNAME): %$(MUNCH_SUFFIX): $(MUNCH_DEPENDS) %$(EXE)
|
|||||||
@$(RM) $@
|
@$(RM) $@
|
||||||
$(MUNCH_CMD)
|
$(MUNCH_CMD)
|
||||||
|
|
||||||
|
$(TESTMUNCHNAME): %$(MUNCH_SUFFIX): $(MUNCH_DEPENDS) %$(EXE)
|
||||||
|
@$(RM) $@
|
||||||
|
$(MUNCH_CMD)
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# GeSys modules for RTEMS
|
# GeSys modules for RTEMS
|
||||||
$(MODNAME): %$(MODEXT): %$(EXE)
|
$(MODNAME): %$(MODEXT): %$(EXE)
|
||||||
@@ -349,14 +356,17 @@ ifneq ($(TAPFILES),)
|
|||||||
ifdef RUNTESTS_ENABLED
|
ifdef RUNTESTS_ENABLED
|
||||||
prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES)
|
prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
|
||||||
|
CURRENT_JUNITFILES := $(wildcard $(JUNITFILES))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
clean-tests:
|
clean-tests:
|
||||||
ifneq ($(TAPFILES),)
|
ifneq ($(CURRENT_TAPFILES),)
|
||||||
$(RM) $(TAPFILES)
|
$(RM) $(CURRENT_TAPFILES)
|
||||||
endif
|
endif
|
||||||
ifneq ($(JUNITFILES),)
|
ifneq ($(CURRENT_JUNITFILES),)
|
||||||
$(RM) $(JUNITFILES)
|
$(RM) $(CURRENT_JUNITFILES)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
tapfiles: $(TESTSCRIPTS) $(TAPFILES)
|
tapfiles: $(TESTSCRIPTS) $(TAPFILES)
|
||||||
@@ -380,7 +390,7 @@ endif
|
|||||||
# Generate a perl program to exec the real test binary.
|
# Generate a perl program to exec the real test binary.
|
||||||
%.t: %$(EXE) $(TOOLS)/makeTestfile.pl
|
%.t: %$(EXE) $(TOOLS)/makeTestfile.pl
|
||||||
@$(RM) $@
|
@$(RM) $@
|
||||||
$(PERL) $(TOOLS)/makeTestfile.pl $@ $<
|
$(PERL) $(TOOLS)/makeTestfile.pl $(T_A) $(EPICS_HOST_ARCH) $@ $<
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Generate header with version number from VCS
|
# Generate header with version number from VCS
|
||||||
@@ -517,7 +527,7 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
|
|||||||
$(ECHO) "Installing $@"
|
$(ECHO) "Installing $@"
|
||||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||||
|
|
||||||
-include $(CONFIG)/RULES_EXPAND
|
include $(CONFIG)/RULES_EXPAND
|
||||||
|
|
||||||
.PRECIOUS: %.i %.o %.c %.nm %.cpp %.cc
|
.PRECIOUS: %.i %.o %.c %.nm %.cpp %.cc
|
||||||
.PRECIOUS: $(COMMON_INC)
|
.PRECIOUS: $(COMMON_INC)
|
||||||
@@ -526,5 +536,9 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
|
|||||||
.PHONY: runtests tapfiles clean-tests test-results junitfiles
|
.PHONY: runtests tapfiles clean-tests test-results junitfiles
|
||||||
.PHONY: checkRelease warnRelease noCheckRelease FORCE
|
.PHONY: checkRelease warnRelease noCheckRelease FORCE
|
||||||
|
|
||||||
|
include $(CONFIG)/RULES_COMMON
|
||||||
|
|
||||||
|
else
|
||||||
|
$(warning RULES_BUILD included more than once. \
|
||||||
|
Use 'make show-makefiles' to work out why.)
|
||||||
endif # BASE_RULES_BUILD
|
endif # BASE_RULES_BUILD
|
||||||
# EOF RULES_BUILD
|
|
||||||
|
|||||||
35
configure/RULES_COMMON
Normal file
35
configure/RULES_COMMON
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#*************************************************************************
|
||||||
|
# Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne
|
||||||
|
# National Laboratory.
|
||||||
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||||
|
# in the file LICENSE that is included with this distribution.
|
||||||
|
#*************************************************************************
|
||||||
|
|
||||||
|
# These rules show the set of Makefiles, config files and
|
||||||
|
# rules files loaded by GNUmake.
|
||||||
|
|
||||||
|
# Protect against filenames containing colons (Windows)
|
||||||
|
SAFE_MAKEFILES = $(subst :,__colon__,$(MAKEFILE_LIST))
|
||||||
|
SHOW_MAKEFILES = $(SAFE_MAKEFILES:%=show-makefile.%)
|
||||||
|
show-makefiles: $(SHOW_MAKEFILES)
|
||||||
|
|
||||||
|
# The sort prevents warnings about duplicate targets:
|
||||||
|
$(sort $(SHOW_MAKEFILES)): show-makefile.%:
|
||||||
|
@echo " $(subst __colon__,:,$(@:show-makefile.%=%))"
|
||||||
|
|
||||||
|
.PHONY: show-makefiles show-makefile.%
|
||||||
|
|
||||||
|
# These rules support printing a Makefile variable values.
|
||||||
|
# Many variables are only set inside an O.<arch> build directory.
|
||||||
|
# make PRINT.T_A
|
||||||
|
|
||||||
|
PRINT_Var = $(@:PRINT.%=%)
|
||||||
|
PRINT.%:
|
||||||
|
@echo $(PRINT_Var) = '$($(PRINT_Var))'
|
||||||
|
|
||||||
|
.PHONY: PRINT PRINT.%
|
||||||
|
|
||||||
|
|
||||||
|
# User specific rules
|
||||||
|
#
|
||||||
|
-include $(HOME)/configure/RULES_USER
|
||||||
@@ -92,7 +92,4 @@ $(ARCHS) $(ACTIONS) $(actionArchTargets) :%: \
|
|||||||
.PHONY : $(dirActionArchTargets)
|
.PHONY : $(dirActionArchTargets)
|
||||||
.PHONY : $(actionArchTargets)
|
.PHONY : $(actionArchTargets)
|
||||||
|
|
||||||
|
include $(CONFIG)/RULES_COMMON
|
||||||
# User specific rules
|
|
||||||
#
|
|
||||||
-include $(HOME)/configure/RULES_USER
|
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
# <top>/configure/RULES_EXPAND
|
#*************************************************************************
|
||||||
|
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
|
||||||
|
# National Laboratory.
|
||||||
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
|
# Operator of Los Alamos National Laboratory.
|
||||||
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||||
|
# in the file LICENSE that is included with this distribution.
|
||||||
|
#*************************************************************************
|
||||||
|
|
||||||
|
# RULES_EXPAND
|
||||||
|
|
||||||
vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
|
vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
# in the file LICENSE that is included with this distribution.
|
# in the file LICENSE that is included with this distribution.
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
|
|
||||||
# Include <top>/configure/RULES_BUILD from tops defined in RELEASE* files
|
# Include <top>/configure/RULES_BUILD from tops defined in RELEASE* files,
|
||||||
|
# excluding EPICS_BASE
|
||||||
#
|
#
|
||||||
RELEASE_RULES_BUILDS = $(foreach top, $(RELEASE_TOPS), \
|
RELEASE_RULES_BUILDS = $(foreach top, \
|
||||||
|
$(filter-out EPICS_BASE, $(RELEASE_TOPS)), \
|
||||||
$(wildcard $($(top))/configure/RULES_BUILD))
|
$(wildcard $($(top))/configure/RULES_BUILD))
|
||||||
ifneq ($(RELEASE_RULES_BUILDS),)
|
ifneq ($(RELEASE_RULES_BUILDS),)
|
||||||
include $(RELEASE_RULES_BUILDS)
|
include $(RELEASE_RULES_BUILDS)
|
||||||
@@ -23,7 +25,7 @@ ifneq ($(RELEASE_CFG_RULES),)
|
|||||||
include $(RELEASE_CFG_RULES)
|
include $(RELEASE_CFG_RULES)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# If this is not BASE then include <TOP>/configure/RULES_BUILD
|
# If this is not BASE then include <top>/configure/RULES_BUILD
|
||||||
#
|
#
|
||||||
ifeq ($(wildcard $(TOP)/configure/CONFIG_BASE_VERSION),)
|
ifeq ($(wildcard $(TOP)/configure/CONFIG_BASE_VERSION),)
|
||||||
TOP_RULES_BUILDS = $(wildcard $(TOP)/configure/RULES_BUILD)
|
TOP_RULES_BUILDS = $(wildcard $(TOP)/configure/RULES_BUILD)
|
||||||
@@ -67,7 +69,3 @@ file_type_clean:
|
|||||||
@$(RM) $(foreach type, $(FILE_TYPE), $($(type)))
|
@$(RM) $(foreach type, $(FILE_TYPE), $($(type)))
|
||||||
|
|
||||||
.PHONY : file_type_clean
|
.PHONY : file_type_clean
|
||||||
|
|
||||||
# User specific rules
|
|
||||||
#
|
|
||||||
-include $(HOME)/configure/RULES_USER
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
|
||||||
# National Laboratory.
|
# National Laboratory.
|
||||||
# Copyright (c) 2002 The Regents of the University of California, as
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
# Operator of Los Alamos National Laboratory.
|
# Operator of Los Alamos National Laboratory.
|
||||||
# EPICS BASE Versions 3.13.7
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||||
# and higher are distributed subject to a Software License Agreement found
|
# in the file LICENSE that is included with this distribution.
|
||||||
# in file LICENSE that is included with this distribution.
|
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
|
|
||||||
# Octave definitions and rules
|
# Octave definitions and rules
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
|
||||||
# National Laboratory.
|
# National Laboratory.
|
||||||
# Copyright (c) 2002 The Regents of the University of California, as
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
# Operator of Los Alamos National Laboratory.
|
# Operator of Los Alamos National Laboratory.
|
||||||
# EPICS BASE Versions 3.13.7
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||||
# and higher are distributed subject to a Software License Agreement found
|
# in the file LICENSE that is included with this distribution.
|
||||||
# in file LICENSE that is included with this distribution.
|
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
#
|
|
||||||
# RULES_TARGET
|
# RULES_TARGET
|
||||||
#
|
|
||||||
# This file is to be maintained by the community.
|
|
||||||
#
|
|
||||||
#-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
define TARGET_template
|
define TARGET_template
|
||||||
$(1)_$(2) += $$(if $$(strip $$($(1)_$(2)_$$(OS_CLASS))), \
|
$(1)_$(2) += $$(if $$(strip $$($(1)_$(2)_$$(OS_CLASS))), \
|
||||||
@@ -38,6 +33,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
|
define TARGET2_template
|
||||||
$(1)_LDLIBS += $$($(1)_LIBS)
|
$(1)_LDLIBS += $$($(1)_LIBS)
|
||||||
$(1)_LDLIBS += $$(if $$(strip $$($(1)_LIBS_$(OS_CLASS))), \
|
$(1)_LDLIBS += $$(if $$(strip $$($(1)_LIBS_$(OS_CLASS))), \
|
||||||
@@ -123,16 +129,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
|
define LOADABLE_LIBRARY_template
|
||||||
LOADABLE_BUILD_LIBRARY += $$(if $$(strip $$($(1)_OBJSNAME) $$(LIBRARY_OBJS)),$(1),)
|
LOADABLE_BUILD_LIBRARY += $$(if $$(strip $$($(1)_OBJSNAME) $$(LIBRARY_OBJS)),$(1),)
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,13 @@ ifneq ($(CONFIG),$(TOP)/configure)
|
|||||||
-include $(TOP)/configure/CONFIG_SITE.Common.RTEMS
|
-include $(TOP)/configure/CONFIG_SITE.Common.RTEMS
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
#--------------------------------------------------
|
||||||
|
# Set RTEMS_BSP from T_A if not already done
|
||||||
|
RTEMS_BSP ?= $(subst RTEMS-,,$(T_A))
|
||||||
|
|
||||||
#-------------------------------------------------------
|
#-------------------------------------------------------
|
||||||
# Pick up the RTEMS tool/path definitions from the RTEMS BSP directory.
|
# Pick up the RTEMS tool/path definitions from the RTEMS BSP directory.
|
||||||
include $(RTEMS_BASE)/$(RTEMS_TARGET_CPU)-rtems$(RTEMS_VERSION)/$(subst RTEMS-,,$(T_A))/Makefile.inc
|
include $(RTEMS_BASE)/$(RTEMS_TARGET_CPU)-rtems$(RTEMS_VERSION)/$(RTEMS_BSP)/Makefile.inc
|
||||||
include $(RTEMS_CUSTOM)
|
include $(RTEMS_CUSTOM)
|
||||||
include $(CONFIG.CC)
|
include $(CONFIG.CC)
|
||||||
|
|
||||||
@@ -72,7 +76,7 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
|
|||||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
||||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
|
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
|
||||||
|
|
||||||
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
|
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
|
||||||
|
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
# Although RTEMS uses gcc, it wants to use gcc its own way
|
# Although RTEMS uses gcc, it wants to use gcc its own way
|
||||||
@@ -136,6 +140,13 @@ MOD_LDFLAGS = $(OPT_LDFLAGS) $(TARGET_LDFLAGS) $(USR_LDFLAGS) $(POSIX_LDFLAGS) \
|
|||||||
LINK.mod = $(CCC) -o $@ $(PRODDIR_LDFLAGS) $(MOD_LDFLAGS)
|
LINK.mod = $(CCC) -o $@ $(PRODDIR_LDFLAGS) $(MOD_LDFLAGS)
|
||||||
LINK.mod += $(PROD_LDFLAGS) $(PROD_LD_OBJS) $(PROD_LD_RESS) $(MOD_LDLIBS)
|
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
|
# RTEMS has neither shared libraries nor dynamic loading
|
||||||
STATIC_BUILD=YES
|
STATIC_BUILD=YES
|
||||||
|
|||||||
@@ -9,5 +9,6 @@
|
|||||||
#
|
#
|
||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
RTEMS_TARGET_CPU=arm
|
RTEMS_BSP = at91rm9200ek
|
||||||
|
RTEMS_TARGET_CPU = arm
|
||||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
EXE = .elf
|
EXE = .elf
|
||||||
|
RTEMS_BSP = beatnik
|
||||||
RTEMS_TARGET_CPU = powerpc
|
RTEMS_TARGET_CPU = powerpc
|
||||||
GNU_TARGET = powerpc-rtems
|
GNU_TARGET = powerpc-rtems
|
||||||
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
||||||
@@ -15,7 +16,6 @@ ARCH_DEP_CFLAGS += -DRTEMS_NETWORK_CONFIG_CLUSTER_SPACE=5120
|
|||||||
OP_SYS_LDLIBS += -lbspExt
|
OP_SYS_LDLIBS += -lbspExt
|
||||||
|
|
||||||
MUNCH_SUFFIX = .boot
|
MUNCH_SUFFIX = .boot
|
||||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
|
||||||
define MUNCH_CMD
|
define MUNCH_CMD
|
||||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
||||||
endef
|
endef
|
||||||
|
|||||||
@@ -5,5 +5,6 @@
|
|||||||
#
|
#
|
||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
RTEMS_TARGET_CPU=m68k
|
RTEMS_BSP = gen68360
|
||||||
|
RTEMS_TARGET_CPU = m68k
|
||||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||||
|
|||||||
@@ -5,5 +5,6 @@
|
|||||||
#
|
#
|
||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
RTEMS_TARGET_CPU=ppc
|
RTEMS_BSP = mcp750
|
||||||
|
RTEMS_TARGET_CPU = ppc
|
||||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||||
|
|||||||
@@ -5,5 +5,6 @@
|
|||||||
#
|
#
|
||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
RTEMS_TARGET_CPU=m68k
|
RTEMS_BSP = mvme167
|
||||||
|
RTEMS_TARGET_CPU = m68k
|
||||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
EXE = .elf
|
EXE = .elf
|
||||||
|
RTEMS_BSP = mvme2100
|
||||||
RTEMS_TARGET_CPU = powerpc
|
RTEMS_TARGET_CPU = powerpc
|
||||||
GNU_TARGET = powerpc-rtems
|
GNU_TARGET = powerpc-rtems
|
||||||
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
||||||
@@ -13,7 +14,6 @@ ARCH_DEP_CFLAGS += -DHAVE_PPCBUG
|
|||||||
OP_SYS_LDLIBS += -lbspExt
|
OP_SYS_LDLIBS += -lbspExt
|
||||||
|
|
||||||
MUNCH_SUFFIX = .boot
|
MUNCH_SUFFIX = .boot
|
||||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
|
||||||
define MUNCH_CMD
|
define MUNCH_CMD
|
||||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
||||||
gzip -f9 rtems
|
gzip -f9 rtems
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#
|
#
|
||||||
# Author: Matt Rippa
|
# Author: Matt Rippa
|
||||||
#
|
#
|
||||||
|
RTEMS_BSP = mvme2700
|
||||||
RTEMS_TARGET_CPU = powerpc
|
RTEMS_TARGET_CPU = powerpc
|
||||||
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
||||||
ARCH_DEP_CFLAGS += -DHAVE_PPCBUG
|
ARCH_DEP_CFLAGS += -DHAVE_PPCBUG
|
||||||
ARCH_DEP_CFLAGS += -DNVRAM_INDIRECT
|
ARCH_DEP_CFLAGS += -DNVRAM_INDIRECT
|
||||||
|
|
||||||
MUNCH_SUFFIX = .boot
|
MUNCH_SUFFIX = .boot
|
||||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
|
||||||
define MUNCH_CMD
|
define MUNCH_CMD
|
||||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
|
||||||
gzip -f9 rtems
|
gzip -f9 rtems
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
EXE = .elf
|
EXE = .elf
|
||||||
|
RTEMS_BSP = mvme3100
|
||||||
RTEMS_TARGET_CPU = powerpc
|
RTEMS_TARGET_CPU = powerpc
|
||||||
GNU_TARGET = powerpc-rtems
|
GNU_TARGET = powerpc-rtems
|
||||||
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
||||||
@@ -15,7 +16,6 @@ ARCH_DEP_CFLAGS += -DRTEMS_NETWORK_CONFIG_CLUSTER_SPACE=5120
|
|||||||
OP_SYS_LDLIBS += -lbspExt
|
OP_SYS_LDLIBS += -lbspExt
|
||||||
|
|
||||||
MUNCH_SUFFIX = .boot
|
MUNCH_SUFFIX = .boot
|
||||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
|
||||||
define MUNCH_CMD
|
define MUNCH_CMD
|
||||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
||||||
endef
|
endef
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
EXE = .elf
|
EXE = .elf
|
||||||
|
RTEMS_BSP = mvme5500
|
||||||
RTEMS_TARGET_CPU = powerpc
|
RTEMS_TARGET_CPU = powerpc
|
||||||
GNU_TARGET = powerpc-rtems
|
GNU_TARGET = powerpc-rtems
|
||||||
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
||||||
@@ -16,7 +17,6 @@ ARCH_DEP_CFLAGS += -DBSP_NVRAM_BASE_ADDR=0xf1110000
|
|||||||
OP_SYS_LDLIBS += -lbspExt
|
OP_SYS_LDLIBS += -lbspExt
|
||||||
|
|
||||||
MUNCH_SUFFIX = .boot
|
MUNCH_SUFFIX = .boot
|
||||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
|
||||||
define MUNCH_CMD
|
define MUNCH_CMD
|
||||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $< $@
|
||||||
endef
|
endef
|
||||||
|
|||||||
@@ -5,15 +5,15 @@
|
|||||||
#
|
#
|
||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
RTEMS_TARGET_CPU=i386
|
RTEMS_BSP = pc386
|
||||||
|
RTEMS_TARGET_CPU = i386
|
||||||
|
|
||||||
MUNCH_SUFFIX = .boot
|
MUNCH_SUFFIX = .boot
|
||||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
|
||||||
define MUNCH_CMD
|
define MUNCH_CMD
|
||||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< temp.bin
|
$(RM) $*.bin
|
||||||
|
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< $*.bin
|
||||||
$(BIN2BOOT) $@ 0x00097E00 \
|
$(BIN2BOOT) $@ 0x00097E00 \
|
||||||
$(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 temp.bin 0x00100000 0
|
$(PROJECT_RELEASE)/lib/start16.bin 0x00097C00 0 $*.bin 0x00100000 0
|
||||||
rm -f temp.bin
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||||
|
|||||||
11
configure/os/CONFIG.Common.RTEMS-pc386-qemu
Normal file
11
configure/os/CONFIG.Common.RTEMS-pc386-qemu
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# CONFIG.Common.RTEMS-pc386-qemu
|
||||||
|
#
|
||||||
|
# Definitions for the RTEMS-pc386-qemu target
|
||||||
|
# Site-specific overrides go in CONFIG_SITE.Common.RTEMS-pc386-qemu
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------
|
||||||
|
|
||||||
|
# Include definitions from RTEMS-pc386
|
||||||
|
include $(CONFIG)/os/CONFIG.Common.RTEMS-pc386
|
||||||
|
|
||||||
|
RTEMS_QEMU_FIXUPS = YES
|
||||||
@@ -5,5 +5,6 @@
|
|||||||
#
|
#
|
||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
RTEMS_TARGET_CPU=ppc
|
RTEMS_BSP = psim
|
||||||
|
RTEMS_TARGET_CPU = ppc
|
||||||
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
include $(CONFIG)/os/CONFIG.Common.RTEMS
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
#
|
#
|
||||||
# All RTEMS targets use the same Makefile fragment
|
# All RTEMS targets use the same Makefile fragment
|
||||||
#
|
#
|
||||||
|
RTEMS_BSP = uC5282
|
||||||
RTEMS_TARGET_CPU = m68k
|
RTEMS_TARGET_CPU = m68k
|
||||||
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
ARCH_DEP_CFLAGS += -DMY_DO_BOOTP=NULL
|
||||||
|
|
||||||
MUNCH_SUFFIX = .boot
|
MUNCH_SUFFIX = .boot
|
||||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
|
||||||
define MUNCH_CMD
|
define MUNCH_CMD
|
||||||
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< $@
|
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< $@
|
||||||
endef
|
endef
|
||||||
|
|||||||
@@ -146,8 +146,10 @@ SHRLIB_CFLAGS =
|
|||||||
SHRLIB_LDFLAGS =
|
SHRLIB_LDFLAGS =
|
||||||
|
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
# Earlier versions of gcc don't understand -MF
|
# Don't use gcc 2.x for dependency generation
|
||||||
HDEPENDS_COMPFLAGS = -MM > $@
|
|
||||||
|
HDEPENDS_METHOD_2 = MKMF
|
||||||
|
HDEPENDS_METHOD = $(firstword $(HDEPENDS_METHOD_$(VX_GNU_MAJOR_VERSION)) COMP)
|
||||||
|
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
# osithead use default stack, YES or NO override
|
# osithead use default stack, YES or NO override
|
||||||
@@ -170,6 +172,10 @@ COMPILE.ctdt = $(CC) -c $(CPPFLAGS) $(CFLAGS_ctdt) $(INCLUDES) $(SOURCE_FLAG)
|
|||||||
VXCPPFLAGS = $(filter-out $(OP_SYS_INCLUDE_CPPFLAGS),$(CPPFLAGS))
|
VXCPPFLAGS = $(filter-out $(OP_SYS_INCLUDE_CPPFLAGS),$(CPPFLAGS))
|
||||||
PREPROCESS.cpp = $(CPP) $(VXCPPFLAGS) $(INCLUDES) $< > $@
|
PREPROCESS.cpp = $(CPP) $(VXCPPFLAGS) $(INCLUDES) $< > $@
|
||||||
|
|
||||||
|
#--------------------------------------------------
|
||||||
|
# Use LEDLIB for command-line editing
|
||||||
|
COMMANDLINE_LIBRARY = LEDLIB
|
||||||
|
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
# Allow site overrides
|
# Allow site overrides
|
||||||
-include $(CONFIG)/os/CONFIG_SITE.Common.vxWorksCommon
|
-include $(CONFIG)/os/CONFIG_SITE.Common.vxWorksCommon
|
||||||
|
|||||||
@@ -65,14 +65,14 @@ GNU = NO
|
|||||||
#
|
#
|
||||||
# Darwin shared libraries
|
# Darwin shared libraries
|
||||||
#
|
#
|
||||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined suppress \
|
SHRLIB_LDFLAGS = -dynamiclib -undefined dynamic_lookup \
|
||||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||||
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
|
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
|
||||||
$(addprefix -current_version , $(SHRLIB_VERSION))
|
$(addprefix -current_version , $(SHRLIB_VERSION))
|
||||||
SHRLIB_SUFFIX_BASE = .dylib
|
SHRLIB_SUFFIX_BASE = .dylib
|
||||||
SHRLIB_SUFFIX = $(addprefix ., $(SHRLIB_VERSION))$(SHRLIB_SUFFIX_BASE)
|
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.
|
# Position-independent code is the default on Darwin.
|
||||||
|
|||||||
@@ -79,16 +79,20 @@ CPP = cl -nologo -C -E
|
|||||||
|
|
||||||
# Configure OS vendor C++ compiler
|
# 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
|
# -EHsc - generate code for exceptions
|
||||||
# -GR - generate code for run time type identification
|
# -GR - generate code for run time type identification
|
||||||
#
|
#
|
||||||
CCC = cl -EHsc -GR
|
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
|
CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
|
||||||
|
|
||||||
|
|
||||||
@@ -136,6 +140,16 @@ STATIC_LDLIBS_NO=
|
|||||||
STATIC_LDFLAGS=
|
STATIC_LDFLAGS=
|
||||||
RANLIB=
|
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
|
# add -profile here to run the ms profiler
|
||||||
# -LTCG whole program optimization
|
# -LTCG whole program optimization
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#
|
|
||||||
# Site-specific overrides for RTEMS-pc386 target
|
|
||||||
#
|
|
||||||
9
configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu
Normal file
9
configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# CONFIG_SITE.Common.RTEMS-pc386-qemu
|
||||||
|
#
|
||||||
|
# Site-specific overrides for the RTEMS-pc386-qemu target
|
||||||
|
#
|
||||||
|
|
||||||
|
# If you're building this architecture you _probably_ want to
|
||||||
|
# run the tests for it under QEMU, but if not you can turn
|
||||||
|
# them off here by commenting out this line:
|
||||||
|
CROSS_COMPILER_RUNTEST_ARCHS += RTEMS-pc386-qemu
|
||||||
@@ -67,8 +67,9 @@
|
|||||||
Software requirements
|
Software requirements
|
||||||
|
|
||||||
GNU make
|
GNU make
|
||||||
You must use GNU make, gnumake, for any EPICS builds. Set your path so
|
You must use the GNU version of make for EPICS builds, and we now
|
||||||
that a gnumake version 3.81 or later is available.
|
recommend version 4.1 or later (version 3.82 may work on Linux, but
|
||||||
|
doesn't on Windows).
|
||||||
|
|
||||||
Perl
|
Perl
|
||||||
You must have Perl version 5.8.1 or later installed. The EPICS
|
You must have Perl version 5.8.1 or later installed. The EPICS
|
||||||
@@ -99,20 +100,17 @@
|
|||||||
|
|
||||||
RTEMS
|
RTEMS
|
||||||
For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or
|
For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or
|
||||||
later.
|
4.10. The newer 4.11 or 5.x releases are not supported yet.
|
||||||
|
|
||||||
GNU readline or Tecla library
|
Command-line editing libraries
|
||||||
GNU readline and Tecla libraries can be used by the IOC shell to provide
|
GNU readline or other OS-specific libraries can be used by the IOC shell
|
||||||
command line editing and command line history recall and edit. GNU
|
to provide command line editing and history recall. The default setting
|
||||||
readline (or Tecla library) must be installed on your target system when
|
is different for each OS. On Linux the default is to use READLINE since
|
||||||
COMMANDLINE_LIBRARY is set to READLINE (or TECLA) for that target. EPICS
|
most distributions include it. On MacOS the default is also READLINE
|
||||||
(EPICS shell) is the default specified in CONFIG_COMMON. A READLINE
|
since Apple provides a compatible library, although it isn't GNU. On
|
||||||
override is defined for linux-x86 in the EPICS distribution. Comment out
|
RTEMS we support GNU readline and Tecla, although the default is to use
|
||||||
COMMANDLINE_LIBRARY=READLINE in
|
neither since these have to be added to the RTEMS installation
|
||||||
configure/os/CONFIG_SITE.Common.linux-x86 if readline is not installed
|
separately. On vxWorks we support the built-in ledLib library.
|
||||||
on linux-x86. Command-line editing and history will then be those
|
|
||||||
supplied by the os. On vxWorks the ledLib command-line input library is
|
|
||||||
used instead.
|
|
||||||
|
|
||||||
Host system storage requirements
|
Host system storage requirements
|
||||||
|
|
||||||
@@ -166,12 +164,11 @@
|
|||||||
|
|
||||||
base/startup directory - contains scripts to set environment and path
|
base/startup directory - contains scripts to set environment and path
|
||||||
|
|
||||||
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable
|
EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
|
||||||
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable
|
unix.csh C shell script to set path and env variables
|
||||||
Site.profile bourne shell script to set path and env variables
|
unix.sh Bourne shell script to set path and env variables
|
||||||
Site.cshrc c shell script to set path and env variables
|
win32.bat Bat file example to configure win32-x86 target
|
||||||
cygwin.bat WIN32 bat file to set cygwin path and env variables
|
windows.bat Bat file example to configure windows-x64 target
|
||||||
win32.bat WIN32 bat file to set path and env variables
|
|
||||||
|
|
||||||
base/configure directory - contains build definitions and rules
|
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_BASE="${HOME}/src/EPICS/base"
|
||||||
EPICS_EXTENSIONS="${HOME}/src/EPICS/extensions"
|
EPICS_EXTENSIONS="${HOME}/src/EPICS/extensions"
|
||||||
<strong>.</strong> "${EPICS_BASE}"/startup/Site.profile
|
<strong>.</strong> "${EPICS_BASE}"/startup/unix.sh
|
||||||
</pre>
|
</pre>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -72,8 +72,8 @@
|
|||||||
<H3><A NAME="0_0_6"> Software requirements</A></H3>
|
<H3><A NAME="0_0_6"> Software requirements</A></H3>
|
||||||
|
|
||||||
<BLOCKQUOTE><B>GNU make</B><BR>
|
<BLOCKQUOTE><B>GNU make</B><BR>
|
||||||
You must use GNU make, gnumake, for any EPICS builds. Set your path
|
You must use the GNU version of make for EPICS builds, and we now recommend
|
||||||
so that a gnumake version 3.81 or later is available.
|
version 4.1 or later (version 3.82 may work on Linux, but doesn't on Windows).
|
||||||
|
|
||||||
<P><B>Perl</B><BR>
|
<P><B>Perl</B><BR>
|
||||||
You must have Perl version 5.8.1 or later installed. The EPICS configuration
|
You must have Perl version 5.8.1 or later installed. The EPICS configuration
|
||||||
@@ -98,25 +98,25 @@
|
|||||||
base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its
|
base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its
|
||||||
target-specific overrides.</P>
|
target-specific overrides.</P>
|
||||||
|
|
||||||
<P>Consult the <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
|
<P>Consult the <a href="https://epics.anl.gov/base/vxWorks6.php">vxWorks
|
||||||
6.x</a> EPICS web pages and the vxWorks documentation for information
|
6.x</a> EPICS web pages and the vxWorks documentation for information
|
||||||
about configuring your vxWorks operating system for use with EPICS.</P>
|
about configuring your vxWorks operating system for use with EPICS.</P>
|
||||||
|
|
||||||
<P><B>RTEMS</B><BR>
|
<P><B>RTEMS</B><BR>
|
||||||
For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or later.</P>
|
For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or 4.10. The
|
||||||
|
newer 4.11 or 5.x releases are not supported yet.</P>
|
||||||
|
|
||||||
|
<P><B>Command-line editing libraries</B><BR>
|
||||||
|
|
||||||
|
GNU readline or other OS-specific libraries can be used by the IOC shell to
|
||||||
|
provide command line editing and history recall. The default setting is
|
||||||
|
different for each OS. On Linux the default is to use READLINE since most
|
||||||
|
distributions include it. On MacOS the default is also READLINE since Apple
|
||||||
|
provides a compatible library, although it isn't GNU. On RTEMS we support GNU
|
||||||
|
readline and Tecla, although the default is to use neither since these have to
|
||||||
|
be added to the RTEMS installation separately. On vxWorks we support the
|
||||||
|
built-in ledLib library.</P>
|
||||||
|
|
||||||
<P><B>GNU readline or Tecla library</B><BR>
|
|
||||||
GNU readline and Tecla libraries can be used by the IOC shell to
|
|
||||||
provide command line editing and command line history recall and edit.
|
|
||||||
GNU readline (or Tecla library) must be installed on your target system
|
|
||||||
when COMMANDLINE_LIBRARY is set to READLINE (or TECLA) for that target.
|
|
||||||
EPICS (EPICS shell) is the default specified in CONFIG_COMMON. A
|
|
||||||
READLINE override is defined for linux-x86 in the EPICS distribution.
|
|
||||||
Comment out COMMANDLINE_LIBRARY=READLINE in
|
|
||||||
configure/os/CONFIG_SITE.Common.linux-x86 if readline is not installed
|
|
||||||
on linux-x86. Command-line editing and history will then be those
|
|
||||||
supplied by the os. On vxWorks the ledLib command-line input library is
|
|
||||||
used instead.</P>
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3><A NAME="0_0_7"> Host system storage requirements</A></H3>
|
<H3><A NAME="0_0_7"> Host system storage requirements</A></H3>
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
<H3><A NAME="0_0_8"> Documentation</A></H3>
|
<H3><A NAME="0_0_8"> Documentation</A></H3>
|
||||||
<BLOCKQUOTE>EPICS documentation is available through the
|
<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
|
<P>Release specific documentation can also be found in the base/documentation
|
||||||
directory of the distribution.</BLOCKQUOTE>
|
directory of the distribution.</BLOCKQUOTE>
|
||||||
|
|
||||||
@@ -176,12 +176,11 @@
|
|||||||
|
|
||||||
<H4>base/startup directory - contains scripts to set environment and path</H4>
|
<H4>base/startup directory - contains scripts to set environment and path</H4>
|
||||||
<PRE>
|
<PRE>
|
||||||
EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable
|
EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable
|
||||||
EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable
|
unix.csh C shell script to set path and env variables
|
||||||
Site.profile bourne shell script to set path and env variables
|
unix.sh Bourne shell script to set path and env variables
|
||||||
Site.cshrc c shell script to set path and env variables
|
win32.bat Bat file example to configure win32-x86 target
|
||||||
cygwin.bat WIN32 bat file to set cygwin path and env variables
|
windows.bat Bat file example to configure windows-x64 target
|
||||||
win32.bat WIN32 bat file to set path and env variables
|
|
||||||
</PRE>
|
</PRE>
|
||||||
|
|
||||||
<H4>base/configure directory - contains build definitions and rules</H4>
|
<H4>base/configure directory - contains build definitions and rules</H4>
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||||
<title>EPICS Base R3.16.1 Release Notes</title>
|
<title>EPICS Base R3.16.2 Release Notes</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body lang="en">
|
<body lang="en">
|
||||||
<h1 align="center">EPICS Base Release 3.16.1</h1>
|
<h1 align="center">EPICS Base Release 3.16.2</h1>
|
||||||
|
|
||||||
|
<h2 align="center">Changes made between 3.16.1 and 3.16.2</h2>
|
||||||
|
|
||||||
<!-- Insert new items immediately below this template ...
|
<!-- Insert new items immediately below this template ...
|
||||||
|
|
||||||
@@ -17,6 +19,226 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<h3>Launchpad Bugs</h3>
|
||||||
|
|
||||||
|
<p>The list of tracked bugs fixed in this release can be found on the
|
||||||
|
<a href="https://launchpad.net/epics-base/+milestone/3.16.2">Launchpad Milestone
|
||||||
|
page for EPICS Base 3.16.2</a>.</p>
|
||||||
|
|
||||||
|
<h3>Status reporting for the callback and scanOnce task queues</h3>
|
||||||
|
|
||||||
|
<p>Two new iocsh commands and some associated underlying APIs have been added to
|
||||||
|
show the state of the queues that feed the three callback tasks and the scanOnce
|
||||||
|
task, including a high-water mark which can optionally be reset. The new iocsh
|
||||||
|
commands are <tt>callbackQueueShow</tt> and <tt>scanOnceQueueShow</tt>; both
|
||||||
|
take an optional integer argument which must be non-zero to reset the
|
||||||
|
high-water mark.</p>
|
||||||
|
|
||||||
|
<h3>Support for event codes greater than or equal to NUM_TIME_EVENTS</h3>
|
||||||
|
|
||||||
|
<p>Event numbers greater than or equal to NUM_TIME_EVENTS are now allowed if
|
||||||
|
supported by the registered event time provider, which must provide its own
|
||||||
|
advancing timestamp validation for such events.</p>
|
||||||
|
|
||||||
|
<p>Time events numbered 0 through (NUM_TIME_EVENTS-1) are still validated by
|
||||||
|
code in epicsGeneralTime.c that checks for advancing timestamps and enforces
|
||||||
|
that restriction.</p>
|
||||||
|
|
||||||
|
<h3>Type-safe Device and Driver Support Tables</h3>
|
||||||
|
|
||||||
|
<p>Type-safe versions of the device and driver support structures <tt>dset</tt>
|
||||||
|
and <tt>drvet</tt> have been added to the devSup.h and drvSup.h headers
|
||||||
|
respectively. The original structure definitions have not been changed so
|
||||||
|
existing support modules will still build normally, but older modules can be
|
||||||
|
modified and new code written to be compatible with both.</p>
|
||||||
|
|
||||||
|
<p>The old structure definitions will be replaced by the new ones if the macros
|
||||||
|
<tt>USE_TYPED_DSET</tt> and/or <tt>USE_TYPED_DRVET</tt> are defined when the
|
||||||
|
appropriate header is included. The best place to define these is in the
|
||||||
|
Makefile, as with the <tt>USE_TYPED_RSET</tt> macro that was introduced in
|
||||||
|
Base-3.16.1 and described below. See the comments in devSup.h for a brief usage
|
||||||
|
example, or look at <a href="https://github.com/epics-modules/ipac/commit/a7e0ff4089b9aa39108bc8569e95ba7fcf07cee9">
|
||||||
|
this commit</a> to the ipac module to see a module conversion.</p>
|
||||||
|
|
||||||
|
<p>A helper function <tt>DBLINK* dbGetDevLink(dbCommon *prec)</tt> has also been
|
||||||
|
added to devSup.h which fetches a pointer to the INP or OUT field of the
|
||||||
|
record.</p>
|
||||||
|
|
||||||
|
<h3>RTEMS build configuration update, running tests under QEMU</h3>
|
||||||
|
|
||||||
|
<p>This release includes the ability to run the EPICS unit tests built for a
|
||||||
|
special version of the RTEMS-pc386 target architecture on systems that have an
|
||||||
|
appropriate QEMU emulator installed (<tt>qemu-system-i386</tt>). It is also now
|
||||||
|
possible to create sub-architectures of RTEMS targets, whereas previously the
|
||||||
|
EPICS target architecture name had to be <tt>RTEMS-$(RTEMS_BSP)</tt>.</p>
|
||||||
|
|
||||||
|
<p>The new target <tt>RTEMS-pc386-qemu</tt> builds binaries that can be run in
|
||||||
|
the <tt>qemu-system-i386</tt> PC System emulator. This target is a derivative of
|
||||||
|
the original <tt>RTEMS-pc386</tt> target but with additional software to build
|
||||||
|
an in-memory file-system, and some minor modifications to allow the unit tests
|
||||||
|
to work properly under QEMU. When this target is enabled, building any of the
|
||||||
|
make targets that cause the built-in self-tests to be run (such as
|
||||||
|
<tt>make runtests</tt>) will also run the tests for RTEMS using QEMU.</p>
|
||||||
|
|
||||||
|
<p>To allow the new 3-component RTEMS target name, the EPICS build system for
|
||||||
|
RTEMS was modified to allow a <tt>configure/os/CONFIG.Common.<arch></tt>
|
||||||
|
file to set the <tt>RTEMS_BSP</tt> variable to inform the build what RTEMS BSP
|
||||||
|
to use. Previously this was inferred from the value of the <tt>T_A</tt> make
|
||||||
|
variable, but that prevents having multiple EPICS targets that build against the
|
||||||
|
same BSP. All the included RTEMS target configuration files have been updated;
|
||||||
|
build configuration files for out-of-tree RTEMS targets will continue to work as
|
||||||
|
the original rules are used to set <tt>RTEMS_BSP</tt> if it hasn't been set when
|
||||||
|
needed.</p>
|
||||||
|
|
||||||
|
<h3>Link type enhancements</h3>
|
||||||
|
|
||||||
|
<p>This release adds three new link types: "state", "debug" and "trace". The
|
||||||
|
"state" link type gets and puts boolean values from/to the dbState library that
|
||||||
|
was added in the 3.15.1 release. The "debug" link type sets the
|
||||||
|
<code>jlink::debug</code> flag in its child link, while the "trace" link type
|
||||||
|
also causes the arguments and return values for all calls to the child link's
|
||||||
|
jlif and lset routines to be printed on stdout. The debug flag can no longer be
|
||||||
|
set using an info tag. The addition of the "trace" link type has allowed over
|
||||||
|
200 lines of conditional diagnostic printf() calls to be removed from the other
|
||||||
|
link types.</p>
|
||||||
|
|
||||||
|
<p>The "calc" link type can now be used for output links as well as input links.
|
||||||
|
This allows modification of the output value and even combining it with values
|
||||||
|
from other input links. See the separate JSON Link types document for
|
||||||
|
details.</p>
|
||||||
|
|
||||||
|
<p>A new <code>start_child()</code> method was added to the end of the jlif
|
||||||
|
interface table.</p>
|
||||||
|
|
||||||
|
<p>The <code>lset</code> methods have now been properly documented in the
|
||||||
|
dbLink.h header file using Doxygen annotations, although we do not run Doxygen
|
||||||
|
on the source tree yet to generate API documentation.</p>
|
||||||
|
|
||||||
|
<p>Link types that utilize child links must now indicate whether the child will
|
||||||
|
be used for input, output or forward linking by the return value from its
|
||||||
|
<code>parse_start_map()</code> method. The <code>jlif_key_result</code> enum now
|
||||||
|
contains 3 values <code>jlif_key_child_inlink</code>,
|
||||||
|
<code>jlif_key_child_outlink</code> and <code>jlif_key_child_fwdlink</code>
|
||||||
|
instead of the single <code>jlif_key_child_link</code> that was previously used
|
||||||
|
for this.</p>
|
||||||
|
|
||||||
|
<h3>GNUmake targets for debugging</h3>
|
||||||
|
|
||||||
|
<p>Some additional build rules have been added to help debug configuration
|
||||||
|
problems with the build system. Run <tt>make show-makefiles</tt> to get a sorted
|
||||||
|
list of all the files that the build system includes when building in the
|
||||||
|
current directory.</p>
|
||||||
|
|
||||||
|
<p>A new pattern rule for <tt>PRINT.%</tt> can be used to show the value of any
|
||||||
|
GNUmake variable for the current build directory (make sure you are in the right
|
||||||
|
directory though, many variables are only set when inside the
|
||||||
|
<tt>O.<i>arch</i></tt> build directory). For example <tt>make PRINT.T_A</tt>
|
||||||
|
will display the build target architecture name from inside a
|
||||||
|
<tt>O.<i>arch</i></tt> directory but the variable will be empty from an
|
||||||
|
application top or src directory. <tt>make PRINT.EPICS_BASE</tt> will show the
|
||||||
|
path to Base from any EPICS application directory though.</p>
|
||||||
|
|
||||||
|
<h3>Propagate PUTF across Asynchronous record processing</h3>
|
||||||
|
|
||||||
|
<p>The IOC contains a mechanism involving the PUTF and RPRO fields of each
|
||||||
|
record to ensure that if a record is busy when it receives a put to one of its
|
||||||
|
fields, the record will be processed again to ensure that the new field value
|
||||||
|
has been correctly acted on. Until now that mechanism only worked if the put was
|
||||||
|
to the asynchronous record itself, so puts that were chained from some other
|
||||||
|
record via a DB link did not cause reprocessing.</p>
|
||||||
|
|
||||||
|
<p>In this release the mechanism has been extended to propagate the PUTF state
|
||||||
|
across DB links until all downstream records have been reprocessed. Some
|
||||||
|
additional information about the record state can be shown by setting the TPRO
|
||||||
|
field of an upstream record, and even more trace data is displayed if the
|
||||||
|
debugging variable <tt>dbAccessDebugPUTF</tt> is set in addition to TPRO.</p>
|
||||||
|
|
||||||
|
<h3>Finding info fields</h3>
|
||||||
|
|
||||||
|
<p>A new iocsh command <code>dbli</code> lists the info fields defined in the
|
||||||
|
database, and can take a glob pattern to limit output to specific info names.
|
||||||
|
The newly added dbStaticLib function <code>dbNextMatchingInfo()</code> iterates
|
||||||
|
through the info fields defined in the current record, and is used to implement
|
||||||
|
the new command.</p>
|
||||||
|
|
||||||
|
<h3>Output from <tt>dbpr</tt> command enhanced</h3>
|
||||||
|
|
||||||
|
<p>The "DataBase Print Record" command <tt>dbpr</tt> now generates slightly
|
||||||
|
better output, with more field types having their own display methods. This
|
||||||
|
release also includes additional protection against buffer overflows while
|
||||||
|
printing long links in <tt>dbpr</tt>, and corrects the output of long strings
|
||||||
|
from the <tt>dbgf</tt> command.</p>
|
||||||
|
|
||||||
|
<h3>Record types mbbiDirect and mbboDirect upgraded to 32 bit</h3>
|
||||||
|
|
||||||
|
<p>The VAL fields and related fields of these records are now <tt>DBF_LONG</tt>.
|
||||||
|
(Not <tt>DBF_ULONG</tt> in order to prevent Channel Access from promoting them
|
||||||
|
to <tt>DBF_DOUBLE</tt>.) Additional bit fields <tt>B10</tt>...<tt>B1F</tt> have
|
||||||
|
been added.</p>
|
||||||
|
|
||||||
|
<p>Device support that accesses <tt>VAL</tt> or the bit fields directly (most
|
||||||
|
don't) and aims for compatibility with old and new versions of these records
|
||||||
|
should use at least 32 bit integer types to avoid bit loss. The number of bit
|
||||||
|
fields can be calculated using <code>8 * sizeof(prec->val)</code>
|
||||||
|
which is correct in both versions.</p>
|
||||||
|
|
||||||
|
<h3>Restore use of ledlib for VxWorks command editing</h3>
|
||||||
|
|
||||||
|
<p>The epicsReadline refactoring work described below unfortunately disabled the
|
||||||
|
VxWorks implementation of the osdReadline.c API that uses ledlib for command
|
||||||
|
editing and history. This functionality has now been restored, see Launchpad
|
||||||
|
<a href="https://bugs.launchpad.net/bugs/1741578">bug #1741578</a>.</p>
|
||||||
|
|
||||||
|
<h3>Constant link types</h3>
|
||||||
|
|
||||||
|
<p>Constant links can now hold 64-bit integer values, either as scalars or
|
||||||
|
arrays. Only base 10 is supported by the JSON parser though, the JSON standard
|
||||||
|
doesn't allow for hexadecimal numbers.</p>
|
||||||
|
|
||||||
|
<h3>Upgraded the YAJL JSON Library</h3>
|
||||||
|
|
||||||
|
<p>The third-party YAJL library that has been included in libCom for several
|
||||||
|
years has been upgraded to version 2.1.0 and several bugs fixed. This has an
|
||||||
|
updated API, requiring any code that uses it to parse its own JSON files to be
|
||||||
|
modified to match. The changes are mainly that it uses <tt>size_t</tt> instead
|
||||||
|
<tt>unsigned int</tt> for string lengths, but it also uses <tt>long long</tt>
|
||||||
|
instead of <tt>long</tt> for JSON integer values, which was the main motivation
|
||||||
|
for the upgrade.</p>
|
||||||
|
|
||||||
|
<p>The self-tests that YAJL comes with have been imported and are now run as an
|
||||||
|
EPICS Unit Test program, and the JSON syntax accepted by the parser was extended
|
||||||
|
to permit trailing commas in both arrays and maps. The difference between the
|
||||||
|
old and new YAJL APIs can be detected at compile time by looking for the macro
|
||||||
|
<tt>EPICS_YAJL_VERSION</tt> which is defined in the yajl_common.h header file
|
||||||
|
along with a brief description of the API changes.</p>
|
||||||
|
|
||||||
|
<h3>Timestamp support for the calc link type</h3>
|
||||||
|
|
||||||
|
<p>A new optional parameter can be given when specifying a calc JSON link. The
|
||||||
|
<tt>time</tt> parameter is a string containing a single letter <tt>A..L</tt>
|
||||||
|
that selects one of the input links to be used for the timestamp of calculation
|
||||||
|
if requested. The timestamp will be fetched atomically with the value from the
|
||||||
|
chosen input link (providing that input link type supports the readLocked()
|
||||||
|
method).</p>
|
||||||
|
|
||||||
|
<h3>Silence errors from puts to constant link types</h3>
|
||||||
|
|
||||||
|
<p>A soft channel output record with the OUT link unset uses the CONSTANT link
|
||||||
|
type. The new link type code was causing some soft channel device supports to
|
||||||
|
return an error status from the write method of that link type, which would
|
||||||
|
cause a ca_put() operation to such a record to generate an exception. This has
|
||||||
|
been silenced by giving the constant link types a dummy putValue method. A new
|
||||||
|
test program has been added to prevent regressions of this behaviour.</p>
|
||||||
|
|
||||||
|
<h3>RSRV expanding large buffer causes crash</h3>
|
||||||
|
|
||||||
|
<p>In the 3.16.1 release a crash can occur in the IOC's RSRV server when a large
|
||||||
|
array is made even larger; the previous array buffer was not being released
|
||||||
|
correctly. See Launchpad
|
||||||
|
<a href="https://bugs.launchpad.net/epics-base/+bug/1706703">bug
|
||||||
|
#1706703</a>.</p>
|
||||||
|
|
||||||
|
|
||||||
<h2 align="center">Changes made between 3.16.0.1 and 3.16.1</h2>
|
<h2 align="center">Changes made between 3.16.0.1 and 3.16.1</h2>
|
||||||
|
|
||||||
<h3>IOC Database Support for 64-bit integers</h3>
|
<h3>IOC Database Support for 64-bit integers</h3>
|
||||||
@@ -50,6 +272,27 @@ preprocessor macro):</p>
|
|||||||
#endif
|
#endif
|
||||||
</pre></blockquote>
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>If the code uses the old db_access.h types (probably because it's calling
|
||||||
|
Channel Access APIs) then it will have to test against the EPICS version number
|
||||||
|
instead, like this:</p>
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
#include <epicsVersion.h>
|
||||||
|
|
||||||
|
#ifndef VERSION_INT
|
||||||
|
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
|
||||||
|
#endif
|
||||||
|
#ifndef EPICS_VERSION_INT
|
||||||
|
# define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if EPICS_VERSION_INT >= VERSION_INT(3,16,1,0)
|
||||||
|
/* Code where Base has INT64 support */
|
||||||
|
#else
|
||||||
|
/* Code for older versions */
|
||||||
|
#endif
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
<p>Channel Access does not (and probably never will) directly support 64-bit
|
<p>Channel Access does not (and probably never will) directly support 64-bit
|
||||||
integer types, so the new field types are presented to the CA server as
|
integer types, so the new field types are presented to the CA server as
|
||||||
<tt>DBF_DOUBLE</tt> values. This means that field values larger than 2^52
|
<tt>DBF_DOUBLE</tt> values. This means that field values larger than 2^52
|
||||||
@@ -217,15 +460,15 @@ to implement the link APIs, so will work properly after these conversions:</p>
|
|||||||
link type, i.e. change this code:
|
link type, i.e. change this code:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
if (prec->siml.type == CONSTANT) {
|
if (prec->siml.type == CONSTANT) {
|
||||||
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
|
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
into this:
|
into this:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
|
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Note that <tt>recGblInitConstantLink()</tt> still returns TRUE if the field was
|
Note that <tt>recGblInitConstantLink()</tt> still returns TRUE if the field was
|
||||||
@@ -238,20 +481,20 @@ or undefined links, FALSE for links whose <tt>dbGetLink()</tt> routine may
|
|||||||
return different values on different calls. For example this:
|
return different values on different calls. For example this:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
if (prec->dol.type != CONSTANT)
|
if (prec->dol.type != CONSTANT)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
should become this:
|
should become this:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
if (!dbLinkIsConstant(&prec->dol))
|
if (!dbLinkIsConstant(&prec->dol))
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
When the converted software is also required to build against older versions of
|
When the converted software is also required to build against older versions of
|
||||||
Base, this macro definition may be useful:
|
Base, this macro definition may be useful:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
#define dbLinkIsConstant(lnk) ((lnk)->type == CONSTANT)
|
#define dbLinkIsConstant(lnk) ((lnk)->type == CONSTANT)
|
||||||
</pre>
|
</pre>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -259,7 +502,7 @@ Base, this macro definition may be useful:
|
|||||||
link has been resolved as a CA link using code such as
|
link has been resolved as a CA link using code such as
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
if (prec->inp.type == CA_LINK)
|
if (prec->inp.type == CA_LINK)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
will still compile and run, but will only work properly with the old CA link
|
will still compile and run, but will only work properly with the old CA link
|
||||||
@@ -269,7 +512,7 @@ examine or modify data inside the link. After conversion the above line would
|
|||||||
probably become:
|
probably become:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
if (dbLinkIsVolatile(&prec->inp))
|
if (dbLinkIsVolatile(&prec->inp))
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
A volatile link is one like a Channel Access link which may disconnect and
|
A volatile link is one like a Channel Access link which may disconnect and
|
||||||
@@ -279,7 +522,7 @@ same state they started in. For compatibility when building against older
|
|||||||
versions of Base, this macro definition may be useful:
|
versions of Base, this macro definition may be useful:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
#define dbLinkIsVolatile(lnk) ((lnk)->type == CA_LINK)
|
#define dbLinkIsVolatile(lnk) ((lnk)->type == CA_LINK)
|
||||||
</pre>
|
</pre>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -579,11 +822,62 @@ the stdout stream, making it hard to parse.</p>
|
|||||||
callback.h header and removed the need for dbScan.c to reach into the internals
|
callback.h header and removed the need for dbScan.c to reach into the internals
|
||||||
of its CALLBACK objects.</p>
|
of its CALLBACK objects.</p>
|
||||||
|
|
||||||
|
<h2 align="center">Changes from the 3.15 branch since 3.15.6</h2>
|
||||||
<h2 align="center">Changes from the 3.15 branch since 3.15.5</h2>
|
|
||||||
|
|
||||||
<!-- Insert inherited items immediately below here ... -->
|
<!-- Insert inherited items immediately below here ... -->
|
||||||
|
|
||||||
|
|
||||||
|
<h2 align="center">Changes made between 3.15.5 and 3.15.6</h2>
|
||||||
|
|
||||||
|
<h3>Unsetting environment variables</h3>
|
||||||
|
|
||||||
|
<p>The new command <code>epicsEnvUnset <i>varname</i></code> can be used to
|
||||||
|
unset an environment variable.</p>
|
||||||
|
|
||||||
|
<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>
|
<h3>Add osiSockOptMcastLoop_t and osiSockTest</h3>
|
||||||
|
|
||||||
<p>Added a new OS-independent typedef for multicast socket options, and a test
|
<p>Added a new OS-independent typedef for multicast socket options, and a test
|
||||||
@@ -598,9 +892,115 @@ of having go modify or replace the original. A new .gitignore pattern
|
|||||||
tells git to ignore all configure/*.local files.</p>
|
tells git to ignore all configure/*.local files.</p>
|
||||||
|
|
||||||
|
|
||||||
<h2 align="center">Changes from the 3.14 branch since 3.15.5</h2>
|
<h2 align="center">Changes from the 3.14 branch between 3.15.5 and 3.15.6</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>
|
<h3>Extend maximum Posix epicsEventWaitWithTimeout() delay</h3>
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ the final release version.</p>
|
|||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td>Release Manager</td>
|
<td>Release Manager</td>
|
||||||
<td>Tag the module in Git using these tag conventions:
|
<td>Tag the module in Git, using these tag conventions:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<tt>R3.16.1-pre<i>n</i></tt>
|
<tt>R3.16.1-pre<i>n</i></tt>
|
||||||
@@ -141,7 +141,7 @@ the final release version.</p>
|
|||||||
<tt>R3.16.1-rc<i>n</i></tt>
|
<tt>R3.16.1-rc<i>n</i></tt>
|
||||||
— release candidate tag
|
— release candidate tag
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<blockquote><tt>
|
<blockquote><tt>
|
||||||
cd base-3.16<br />
|
cd base-3.16<br />
|
||||||
git tag -m 'ANJ: Tagged for 3.16.1-rc1' R3.16.1-rc1
|
git tag -m 'ANJ: Tagged for 3.16.1-rc1' R3.16.1-rc1
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# Copyright (c) 2002 The Regents of the University of California, as
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
# Operator of Los Alamos National Laboratory.
|
# Operator of Los Alamos National Laboratory.
|
||||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
# 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.
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
|
|
||||||
TOP = ..
|
TOP = ..
|
||||||
@@ -72,9 +72,11 @@ std_DEPEND_DIRS = ioc libCom/RTEMS
|
|||||||
DIRS += std/filters/test
|
DIRS += std/filters/test
|
||||||
std/filters/test_DEPEND_DIRS = std
|
std/filters/test_DEPEND_DIRS = std
|
||||||
|
|
||||||
|
DIRS += std/link/test
|
||||||
|
std/link/test_DEPEND_DIRS = std
|
||||||
|
|
||||||
DIRS += std/rec/test
|
DIRS += std/rec/test
|
||||||
std/rec/test_DEPEND_DIRS = std
|
std/rec/test_DEPEND_DIRS = std
|
||||||
|
|
||||||
|
|
||||||
include $(TOP)/configure/RULES_DIRS
|
include $(TOP)/configure/RULES_DIRS
|
||||||
|
|
||||||
|
|||||||
@@ -1021,7 +1021,7 @@ d:/user/epics/base-3.15/lib/win32-x86/Com.lib</code></p>
|
|||||||
<h2><a name="CommandUtils">Command Line Utilities</a></h2>
|
<h2><a name="CommandUtils">Command Line Utilities</a></h2>
|
||||||
|
|
||||||
<h3><a name="acctst">acctst</a></h3>
|
<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>
|
[test repetition count] [enable preemptive callback]</pre>
|
||||||
|
|
||||||
<h4>Description</h4>
|
<h4>Description</h4>
|
||||||
@@ -2091,7 +2091,7 @@ example, be beneficial when tuning an archiver installation.</p>
|
|||||||
<p>Significant performance gains can be realized when the CA client library
|
<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
|
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)
|
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_pend_io()</code>, <code>ca_pend_event()</code>, or
|
||||||
<code>ca_sg_block()</code> are called allowing several operations to be
|
<code>ca_sg_block()</code> are called allowing several operations to be
|
||||||
efficiently sent over the network together. Any process variable values written
|
efficiently sent over the network together. Any process variable values written
|
||||||
@@ -2115,16 +2115,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
|
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
|
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>
|
<code>SEVCHK()</code></a> for more information on this topic.</p>
|
||||||
<pre>status = ca_XXXX();
|
<pre>status = ca_XXXX();
|
||||||
SEVCHK( status, "ca_XXXX() returned failure status");
|
SEVCHK( status, "ca_XXXX() returned failure status");
|
||||||
|
|
||||||
if ( status & CA_M_SUCCESS ) {
|
if ( status & CA_M_SUCCESS ) {
|
||||||
printf ( "The requested ca_XXXX() operation didn't complete successfully");
|
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",
|
printf("The requested ca_XXXX() operation didn't complete successfully because \"%s\"\n",
|
||||||
ca_message ( status ) );
|
ca_message ( status ) );
|
||||||
}</pre>
|
}</pre>
|
||||||
|
|
||||||
<h3><a name="Channel">Channel Access Data Types</a></h3>
|
<h3><a name="Channel">Channel Access Data Types</a></h3>
|
||||||
@@ -2297,7 +2297,7 @@ int main ( int argc, char ** argv )
|
|||||||
unsigned nBytes;
|
unsigned nBytes;
|
||||||
unsigned elementCount;
|
unsigned elementCount;
|
||||||
char timeString[32];
|
char timeString[32];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
chid chan;
|
chid chan;
|
||||||
double sum;
|
double sum;
|
||||||
int status;
|
int status;
|
||||||
@@ -2340,7 +2340,7 @@ int main ( int argc, char ** argv )
|
|||||||
epicsTimeToStrftime ( timeString, sizeof ( timeString ),
|
epicsTimeToStrftime ( timeString, sizeof ( timeString ),
|
||||||
"%a %b %d %Y %H:%M:%S.%f", & pTD->stamp );
|
"%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 );
|
argv[1], timeString, sum );
|
||||||
|
|
||||||
ca_clear_channel ( chan );
|
ca_clear_channel ( chan );
|
||||||
@@ -2371,7 +2371,7 @@ executing within the user's callback function.</p>
|
|||||||
<pre>typedef struct event_handler_args {
|
<pre>typedef struct event_handler_args {
|
||||||
void *usr; /* user argument supplied with request */
|
void *usr; /* user argument supplied with request */
|
||||||
chanId chid; /* channel id */
|
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 */
|
long count; /* the element count of the item returned */
|
||||||
const void *dbr; /* a pointer to the item returned */
|
const void *dbr; /* a pointer to the item returned */
|
||||||
int status; /* ECA_XXX status of the requested op from the server */
|
int status; /* ECA_XXX status of the requested op from the server */
|
||||||
@@ -2394,7 +2394,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
|
default exception handler prints a message on the console and exits if the
|
||||||
exception condition is severe. Certain internal exceptions within the CA client
|
exception condition is severe. Certain internal exceptions within the CA client
|
||||||
library, and failures detected by the SEVCHK macro may also cause the exception
|
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>
|
<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
|
<h3><a name="Server">Server and Client Share the Same Address Space on The Same
|
||||||
@@ -2686,6 +2686,14 @@ automatically released by the system when the process exits and
|
|||||||
vxWorks or RTEMS no cleanup occurs unless the application calls
|
vxWorks or RTEMS no cleanup occurs unless the application calls
|
||||||
<code>ca_context_destroy()</code>.</p>
|
<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>
|
<h4>Returns</h4>
|
||||||
|
|
||||||
<p>ECA_NORMAL - Normal successful completion</p>
|
<p>ECA_NORMAL - Normal successful completion</p>
|
||||||
@@ -2831,6 +2839,12 @@ efficiently sent over the network in one message.</p>
|
|||||||
clearing a channel does shutdown and reclaim any channel state change event
|
clearing a channel does shutdown and reclaim any channel state change event
|
||||||
subscriptions (monitors) registered with the channel.</p>
|
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>
|
<h4>Arguments</h4>
|
||||||
<dl>
|
<dl>
|
||||||
<dt><code>CHID</code></dt>
|
<dt><code>CHID</code></dt>
|
||||||
@@ -2845,16 +2859,16 @@ subscriptions (monitors) registered with the channel.</p>
|
|||||||
|
|
||||||
<h3><code><a name="ca_put">ca_put()</a></code></h3>
|
<h3><code><a name="ca_put">ca_put()</a></code></h3>
|
||||||
<pre>#include <cadef.h>
|
<pre>#include <cadef.h>
|
||||||
int ca_put ( chtype TYPE,
|
int ca_put ( chtype TYPE,
|
||||||
chid CHID, void *PVALUE );
|
chid CHID, void *PVALUE );
|
||||||
int ca_array_put ( chtype TYPE, unsigned long COUNT,
|
int ca_array_put ( chtype TYPE, unsigned long COUNT,
|
||||||
chid CHID, const void *PVALUE);
|
chid CHID, const void *PVALUE);
|
||||||
typedef void ( caEventCallBackFunc ) (struct event_handler_args);
|
typedef void ( caEventCallBackFunc ) (struct event_handler_args);
|
||||||
int ca_put_callback ( chtype TYPE,
|
int ca_put_callback ( chtype TYPE,
|
||||||
chid CHID, const void *PVALUE,
|
chid CHID, const void *PVALUE,
|
||||||
caEventCallBackFunc PFUNC, void *USERARG );
|
caEventCallBackFunc PFUNC, void *USERARG );
|
||||||
int ca_array_put_callback ( chtype TYPE, unsigned long COUNT,
|
int ca_array_put_callback ( chtype TYPE, unsigned long COUNT,
|
||||||
chid CHID, const void *PVALUE,
|
chid CHID, const void *PVALUE,
|
||||||
caEventCallBackFunc PFUNC, void *USERARG );</pre>
|
caEventCallBackFunc PFUNC, void *USERARG );</pre>
|
||||||
|
|
||||||
<h4>Description</h4>
|
<h4>Description</h4>
|
||||||
@@ -3081,7 +3095,7 @@ when a CA get request is initiated.</p>
|
|||||||
typedef void ( caEventCallBackFunc ) (struct event_handler_args);
|
typedef void ( caEventCallBackFunc ) (struct event_handler_args);
|
||||||
int ca_create_subscription ( chtype TYPE, unsigned long COUNT,
|
int ca_create_subscription ( chtype TYPE, unsigned long COUNT,
|
||||||
chid CHID, unsigned long MASK,
|
chid CHID, unsigned long MASK,
|
||||||
caEventCallBackFunc USERFUNC, void *USERARG,
|
caEventCallBackFunc USERFUNC, void *USERARG,
|
||||||
evid *PEVID );</pre>
|
evid *PEVID );</pre>
|
||||||
|
|
||||||
<h4>Description</h4>
|
<h4>Description</h4>
|
||||||
@@ -3165,7 +3179,7 @@ indicating the current state of the channel.</p>
|
|||||||
<dt><code>MASK</code></dt>
|
<dt><code>MASK</code></dt>
|
||||||
<dd>A mask with bits set for each of the event trigger types requested. The
|
<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
|
event trigger mask must be a <em>bitwise or</em> of one or more of the
|
||||||
following constants.
|
following constants.
|
||||||
<ul>
|
<ul>
|
||||||
<li>DBE_VALUE - Trigger events when the channel value exceeds the
|
<li>DBE_VALUE - Trigger events when the channel value exceeds the
|
||||||
monitor dead band</li>
|
monitor dead band</li>
|
||||||
@@ -3212,6 +3226,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
|
<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>
|
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>
|
<h4>Arguments</h4>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>EVID</dt>
|
<dt>EVID</dt>
|
||||||
@@ -3376,7 +3397,7 @@ becomes full.</p>
|
|||||||
|
|
||||||
<h3><code><a name="ca_signal">ca_signal()</a></code></h3>
|
<h3><code><a name="ca_signal">ca_signal()</a></code></h3>
|
||||||
<pre>#include <cadef.h>
|
<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>
|
void SEVCHK( CA_STATUS, CONTEXT_STRING );</pre>
|
||||||
|
|
||||||
<h4>Description</h4>
|
<h4>Description</h4>
|
||||||
@@ -3393,7 +3414,7 @@ recommended error handler for simple applications which do not wish to write
|
|||||||
code testing the status returned from each channel access call.</p>
|
code testing the status returned from each channel access call.</p>
|
||||||
|
|
||||||
<h4>Examples</h4>
|
<h4>Examples</h4>
|
||||||
<pre>status = ca_context_create (...);
|
<pre>status = ca_context_create (...);
|
||||||
SEVCHK ( status, "Unable to create a CA client context" );</pre>
|
SEVCHK ( status, "Unable to create a CA client context" );</pre>
|
||||||
|
|
||||||
<p>If the application only wishes to print the message associated with an error
|
<p>If the application only wishes to print the message associated with an error
|
||||||
@@ -3417,7 +3438,7 @@ this purpose.</p>
|
|||||||
|
|
||||||
<h3><code><a
|
<h3><code><a
|
||||||
name="ca_add_exception_event">ca_add_exception_event()</a></code></h3>
|
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 );
|
typedef void (*pCallback) ( struct exception_handler_args HANDLERARGS );
|
||||||
int ca_add_exception_event ( pCallback USERFUNC, void *USERARG );</pre>
|
int ca_add_exception_event ( pCallback USERFUNC, void *USERARG );</pre>
|
||||||
|
|
||||||
@@ -3626,7 +3647,7 @@ specified channel.</p>
|
|||||||
<dt><code>PFUNC</code></dt>
|
<dt><code>PFUNC</code></dt>
|
||||||
<dd>Pointer to a 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>
|
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 {
|
<pre>typedef struct ca_access_rights {
|
||||||
unsigned read_access:1;
|
unsigned read_access:1;
|
||||||
unsigned write_access:1;
|
unsigned write_access:1;
|
||||||
@@ -3966,8 +3987,8 @@ type.</p>
|
|||||||
prints diagnostics to standard out.</p>
|
prints diagnostics to standard out.</p>
|
||||||
|
|
||||||
<h4>Examples</h4>
|
<h4>Examples</h4>
|
||||||
<pre>void ca_test_event ();
|
<pre>void ca_test_event ();
|
||||||
status = ca_create_subscription ( type, chid, ca_test_event, NULL, NULL );
|
status = ca_create_subscription ( type, chid, ca_test_event, NULL, NULL );
|
||||||
SEVCHK ( status, .... );</pre>
|
SEVCHK ( status, .... );</pre>
|
||||||
|
|
||||||
<h4>See Also</h4>
|
<h4>See Also</h4>
|
||||||
@@ -4001,8 +4022,8 @@ outstanding within them at any given time.</p>
|
|||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h4>Examples</h4>
|
<h4>Examples</h4>
|
||||||
<pre>CA_SYNC_GID gid;
|
<pre>CA_SYNC_GID gid;
|
||||||
status = ca_sg_create ( &gid );
|
status = ca_sg_create ( &gid );
|
||||||
SEVCHK ( status, Sync group create failed );</pre>
|
SEVCHK ( status, Sync group create failed );</pre>
|
||||||
|
|
||||||
<h4>Returns</h4>
|
<h4>Returns</h4>
|
||||||
@@ -4040,8 +4061,8 @@ int ca_sg_delete ( CA_SYNC_GID GID );</pre>
|
|||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h4>Examples</h4>
|
<h4>Examples</h4>
|
||||||
<pre>CA_SYNC_GID gid;
|
<pre>CA_SYNC_GID gid;
|
||||||
status = ca_sg_delete ( gid );
|
status = ca_sg_delete ( gid );
|
||||||
SEVCHK ( status, Sync group delete failed );</pre>
|
SEVCHK ( status, Sync group delete failed );</pre>
|
||||||
|
|
||||||
<h4>Returns</h4>
|
<h4>Returns</h4>
|
||||||
@@ -4152,7 +4173,7 @@ will not block unless additional subsequent requests are made.</p>
|
|||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h4>Examples</h4>
|
<h4>Examples</h4>
|
||||||
<pre>CA_SYNC_GID gid;
|
<pre>CA_SYNC_GID gid;
|
||||||
status = ca_sg_reset(gid);</pre>
|
status = ca_sg_reset(gid);</pre>
|
||||||
|
|
||||||
<h4>Returns</h4>
|
<h4>Returns</h4>
|
||||||
@@ -4165,7 +4186,7 @@ status = ca_sg_reset(gid);</pre>
|
|||||||
<pre>#include <cadef.h>
|
<pre>#include <cadef.h>
|
||||||
int ca_sg_put ( CA_SYNC_GID GID, chtype TYPE,
|
int ca_sg_put ( CA_SYNC_GID GID, chtype TYPE,
|
||||||
chid CHID, void *PVALUE );
|
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>
|
unsigned long COUNT, chid CHID, void *PVALUE );</pre>
|
||||||
|
|
||||||
<p>Write a value, or array of values, to a channel and increment the outstanding
|
<p>Write a value, or array of values, to a channel and increment the outstanding
|
||||||
@@ -4306,7 +4327,7 @@ reissued.</p>
|
|||||||
|
|
||||||
<h3><code><a name="ca_client_status">ca_client_status()</a></code></h3>
|
<h3><code><a name="ca_client_status">ca_client_status()</a></code></h3>
|
||||||
<pre>int ca_client_status ( unsigned level );
|
<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>
|
unsigned LEVEL );</pre>
|
||||||
|
|
||||||
<h4>Description</h4>
|
<h4>Description</h4>
|
||||||
|
|||||||
@@ -127,21 +127,10 @@ const char * ca_message_text []
|
|||||||
|
|
||||||
static epicsThreadOnceId caClientContextIdOnce = EPICS_THREAD_ONCE_INIT;
|
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
|
// runs once only for each process
|
||||||
extern "C" void ca_init_client_context ( void * )
|
extern "C" void ca_init_client_context ( void * )
|
||||||
{
|
{
|
||||||
caClientContextId = epicsThreadPrivateCreate ();
|
caClientContextId = epicsThreadPrivateCreate ();
|
||||||
if ( caClientContextId ) {
|
|
||||||
epicsAtExit ( ca_client_exit_handler,0 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ int epicsShareAPI ca_array_get_callback ( chtype type,
|
|||||||
{
|
{
|
||||||
caStatus = ECA_ALLOCMEM;
|
caStatus = ECA_ALLOCMEM;
|
||||||
}
|
}
|
||||||
catch ( cacChannel::msgBodyCacheTooSmall ) {
|
catch ( cacChannel::msgBodyCacheTooSmall & ) {
|
||||||
caStatus = ECA_TOLARGE;
|
caStatus = ECA_TOLARGE;
|
||||||
}
|
}
|
||||||
catch ( ... )
|
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
|
=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
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ Cap5_LIBS = ca Com
|
|||||||
Cap5_INCLUDES = -I$(shell $(PERL) ../perlConfig.pl archlib)/CORE
|
Cap5_INCLUDES = -I$(shell $(PERL) ../perlConfig.pl archlib)/CORE
|
||||||
Cap5_CFLAGS = $(shell $(PERL) ../perlConfig.pl ccflags)
|
Cap5_CFLAGS = $(shell $(PERL) ../perlConfig.pl ccflags)
|
||||||
|
|
||||||
CLEANS += Cap5.c pod2htmd.tmp pod2htmi.tmp
|
CLEANS += Cap5.c
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,10 @@ sub display {
|
|||||||
printf " Lo ctrl limit: %g\n", $data->{lower_ctrl_limit};
|
printf " Lo ctrl limit: %g\n", $data->{lower_ctrl_limit};
|
||||||
printf " Hi ctrl limit: %g\n", $data->{upper_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 {
|
} else {
|
||||||
my $value = format_number($data, $type);
|
my $value = format_number($data, $type);
|
||||||
if ($opt_t) {
|
if ($opt_t) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <alarm.h>
|
#include <alarm.h>
|
||||||
#include <cadef.h>
|
#include <cadef.h>
|
||||||
#include <epicsGetopt.h>
|
#include <epicsGetopt.h>
|
||||||
|
#include "epicsVersion.h"
|
||||||
|
|
||||||
#include "tool_lib.h"
|
#include "tool_lib.h"
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ static void usage (void)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "\nUsage: caget [options] <PV name> ...\n\n"
|
fprintf (stderr, "\nUsage: caget [options] <PV name> ...\n\n"
|
||||||
" -h: Help: Print this message\n"
|
" -h: Help: Print this message\n"
|
||||||
|
" -V: Version: Show EPICS and CA versions\n"
|
||||||
"Channel Access options:\n"
|
"Channel Access options:\n"
|
||||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||||
" -c: Asynchronous get (use ca_get_callback and wait for completion)\n"
|
" -c: Asynchronous get (use ca_get_callback and wait for completion)\n"
|
||||||
@@ -389,11 +391,14 @@ int main (int argc, char *argv[])
|
|||||||
|
|
||||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, ":taicnhsSe:f:g:l:#:d:0:w:p:F:")) != -1) {
|
while ((opt = getopt(argc, argv, ":taicnhsSVe:f:g:l:#:d:0:w:p:F:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h': /* Print usage */
|
case 'h': /* Print usage */
|
||||||
usage();
|
usage();
|
||||||
return 0;
|
return 0;
|
||||||
|
case 'V':
|
||||||
|
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||||
|
return 0;
|
||||||
case 't': /* Terse output mode */
|
case 't': /* Terse output mode */
|
||||||
complainIfNotPlainAndSet(&format, terse);
|
complainIfNotPlainAndSet(&format, terse);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <epicsStdlib.h>
|
#include <epicsStdlib.h>
|
||||||
|
#include "epicsVersion.h"
|
||||||
|
|
||||||
#include <cadef.h>
|
#include <cadef.h>
|
||||||
#include <epicsGetopt.h>
|
#include <epicsGetopt.h>
|
||||||
@@ -36,12 +37,14 @@ void usage (void)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "\nUsage: cainfo [options] <PV name> ...\n\n"
|
fprintf (stderr, "\nUsage: cainfo [options] <PV name> ...\n\n"
|
||||||
" -h: Help: Print this message\n"
|
" -h: Help: Print this message\n"
|
||||||
|
" -V: Version: Show EPICS and CA versions\n"
|
||||||
"Channel Access options:\n"
|
"Channel Access options:\n"
|
||||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||||
" -s <level>: Call ca_client_status with the specified interest level\n"
|
" -s <level>: Call ca_client_status with the specified interest level\n"
|
||||||
" -p <prio>: CA priority (0-%u, default 0=lowest)\n"
|
" -p <prio>: CA priority (0-%u, default 0=lowest)\n"
|
||||||
"\nExample: cainfo my_channel another_channel\n\n"
|
"\nExample: cainfo my_channel another_channel\n\n"
|
||||||
, DEFAULT_TIMEOUT, CA_PRIORITY_MAX);
|
, DEFAULT_TIMEOUT, CA_PRIORITY_MAX);
|
||||||
|
fprintf (stderr, "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -137,11 +140,14 @@ int main (int argc, char *argv[])
|
|||||||
|
|
||||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, ":nhw:s:p:")) != -1) {
|
while ((opt = getopt(argc, argv, ":nhVw:s:p:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h': /* Print usage */
|
case 'h': /* Print usage */
|
||||||
usage();
|
usage();
|
||||||
return 0;
|
return 0;
|
||||||
|
case 'V':
|
||||||
|
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||||
|
return 0;
|
||||||
case 'w': /* Set CA timeout value */
|
case 'w': /* Set CA timeout value */
|
||||||
if(epicsScanDouble(optarg, &caTimeout) != 1)
|
if(epicsScanDouble(optarg, &caTimeout) != 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <epicsStdlib.h>
|
#include <epicsStdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "epicsVersion.h"
|
||||||
|
|
||||||
#include <cadef.h>
|
#include <cadef.h>
|
||||||
#include <epicsGetopt.h>
|
#include <epicsGetopt.h>
|
||||||
@@ -44,7 +45,8 @@ void usage (void)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "\nUsage: camonitor [options] <PV name> ...\n"
|
fprintf (stderr, "\nUsage: camonitor [options] <PV name> ...\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -h: Help; Print this message\n"
|
" -h: Help: Print this message\n"
|
||||||
|
" -V: Version: Show EPICS and CA versions\n"
|
||||||
"Channel Access options:\n"
|
"Channel Access options:\n"
|
||||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||||
" -m <msk>: Specify CA event mask to use. <msk> is any combination of\n"
|
" -m <msk>: Specify CA event mask to use. <msk> is any combination of\n"
|
||||||
@@ -209,11 +211,14 @@ int main (int argc, char *argv[])
|
|||||||
|
|
||||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, ":nhm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
|
while ((opt = getopt(argc, argv, ":nhVm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h': /* Print usage */
|
case 'h': /* Print usage */
|
||||||
usage();
|
usage();
|
||||||
return 0;
|
return 0;
|
||||||
|
case 'V':
|
||||||
|
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||||
|
return 0;
|
||||||
case 'n': /* Print ENUM as index numbers */
|
case 'n': /* Print ENUM as index numbers */
|
||||||
enumAsNr=1;
|
enumAsNr=1;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* Copyright (c) 2002 Berliner Elektronenspeicherringgesellschaft fuer
|
* Copyright (c) 2002 Berliner Elektronenspeicherringgesellschaft fuer
|
||||||
* Synchrotronstrahlung.
|
* Synchrotronstrahlung.
|
||||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
* 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.
|
||||||
\*************************************************************************/
|
\*************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <epicsGetopt.h>
|
#include <epicsGetopt.h>
|
||||||
#include <epicsEvent.h>
|
#include <epicsEvent.h>
|
||||||
#include <epicsString.h>
|
#include <epicsString.h>
|
||||||
|
#include "epicsVersion.h"
|
||||||
|
|
||||||
#include "tool_lib.h"
|
#include "tool_lib.h"
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ 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"
|
" caput -a [options] <PV name> <no of values> <PV value> ...\n\n"
|
||||||
" -h: Help: Print this message\n"
|
" -h: Help: Print this message\n"
|
||||||
|
" -V: Version: Show EPICS and CA versions\n"
|
||||||
"Channel Access options:\n"
|
"Channel Access options:\n"
|
||||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||||
" -c: Asynchronous put (use ca_put_callback and wait for completion)\n"
|
" -c: Asynchronous put (use ca_put_callback and wait for completion)\n"
|
||||||
@@ -281,11 +283,14 @@ int main (int argc, char *argv[])
|
|||||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||||
putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */
|
putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, ":cnlhatsS#:w:p:F:")) != -1) {
|
while ((opt = getopt(argc, argv, ":cnlhatsVS#:w:p:F:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h': /* Print usage */
|
case 'h': /* Print usage */
|
||||||
usage();
|
usage();
|
||||||
return 0;
|
return 0;
|
||||||
|
case 'V':
|
||||||
|
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||||
|
return 0;
|
||||||
case 'n': /* Force interpret ENUM as index number */
|
case 'n': /* Force interpret ENUM as index number */
|
||||||
enumAsNr = 1;
|
enumAsNr = 1;
|
||||||
enumAsString = 0;
|
enumAsString = 0;
|
||||||
@@ -419,7 +424,7 @@ int main (int argc, char *argv[])
|
|||||||
if (argc > optind+1) {
|
if (argc > optind+1) {
|
||||||
for (i = optind + 1; i < argc; i++) {
|
for (i = optind + 1; i < argc; i++) {
|
||||||
strcat(cbuf, " ");
|
strcat(cbuf, " ");
|
||||||
strcat(cbuf, argv[i]);
|
strcat(cbuf, argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +535,11 @@ int main (int argc, char *argv[])
|
|||||||
/* Use standard put with defined timeout */
|
/* Use standard put with defined timeout */
|
||||||
result = ca_array_put (dbrType, count, pvs[0].chid, pbuf);
|
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);
|
result = ca_pend_io(caTimeout);
|
||||||
if (result == ECA_TIMEOUT) {
|
if (result == ECA_TIMEOUT) {
|
||||||
fprintf(stderr, "Write operation timed out: Data was not written.\n");
|
fprintf(stderr, "Write operation timed out: Data was not written.\n");
|
||||||
@@ -545,7 +555,7 @@ int main (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != ECA_NORMAL) {
|
if (result != ECA_NORMAL) {
|
||||||
fprintf(stderr, "Error occured writing data.\n");
|
fprintf(stderr, "Error occured writing data: %s\n", ca_message(result));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -414,6 +414,12 @@ char *dbr2str (const void *value, unsigned type)
|
|||||||
ptsNewS = &((struct TYPE *)value)->stamp; \
|
ptsNewS = &((struct TYPE *)value)->stamp; \
|
||||||
ptsNewC = &tsNow; \
|
ptsNewC = &tsNow; \
|
||||||
\
|
\
|
||||||
|
if (!tsInitS) \
|
||||||
|
{ \
|
||||||
|
tsFirst = *ptsNewS; \
|
||||||
|
tsInitS = 1; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
switch (tsType) { \
|
switch (tsType) { \
|
||||||
case relative: \
|
case relative: \
|
||||||
ptsRefC = &tsStart; \
|
ptsRefC = &tsStart; \
|
||||||
@@ -506,12 +512,6 @@ void print_time_val_sts (pv* pv, unsigned long reqElems)
|
|||||||
epicsTimeGetCurrent(&tsNow);
|
epicsTimeGetCurrent(&tsNow);
|
||||||
epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, &tsNow);
|
epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, &tsNow);
|
||||||
|
|
||||||
if (!tsInitS)
|
|
||||||
{
|
|
||||||
tsFirst = tsNow;
|
|
||||||
tsInitS = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pv->nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
|
if (pv->nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
|
||||||
else printf("%s", pv->name);
|
else printf("%s", pv->name);
|
||||||
printf("%c", fieldSeparator);
|
printf("%c", fieldSeparator);
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ udpiiu::udpiiu (
|
|||||||
|
|
||||||
#ifdef IP_MULTICAST_TTL
|
#ifdef IP_MULTICAST_TTL
|
||||||
{
|
{
|
||||||
int ttl;
|
osiSockOptMcastTTL_t ttl;
|
||||||
long val;
|
long val;
|
||||||
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
|
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
|
||||||
val =1;
|
val =1;
|
||||||
|
|||||||
@@ -665,6 +665,11 @@ caStatus casDGClient::processDG ()
|
|||||||
if ( status != S_cas_success ) {
|
if ( status != S_cas_success ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( this->in.bytesPresent () > 0 && dgInBytesConsumed == 0 && status == S_cas_success ) {
|
||||||
|
this->in.removeMsg ( this->in.bytesPresent() );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Copyright (c) 2002 The Regents of the University of California, as
|
* Copyright (c) 2002 The Regents of the University of California, as
|
||||||
* Operator of Los Alamos National Laboratory.
|
* Operator of Los Alamos National Laboratory.
|
||||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
* 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
|
* Author Jeffrey O. Hill
|
||||||
@@ -26,33 +26,39 @@
|
|||||||
#include "casAsyncIOI.h"
|
#include "casAsyncIOI.h"
|
||||||
#include "casMonitor.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 ) {}
|
nIOAttached ( 0u ), deletePending ( false ) {}
|
||||||
|
|
||||||
casPVI::~casPVI ()
|
casPVI::~casPVI ()
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// all channels should have been destroyed
|
// all channels should have been destroyed
|
||||||
// (otherwise the server tool is yanking the
|
// (otherwise the server tool is yanking the
|
||||||
// PV out from under the server)
|
// PV out from under the server)
|
||||||
//
|
//
|
||||||
casVerify ( this->chanList.count() == 0u );
|
casVerify ( this->chanList.count() == 0u );
|
||||||
|
|
||||||
//
|
//
|
||||||
// all outstanding IO should have been deleted
|
// all outstanding IO should have been deleted
|
||||||
// when we destroyed the channels
|
// when we destroyed the channels
|
||||||
//
|
//
|
||||||
casVerify ( this->nIOAttached == 0u );
|
casVerify ( this->nIOAttached == 0u );
|
||||||
if ( this->nIOAttached ) {
|
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
|
// all monitors should have been deleted
|
||||||
// when we destroyed the channels
|
// when we destroyed the channels
|
||||||
//
|
//
|
||||||
casVerify ( this->nMonAttached == 0u );
|
casVerify ( this->nMonAttached == 0u );
|
||||||
|
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
@@ -139,26 +145,26 @@ caStatus casPVI::attachToServer ( caServerI & cas )
|
|||||||
caStatus casPVI::updateEnumStringTable ( casCtx & ctxIn )
|
caStatus casPVI::updateEnumStringTable ( casCtx & ctxIn )
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
|
|
||||||
//
|
//
|
||||||
// create a gdd with the "enum string table" application type
|
// create a gdd with the "enum string table" application type
|
||||||
//
|
//
|
||||||
// gddArray(int app, aitEnum prim, int dimen, ...);
|
// gddArray(int app, aitEnum prim, int dimen, ...);
|
||||||
gdd * pTmp = new gddScalar ( gddAppType_enums );
|
gdd * pTmp = new gddScalar ( gddAppType_enums );
|
||||||
if ( pTmp == NULL ) {
|
if ( pTmp == NULL ) {
|
||||||
errMessage ( S_cas_noMemory,
|
casErrMessage ( S_cas_noMemory,
|
||||||
"unable to create gdd for read of application type \"enums\" string"
|
"unable to create gdd for read of application type \"enums\" string"
|
||||||
" conversion table for enumerated PV" );
|
" conversion table for enumerated PV" );
|
||||||
return S_cas_noMemory;
|
return S_cas_noMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
caStatus status = convertContainerMemberToAtomic ( *pTmp,
|
caStatus status = convertContainerMemberToAtomic ( *pTmp,
|
||||||
gddAppType_enums, MAX_ENUM_STATES );
|
gddAppType_enums, MAX_ENUM_STATES );
|
||||||
if ( status != S_cas_success ) {
|
if ( status != S_cas_success ) {
|
||||||
pTmp->unreference ();
|
pTmp->unreference ();
|
||||||
errMessage ( status,
|
casErrMessage ( status,
|
||||||
"unable to to config gdd for read of application type \"enums\" string"
|
"unable to config gdd for read of application type \"enums\" string"
|
||||||
" conversion table for enumerated PV");
|
" conversion table for enumerated PV" );
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,12 +175,11 @@ caStatus casPVI::updateEnumStringTable ( casCtx & ctxIn )
|
|||||||
if ( status == S_cas_success ) {
|
if ( status == S_cas_success ) {
|
||||||
updateEnumStringTableAsyncCompletion ( *pTmp );
|
updateEnumStringTableAsyncCompletion ( *pTmp );
|
||||||
}
|
}
|
||||||
else if ( status != S_casApp_asyncCompletion &&
|
else if ( status != S_casApp_asyncCompletion &&
|
||||||
status != S_casApp_postponeAsyncIO ) {
|
status != S_casApp_postponeAsyncIO ) {
|
||||||
errPrintf ( status, __FILE__, __LINE__,
|
casErrMessage ( status,
|
||||||
"- unable to read application type \"enums\" "
|
"unable to read application type \"enums\" "
|
||||||
" (string conversion table) from enumerated native type PV \"%s\"",
|
" (string conversion table) from enumerated native type PV" );
|
||||||
this->getName() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pTmp->unreference ();
|
pTmp->unreference ();
|
||||||
@@ -185,40 +190,39 @@ caStatus casPVI::updateEnumStringTable ( casCtx & ctxIn )
|
|||||||
void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
|
|
||||||
if ( resp.isContainer() ) {
|
if ( resp.isContainer() ) {
|
||||||
errMessage ( S_cas_badType,
|
casErrMessage ( S_cas_badType,
|
||||||
"application type \"enums\" string conversion table for"
|
"Invalid \"enums\" string conversion table for"
|
||||||
" enumerated PV was a container (expected vector of strings)" );
|
" enumerated PV (container instead of vector of strings)" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( resp.dimension() == 0 ) {
|
if ( resp.dimension() == 0 ) {
|
||||||
if ( resp.primitiveType() == aitEnumString ) {
|
if ( resp.primitiveType() == aitEnumString ) {
|
||||||
aitString *pStr = (aitString *) resp.dataVoid ();
|
aitString *pStr = (aitString *) resp.dataVoid ();
|
||||||
if ( ! this->enumStrTbl.setString ( 0, pStr->string() ) ) {
|
if ( ! this->enumStrTbl.setString ( 0, pStr->string() ) ) {
|
||||||
errMessage ( S_cas_noMemory,
|
casErrMessage ( S_cas_noMemory,
|
||||||
"no memory to set enumerated PV string cache" );
|
"no memory to set enumerated PV string cache" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( resp.primitiveType() == aitEnumFixedString ) {
|
else if ( resp.primitiveType() == aitEnumFixedString ) {
|
||||||
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
|
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
|
||||||
if ( ! this->enumStrTbl.setString ( 0, pStr->fixed_string ) ) {
|
if ( ! this->enumStrTbl.setString ( 0, pStr->fixed_string ) ) {
|
||||||
errMessage ( S_cas_noMemory,
|
casErrMessage ( S_cas_noMemory,
|
||||||
"no memory to set enumerated PV string cache" );
|
"no memory to set enumerated PV string cache" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errPrintf ( S_cas_badType, __FILE__, __LINE__,
|
casErrMessage ( S_cas_badType,
|
||||||
"application type \"enums\" string conversion"
|
"application type \"enums\" string conversion"
|
||||||
" table for enumerated PV \"%s\" isnt a string type?",
|
" table for enumerated PV isnt a string type?" );
|
||||||
getName() );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( resp.dimension() == 1 ) {
|
else if ( resp.dimension() == 1 ) {
|
||||||
gddStatus gdd_status;
|
gddStatus gdd_status;
|
||||||
aitIndex index, first, count;
|
aitIndex index, first, count;
|
||||||
|
|
||||||
gdd_status = resp.getBound ( 0, first, count );
|
gdd_status = resp.getBound ( 0, first, count );
|
||||||
assert ( gdd_status == 0 );
|
assert ( gdd_status == 0 );
|
||||||
|
|
||||||
@@ -232,7 +236,7 @@ void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
|||||||
aitString *pStr = (aitString *) resp.dataVoid ();
|
aitString *pStr = (aitString *) resp.dataVoid ();
|
||||||
for ( index = 0; index<count; index++ ) {
|
for ( index = 0; index<count; index++ ) {
|
||||||
if ( ! this->enumStrTbl.setString ( index, pStr[index].string() ) ) {
|
if ( ! this->enumStrTbl.setString ( index, pStr[index].string() ) ) {
|
||||||
errMessage ( S_cas_noMemory,
|
casErrMessage ( S_cas_noMemory,
|
||||||
"no memory to set enumerated PV string cache" );
|
"no memory to set enumerated PV string cache" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,19 +245,18 @@ void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
|||||||
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
|
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
|
||||||
for ( index = 0; index < count; index++ ) {
|
for ( index = 0; index < count; index++ ) {
|
||||||
if ( ! this->enumStrTbl.setString ( index, pStr[index].fixed_string ) ) {
|
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" );
|
"no memory to set enumerated PV string cache" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errMessage ( S_cas_badType,
|
casErrMessage( S_cas_badType,
|
||||||
"application type \"enums\" string conversion"
|
"bad \"enums\" string conversion table for enumerated PV" );
|
||||||
" table for enumerated PV isnt a string type?" );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errMessage ( S_cas_badType,
|
casErrMessage ( S_cas_badType,
|
||||||
"application type \"enums\" string conversion table"
|
"application type \"enums\" string conversion table"
|
||||||
" for enumerated PV was multi-dimensional"
|
" for enumerated PV was multi-dimensional"
|
||||||
" (expected vector of strings)" );
|
" (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 )
|
casMonitor & mon, tsDLList < casMonitor > & monitorList )
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
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 )
|
tsDLList < casMonitor > & list, ca_uint32_t clientIdIn )
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
casMonitor * pMon = 0;
|
casMonitor * pMon = 0;
|
||||||
//
|
//
|
||||||
// (it is reasonable to do a linear search here because
|
// (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)
|
// per channel)
|
||||||
//
|
//
|
||||||
tsDLIter < casMonitor > iter = list.firstIter ();
|
tsDLIter < casMonitor > iter = list.firstIter ();
|
||||||
@@ -359,9 +362,9 @@ void casPVI::installChannel ( chanIntfForPV & chan )
|
|||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
this->chanList.add ( chan );
|
this->chanList.add ( chan );
|
||||||
}
|
}
|
||||||
|
|
||||||
void casPVI::removeChannel (
|
void casPVI::removeChannel (
|
||||||
chanIntfForPV & chan, tsDLList < casMonitor > & src,
|
chanIntfForPV & chan, tsDLList < casMonitor > & src,
|
||||||
tsDLList < casMonitor > & dest )
|
tsDLList < casMonitor > & dest )
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
@@ -380,8 +383,8 @@ void casPVI::clearOutstandingReads ( tsDLList < casAsyncIOI > & ioList )
|
|||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
|
|
||||||
// cancel any pending asynchronous IO
|
// cancel any pending asynchronous IO
|
||||||
tsDLIter < casAsyncIOI > iterIO =
|
tsDLIter < casAsyncIOI > iterIO =
|
||||||
ioList.firstIter ();
|
ioList.firstIter ();
|
||||||
while ( iterIO.valid () ) {
|
while ( iterIO.valid () ) {
|
||||||
tsDLIter < casAsyncIOI > tmp = iterIO;
|
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 )
|
tsDLList < casAsyncIOI > & ioList, casAsyncIOI & io )
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
@@ -416,7 +419,7 @@ void casPVI::installIO (
|
|||||||
this->nIOAttached++;
|
this->nIOAttached++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void casPVI::uninstallIO (
|
void casPVI::uninstallIO (
|
||||||
tsDLList < casAsyncIOI > & ioList, casAsyncIOI & io )
|
tsDLList < casAsyncIOI > & ioList, casAsyncIOI & io )
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -517,8 +520,8 @@ aitEnum casPVI::bestExternalType () const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CA only does 1D arrays for now
|
// CA only does 1D arrays for now
|
||||||
aitIndex casPVI::nativeCount ()
|
aitIndex casPVI::nativeCount ()
|
||||||
{
|
{
|
||||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||||
if ( this->pPV ) {
|
if ( this->pPV ) {
|
||||||
@@ -542,4 +545,3 @@ const char * casPVI::getName () const
|
|||||||
return "<disconnected>";
|
return "<disconnected>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1401,7 +1401,7 @@ caStatus casStrmClient :: searchAction ( epicsGuard < casClientMutex > & guard )
|
|||||||
|
|
||||||
if ( pChanName[0] == '\0' ) {
|
if ( pChanName[0] == '\0' ) {
|
||||||
caServerI::dumpMsg ( this->pHostName, "?", mp, this->ctx.getData(),
|
caServerI::dumpMsg ( this->pHostName, "?", mp, this->ctx.getData(),
|
||||||
"zero length PV name in UDP search request?\n" );
|
"zero length PV name in TCP search request?\n" );
|
||||||
return S_cas_success;
|
return S_cas_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1411,7 +1411,7 @@ caStatus casStrmClient :: searchAction ( epicsGuard < casClientMutex > & guard )
|
|||||||
for ( unsigned i = mp->m_postsize-1; pChanName[i] != '\0'; i-- ) {
|
for ( unsigned i = mp->m_postsize-1; pChanName[i] != '\0'; i-- ) {
|
||||||
if ( i <= 1 ) {
|
if ( i <= 1 ) {
|
||||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||||
"unterminated PV name in UDP search request?\n" );
|
"unterminated PV name in TCP search request?\n" );
|
||||||
return S_cas_success;
|
return S_cas_success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ DBDINC += menuScan
|
|||||||
DBDINC += dbCommon
|
DBDINC += dbCommon
|
||||||
|
|
||||||
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
|
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
|
||||||
HTMLS += $(patsubst %.dbd.pod,%.html,$(menusPod))
|
HTMLS += $(patsubst %.dbd.pod,%.html,$(dbMenusPod))
|
||||||
|
|
||||||
dbCore_SRCS += dbLock.c
|
dbCore_SRCS += dbLock.c
|
||||||
dbCore_SRCS += dbAccess.c
|
dbCore_SRCS += dbAccess.c
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include "epicsExport.h"
|
#include "epicsExport.h"
|
||||||
#include "link.h"
|
#include "link.h"
|
||||||
#include "recSup.h"
|
#include "recSup.h"
|
||||||
|
#include "dbUnitTest.h" /* for testSyncCallback() */
|
||||||
|
|
||||||
|
|
||||||
static int callbackQueueSize = 2000;
|
static int callbackQueueSize = 2000;
|
||||||
@@ -53,6 +54,7 @@ typedef struct cbQueueSet {
|
|||||||
epicsEventId semWakeUp;
|
epicsEventId semWakeUp;
|
||||||
epicsRingPointerId queue;
|
epicsRingPointerId queue;
|
||||||
int queueOverflow;
|
int queueOverflow;
|
||||||
|
int queueOverflows;
|
||||||
int shutdown;
|
int shutdown;
|
||||||
int threadsConfigured;
|
int threadsConfigured;
|
||||||
int threadsRunning;
|
int threadsRunning;
|
||||||
@@ -102,6 +104,51 @@ int callbackSetQueueSize(int size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int callbackQueueStatus(const int reset, callbackQueueStats *result)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (!callbackIsInit) return -1;
|
||||||
|
if (result) {
|
||||||
|
int prio;
|
||||||
|
result->size = callbackQueueSize;
|
||||||
|
for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||||
|
epicsRingPointerId qId = callbackQueue[prio].queue;
|
||||||
|
result->numUsed[prio] = epicsRingPointerGetUsed(qId);
|
||||||
|
result->maxUsed[prio] = epicsRingPointerGetHighWaterMark(qId);
|
||||||
|
result->numOverflow[prio] = epicsAtomicGetIntT(&callbackQueue[prio].queueOverflows);
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
ret = -2;
|
||||||
|
}
|
||||||
|
if (reset) {
|
||||||
|
int prio;
|
||||||
|
for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||||
|
epicsRingPointerResetHighWaterMark(callbackQueue[prio].queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void callbackQueueShow(const int reset)
|
||||||
|
{
|
||||||
|
callbackQueueStats stats;
|
||||||
|
if (callbackQueueStatus(reset, &stats) == -1) {
|
||||||
|
fprintf(stderr, "Callback system not initialized, yet. Please run "
|
||||||
|
"iocInit before using this command.\n");
|
||||||
|
} else {
|
||||||
|
int prio;
|
||||||
|
printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n");
|
||||||
|
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||||
|
double qusage = 100.0 * stats.numUsed[prio] / stats.size;
|
||||||
|
printf("%8s %15d %10d %6d %6.1f %11d\n",
|
||||||
|
threadNamePrefix[prio], stats.maxUsed[prio],
|
||||||
|
stats.numUsed[prio], stats.size, qusage,
|
||||||
|
stats.numOverflow[prio]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int callbackParallelThreads(int count, const char *prio)
|
int callbackParallelThreads(int count, const char *prio)
|
||||||
{
|
{
|
||||||
if (callbackIsInit) {
|
if (callbackIsInit) {
|
||||||
@@ -289,6 +336,7 @@ int callbackRequest(CALLBACK *pcallback)
|
|||||||
if (!pushOK) {
|
if (!pushOK) {
|
||||||
epicsInterruptContextMessage(fullMessage[priority]);
|
epicsInterruptContextMessage(fullMessage[priority]);
|
||||||
mySet->queueOverflow = TRUE;
|
mySet->queueOverflow = TRUE;
|
||||||
|
epicsAtomicIncrIntT(&mySet->queueOverflows);
|
||||||
return S_db_bufFull;
|
return S_db_bufFull;
|
||||||
}
|
}
|
||||||
epicsEventSignal(mySet->semWakeUp);
|
epicsEventSignal(mySet->semWakeUp);
|
||||||
@@ -352,3 +400,86 @@ void callbackRequestProcessCallbackDelayed(CALLBACK *pcallback,
|
|||||||
callbackSetProcess(pcallback, Priority, pRec);
|
callbackSetProcess(pcallback, Priority, pRec);
|
||||||
callbackRequestDelayed(pcallback, seconds);
|
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,10 +42,19 @@ typedef struct callbackPvt {
|
|||||||
int priority;
|
int priority;
|
||||||
void *user; /*for use by callback user*/
|
void *user; /*for use by callback user*/
|
||||||
void *timer; /*for use by callback itself*/
|
void *timer; /*for use by callback itself*/
|
||||||
}CALLBACK;
|
}epicsCallback;
|
||||||
|
|
||||||
|
typedef epicsCallback CALLBACK;
|
||||||
|
|
||||||
typedef void (*CALLBACKFUNC)(struct callbackPvt*);
|
typedef void (*CALLBACKFUNC)(struct callbackPvt*);
|
||||||
|
|
||||||
|
typedef struct callbackQueueStats {
|
||||||
|
int size;
|
||||||
|
int numUsed[NUM_CALLBACK_PRIORITIES];
|
||||||
|
int maxUsed[NUM_CALLBACK_PRIORITIES];
|
||||||
|
int numOverflow[NUM_CALLBACK_PRIORITIES];
|
||||||
|
} callbackQueueStats;
|
||||||
|
|
||||||
#define callbackSetCallback(PFUN, PCALLBACK) \
|
#define callbackSetCallback(PFUN, PCALLBACK) \
|
||||||
( (PCALLBACK)->callback = (PFUN) )
|
( (PCALLBACK)->callback = (PFUN) )
|
||||||
#define callbackSetPriority(PRIORITY, PCALLBACK) \
|
#define callbackSetPriority(PRIORITY, PCALLBACK) \
|
||||||
@@ -71,6 +80,8 @@ epicsShareFunc void callbackCancelDelayed(CALLBACK *pcallback);
|
|||||||
epicsShareFunc void callbackRequestProcessCallbackDelayed(
|
epicsShareFunc void callbackRequestProcessCallbackDelayed(
|
||||||
CALLBACK *pCallback, int Priority, void *pRec, double seconds);
|
CALLBACK *pCallback, int Priority, void *pRec, double seconds);
|
||||||
epicsShareFunc int callbackSetQueueSize(int size);
|
epicsShareFunc int callbackSetQueueSize(int size);
|
||||||
|
epicsShareFunc int callbackQueueStatus(const int reset, callbackQueueStats *result);
|
||||||
|
epicsShareFunc void callbackQueueShow(const int reset);
|
||||||
epicsShareFunc int callbackParallelThreads(int count, const char *prio);
|
epicsShareFunc int callbackParallelThreads(int count, const char *prio);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include "errlog.h"
|
#include "errlog.h"
|
||||||
#include "errMdef.h"
|
#include "errMdef.h"
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#include "epicsExport.h" /* #define epicsExportSharedSymbols */
|
||||||
#include "caeventmask.h"
|
#include "caeventmask.h"
|
||||||
#include "callback.h"
|
#include "callback.h"
|
||||||
#include "dbAccessDefs.h"
|
#include "dbAccessDefs.h"
|
||||||
@@ -65,6 +65,9 @@
|
|||||||
epicsShareDef struct dbBase *pdbbase = 0;
|
epicsShareDef struct dbBase *pdbbase = 0;
|
||||||
epicsShareDef volatile int interruptAccept=FALSE;
|
epicsShareDef volatile int interruptAccept=FALSE;
|
||||||
|
|
||||||
|
epicsShareDef int dbAccessDebugPUTF = 0;
|
||||||
|
epicsExportAddress(int, dbAccessDebugPUTF);
|
||||||
|
|
||||||
/* Hook Routines */
|
/* Hook Routines */
|
||||||
|
|
||||||
epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
|
epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
|
||||||
@@ -293,10 +296,14 @@ static void get_alarm(DBADDR *paddr, char **ppbuffer,
|
|||||||
if (*options & DBR_AL_LONG) {
|
if (*options & DBR_AL_LONG) {
|
||||||
struct dbr_alLong *pal = (struct dbr_alLong*) pbuffer;
|
struct dbr_alLong *pal = (struct dbr_alLong*) pbuffer;
|
||||||
|
|
||||||
pal->upper_alarm_limit = (epicsInt32) ald.upper_alarm_limit;
|
pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ?
|
||||||
pal->upper_warning_limit = (epicsInt32) ald.upper_warning_limit;
|
(epicsInt32) ald.upper_alarm_limit : 0;
|
||||||
pal->lower_warning_limit = (epicsInt32) ald.lower_warning_limit;
|
pal->upper_warning_limit = finite(ald.upper_warning_limit) ?
|
||||||
pal->lower_alarm_limit = (epicsInt32) ald.lower_alarm_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)
|
if (no_data)
|
||||||
*options ^= DBR_AL_LONG; /*Turn off option*/
|
*options ^= DBR_AL_LONG; /*Turn off option*/
|
||||||
@@ -442,22 +449,6 @@ int dbGetFieldIndex(const struct dbAddr *paddr)
|
|||||||
return paddr->pfldDes->indRecordType;
|
return paddr->pfldDes->indRecordType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Process a record if its scan field is passive.
|
|
||||||
* Will notify if processing is complete by callback.
|
|
||||||
* (only if you are interested in completion)
|
|
||||||
*/
|
|
||||||
long dbScanPassive(dbCommon *pfrom, dbCommon *pto)
|
|
||||||
{
|
|
||||||
/* if not passive just return success */
|
|
||||||
if (pto->scan != 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (pfrom && pfrom->ppn)
|
|
||||||
dbNotifyAdd(pfrom,pto);
|
|
||||||
return dbProcess(pto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process the record.
|
* Process the record.
|
||||||
* 1. Check for breakpoints.
|
* 1. Check for breakpoints.
|
||||||
@@ -523,7 +514,8 @@ long dbProcess(dbCommon *precord)
|
|||||||
unsigned short monitor_mask;
|
unsigned short monitor_mask;
|
||||||
|
|
||||||
if (*ptrace)
|
if (*ptrace)
|
||||||
printf("%s: Active %s\n", context, precord->name);
|
printf("%s: dbProcess of Active '%s' with RPRO=%d\n",
|
||||||
|
context, precord->name, precord->rpro);
|
||||||
|
|
||||||
/* raise scan alarm after MAX_LOCK times */
|
/* raise scan alarm after MAX_LOCK times */
|
||||||
if ((precord->stat == SCAN_ALARM) ||
|
if ((precord->stat == SCAN_ALARM) ||
|
||||||
@@ -552,7 +544,8 @@ long dbProcess(dbCommon *precord)
|
|||||||
/* if disabled check disable alarm severity and return success */
|
/* if disabled check disable alarm severity and return success */
|
||||||
if (precord->disa == precord->disv) {
|
if (precord->disa == precord->disv) {
|
||||||
if (*ptrace)
|
if (*ptrace)
|
||||||
printf("%s: Disabled %s\n", context, precord->name);
|
printf("%s: dbProcess of Disabled '%s'\n",
|
||||||
|
context, precord->name);
|
||||||
|
|
||||||
/*take care of caching and notifyCompletion*/
|
/*take care of caching and notifyCompletion*/
|
||||||
precord->rpro = FALSE;
|
precord->rpro = FALSE;
|
||||||
@@ -589,7 +582,7 @@ long dbProcess(dbCommon *precord)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*ptrace)
|
if (*ptrace)
|
||||||
printf("%s: Process %s\n", context, precord->name);
|
printf("%s: dbProcess of '%s'\n", context, precord->name);
|
||||||
|
|
||||||
/* process record */
|
/* process record */
|
||||||
status = prset->process(precord);
|
status = prset->process(precord);
|
||||||
@@ -709,6 +702,18 @@ void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
|
|||||||
pdbentry->precnode = ppvt->recnode;
|
pdbentry->precnode = ppvt->recnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct link* dbGetDevLink(struct dbCommon* prec)
|
||||||
|
{
|
||||||
|
DBLINK *plink = 0;
|
||||||
|
DBENTRY entry;
|
||||||
|
dbInitEntryFromRecord(prec, &entry);
|
||||||
|
if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) {
|
||||||
|
plink = (DBLINK*)entry.pfield;
|
||||||
|
}
|
||||||
|
dbFinishEntry(&entry);
|
||||||
|
return plink;
|
||||||
|
}
|
||||||
|
|
||||||
long dbValueSize(short dbr_type)
|
long dbValueSize(short dbr_type)
|
||||||
{
|
{
|
||||||
/* sizes for value associated with each DBR request type */
|
/* sizes for value associated with each DBR request type */
|
||||||
@@ -1036,7 +1041,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
|||||||
return S_db_badDbrtype;
|
return S_db_badDbrtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = dbParseLink(pstring, pfldDes->field_type, &link_info, 0);
|
status = dbParseLink(pstring, pfldDes->field_type, &link_info);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -1209,8 +1214,8 @@ long dbPutField(DBADDR *paddr, short dbrType,
|
|||||||
precord->scan == 0 &&
|
precord->scan == 0 &&
|
||||||
dbrType < DBR_PUT_ACKT)) {
|
dbrType < DBR_PUT_ACKT)) {
|
||||||
if (precord->pact) {
|
if (precord->pact) {
|
||||||
if (precord->tpro)
|
if (dbAccessDebugPUTF && precord->tpro)
|
||||||
printf("%s: Active %s\n",
|
printf("%s: dbPutField to Active '%s', setting RPRO=1\n",
|
||||||
epicsThreadGetNameSelf(), precord->name);
|
epicsThreadGetNameSelf(), precord->name);
|
||||||
precord->rpro = TRUE;
|
precord->rpro = TRUE;
|
||||||
} else {
|
} else {
|
||||||
@@ -1343,4 +1348,3 @@ done:
|
|||||||
paddr->pfield = pfieldsave;
|
paddr->pfield = pfieldsave;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ extern "C" {
|
|||||||
|
|
||||||
epicsShareExtern struct dbBase *pdbbase;
|
epicsShareExtern struct dbBase *pdbbase;
|
||||||
epicsShareExtern volatile int interruptAccept;
|
epicsShareExtern volatile int interruptAccept;
|
||||||
|
epicsShareExtern int dbAccessDebugPUTF;
|
||||||
|
|
||||||
/* The database field and request types are defined in dbFldTypes.h*/
|
/* The database field and request types are defined in dbFldTypes.h*/
|
||||||
/* Data Base Request Options */
|
/* Data Base Request Options */
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ long dbd(const char *record_name)
|
|||||||
|
|
||||||
precord = addr.precord;
|
precord = addr.precord;
|
||||||
|
|
||||||
if (! (precord->bkpt & BKPT_ON_MASK)) {
|
if (!(precord->bkpt & BKPT_ON_MASK)) {
|
||||||
printf(" BKPT> No breakpoint set in this record\n");
|
printf(" BKPT> No breakpoint set in this record\n");
|
||||||
return(S_db_bkptNotSet);
|
return(S_db_bkptNotSet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -703,7 +703,12 @@ static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
|
|||||||
caLink *pca;
|
caLink *pca;
|
||||||
long status;
|
long status;
|
||||||
|
|
||||||
pcaGetCheck
|
assert(plink);
|
||||||
|
if (plink->type != CA_LINK) return -1;
|
||||||
|
pca = (caLink *)plink->value.pv_link.pvt;
|
||||||
|
assert(pca);
|
||||||
|
epicsMutexMustLock(pca->lock);
|
||||||
|
assert(pca->plink);
|
||||||
status = rtn(plink, priv);
|
status = rtn(plink, priv);
|
||||||
epicsMutexUnlock(pca->lock);
|
epicsMutexUnlock(pca->lock);
|
||||||
return status;
|
return status;
|
||||||
@@ -784,11 +789,16 @@ static void connectionCallback(struct connection_handler_args arg)
|
|||||||
if (pca->gotFirstConnection) {
|
if (pca->gotFirstConnection) {
|
||||||
if (pca->nelements != ca_element_count(arg.chid) ||
|
if (pca->nelements != ca_element_count(arg.chid) ||
|
||||||
pca->dbrType != ca_field_type(arg.chid)) {
|
pca->dbrType != ca_field_type(arg.chid)) {
|
||||||
/* BUG: We have no way to clear any old subscription with the
|
/* Size or type changed, clear everything and let the next call
|
||||||
* originally chosen data type/size. That will continue
|
to dbCaGetLink() and/or dbCaPutLink() reset everything */
|
||||||
* to send us data and will result in an assert() fail.
|
if (pca->evidNative) {
|
||||||
*/
|
ca_clear_event(pca->evidNative);
|
||||||
/* Let next dbCaGetLink and/or dbCaPutLink determine options */
|
pca->evidNative = 0;
|
||||||
|
}
|
||||||
|
if (pca->evidString) {
|
||||||
|
ca_clear_event(pca->evidString);
|
||||||
|
pca->evidString = 0;
|
||||||
|
}
|
||||||
plink->value.pv_link.pvlMask &=
|
plink->value.pv_link.pvlMask &=
|
||||||
~(pvlOptInpNative | pvlOptInpString |
|
~(pvlOptInpNative | pvlOptInpString |
|
||||||
pvlOptOutNative | pvlOptOutString);
|
pvlOptOutNative | pvlOptOutString);
|
||||||
@@ -837,6 +847,7 @@ static void eventCallback(struct event_handler_args arg)
|
|||||||
struct dbr_time_double *pdbr_time_double;
|
struct dbr_time_double *pdbr_time_double;
|
||||||
dbCaCallback monitor = 0;
|
dbCaCallback monitor = 0;
|
||||||
void *userPvt = 0;
|
void *userPvt = 0;
|
||||||
|
int doScan = 1;
|
||||||
|
|
||||||
assert(pca);
|
assert(pca);
|
||||||
epicsMutexMustLock(pca->lock);
|
epicsMutexMustLock(pca->lock);
|
||||||
@@ -867,10 +878,13 @@ static void eventCallback(struct event_handler_args arg)
|
|||||||
memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size);
|
memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size);
|
||||||
pca->gotInString = TRUE;
|
pca->gotInString = TRUE;
|
||||||
} else switch (arg.type){
|
} 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_STRING:
|
||||||
case DBR_TIME_SHORT:
|
case DBR_TIME_SHORT:
|
||||||
case DBR_TIME_FLOAT:
|
case DBR_TIME_FLOAT:
|
||||||
case DBR_TIME_ENUM:
|
|
||||||
case DBR_TIME_CHAR:
|
case DBR_TIME_CHAR:
|
||||||
case DBR_TIME_LONG:
|
case DBR_TIME_LONG:
|
||||||
case DBR_TIME_DOUBLE:
|
case DBR_TIME_DOUBLE:
|
||||||
@@ -888,7 +902,7 @@ static void eventCallback(struct event_handler_args arg)
|
|||||||
pca->sevr = pdbr_time_double->severity;
|
pca->sevr = pdbr_time_double->severity;
|
||||||
pca->stat = pdbr_time_double->status;
|
pca->stat = pdbr_time_double->status;
|
||||||
memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp));
|
memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp));
|
||||||
if (precord) {
|
if (doScan && precord) {
|
||||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||||
|
|
||||||
if ((ppv_link->pvlMask & pvlOptCP) ||
|
if ((ppv_link->pvlMask & pvlOptCP) ||
|
||||||
@@ -1149,7 +1163,8 @@ static void dbCaTask(void *arg)
|
|||||||
status = ca_add_array_event(
|
status = ca_add_array_event(
|
||||||
dbf_type_to_DBR_TIME(ca_field_type(pca->chid)),
|
dbf_type_to_DBR_TIME(ca_field_type(pca->chid)),
|
||||||
0, /* dynamic size */
|
0, /* dynamic size */
|
||||||
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) {
|
if (status != ECA_NORMAL) {
|
||||||
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
||||||
ca_message(status));
|
ca_message(status));
|
||||||
@@ -1161,7 +1176,8 @@ static void dbCaTask(void *arg)
|
|||||||
pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
|
pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
|
||||||
epicsMutexUnlock(pca->lock);
|
epicsMutexUnlock(pca->lock);
|
||||||
status = ca_add_array_event(DBR_TIME_STRING, 1,
|
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) {
|
if (status != ECA_NORMAL) {
|
||||||
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
||||||
ca_message(status));
|
ca_message(status));
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ typedef struct caLink
|
|||||||
char *pgetString;
|
char *pgetString;
|
||||||
void *pputNative;
|
void *pputNative;
|
||||||
char *pputString;
|
char *pputString;
|
||||||
|
evid evidNative;
|
||||||
|
evid evidString;
|
||||||
char gotInNative;
|
char gotInNative;
|
||||||
char gotInString;
|
char gotInString;
|
||||||
char gotOutNative;
|
char gotOutNative;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "cantProceed.h"
|
#include "cantProceed.h"
|
||||||
#include "epicsAssert.h"
|
#include "epicsAssert.h"
|
||||||
#include "epicsString.h"
|
#include "epicsString.h"
|
||||||
|
#include "epicsStdio.h"
|
||||||
#include "errlog.h"
|
#include "errlog.h"
|
||||||
#include "freeList.h"
|
#include "freeList.h"
|
||||||
#include "gpHash.h"
|
#include "gpHash.h"
|
||||||
|
|||||||
@@ -12,6 +12,29 @@
|
|||||||
* Current Author: Andrew Johnson
|
* Current Author: Andrew Johnson
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* The PUTF and RPRO fields in dbCommon are flags that indicate when a record
|
||||||
|
* is being processed as a result of an external put (i.e. some server process
|
||||||
|
* calling dbPutField()), ensuring that the record and its successors will
|
||||||
|
* eventually get processed even if they happen to be busy at the time of the
|
||||||
|
* put. From Base-3.16.2 and 7.0.2 the code ensures that all records downstream
|
||||||
|
* from the original are processed even if a busy asynchronous device appears
|
||||||
|
* in the processing chain (this breaks the chain in older versions).
|
||||||
|
*
|
||||||
|
* PUTF - This field is set in dbPutField() prior to it calling dbProcess().
|
||||||
|
* It is normally cleared at the end of processing in recGblFwdLink().
|
||||||
|
* It may also be cleared in dbProcess() if DISA==DISV (scan disabled),
|
||||||
|
* or by the processTarget() function below.
|
||||||
|
*
|
||||||
|
* If PUTF is TRUE before a call to dbProcess(prec), then after it returns
|
||||||
|
* either PACT is TRUE, or PUTF will be FALSE.
|
||||||
|
*
|
||||||
|
* RPRO - This field is set by dbPutField() or by the processTarget() function
|
||||||
|
* below when a record to be processed is found to be busy (PACT==1).
|
||||||
|
* It is normally cleared in recGblFwdLink() when the record is queued
|
||||||
|
* for re-processing, or in dbProcess() if DISA==DISV (scan disabled).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -43,17 +66,22 @@
|
|||||||
#include "dbNotify.h"
|
#include "dbNotify.h"
|
||||||
#include "dbScan.h"
|
#include "dbScan.h"
|
||||||
#include "dbStaticLib.h"
|
#include "dbStaticLib.h"
|
||||||
|
#include "dbServer.h"
|
||||||
#include "devSup.h"
|
#include "devSup.h"
|
||||||
#include "link.h"
|
#include "link.h"
|
||||||
#include "recGbl.h"
|
#include "recGbl.h"
|
||||||
#include "recSup.h"
|
#include "recSup.h"
|
||||||
#include "special.h"
|
#include "special.h"
|
||||||
|
#include "dbDbLink.h"
|
||||||
|
|
||||||
|
|
||||||
/***************************** Database Links *****************************/
|
/***************************** Database Links *****************************/
|
||||||
|
|
||||||
/* Forward definition */
|
/* Forward definitions */
|
||||||
static lset dbDb_lset;
|
static lset dbDb_lset;
|
||||||
|
|
||||||
|
static long processTarget(dbCommon *psrc, dbCommon *pdst);
|
||||||
|
|
||||||
long dbDbInitLink(struct link *plink, short dbfType)
|
long dbDbInitLink(struct link *plink, short dbfType)
|
||||||
{
|
{
|
||||||
DBADDR dbaddr;
|
DBADDR dbaddr;
|
||||||
@@ -138,11 +166,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
|||||||
|
|
||||||
/* scan passive records if link is process passive */
|
/* scan passive records if link is process passive */
|
||||||
if (ppv_link->pvlMask & pvlOptPP) {
|
if (ppv_link->pvlMask & pvlOptPP) {
|
||||||
unsigned char pact = precord->pact;
|
|
||||||
|
|
||||||
precord->pact = TRUE;
|
|
||||||
status = dbScanPassive(precord, paddr->precord);
|
status = dbScanPassive(precord, paddr->precord);
|
||||||
precord->pact = pact;
|
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -311,22 +335,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
|
|||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (paddr->pfield == (void *) &pdest->proc ||
|
if (paddr->pfield == (void *) &pdest->proc ||
|
||||||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
|
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
|
||||||
/* if dbPutField caused asyn record to process */
|
status = processTarget(psrce, pdest);
|
||||||
/* ask for reprocessing*/
|
|
||||||
if (pdest->putf) {
|
|
||||||
pdest->rpro = TRUE;
|
|
||||||
} else { /* process dest record with source's PACT true */
|
|
||||||
unsigned char pact;
|
|
||||||
|
|
||||||
if (psrce && psrce->ppn)
|
|
||||||
dbNotifyAdd(psrce, pdest);
|
|
||||||
pact = psrce->pact;
|
|
||||||
psrce->pact = TRUE;
|
|
||||||
status = dbProcess(pdest);
|
|
||||||
psrce->pact = pact;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,3 +368,75 @@ static lset dbDb_lset = {
|
|||||||
dbDbPutValue, NULL,
|
dbDbPutValue, NULL,
|
||||||
dbDbScanFwdLink, doLocked
|
dbDbScanFwdLink, doLocked
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a record if its scan field is passive.
|
||||||
|
*/
|
||||||
|
long dbScanPassive(dbCommon *pfrom, dbCommon *pto)
|
||||||
|
{
|
||||||
|
/* if not passive we're done */
|
||||||
|
if (pto->scan != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return processTarget(pfrom, pto);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long processTarget(dbCommon *psrc, dbCommon *pdst)
|
||||||
|
{
|
||||||
|
char context[40] = "";
|
||||||
|
int trace = dbAccessDebugPUTF && *dbLockSetAddrTrace(psrc);
|
||||||
|
long status;
|
||||||
|
epicsUInt8 pact = psrc->pact;
|
||||||
|
|
||||||
|
psrc->pact = TRUE;
|
||||||
|
|
||||||
|
if (psrc && psrc->ppn)
|
||||||
|
dbNotifyAdd(psrc, pdst);
|
||||||
|
|
||||||
|
if (trace && dbServerClient(context, sizeof(context))) {
|
||||||
|
/* No client, use thread name */
|
||||||
|
strncpy(context, epicsThreadGetNameSelf(), sizeof(context));
|
||||||
|
context[sizeof(context) - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pdst->pact) {
|
||||||
|
/* Normal propagation of PUTF from src to dst */
|
||||||
|
if (trace)
|
||||||
|
printf("%s: '%s' -> '%s' with PUTF=%u\n",
|
||||||
|
context, psrc->name, pdst->name, psrc->putf);
|
||||||
|
|
||||||
|
if (pdst->putf)
|
||||||
|
errlogPrintf("Warning: '%s.PUTF' found true with PACT false\n",
|
||||||
|
pdst->name);
|
||||||
|
|
||||||
|
pdst->putf = psrc->putf;
|
||||||
|
}
|
||||||
|
else if (psrc->putf) {
|
||||||
|
/* The dst record is busy (awaiting async reprocessing) and
|
||||||
|
* we were originally triggered by a call to dbPutField(),
|
||||||
|
* so we mark the dst record for reprocessing once the async
|
||||||
|
* completion is over.
|
||||||
|
*/
|
||||||
|
if (trace)
|
||||||
|
printf("%s: '%s' -> Active '%s', setting RPRO=1\n",
|
||||||
|
context, psrc->name, pdst->name);
|
||||||
|
|
||||||
|
pdst->putf = FALSE;
|
||||||
|
pdst->rpro = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* The dst record is busy, but we weren't triggered by a call
|
||||||
|
* to dbPutField(). Do nothing.
|
||||||
|
*/
|
||||||
|
if (trace)
|
||||||
|
printf("%s: '%s' -> Active '%s', done\n",
|
||||||
|
context, psrc->name, pdst->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = dbProcess(pdst);
|
||||||
|
|
||||||
|
psrc->pact = pact;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ static char *EVENT_PEND_NAME = "eventTask";
|
|||||||
|
|
||||||
static struct evSubscrip canceledEvent;
|
static struct evSubscrip canceledEvent;
|
||||||
|
|
||||||
|
static epicsMutexId stopSync;
|
||||||
|
|
||||||
static unsigned short ringSpace ( const struct event_que *pevq )
|
static unsigned short ringSpace ( const struct event_que *pevq )
|
||||||
{
|
{
|
||||||
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
|
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
|
||||||
@@ -258,6 +260,10 @@ dbEventCtx db_init_events (void)
|
|||||||
{
|
{
|
||||||
struct event_user * evUser;
|
struct event_user * evUser;
|
||||||
|
|
||||||
|
if (!stopSync) {
|
||||||
|
stopSync = epicsMutexMustCreate();
|
||||||
|
}
|
||||||
|
|
||||||
if (!dbevEventUserFreeList) {
|
if (!dbevEventUserFreeList) {
|
||||||
freeListInitPvt(&dbevEventUserFreeList,
|
freeListInitPvt(&dbevEventUserFreeList,
|
||||||
sizeof(struct event_user),8);
|
sizeof(struct event_user),8);
|
||||||
@@ -337,6 +343,7 @@ epicsShareFunc void db_cleanup_events(void)
|
|||||||
dbevFieldLogFreeList = NULL;
|
dbevFieldLogFreeList = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* intentionally leak stopSync to avoid possible shutdown races */
|
||||||
/*
|
/*
|
||||||
* DB_CLOSE_EVENTS()
|
* DB_CLOSE_EVENTS()
|
||||||
*
|
*
|
||||||
@@ -372,11 +379,15 @@ void db_close_events (dbEventCtx ctx)
|
|||||||
|
|
||||||
epicsMutexUnlock ( evUser->lock );
|
epicsMutexUnlock ( evUser->lock );
|
||||||
|
|
||||||
|
epicsMutexMustLock (stopSync);
|
||||||
|
|
||||||
epicsEventDestroy(evUser->pexitsem);
|
epicsEventDestroy(evUser->pexitsem);
|
||||||
epicsEventDestroy(evUser->ppendsem);
|
epicsEventDestroy(evUser->ppendsem);
|
||||||
epicsEventDestroy(evUser->pflush_sem);
|
epicsEventDestroy(evUser->pflush_sem);
|
||||||
epicsMutexDestroy(evUser->lock);
|
epicsMutexDestroy(evUser->lock);
|
||||||
|
|
||||||
|
epicsMutexUnlock (stopSync);
|
||||||
|
|
||||||
freeListFree(dbevEventUserFreeList, evUser);
|
freeListFree(dbevEventUserFreeList, evUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,8 +1070,15 @@ static void event_task (void *pParm)
|
|||||||
|
|
||||||
taskwdRemove(epicsThreadGetIdSelf());
|
taskwdRemove(epicsThreadGetIdSelf());
|
||||||
|
|
||||||
|
/* use stopSync to ensure pexitsem is not destroy'd
|
||||||
|
* until epicsEventSignal() has returned.
|
||||||
|
*/
|
||||||
|
epicsMutexMustLock (stopSync);
|
||||||
|
|
||||||
epicsEventSignal(evUser->pexitsem);
|
epicsEventSignal(evUser->pexitsem);
|
||||||
|
|
||||||
|
epicsMutexUnlock(stopSync);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ static const iocshArg * const dbnrArgs[1] = {&dbnrArg0};
|
|||||||
static const iocshFuncDef dbnrFuncDef = {"dbnr",1,dbnrArgs};
|
static const iocshFuncDef dbnrFuncDef = {"dbnr",1,dbnrArgs};
|
||||||
static void dbnrCallFunc(const iocshArgBuf *args) { dbnr(args[0].ival);}
|
static void dbnrCallFunc(const iocshArgBuf *args) { dbnr(args[0].ival);}
|
||||||
|
|
||||||
|
/* dbli */
|
||||||
|
static const iocshArg dbliArg0 = { "pattern",iocshArgString};
|
||||||
|
static const iocshArg * const dbliArgs[1] = {&dbliArg0};
|
||||||
|
static const iocshFuncDef dbliFuncDef = {"dbli",1,dbliArgs};
|
||||||
|
static void dbliCallFunc(const iocshArgBuf *args) { dbli(args[0].sval);}
|
||||||
|
|
||||||
/* dbla */
|
/* dbla */
|
||||||
static const iocshArg dblaArg0 = { "pattern",iocshArgString};
|
static const iocshArg dblaArg0 = { "pattern",iocshArgString};
|
||||||
static const iocshArg * const dblaArgs[1] = {&dblaArg0};
|
static const iocshArg * const dblaArgs[1] = {&dblaArg0};
|
||||||
@@ -290,6 +296,17 @@ static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
|
|||||||
scanOnceSetQueueSize(args[0].ival);
|
scanOnceSetQueueSize(args[0].ival);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* scanOnceQueueShow */
|
||||||
|
static const iocshArg scanOnceQueueShowArg0 = { "reset",iocshArgInt};
|
||||||
|
static const iocshArg * const scanOnceQueueShowArgs[1] =
|
||||||
|
{&scanOnceQueueShowArg0};
|
||||||
|
static const iocshFuncDef scanOnceQueueShowFuncDef =
|
||||||
|
{"scanOnceQueueShow",1,scanOnceQueueShowArgs};
|
||||||
|
static void scanOnceQueueShowCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
scanOnceQueueShow(args[0].ival);
|
||||||
|
}
|
||||||
|
|
||||||
/* scanppl */
|
/* scanppl */
|
||||||
static const iocshArg scanpplArg0 = { "rate",iocshArgDouble};
|
static const iocshArg scanpplArg0 = { "rate",iocshArgDouble};
|
||||||
static const iocshArg * const scanpplArgs[1] = {&scanpplArg0};
|
static const iocshArg * const scanpplArgs[1] = {&scanpplArg0};
|
||||||
@@ -329,6 +346,17 @@ static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
|
|||||||
callbackSetQueueSize(args[0].ival);
|
callbackSetQueueSize(args[0].ival);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* callbackQueueShow */
|
||||||
|
static const iocshArg callbackQueueShowArg0 = { "reset", iocshArgInt};
|
||||||
|
static const iocshArg * const callbackQueueShowArgs[1] =
|
||||||
|
{&callbackQueueShowArg0};
|
||||||
|
static const iocshFuncDef callbackQueueShowFuncDef =
|
||||||
|
{"callbackQueueShow",1,callbackQueueShowArgs};
|
||||||
|
static void callbackQueueShowCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
callbackQueueShow(args[0].ival);
|
||||||
|
}
|
||||||
|
|
||||||
/* callbackParallelThreads */
|
/* callbackParallelThreads */
|
||||||
static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgInt};
|
static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgInt};
|
||||||
static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString};
|
static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString};
|
||||||
@@ -415,6 +443,7 @@ void dbIocRegister(void)
|
|||||||
iocshRegister(&dblFuncDef,dblCallFunc);
|
iocshRegister(&dblFuncDef,dblCallFunc);
|
||||||
iocshRegister(&dbnrFuncDef,dbnrCallFunc);
|
iocshRegister(&dbnrFuncDef,dbnrCallFunc);
|
||||||
iocshRegister(&dblaFuncDef,dblaCallFunc);
|
iocshRegister(&dblaFuncDef,dblaCallFunc);
|
||||||
|
iocshRegister(&dbliFuncDef,dbliCallFunc);
|
||||||
iocshRegister(&dbgrepFuncDef,dbgrepCallFunc);
|
iocshRegister(&dbgrepFuncDef,dbgrepCallFunc);
|
||||||
iocshRegister(&dbgfFuncDef,dbgfCallFunc);
|
iocshRegister(&dbgfFuncDef,dbgfCallFunc);
|
||||||
iocshRegister(&dbpfFuncDef,dbpfCallFunc);
|
iocshRegister(&dbpfFuncDef,dbpfCallFunc);
|
||||||
@@ -434,12 +463,14 @@ void dbIocRegister(void)
|
|||||||
iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc);
|
iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc);
|
||||||
|
|
||||||
iocshRegister(&scanOnceSetQueueSizeFuncDef,scanOnceSetQueueSizeCallFunc);
|
iocshRegister(&scanOnceSetQueueSizeFuncDef,scanOnceSetQueueSizeCallFunc);
|
||||||
|
iocshRegister(&scanOnceQueueShowFuncDef,scanOnceQueueShowCallFunc);
|
||||||
iocshRegister(&scanpplFuncDef,scanpplCallFunc);
|
iocshRegister(&scanpplFuncDef,scanpplCallFunc);
|
||||||
iocshRegister(&scanpelFuncDef,scanpelCallFunc);
|
iocshRegister(&scanpelFuncDef,scanpelCallFunc);
|
||||||
iocshRegister(&postEventFuncDef,postEventCallFunc);
|
iocshRegister(&postEventFuncDef,postEventCallFunc);
|
||||||
iocshRegister(&scanpiolFuncDef,scanpiolCallFunc);
|
iocshRegister(&scanpiolFuncDef,scanpiolCallFunc);
|
||||||
|
|
||||||
iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc);
|
iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc);
|
||||||
|
iocshRegister(&callbackQueueShowFuncDef,callbackQueueShowCallFunc);
|
||||||
iocshRegister(&callbackParallelThreadsFuncDef,callbackParallelThreadsCallFunc);
|
iocshRegister(&callbackParallelThreadsFuncDef,callbackParallelThreadsCallFunc);
|
||||||
|
|
||||||
/* Needed before callback system is initialized */
|
/* Needed before callback system is initialized */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||||
* National Laboratory.
|
* National Laboratory.
|
||||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
* 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.
|
||||||
\*************************************************************************/
|
\*************************************************************************/
|
||||||
/* dbJLink.c */
|
/* dbJLink.c */
|
||||||
|
|
||||||
@@ -25,19 +25,33 @@
|
|||||||
#include "dbLock.h"
|
#include "dbLock.h"
|
||||||
#include "dbStaticLib.h"
|
#include "dbStaticLib.h"
|
||||||
#include "link.h"
|
#include "link.h"
|
||||||
|
#include "epicsExport.h"
|
||||||
|
|
||||||
#define IFDEBUG(n) if(parser->parse_debug)
|
epicsShareDef int dbJLinkDebug = 0;
|
||||||
|
epicsExportAddress(int, dbJLinkDebug);
|
||||||
|
|
||||||
|
#define IFDEBUG(n) if (dbJLinkDebug >= (n))
|
||||||
|
|
||||||
typedef struct parseContext {
|
typedef struct parseContext {
|
||||||
jlink *pjlink;
|
jlink *pjlink;
|
||||||
jlink *product;
|
jlink *product;
|
||||||
short dbfType;
|
short dbfType;
|
||||||
short jsonDepth;
|
short jsonDepth;
|
||||||
unsigned key_is_link:1;
|
|
||||||
unsigned parse_debug:1;
|
|
||||||
unsigned lset_debug:1;
|
|
||||||
} parseContext;
|
} parseContext;
|
||||||
|
|
||||||
|
epicsShareDef const char *jlif_result_name[2] = {
|
||||||
|
"jlif_stop",
|
||||||
|
"jlif_continue",
|
||||||
|
};
|
||||||
|
|
||||||
|
epicsShareDef const char *jlif_key_result_name[5] = {
|
||||||
|
"jlif_key_stop",
|
||||||
|
"jlif_key_continue",
|
||||||
|
"jlif_key_child_inlink",
|
||||||
|
"jlif_key_child_outlink",
|
||||||
|
"jlif_key_child_fwdlink"
|
||||||
|
};
|
||||||
|
|
||||||
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
|
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
|
||||||
|
|
||||||
static int dbjl_return(parseContext *parser, jlif_result result) {
|
static int dbjl_return(parseContext *parser, jlif_result result) {
|
||||||
@@ -45,8 +59,8 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
|
|||||||
|
|
||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
||||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == jlif_stop && pjlink) {
|
if (result == jlif_stop && pjlink) {
|
||||||
@@ -59,6 +73,9 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
|
|||||||
pjlink->pif->free_jlink(pjlink);
|
pjlink->pif->free_jlink(pjlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IFDEBUG(10)
|
||||||
|
printf(" returning %d %s\n", result,
|
||||||
|
result == jlif_stop ? "*** STOP ***" : "Continue");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,8 +85,8 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
|
|||||||
|
|
||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
||||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == jlif_stop || pjlink->parseDepth > 0)
|
if (result == jlif_stop || pjlink->parseDepth > 0)
|
||||||
@@ -81,7 +98,6 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
|
|||||||
} else if (parent->pif->end_child) {
|
} else if (parent->pif->end_child) {
|
||||||
parent->pif->end_child(parent, pjlink);
|
parent->pif->end_child(parent, pjlink);
|
||||||
}
|
}
|
||||||
pjlink->debug = 0;
|
|
||||||
|
|
||||||
parser->pjlink = parent;
|
parser->pjlink = parent;
|
||||||
|
|
||||||
@@ -159,29 +175,46 @@ static int dbjl_start_map(void *ctx) {
|
|||||||
if (!pjlink) {
|
if (!pjlink) {
|
||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_start_map(NULL)\t");
|
printf("dbjl_start_map(NULL)\t");
|
||||||
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
|
||||||
parser->jsonDepth, parser->key_is_link);
|
parser->jsonDepth, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(parser->jsonDepth == 0);
|
assert(parser->jsonDepth == 0);
|
||||||
parser->jsonDepth++;
|
parser->jsonDepth++;
|
||||||
parser->key_is_link = 1;
|
|
||||||
return jlif_continue; /* Opening '{' */
|
return jlif_continue; /* Opening '{' */
|
||||||
}
|
}
|
||||||
|
|
||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
pjlink->parseDepth++;
|
pjlink->parseDepth++;
|
||||||
parser->jsonDepth++;
|
parser->jsonDepth++;
|
||||||
|
|
||||||
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
|
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
|
||||||
if (result == jlif_key_child_link) {
|
switch (result) {
|
||||||
parser->key_is_link = 1;
|
case jlif_key_child_inlink:
|
||||||
|
parser->dbfType = DBF_INLINK;
|
||||||
result = jlif_continue;
|
result = jlif_continue;
|
||||||
|
break;
|
||||||
|
case jlif_key_child_outlink:
|
||||||
|
parser->dbfType = DBF_OUTLINK;
|
||||||
|
result = jlif_continue;
|
||||||
|
break;
|
||||||
|
case jlif_key_child_fwdlink:
|
||||||
|
parser->dbfType = DBF_FWDLINK;
|
||||||
|
result = jlif_continue;
|
||||||
|
break;
|
||||||
|
case jlif_key_stop:
|
||||||
|
case jlif_key_continue:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errlogPrintf("dbJLinkInit: Bad return %d from '%s'::parse_start_map()\n",
|
||||||
|
result, pjlink->pif->name);
|
||||||
|
result = jlif_stop;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
IFDEBUG(10)
|
IFDEBUG(10)
|
||||||
@@ -196,8 +229,9 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
|||||||
char *link_name;
|
char *link_name;
|
||||||
linkSup *linkSup;
|
linkSup *linkSup;
|
||||||
jlif *pjlif;
|
jlif *pjlif;
|
||||||
|
jlink *child;
|
||||||
|
|
||||||
if (!parser->key_is_link) {
|
if (parser->dbfType == 0) {
|
||||||
if (!pjlink) {
|
if (!pjlink) {
|
||||||
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
|
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
|
||||||
(int) len, key);
|
(int) len, key);
|
||||||
@@ -207,8 +241,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
|||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
|
printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
|
||||||
pjlink->pif->name, pjlink, (int) len, key);
|
pjlink->pif->name, pjlink, (int) len, key);
|
||||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pjlink->parseDepth > 0);
|
assert(pjlink->parseDepth > 0);
|
||||||
@@ -219,8 +253,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
|||||||
|
|
||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key);
|
printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key);
|
||||||
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n",
|
||||||
parser->jsonDepth, parser->key_is_link);
|
parser->jsonDepth, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
link_name = dbmfStrndup((const char *) key, len);
|
link_name = dbmfStrndup((const char *) key, len);
|
||||||
@@ -241,27 +275,35 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
|
|||||||
return dbjl_return(parser, jlif_stop);
|
return dbjl_return(parser, jlif_stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbmfFree(link_name);
|
child = pjlif->alloc_jlink(parser->dbfType);
|
||||||
|
if (!child) {
|
||||||
pjlink = pjlif->alloc_jlink(parser->dbfType);
|
errlogPrintf("dbJLinkInit: Link type '%s' allocation failed. \n",
|
||||||
if (!pjlink) {
|
link_name);
|
||||||
errlogPrintf("dbJLinkInit: Out of memory\n");
|
dbmfFree(link_name);
|
||||||
return dbjl_return(parser, jlif_stop);
|
return dbjl_return(parser, jlif_stop);
|
||||||
}
|
}
|
||||||
pjlink->pif = pjlif;
|
|
||||||
pjlink->parent = NULL;
|
child->pif = pjlif;
|
||||||
pjlink->parseDepth = 0;
|
child->parseDepth = 0;
|
||||||
pjlink->debug = !!parser->lset_debug;
|
child->debug = 0;
|
||||||
|
|
||||||
if (parser->pjlink) {
|
if (parser->pjlink) {
|
||||||
/* We're starting a child link, save its parent */
|
/* We're starting a child link, save its parent */
|
||||||
pjlink->parent = parser->pjlink;
|
child->parent = pjlink;
|
||||||
|
|
||||||
|
if (pjlink->pif->start_child)
|
||||||
|
pjlink->pif->start_child(pjlink, child);
|
||||||
}
|
}
|
||||||
parser->pjlink = pjlink;
|
else
|
||||||
parser->key_is_link = 0;
|
child->parent = NULL;
|
||||||
|
|
||||||
|
parser->pjlink = child;
|
||||||
|
parser->dbfType = 0;
|
||||||
|
|
||||||
|
dbmfFree(link_name);
|
||||||
|
|
||||||
IFDEBUG(8)
|
IFDEBUG(8)
|
||||||
printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink);
|
printf("dbjl_map_key: New %s@%p\n", child ? child->pif->name : "", child);
|
||||||
|
|
||||||
return jlif_continue;
|
return jlif_continue;
|
||||||
}
|
}
|
||||||
@@ -274,9 +316,9 @@ static int dbjl_end_map(void *ctx) {
|
|||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_end_map(%s@%p)\t",
|
printf("dbjl_end_map(%s@%p)\t",
|
||||||
pjlink ? pjlink->pif->name : "NULL", pjlink);
|
pjlink ? pjlink->pif->name : "NULL", pjlink);
|
||||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0,
|
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0,
|
||||||
parser->key_is_link);
|
parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser->jsonDepth--;
|
parser->jsonDepth--;
|
||||||
@@ -298,8 +340,8 @@ static int dbjl_start_array(void *ctx) {
|
|||||||
|
|
||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pjlink);
|
assert(pjlink);
|
||||||
@@ -316,8 +358,8 @@ static int dbjl_end_array(void *ctx) {
|
|||||||
|
|
||||||
IFDEBUG(10) {
|
IFDEBUG(10) {
|
||||||
printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pjlink);
|
assert(pjlink);
|
||||||
@@ -335,7 +377,7 @@ static yajl_callbacks dbjl_callbacks = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
||||||
jlink **ppjlink, unsigned opts)
|
jlink **ppjlink)
|
||||||
{
|
{
|
||||||
parseContext context, *parser = &context;
|
parseContext context, *parser = &context;
|
||||||
yajl_alloc_funcs dbjl_allocs;
|
yajl_alloc_funcs dbjl_allocs;
|
||||||
@@ -347,17 +389,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
|||||||
parser->product = NULL;
|
parser->product = NULL;
|
||||||
parser->dbfType = dbfType;
|
parser->dbfType = dbfType;
|
||||||
parser->jsonDepth = 0;
|
parser->jsonDepth = 0;
|
||||||
parser->key_is_link = 0;
|
|
||||||
parser->parse_debug = !!(opts&LINK_DEBUG_JPARSE);
|
|
||||||
parser->lset_debug = !!(opts&LINK_DEBUG_LSET);
|
|
||||||
|
|
||||||
IFDEBUG(10)
|
IFDEBUG(10)
|
||||||
printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
|
printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
|
||||||
(int) jlen, json, dbfType, ppjlink);
|
(int) jlen, json, dbfType, ppjlink);
|
||||||
|
|
||||||
IFDEBUG(10)
|
IFDEBUG(10)
|
||||||
printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n",
|
printf("dbJLinkInit: jsonDepth=%d, dbfType=%d\n",
|
||||||
parser->jsonDepth, parser->key_is_link);
|
parser->jsonDepth, parser->dbfType);
|
||||||
|
|
||||||
yajl_set_default_alloc_funcs(&dbjl_allocs);
|
yajl_set_default_alloc_funcs(&dbjl_allocs);
|
||||||
yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser);
|
yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser);
|
||||||
@@ -365,8 +404,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
|||||||
return S_db_noMemory;
|
return S_db_noMemory;
|
||||||
|
|
||||||
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
|
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
|
||||||
if (ys == yajl_status_ok)
|
IFDEBUG(10)
|
||||||
|
printf("dbJLinkInit: yajl_parse() returned %d\n", ys);
|
||||||
|
|
||||||
|
if (ys == yajl_status_ok) {
|
||||||
ys = yajl_complete_parse(yh);
|
ys = yajl_complete_parse(yh);
|
||||||
|
IFDEBUG(10)
|
||||||
|
printf("dbJLinkInit: yajl_complete_parse() returned %d\n", ys);
|
||||||
|
}
|
||||||
|
|
||||||
switch (ys) {
|
switch (ys) {
|
||||||
unsigned char *err;
|
unsigned char *err;
|
||||||
@@ -378,6 +423,9 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case yajl_status_error:
|
case yajl_status_error:
|
||||||
|
IFDEBUG(10)
|
||||||
|
printf(" jsonDepth=%d, product=%p, pjlink=%p\n",
|
||||||
|
parser->jsonDepth, parser->product, parser->pjlink);
|
||||||
err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
|
err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
|
||||||
errlogPrintf("dbJLinkInit: %s\n", err);
|
errlogPrintf("dbJLinkInit: %s\n", err);
|
||||||
yajl_free_error(yh, err);
|
yajl_free_error(yh, err);
|
||||||
@@ -389,18 +437,24 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
yajl_free(yh);
|
yajl_free(yh);
|
||||||
|
|
||||||
|
IFDEBUG(10)
|
||||||
|
printf("dbJLinkInit: returning status=0x%lx\n\n",
|
||||||
|
status);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
long dbJLinkInit(struct link *plink)
|
long dbJLinkInit(struct link *plink)
|
||||||
{
|
{
|
||||||
jlink *pjlink;
|
|
||||||
|
|
||||||
assert(plink);
|
assert(plink);
|
||||||
pjlink = plink->value.json.jlink;
|
|
||||||
|
|
||||||
if (pjlink)
|
if (plink->type == JSON_LINK) {
|
||||||
plink->lset = pjlink->pif->get_lset(pjlink);
|
jlink *pjlink = plink->value.json.jlink;
|
||||||
|
|
||||||
|
if (pjlink)
|
||||||
|
plink->lset = pjlink->pif->get_lset(pjlink);
|
||||||
|
}
|
||||||
|
|
||||||
dbLinkOpen(plink);
|
dbLinkOpen(plink);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||||
* National Laboratory.
|
* National Laboratory.
|
||||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
* 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.
|
||||||
\*************************************************************************/
|
\*************************************************************************/
|
||||||
/* dbJLink.h */
|
/* dbJLink.h */
|
||||||
|
|
||||||
@@ -21,12 +21,16 @@ typedef enum {
|
|||||||
jlif_continue = 1
|
jlif_continue = 1
|
||||||
} jlif_result;
|
} jlif_result;
|
||||||
|
|
||||||
|
epicsShareExtern const char *jlif_result_name[2];
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
jlif_key_stop = jlif_stop,
|
jlif_key_stop = jlif_stop,
|
||||||
jlif_key_continue = jlif_continue,
|
jlif_key_continue = jlif_continue,
|
||||||
jlif_key_child_link
|
jlif_key_child_inlink, jlif_key_child_outlink, jlif_key_child_fwdlink
|
||||||
} jlif_key_result;
|
} jlif_key_result;
|
||||||
|
|
||||||
|
epicsShareExtern const char *jlif_key_result_name[5];
|
||||||
|
|
||||||
struct link;
|
struct link;
|
||||||
struct lset;
|
struct lset;
|
||||||
struct jlif;
|
struct jlif;
|
||||||
@@ -35,7 +39,7 @@ typedef struct jlink {
|
|||||||
struct jlif *pif; /* Link methods */
|
struct jlif *pif; /* Link methods */
|
||||||
struct jlink *parent; /* NULL for top-level links */
|
struct jlink *parent; /* NULL for top-level links */
|
||||||
int parseDepth; /* Used by parser, unused afterwards */
|
int parseDepth; /* Used by parser, unused afterwards */
|
||||||
unsigned debug:1; /* set by caller of jlif operations to request debug output to console */
|
unsigned debug:1; /* Set to request debug output to console */
|
||||||
/* Link types extend or embed this structure for private storage */
|
/* Link types extend or embed this structure for private storage */
|
||||||
} jlink;
|
} jlink;
|
||||||
|
|
||||||
@@ -72,8 +76,9 @@ typedef struct jlif {
|
|||||||
/* Optional, parser saw a string value */
|
/* Optional, parser saw a string value */
|
||||||
|
|
||||||
jlif_key_result (*parse_start_map)(jlink *);
|
jlif_key_result (*parse_start_map)(jlink *);
|
||||||
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_link
|
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_inlink,
|
||||||
* to expect a child link next (extra key/value pairs may follow).
|
* jlif_key_child_outlink, or jlif_key_child_fwdlink to expect a child
|
||||||
|
* link next (extra key/value pairs may follow)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
|
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
|
||||||
@@ -90,7 +95,8 @@ typedef struct jlif {
|
|||||||
|
|
||||||
void (*end_child)(jlink *parent, jlink *child);
|
void (*end_child)(jlink *parent, jlink *child);
|
||||||
/* Optional, called with pointer to the new child link after
|
/* Optional, called with pointer to the new child link after
|
||||||
* parse_start_map() returned jlif_key_child_link */
|
* the child link has finished parsing successfully
|
||||||
|
*/
|
||||||
|
|
||||||
struct lset* (*get_lset)(const jlink *);
|
struct lset* (*get_lset)(const jlink *);
|
||||||
/* Required, return lset for this link instance */
|
/* Required, return lset for this link instance */
|
||||||
@@ -98,7 +104,7 @@ typedef struct jlif {
|
|||||||
void (*report)(const jlink *, int level, int indent);
|
void (*report)(const jlink *, int level, int indent);
|
||||||
/* Optional, print status information about this link instance, then
|
/* Optional, print status information about this link instance, then
|
||||||
* if (level > 0) print a link identifier (at indent+2) and call
|
* if (level > 0) print a link identifier (at indent+2) and call
|
||||||
* dbJLinkReport(child, level-1, indent+4)
|
* dbJLinkReport(child, level-1, indent+4)
|
||||||
* for each child.
|
* for each child.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -107,13 +113,19 @@ typedef struct jlif {
|
|||||||
* Stop immediately and return status if non-zero.
|
* Stop immediately and return status if non-zero.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void (*start_child)(jlink *parent, jlink *child);
|
||||||
|
/* Optional, called with pointer to the new child link after
|
||||||
|
* parse_start_map() returned a jlif_key_child_link value and
|
||||||
|
* the child link has been allocated (but not parsed yet)
|
||||||
|
*/
|
||||||
|
|
||||||
/* Link types must NOT extend this table with their own routines,
|
/* Link types must NOT extend this table with their own routines,
|
||||||
* this space is reserved for extensions to the jlink interface.
|
* this space is reserved for extensions to the jlink interface.
|
||||||
*/
|
*/
|
||||||
} jlif;
|
} jlif;
|
||||||
|
|
||||||
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
|
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
|
||||||
jlink **ppjlink, unsigned opts);
|
jlink **ppjlink);
|
||||||
epicsShareFunc long dbJLinkInit(struct link *plink);
|
epicsShareFunc long dbJLinkInit(struct link *plink);
|
||||||
|
|
||||||
epicsShareFunc void dbJLinkFree(jlink *);
|
epicsShareFunc void dbJLinkFree(jlink *);
|
||||||
@@ -130,4 +142,3 @@ epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* INC_dbJLink_H */
|
#endif /* INC_dbJLink_H */
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
#include "special.h"
|
#include "special.h"
|
||||||
|
|
||||||
/* How to identify links in error messages */
|
/* How to identify links in error messages */
|
||||||
static const char * link_field_name(const struct link *plink)
|
const char * dbLinkFieldName(const struct link *plink)
|
||||||
{
|
{
|
||||||
const struct dbCommon *precord = plink->precord;
|
const struct dbCommon *precord = plink->precord;
|
||||||
const dbRecordType *pdbRecordType = precord->rdes;
|
const dbRecordType *pdbRecordType = precord->rdes;
|
||||||
@@ -136,7 +136,7 @@ void dbInitLink(struct link *plink, short dbfType)
|
|||||||
errlogPrintf("Forward-link uses Channel Access "
|
errlogPrintf("Forward-link uses Channel Access "
|
||||||
"without pointing to PROC field\n"
|
"without pointing to PROC field\n"
|
||||||
" %s.%s => %s\n",
|
" %s.%s => %s\n",
|
||||||
precord->name, link_field_name(plink),
|
precord->name, dbLinkFieldName(plink),
|
||||||
plink->value.pv_link.pvname);
|
plink->value.pv_link.pvname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,8 +265,19 @@ int dbIsLinkConnected(const struct link *plink)
|
|||||||
{
|
{
|
||||||
lset *plset = plink->lset;
|
lset *plset = plink->lset;
|
||||||
|
|
||||||
if (!plset || !plset->isConnected)
|
if (!plset)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
if (!plset->isVolatile)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!plset->isConnected) {
|
||||||
|
struct dbCommon *precord = plink->precord;
|
||||||
|
|
||||||
|
errlogPrintf("dbLink: Link type for '%s.%s' is volatile but has no"
|
||||||
|
" lset::isConnected() method\n",
|
||||||
|
precord->name, dbLinkFieldName(plink));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return plset->isConnected(plink);
|
return plset->isConnected(plink);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,60 +27,345 @@ extern "C" {
|
|||||||
|
|
||||||
struct dbLocker;
|
struct dbLocker;
|
||||||
|
|
||||||
|
/** @file dbLink.h
|
||||||
|
* @brief Link Support API
|
||||||
|
*
|
||||||
|
* Link support run-time API, all link types provide an lset which is used by
|
||||||
|
* the IOC database to control and operate the link. This file also declares the
|
||||||
|
* dbLink routines that IOC, record and device code can call to perform link
|
||||||
|
* operations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief callback routine for locked link operations
|
||||||
|
*
|
||||||
|
* Called by the lset::doLocked method to permit multiple link operations
|
||||||
|
* while the link instance is locked.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param priv context for the callback routine
|
||||||
|
*/
|
||||||
typedef long (*dbLinkUserCallback)(struct link *plink, void *priv);
|
typedef long (*dbLinkUserCallback)(struct link *plink, void *priv);
|
||||||
|
|
||||||
|
/** @brief Link Support Entry Table
|
||||||
|
*
|
||||||
|
* This structure provides information about and methods for an individual link
|
||||||
|
* type. A pointer to this structure is included in every link's lset field, and
|
||||||
|
* is used to perform operations on the link. For JSON links the pointer is
|
||||||
|
* obtained by calling pjlink->pif->get_lset() at link initialization time,
|
||||||
|
* immediately before calling dbLinkOpen() to activate the link.
|
||||||
|
*/
|
||||||
typedef struct lset {
|
typedef struct lset {
|
||||||
/* Characteristics of the link type */
|
/* Characteristics of the link type */
|
||||||
|
|
||||||
|
/** @brief link constancy
|
||||||
|
*
|
||||||
|
* 1 means this is a constant link type whose value doesn't change.
|
||||||
|
* The link's value will be obtained using one of the methods loadScalar,
|
||||||
|
* loadLS or loadArray.
|
||||||
|
*/
|
||||||
const unsigned isConstant:1;
|
const unsigned isConstant:1;
|
||||||
|
|
||||||
|
/** @brief link volatility
|
||||||
|
*
|
||||||
|
* 0 means the link is always connected.
|
||||||
|
*/
|
||||||
const unsigned isVolatile:1;
|
const unsigned isVolatile:1;
|
||||||
|
|
||||||
/* Activation */
|
/** @brief activate link
|
||||||
|
*
|
||||||
|
* Optional, called whenever a JSON link is initialized or added at runtime.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
*/
|
||||||
void (*openLink)(struct link *plink);
|
void (*openLink)(struct link *plink);
|
||||||
|
|
||||||
/* Destructor */
|
/** @brief deactivate link
|
||||||
|
*
|
||||||
|
* Optional, called whenever a link address is changed at runtime, or the
|
||||||
|
* IOC is shutting down.
|
||||||
|
*
|
||||||
|
* @param locker
|
||||||
|
* @param plink the link
|
||||||
|
*/
|
||||||
void (*removeLink)(struct dbLocker *locker, struct link *plink);
|
void (*removeLink)(struct dbLocker *locker, struct link *plink);
|
||||||
|
|
||||||
/* Const init, data type hinting */
|
/* Constant link initialization and data type hinting */
|
||||||
|
|
||||||
|
/** @brief load constant scalar from link type
|
||||||
|
*
|
||||||
|
* Usually called during IOC initialization, constant link types must copy a
|
||||||
|
* scalar value of the indicated data type to the buffer provided and return
|
||||||
|
* 0. A non-constant link type can use this method call as an early hint
|
||||||
|
* that subsequent calls to dbGetLink() will request scalar data of the
|
||||||
|
* indicated type, although the type might change.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param dbrType data type code
|
||||||
|
* @param pbuffer where to put the value
|
||||||
|
* @returns 0 if a value was loaded, non-zero otherwise
|
||||||
|
*/
|
||||||
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
|
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
|
||||||
|
|
||||||
|
/** @brief load constant long string from link type
|
||||||
|
*
|
||||||
|
* Usually called during IOC initialization, constant link types must copy a
|
||||||
|
* nil-terminated string up to size characters long to the buffer provided,
|
||||||
|
* and write the length of that string to the plen location. A non-constant
|
||||||
|
* link type can use this as an early hint that subsequent calls to
|
||||||
|
* dbGetLink() will request long string data, although this might change.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param pbuffer where to put the string
|
||||||
|
* @param size length of pbuffer in chars
|
||||||
|
* @param plen set to number of chars written
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
|
long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||||
epicsUInt32 *plen);
|
epicsUInt32 *plen);
|
||||||
|
|
||||||
|
/** @brief load constant array from link type
|
||||||
|
*
|
||||||
|
* Usually called during IOC initialization, constant link types must copy
|
||||||
|
* an array value of the indicated data type to the buffer provided, update
|
||||||
|
* the pnRequest location to indicate how many elements were loaded, and
|
||||||
|
* return 0. A non-constant link type can use this method call as an early
|
||||||
|
* hint that subsequent calls to dbGetLink() will request array data of the
|
||||||
|
* indicated type and max size, although the request might change.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param dbrType data type code
|
||||||
|
* @param pbuffer where to put the value
|
||||||
|
* @param pnRequest Max elements on entry, actual on exit
|
||||||
|
* @returns 0 if elements were loaded, non-zero otherwise
|
||||||
|
*/
|
||||||
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
|
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
|
||||||
long *pnRequest);
|
long *pnRequest);
|
||||||
|
|
||||||
/* Metadata */
|
/* Metadata */
|
||||||
|
|
||||||
|
/** @brief return link connection status
|
||||||
|
*
|
||||||
|
* Return an indication whether this link is connected or not. This routine
|
||||||
|
* is polled by the calcout and some external record types. Not required for
|
||||||
|
* non-volatile link types, which are by definition always connected.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @returns 1 if connected, 0 if disconnected
|
||||||
|
*/
|
||||||
int (*isConnected)(const struct link *plink);
|
int (*isConnected)(const struct link *plink);
|
||||||
|
|
||||||
|
/** @brief get data type of link destination
|
||||||
|
*
|
||||||
|
* Called on both input and output links by long string support code to
|
||||||
|
* decide whether to use DBR_CHAR/DBR_UCHAR or DBR_STRING for a subsequent
|
||||||
|
* dbPutLink() or dbGetLink() call. Optional, but if not provided long
|
||||||
|
* strings cannot be transported over this link type, and no warning or
|
||||||
|
* error will appear to explain why. Not required for constant link types.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @returns DBF_* type code, or -1 on error/disconnected link
|
||||||
|
*/
|
||||||
int (*getDBFtype)(const struct link *plink);
|
int (*getDBFtype)(const struct link *plink);
|
||||||
long (*getElements)(const struct link *plink, long *nelements);
|
|
||||||
|
|
||||||
/* Get data */
|
/* Get data */
|
||||||
|
|
||||||
|
/** @brief get array size of an input link
|
||||||
|
*
|
||||||
|
* Called on input links by the compress record type for memory allocation
|
||||||
|
* purposes, before using the dbGetLink() routine to fetch the actual
|
||||||
|
* array data.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param pnElements where to put the answer
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
|
long (*getElements)(const struct link *plink, long *pnElements);
|
||||||
|
|
||||||
|
/** @brief get value from an input link
|
||||||
|
*
|
||||||
|
* Called to fetch data from the link, which must be converted into the
|
||||||
|
* given data type and placed in the buffer indicated. The actual number of
|
||||||
|
* elements retrieved should be updated in the pnRequest location. If this
|
||||||
|
* method returns an error status value, the link's record will be placed
|
||||||
|
* into an Invalid severity / Link Alarm state by the dbGetLink() routine
|
||||||
|
* that calls this method.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param dbrType data type code
|
||||||
|
* @param pbuffer where to put the value
|
||||||
|
* @param pnRequest max elements on entry, actual on exit
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
|
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
|
||||||
long *pnRequest);
|
long *pnRequest);
|
||||||
|
|
||||||
|
/** @brief get the control range for an output link
|
||||||
|
*
|
||||||
|
* Called to fetch the control range for the link target, as a pair of
|
||||||
|
* double values for the lowest and highest values that the target will
|
||||||
|
* accept. This method is not used at all by the IOC or built-in record
|
||||||
|
* types, although external record types may require it.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param lo lowest accepted value
|
||||||
|
* @param hi highest accepted value
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
|
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
|
||||||
|
|
||||||
|
/** @brief get the display range from an input link
|
||||||
|
*
|
||||||
|
* Called to fetch the display range for an input link target, as a pair of
|
||||||
|
* double values for the lowest and highest values that the PV expects to
|
||||||
|
* return. This method is used by several built-in record types to obtain
|
||||||
|
* the display range for their generic input links.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param lo lowest accepted value
|
||||||
|
* @param hi highest accepted value
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
|
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
|
||||||
|
|
||||||
|
/** @brief get the alarm limits from an input link
|
||||||
|
*
|
||||||
|
* Called to fetch the alarm limits for an input link target, as four
|
||||||
|
* double values for the warning and alarm levels that the PV checks its
|
||||||
|
* value against. This method is used by several built-in record types to
|
||||||
|
* obtain the alarm limits for their generic input links.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param lolo low alarm value
|
||||||
|
* @param lo low warning value
|
||||||
|
* @param hi high warning value
|
||||||
|
* @param hihi high alarm value
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
|
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
|
||||||
double *hi, double *hihi);
|
double *hi, double *hihi);
|
||||||
|
|
||||||
|
/** @brief get the precision from an input link
|
||||||
|
*
|
||||||
|
* Called to fetch the precision for an input link target. This method is
|
||||||
|
* used by several built-in record types to obtain the precision for their
|
||||||
|
* generic input links.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param precision where to put the answer
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getPrecision)(const struct link *plink, short *precision);
|
long (*getPrecision)(const struct link *plink, short *precision);
|
||||||
|
|
||||||
|
/** @brief get the units string from an input link
|
||||||
|
*
|
||||||
|
* Called to fetch the units string for an input link target. This method is
|
||||||
|
* used by several built-in record types to obtain the units string for
|
||||||
|
* their generic input links.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param units where to put the answer
|
||||||
|
* @param unitsSize buffer size for the answer
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getUnits)(const struct link *plink, char *units, int unitsSize);
|
long (*getUnits)(const struct link *plink, char *units, int unitsSize);
|
||||||
|
|
||||||
|
/** @brief get the alarm condition from an input link
|
||||||
|
*
|
||||||
|
* Called to fetch the alarm status and severity for an input link target.
|
||||||
|
* Either status or severity pointers may be NULL when that value is not
|
||||||
|
* needed by the calling code. This method is used by several built-in
|
||||||
|
* record types to obtain the alarm condition for their generic input links.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param status where to put the alarm status (or NULL)
|
||||||
|
* @param severity where to put the severity (or NULL)
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
|
long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
|
||||||
epicsEnum16 *severity);
|
epicsEnum16 *severity);
|
||||||
|
|
||||||
|
/** @brief get the time-stamp from an input link
|
||||||
|
*
|
||||||
|
* Called to fetch the time-stamp for an input link target. This method is
|
||||||
|
* used by many built-in device supports to obtain the precision for their
|
||||||
|
* generic input links.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param pstamp where to put the answer
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
|
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
|
||||||
|
|
||||||
/* Put data */
|
/* Put data */
|
||||||
|
|
||||||
|
/** @brief put a value to an output link
|
||||||
|
*
|
||||||
|
* Called to send nRequest elements of type dbrType found at pbuffer to an
|
||||||
|
* output link target.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param dbrType data type code
|
||||||
|
* @param pbuffer where to put the value
|
||||||
|
* @param nRequest number of elements to send
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*putValue)(struct link *plink, short dbrType,
|
long (*putValue)(struct link *plink, short dbrType,
|
||||||
const void *pbuffer, long nRequest);
|
const void *pbuffer, long nRequest);
|
||||||
|
|
||||||
|
/** @brief put a value to an output link with asynchronous completion
|
||||||
|
*
|
||||||
|
* Called to send nRequest elements of type dbrType found at pbuffer to an
|
||||||
|
* output link target. If the return status is zero, the link type will
|
||||||
|
* later indicate the put has completed by calling dbLinkAsyncComplete()
|
||||||
|
* from a background thread, which will be used to continue the record
|
||||||
|
* process operation from where it left off.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param dbrType data type code
|
||||||
|
* @param pbuffer where to put the value
|
||||||
|
* @param nRequest number of elements to send
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*putAsync)(struct link *plink, short dbrType,
|
long (*putAsync)(struct link *plink, short dbrType,
|
||||||
const void *pbuffer, long nRequest);
|
const void *pbuffer, long nRequest);
|
||||||
|
|
||||||
/* Process */
|
/* Process */
|
||||||
|
|
||||||
|
/** @brief trigger processing of a forward link
|
||||||
|
*
|
||||||
|
* Called to trigger processing of the record pointed to by a forward link.
|
||||||
|
* This routine is optional, but if not provided no warning message will be
|
||||||
|
* shown when called by dbScanFwdLink(). JSON link types that do not support
|
||||||
|
* this operation should return NULL from their jlif::alloc_jlink() method
|
||||||
|
* if it gets called with a dbfType of DBF_FWDLINK.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
*/
|
||||||
void (*scanForward)(struct link *plink);
|
void (*scanForward)(struct link *plink);
|
||||||
|
|
||||||
/* Atomicity */
|
/* Atomicity */
|
||||||
|
|
||||||
|
/** @brief execute a callback routine with link locked
|
||||||
|
*
|
||||||
|
* Called on an input link when multiple link attributes need to be fetched
|
||||||
|
* in an atomic fashion. The link type must call the callback routine and
|
||||||
|
* prevent any background I/O from updating any cached link data until that
|
||||||
|
* routine returns. This method is used by most input device support to
|
||||||
|
* fetch the timestamp along with the value when the record's TSE field is
|
||||||
|
* set to epicsTimeEventDeviceTime.
|
||||||
|
*
|
||||||
|
* @param plink the link
|
||||||
|
* @param rtn routine to execute
|
||||||
|
* @returns status value
|
||||||
|
*/
|
||||||
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
|
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
|
||||||
} lset;
|
} lset;
|
||||||
|
|
||||||
#define dbGetSevr(link, sevr) \
|
#define dbGetSevr(link, sevr) \
|
||||||
dbGetAlarm(link, NULL, sevr)
|
dbGetAlarm(link, NULL, sevr)
|
||||||
|
|
||||||
|
epicsShareFunc const char * dbLinkFieldName(const struct link *plink);
|
||||||
|
|
||||||
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
|
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
|
||||||
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
|
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
|
||||||
short dbfType, DBADDR *ptarget);
|
short dbfType, DBADDR *ptarget);
|
||||||
@@ -97,9 +382,10 @@ epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
|
|||||||
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
|
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
|
||||||
long *pnRequest);
|
long *pnRequest);
|
||||||
|
|
||||||
epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
|
epicsShareFunc long dbGetNelements(const struct link *plink, long *pnElements);
|
||||||
epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
|
epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
|
||||||
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
|
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
|
||||||
|
|
||||||
epicsShareFunc long dbGetLink(struct link *, short dbrType, void *pbuffer,
|
epicsShareFunc long dbGetLink(struct link *, short dbrType, void *pbuffer,
|
||||||
long *options, long *nRequest);
|
long *options, long *nRequest);
|
||||||
epicsShareFunc long dbGetControlLimits(const struct link *plink, double *low,
|
epicsShareFunc long dbGetControlLimits(const struct link *plink, double *low,
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#ifndef INCdbLockh
|
#ifndef INCdbLockh
|
||||||
#define INCdbLockh
|
#define INCdbLockh
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "ellLib.h"
|
#include "ellLib.h"
|
||||||
#include "shareLib.h"
|
#include "shareLib.h"
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Copyright (c) 2013 Helmholtz-Zentrum Berlin
|
* Copyright (c) 2013 Helmholtz-Zentrum Berlin
|
||||||
* für Materialien und Energie GmbH.
|
* für Materialien und Energie GmbH.
|
||||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
* 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 */
|
/* dbScan.c */
|
||||||
/* tasks and subroutines to scan the database */
|
/* tasks and subroutines to scan the database */
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "cantProceed.h"
|
#include "cantProceed.h"
|
||||||
#include "dbDefs.h"
|
#include "dbDefs.h"
|
||||||
#include "ellLib.h"
|
#include "ellLib.h"
|
||||||
|
#include "epicsAtomic.h"
|
||||||
#include "epicsEvent.h"
|
#include "epicsEvent.h"
|
||||||
#include "epicsMutex.h"
|
#include "epicsMutex.h"
|
||||||
#include "epicsPrint.h"
|
#include "epicsPrint.h"
|
||||||
@@ -63,6 +64,7 @@ static volatile enum ctl scanCtl;
|
|||||||
static int onceQueueSize = 1000;
|
static int onceQueueSize = 1000;
|
||||||
static epicsEventId onceSem;
|
static epicsEventId onceSem;
|
||||||
static epicsRingBytesId onceQ;
|
static epicsRingBytesId onceQ;
|
||||||
|
static int onceQOverruns = 0;
|
||||||
static epicsThreadId onceTaskId;
|
static epicsThreadId onceTaskId;
|
||||||
static void *exitOnce;
|
static void *exitOnce;
|
||||||
|
|
||||||
@@ -109,8 +111,8 @@ static char *priorityName[NUM_CALLBACK_PRIORITIES] = {
|
|||||||
typedef struct event_list {
|
typedef struct event_list {
|
||||||
CALLBACK callback[NUM_CALLBACK_PRIORITIES];
|
CALLBACK callback[NUM_CALLBACK_PRIORITIES];
|
||||||
scan_list scan_list[NUM_CALLBACK_PRIORITIES];
|
scan_list scan_list[NUM_CALLBACK_PRIORITIES];
|
||||||
struct event_list *next;
|
struct event_list *next;
|
||||||
char event_name[MAX_STRING_SIZE];
|
char eventname[1]; /* actually arbitrary size */
|
||||||
} event_list;
|
} event_list;
|
||||||
static event_list * volatile pevent_list[256];
|
static event_list * volatile pevent_list[256];
|
||||||
static epicsMutexId event_lock;
|
static epicsMutexId event_lock;
|
||||||
@@ -247,11 +249,6 @@ void scanAdd(struct dbCommon *precord)
|
|||||||
event_list *pel;
|
event_list *pel;
|
||||||
|
|
||||||
eventname = precord->evnt;
|
eventname = precord->evnt;
|
||||||
if (strlen(eventname) >= MAX_STRING_SIZE) {
|
|
||||||
recGblRecordError(S_db_badField, (void *)precord,
|
|
||||||
"scanAdd: too long EVNT value");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prio = precord->prio;
|
prio = precord->prio;
|
||||||
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
|
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
|
||||||
recGblRecordError(-1, (void *)precord,
|
recGblRecordError(-1, (void *)precord,
|
||||||
@@ -315,24 +312,17 @@ void scanDelete(struct dbCommon *precord)
|
|||||||
recGblRecordError(-1, (void *)precord,
|
recGblRecordError(-1, (void *)precord,
|
||||||
"scanDelete detected illegal SCAN value");
|
"scanDelete detected illegal SCAN value");
|
||||||
} else if (scan == menuScanEvent) {
|
} else if (scan == menuScanEvent) {
|
||||||
char* eventname;
|
|
||||||
int prio;
|
int prio;
|
||||||
event_list *pel;
|
event_list *pel;
|
||||||
scan_list *psl = 0;
|
scan_list *psl = 0;
|
||||||
|
|
||||||
eventname = precord->evnt;
|
|
||||||
prio = precord->prio;
|
prio = precord->prio;
|
||||||
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
|
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
|
||||||
recGblRecordError(-1, (void *)precord,
|
recGblRecordError(-1, (void *)precord,
|
||||||
"scanDelete detected illegal PRIO field");
|
"scanDelete detected illegal PRIO field");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
do /* multithreading: make sure pel is consistent */
|
pel = eventNameToHandle(precord->evnt);
|
||||||
pel = pevent_list[0];
|
|
||||||
while (pel != pevent_list[0]);
|
|
||||||
for (; pel; pel=pel->next) {
|
|
||||||
if (strcmp(pel->event_name, eventname) == 0) break;
|
|
||||||
}
|
|
||||||
if (pel && (psl = &pel->scan_list[prio]))
|
if (pel && (psl = &pel->scan_list[prio]))
|
||||||
deleteFromList(precord, psl);
|
deleteFromList(precord, psl);
|
||||||
} else if (scan == menuScanI_O_Intr) {
|
} else if (scan == menuScanI_O_Intr) {
|
||||||
@@ -420,14 +410,12 @@ int scanpel(const char* eventname) /* print event list */
|
|||||||
int prio;
|
int prio;
|
||||||
event_list *pel;
|
event_list *pel;
|
||||||
|
|
||||||
do /* multithreading: make sure pel is consistent */
|
for (pel = pevent_list[0]; pel; pel = pel->next) {
|
||||||
pel = pevent_list[0];
|
if (!eventname || epicsStrGlobMatch(pel->eventname, eventname)) {
|
||||||
while (pel != pevent_list[0]);
|
printf("Event \"%s\"\n", pel->eventname);
|
||||||
for (; pel; pel = pel->next) {
|
|
||||||
if (!eventname || strcmp(pel->event_name, eventname) == 0) {
|
|
||||||
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||||
if (ellCount(&pel->scan_list[prio].list) == 0) continue;
|
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);
|
printList(&pel->scan_list[prio], message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,20 +466,52 @@ event_list *eventNameToHandle(const char *eventname)
|
|||||||
int prio;
|
int prio;
|
||||||
event_list *pel;
|
event_list *pel;
|
||||||
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
||||||
|
double eventnumber = 0;
|
||||||
|
size_t namelength;
|
||||||
|
|
||||||
if (!eventname || eventname[0] == 0)
|
if (!eventname) return NULL;
|
||||||
return NULL;
|
while (isspace((int) eventname[0])) eventname++;
|
||||||
|
if (!eventname[0]) return NULL;
|
||||||
|
namelength = strlen(eventname);
|
||||||
|
while (isspace((int) 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);
|
epicsThreadOnce(&onceId, eventOnce, NULL);
|
||||||
epicsMutexMustLock(event_lock);
|
epicsMutexMustLock(event_lock);
|
||||||
for (pel = pevent_list[0]; pel; pel=pel->next) {
|
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) {
|
if (pel == NULL) {
|
||||||
pel = calloc(1, sizeof(event_list));
|
pel = calloc(1, sizeof(event_list) + namelength);
|
||||||
if (!pel)
|
if (!pel)
|
||||||
goto done;
|
goto done;
|
||||||
strcpy(pel->event_name, eventname);
|
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++) {
|
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||||
callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]);
|
callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]);
|
||||||
callbackSetPriority(prio, &pel->callback[prio]);
|
callbackSetPriority(prio, &pel->callback[prio]);
|
||||||
@@ -501,12 +521,6 @@ event_list *eventNameToHandle(const char *eventname)
|
|||||||
}
|
}
|
||||||
pel->next=pevent_list[0];
|
pel->next=pevent_list[0];
|
||||||
pevent_list[0]=pel;
|
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:
|
done:
|
||||||
epicsMutexUnlock(event_lock);
|
epicsMutexUnlock(event_lock);
|
||||||
@@ -528,13 +542,8 @@ void postEvent(event_list *pel)
|
|||||||
/* backward compatibility */
|
/* backward compatibility */
|
||||||
void post_event(int event)
|
void post_event(int event)
|
||||||
{
|
{
|
||||||
event_list* pel;
|
|
||||||
|
|
||||||
if (event <= 0 || event > 255) return;
|
if (event <= 0 || event > 255) return;
|
||||||
do { /* multithreading: make sure pel is consistent */
|
postEvent(pevent_list[event]);
|
||||||
pel = pevent_list[event];
|
|
||||||
} while (pel != pevent_list[event]);
|
|
||||||
postEvent(pel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ioscanOnce(void *arg)
|
static void ioscanOnce(void *arg)
|
||||||
@@ -669,6 +678,7 @@ int scanOnceCallback(struct dbCommon *precord, once_complete cb, void *usr)
|
|||||||
if (!pushOK) {
|
if (!pushOK) {
|
||||||
if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n");
|
if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n");
|
||||||
newOverflow = FALSE;
|
newOverflow = FALSE;
|
||||||
|
epicsAtomicIncrIntT(&onceQOverruns);
|
||||||
} else {
|
} else {
|
||||||
newOverflow = TRUE;
|
newOverflow = TRUE;
|
||||||
}
|
}
|
||||||
@@ -715,6 +725,40 @@ int scanOnceSetQueueSize(int size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (!onceQ) return -1;
|
||||||
|
if (result) {
|
||||||
|
result->size = epicsRingBytesSize(onceQ) / sizeof(onceEntry);
|
||||||
|
result->numUsed = epicsRingBytesUsedBytes(onceQ) / sizeof(onceEntry);
|
||||||
|
result->maxUsed = epicsRingBytesHighWaterMark(onceQ) / sizeof(onceEntry);
|
||||||
|
result->numOverflow = epicsAtomicGetIntT(&onceQOverruns);
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
ret = -2;
|
||||||
|
}
|
||||||
|
if (reset) {
|
||||||
|
epicsRingBytesResetHighWaterMark(onceQ);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scanOnceQueueShow(const int reset)
|
||||||
|
{
|
||||||
|
scanOnceQueueStats stats;
|
||||||
|
if (scanOnceQueueStatus(reset, &stats) == -1) {
|
||||||
|
fprintf(stderr, "scanOnce system not initialized, yet. Please run "
|
||||||
|
"iocInit before using this command.\n");
|
||||||
|
} else {
|
||||||
|
double qusage = 100.0 * stats.numUsed / stats.size;
|
||||||
|
printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n");
|
||||||
|
printf("%8s %15d %10d %6d %6.1f %11d\n", "scanOnce", stats.maxUsed,
|
||||||
|
stats.numUsed, stats.size, qusage,
|
||||||
|
epicsAtomicGetIntT(&onceQOverruns));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void initOnce(void)
|
static void initOnce(void)
|
||||||
{
|
{
|
||||||
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
|
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "menuScan.h"
|
#include "menuScan.h"
|
||||||
#include "shareLib.h"
|
#include "shareLib.h"
|
||||||
#include "compilerDependencies.h"
|
#include "compilerDependencies.h"
|
||||||
|
#include "devSup.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -33,9 +34,7 @@ extern "C" {
|
|||||||
#define MIN_PHASE SHRT_MIN
|
#define MIN_PHASE SHRT_MIN
|
||||||
|
|
||||||
/*definitions for I/O Interrupt Scanning */
|
/*definitions for I/O Interrupt Scanning */
|
||||||
struct ioscan_head;
|
/* IOSCANPVT now defined in devSup.h */
|
||||||
|
|
||||||
typedef struct ioscan_head *IOSCANPVT;
|
|
||||||
typedef struct event_list *EVENTPVT;
|
typedef struct event_list *EVENTPVT;
|
||||||
|
|
||||||
struct dbCommon;
|
struct dbCommon;
|
||||||
@@ -43,6 +42,13 @@ struct dbCommon;
|
|||||||
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
|
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
|
||||||
typedef void (*once_complete)(void *usr, struct dbCommon*);
|
typedef void (*once_complete)(void *usr, struct dbCommon*);
|
||||||
|
|
||||||
|
typedef struct scanOnceQueueStats {
|
||||||
|
int size;
|
||||||
|
int numUsed;
|
||||||
|
int maxUsed;
|
||||||
|
int numOverflow;
|
||||||
|
} scanOnceQueueStats;
|
||||||
|
|
||||||
epicsShareFunc long scanInit(void);
|
epicsShareFunc long scanInit(void);
|
||||||
epicsShareFunc void scanRun(void);
|
epicsShareFunc void scanRun(void);
|
||||||
epicsShareFunc void scanPause(void);
|
epicsShareFunc void scanPause(void);
|
||||||
@@ -51,13 +57,15 @@ epicsShareFunc void scanCleanup(void);
|
|||||||
|
|
||||||
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
|
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
|
||||||
epicsShareFunc void postEvent(EVENTPVT epvt);
|
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 scanAdd(struct dbCommon *);
|
||||||
epicsShareFunc void scanDelete(struct dbCommon *);
|
epicsShareFunc void scanDelete(struct dbCommon *);
|
||||||
epicsShareFunc double scanPeriod(int scan);
|
epicsShareFunc double scanPeriod(int scan);
|
||||||
epicsShareFunc int scanOnce(struct dbCommon *);
|
epicsShareFunc int scanOnce(struct dbCommon *);
|
||||||
epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
|
epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
|
||||||
epicsShareFunc int scanOnceSetQueueSize(int size);
|
epicsShareFunc int scanOnceSetQueueSize(int size);
|
||||||
|
epicsShareFunc int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result);
|
||||||
|
epicsShareFunc void scanOnceQueueShow(const int reset);
|
||||||
|
|
||||||
/*print periodic lists*/
|
/*print periodic lists*/
|
||||||
epicsShareFunc int scanppl(double rate);
|
epicsShareFunc int scanppl(double rate);
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ dbStateId dbStateFind(const char *name)
|
|||||||
ELLNODE *node;
|
ELLNODE *node;
|
||||||
dbStateId id;
|
dbStateId id;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (node = ellFirst(&states); node; node = ellNext(node)) {
|
for (node = ellFirst(&states); node; node = ellNext(node)) {
|
||||||
id = CONTAINER(node, dbState, node);
|
id = CONTAINER(node, dbState, node);
|
||||||
if (strcmp(id->name, name) == 0)
|
if (strcmp(id->name, name) == 0)
|
||||||
@@ -49,6 +52,9 @@ dbStateId dbStateCreate(const char *name)
|
|||||||
{
|
{
|
||||||
dbStateId id;
|
dbStateId id;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if ((id = dbStateFind(name)))
|
if ((id = dbStateFind(name)))
|
||||||
return id;
|
return id;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
#include "shareLib.h"
|
#include "shareLib.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/** @file dbState.h
|
/** @file dbState.h
|
||||||
* @brief Generic IOC state facility
|
* @brief Generic IOC state facility
|
||||||
*
|
*
|
||||||
@@ -89,4 +93,9 @@ epicsShareFunc void dbStateShow(dbStateId id, unsigned int level);
|
|||||||
*/
|
*/
|
||||||
epicsShareFunc void dbStateShowAll(unsigned int level);
|
epicsShareFunc void dbStateShowAll(unsigned int level);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // INCdbStateH
|
#endif // INCdbStateH
|
||||||
|
|||||||
@@ -42,12 +42,13 @@
|
|||||||
#include "special.h"
|
#include "special.h"
|
||||||
|
|
||||||
#define MAXLINE 80
|
#define MAXLINE 80
|
||||||
|
#define MAXMESS 128
|
||||||
struct msgBuff { /* line output structure */
|
struct msgBuff { /* line output structure */
|
||||||
char out_buff[MAXLINE + 1];
|
char out_buff[MAXLINE + 1];
|
||||||
char *pNext;
|
char *pNext;
|
||||||
char *pLast;
|
char *pLast;
|
||||||
char *pNexTab;
|
char *pNexTab;
|
||||||
char message[128];
|
char message[MAXMESS];
|
||||||
};
|
};
|
||||||
typedef struct msgBuff TAB_BUFFER;
|
typedef struct msgBuff TAB_BUFFER;
|
||||||
|
|
||||||
@@ -257,7 +258,30 @@ long dbla(const char *pmask)
|
|||||||
dbFinishEntry(pdbentry);
|
dbFinishEntry(pdbentry);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long dbli(const char *pattern)
|
||||||
|
{
|
||||||
|
DBENTRY dbentry;
|
||||||
|
void* ptr;
|
||||||
|
|
||||||
|
if (!pdbbase) {
|
||||||
|
printf("No database loaded\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbInitEntry(pdbbase, &dbentry);
|
||||||
|
while (dbNextMatchingInfo(&dbentry, pattern) == 0)
|
||||||
|
{
|
||||||
|
printf("%s info(%s, \"%s\"", dbGetRecordName(&dbentry),
|
||||||
|
dbGetInfoName(&dbentry), dbGetInfoString(&dbentry));
|
||||||
|
if ((ptr = dbGetInfoPointer(&dbentry)) != NULL)
|
||||||
|
printf(", %p", ptr);
|
||||||
|
printf(")\n");
|
||||||
|
}
|
||||||
|
dbFinishEntry(&dbentry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
long dbgrep(const char *pmask)
|
long dbgrep(const char *pmask)
|
||||||
{
|
{
|
||||||
DBENTRY dbentry;
|
DBENTRY dbentry;
|
||||||
@@ -309,6 +333,11 @@ long dbgf(const char *pname)
|
|||||||
if (nameToAddr(pname, &addr))
|
if (nameToAddr(pname, &addr))
|
||||||
return -1;
|
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);
|
no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size);
|
||||||
if (addr.dbr_field_type == DBR_ENUM) {
|
if (addr.dbr_field_type == DBR_ENUM) {
|
||||||
long status = dbGetField(&addr, DBR_STRING, pbuffer,
|
long status = dbGetField(&addr, DBR_STRING, pbuffer,
|
||||||
@@ -345,6 +374,11 @@ long dbpf(const char *pname,const char *pvalue)
|
|||||||
if (nameToAddr(pname, &addr))
|
if (nameToAddr(pname, &addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (addr.precord->lset == NULL) {
|
||||||
|
printf("dbpf only works after iocInit\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (addr.no_elements > 1 &&
|
if (addr.no_elements > 1 &&
|
||||||
(addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR)) {
|
(addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR)) {
|
||||||
dbrType = addr.dbr_field_type;
|
dbrType = addr.dbr_field_type;
|
||||||
@@ -399,6 +433,11 @@ long dbtr(const char *pname)
|
|||||||
if (nameToAddr(pname, &addr))
|
if (nameToAddr(pname, &addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (addr.precord->lset == NULL) {
|
||||||
|
printf("dbtr only works after iocInit\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
precord = (struct dbCommon*)addr.precord;
|
precord = (struct dbCommon*)addr.precord;
|
||||||
if (precord->pact) {
|
if (precord->pact) {
|
||||||
printf("record active\n");
|
printf("record active\n");
|
||||||
@@ -438,6 +477,11 @@ long dbtgf(const char *pname)
|
|||||||
if (nameToAddr(pname, &addr))
|
if (nameToAddr(pname, &addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (addr.precord->lset == NULL) {
|
||||||
|
printf("dbtgf only works after iocInit\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* try all options first */
|
/* try all options first */
|
||||||
req_options = 0xffffffff;
|
req_options = 0xffffffff;
|
||||||
ret_options = req_options;
|
ret_options = req_options;
|
||||||
@@ -534,6 +578,11 @@ long dbtpf(const char *pname, const char *pvalue)
|
|||||||
if (nameToAddr(pname, &addr))
|
if (nameToAddr(pname, &addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (addr.precord->lset == NULL) {
|
||||||
|
printf("dbtpf only works after iocInit\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (put_type = DBR_STRING; put_type <= DBF_ENUM; put_type++) {
|
for (put_type = DBR_STRING; put_type <= DBF_ENUM; put_type++) {
|
||||||
union {
|
union {
|
||||||
epicsInt8 i8;
|
epicsInt8 i8;
|
||||||
@@ -795,7 +844,7 @@ static void printBuffer(
|
|||||||
|
|
||||||
printf("no_strs = %u:\n",
|
printf("no_strs = %u:\n",
|
||||||
pdbr_enumStrs->no_str);
|
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]);
|
printf("\t\"%s\"\n", pdbr_enumStrs->strs[i]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -938,7 +987,7 @@ static void printBuffer(
|
|||||||
int chunk = (len > MAXLINE - 5) ? MAXLINE - 5 : len;
|
int chunk = (len > MAXLINE - 5) ? MAXLINE - 5 : len;
|
||||||
|
|
||||||
sprintf(pmsg, "\"%.*s\"", chunk, (char *)pbuffer + i);
|
sprintf(pmsg, "\"%.*s\"", chunk, (char *)pbuffer + i);
|
||||||
len -= chunk;
|
len -= chunk; i += chunk;
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
strcat(pmsg, " +");
|
strcat(pmsg, " +");
|
||||||
dbpr_msgOut(pMsgBuff, tab_size);
|
dbpr_msgOut(pMsgBuff, tab_size);
|
||||||
@@ -1104,7 +1153,7 @@ static int dbpr_report(
|
|||||||
case DBF_DEVICE:
|
case DBF_DEVICE:
|
||||||
status = dbFindField(pdbentry,pfield_name);
|
status = dbFindField(pdbentry,pfield_name);
|
||||||
pfield_value = dbGetString(pdbentry);
|
pfield_value = dbGetString(pdbentry);
|
||||||
sprintf(pmsg, "%s: %s", pfield_name,
|
sprintf(pmsg, "%-4s: %s", pfield_name,
|
||||||
(pfield_value ? pfield_value : "<nil>"));
|
(pfield_value ? pfield_value : "<nil>"));
|
||||||
dbpr_msgOut(pMsgBuff, tab_size);
|
dbpr_msgOut(pMsgBuff, tab_size);
|
||||||
break;
|
break;
|
||||||
@@ -1114,19 +1163,18 @@ static int dbpr_report(
|
|||||||
case DBF_FWDLINK: {
|
case DBF_FWDLINK: {
|
||||||
DBLINK *plink = (DBLINK *)pfield;
|
DBLINK *plink = (DBLINK *)pfield;
|
||||||
int ind;
|
int ind;
|
||||||
|
const char *type = "LINK";
|
||||||
|
|
||||||
status = dbFindField(pdbentry,pfield_name);
|
status = dbFindField(pdbentry,pfield_name);
|
||||||
for (ind=0; ind<LINK_NTYPES; ind++) {
|
if (!plink->text)
|
||||||
if (pamaplinkType[ind].value == plink->type)
|
for (ind=0; ind<LINK_NTYPES; ind++) {
|
||||||
break;
|
if (pamaplinkType[ind].value == plink->type) {
|
||||||
}
|
type = pamaplinkType[ind].strvalue;
|
||||||
if (ind>=LINK_NTYPES) {
|
break;
|
||||||
sprintf(pmsg,"%s: Illegal Link Type", pfield_name);
|
}
|
||||||
}
|
}
|
||||||
else {
|
epicsSnprintf(pmsg, MAXMESS, "%-4s: %s %s", pfield_name,
|
||||||
sprintf(pmsg,"%s:%s %s", pfield_name,
|
type, dbGetString(pdbentry));
|
||||||
pamaplinkType[ind].strvalue,dbGetString(pdbentry));
|
|
||||||
}
|
|
||||||
dbpr_msgOut(pMsgBuff, tab_size);
|
dbpr_msgOut(pMsgBuff, tab_size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1137,13 +1185,21 @@ static int dbpr_report(
|
|||||||
char time_buf[40];
|
char time_buf[40];
|
||||||
epicsTimeToStrftime(time_buf, 40, "%Y-%m-%d %H:%M:%S.%09f",
|
epicsTimeToStrftime(time_buf, 40, "%Y-%m-%d %H:%M:%S.%09f",
|
||||||
&paddr->precord->time);
|
&paddr->precord->time);
|
||||||
sprintf(pmsg, "%s: %s", pfield_name, time_buf);
|
sprintf(pmsg, "%-4s: %s", pfield_name, time_buf);
|
||||||
dbpr_msgOut(pMsgBuff, tab_size);
|
dbpr_msgOut(pMsgBuff, tab_size);
|
||||||
}
|
}
|
||||||
else if (pdbFldDes->size == sizeof(void *) &&
|
else if (pdbFldDes->size == sizeof(void *) &&
|
||||||
strchr(pdbFldDes->extra, '*')) {
|
strchr(pdbFldDes->extra, '*')) {
|
||||||
/* Special for pointers, needed on little-endian CPUs */
|
/* Special for pointers */
|
||||||
sprintf(pmsg, "%s: %p", pfield_name, *(void **)pfield);
|
sprintf(pmsg, "%-4s: PTR %p", pfield_name, *(void **)pfield);
|
||||||
|
dbpr_msgOut(pMsgBuff, tab_size);
|
||||||
|
}
|
||||||
|
else if (pdbFldDes->size == sizeof(ELLLIST) &&
|
||||||
|
!strncmp(pdbFldDes->extra, "ELLLIST", 7)) {
|
||||||
|
/* Special for linked lists */
|
||||||
|
ELLLIST *plist = (ELLLIST *)pfield;
|
||||||
|
sprintf(pmsg, "%-4s: ELL %d [%p .. %p]", pfield_name,
|
||||||
|
ellCount(plist), ellFirst(plist), ellLast(plist));
|
||||||
dbpr_msgOut(pMsgBuff, tab_size);
|
dbpr_msgOut(pMsgBuff, tab_size);
|
||||||
}
|
}
|
||||||
else { /* just print field as hex bytes */
|
else { /* just print field as hex bytes */
|
||||||
@@ -1159,7 +1215,7 @@ static int dbpr_report(
|
|||||||
value = (unsigned int)*pchar;
|
value = (unsigned int)*pchar;
|
||||||
sprintf(ptemp_buf, "%02x ", value);
|
sprintf(ptemp_buf, "%02x ", value);
|
||||||
}
|
}
|
||||||
sprintf(pmsg, "%s: %s", pfield_name,temp_buf);
|
sprintf(pmsg, "%-4s: %s", pfield_name,temp_buf);
|
||||||
dbpr_msgOut(pMsgBuff, tab_size);
|
dbpr_msgOut(pMsgBuff, tab_size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ epicsShareFunc long dbl(
|
|||||||
epicsShareFunc long dbnr(int verbose);
|
epicsShareFunc long dbnr(int verbose);
|
||||||
/* list aliases */
|
/* list aliases */
|
||||||
epicsShareFunc long dbla(const char *pmask);
|
epicsShareFunc long dbla(const char *pmask);
|
||||||
|
/* list infos */
|
||||||
|
epicsShareFunc long dbli(const char *patern);
|
||||||
/*list records with mask*/
|
/*list records with mask*/
|
||||||
epicsShareFunc long dbgrep(const char *pmask);
|
epicsShareFunc long dbgrep(const char *pmask);
|
||||||
/*get field value*/
|
/*get field value*/
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "osiUnistd.h"
|
#include "osiUnistd.h"
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
#include "epicsEvent.h"
|
#include "epicsEvent.h"
|
||||||
|
#include "epicsThread.h"
|
||||||
|
|
||||||
#define epicsExportSharedSymbols
|
#define epicsExportSharedSymbols
|
||||||
#include "dbAccess.h"
|
#include "dbAccess.h"
|
||||||
@@ -414,3 +415,26 @@ unsigned testMonitorCount(testMonitor *mon, unsigned reset)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,65 @@ epicsShareFunc void testMonitorWait(testMonitor*);
|
|||||||
*/
|
*/
|
||||||
epicsShareFunc unsigned testMonitorCount(testMonitor*, unsigned reset);
|
epicsShareFunc unsigned testMonitorCount(testMonitor*, unsigned reset);
|
||||||
|
|
||||||
|
/** 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,11 +1,48 @@
|
|||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
|
# Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne
|
||||||
# National Laboratory.
|
# National Laboratory.
|
||||||
# Copyright (c) 2002 The Regents of the University of California, as
|
# Copyright (c) 2002 The Regents of the University of California, as
|
||||||
# Operator of Los Alamos National Laboratory.
|
# Operator of Los Alamos National Laboratory.
|
||||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
# 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.
|
||||||
#*************************************************************************
|
#*************************************************************************
|
||||||
|
|
||||||
|
=head1 Menu menuScan
|
||||||
|
|
||||||
|
This menu is used for the C<SCAN> field of all record types.
|
||||||
|
|
||||||
|
The set of periodic scan rates may be modified for an individual IOC by
|
||||||
|
copying the F<menuScan.dbd> file from Base into the IOC's source
|
||||||
|
directory and changing it to contain the desired scan rates.
|
||||||
|
|
||||||
|
The scan periods are extracted from the choice strings at runtime, which
|
||||||
|
must be expressed as a number with any of the following units appended:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
second
|
||||||
|
seconds
|
||||||
|
minute
|
||||||
|
minutes
|
||||||
|
hour
|
||||||
|
hours
|
||||||
|
Hertz
|
||||||
|
Hz
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
At IOC start-up a separate scan thread will be created for each period,
|
||||||
|
with thread priority increasing further down the list, so faster periods
|
||||||
|
should appear after slower ones.
|
||||||
|
|
||||||
|
Scan rates that cannot be achieved will generate a warning message from
|
||||||
|
the C<iocInit> command.
|
||||||
|
|
||||||
|
|
||||||
|
=menu menuScan
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
menu(menuScan) {
|
menu(menuScan) {
|
||||||
choice(menuScanPassive,"Passive")
|
choice(menuScanPassive,"Passive")
|
||||||
choice(menuScanEvent,"Event")
|
choice(menuScanEvent,"Event")
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "alarm.h"
|
#include "alarm.h"
|
||||||
#include "dbDefs.h"
|
#include "dbDefs.h"
|
||||||
|
#include "alarm.h"
|
||||||
#include "epicsMath.h"
|
#include "epicsMath.h"
|
||||||
#include "epicsPrint.h"
|
#include "epicsPrint.h"
|
||||||
#include "epicsStdlib.h"
|
#include "epicsStdlib.h"
|
||||||
@@ -178,6 +179,9 @@ unsigned short recGblResetAlarms(void *precord)
|
|||||||
epicsEnum16 val_mask = 0;
|
epicsEnum16 val_mask = 0;
|
||||||
epicsEnum16 stat_mask = 0;
|
epicsEnum16 stat_mask = 0;
|
||||||
|
|
||||||
|
if (new_sevr > INVALID_ALARM)
|
||||||
|
new_sevr = INVALID_ALARM;
|
||||||
|
|
||||||
pdbc->stat = new_stat;
|
pdbc->stat = new_stat;
|
||||||
pdbc->sevr = new_sevr;
|
pdbc->sevr = new_sevr;
|
||||||
pdbc->nsta = 0;
|
pdbc->nsta = 0;
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ testHarness_SRCS += epicsRunDbTests.c
|
|||||||
dbTestHarness_SRCS += $(testHarness_SRCS)
|
dbTestHarness_SRCS += $(testHarness_SRCS)
|
||||||
dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
|
dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
|
||||||
|
|
||||||
|
PROD_SRCS_RTEMS += rtemsTestData.c
|
||||||
|
|
||||||
PROD_vxWorks = dbTestHarness
|
PROD_vxWorks = dbTestHarness
|
||||||
PROD_RTEMS = dbTestHarness
|
PROD_RTEMS = dbTestHarness
|
||||||
|
|
||||||
@@ -182,6 +184,10 @@ TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests
|
|||||||
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
|
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
|
||||||
|
|
||||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||||
|
ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
|
||||||
|
TESTPROD_RTEMS = $(TESTPROD_HOST)
|
||||||
|
TESTSCRIPTS_RTEMS += $(TESTS:%=%.t)
|
||||||
|
endif
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
||||||
|
|
||||||
@@ -193,3 +199,5 @@ devx$(DEP): $(COMMON_DIR)/xRecord.h
|
|||||||
scanIoTest$(DEP): $(COMMON_DIR)/xRecord.h
|
scanIoTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||||
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
|
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
|
||||||
|
|
||||||
|
rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl
|
||||||
|
$(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES)
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
*
|
*
|
||||||
* Two time intervals are measured. The time to queue and run each of
|
* Two time intervals are measured. The time to queue and run each of
|
||||||
* the immediate callbacks, and the actual delay of the delayed callback.
|
* 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
|
#define NCALLBACKS 169
|
||||||
@@ -108,7 +110,7 @@ MAIN(callbackParallelTest)
|
|||||||
for (j = 0; j < 5; j++)
|
for (j = 0; j < 5; j++)
|
||||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||||
|
|
||||||
testPlan(4);
|
testPlan(2);
|
||||||
|
|
||||||
testDiag("Starting %d parallel callback threads", noCpus);
|
testDiag("Starting %d parallel callback threads", noCpus);
|
||||||
|
|
||||||
@@ -165,7 +167,8 @@ MAIN(callbackParallelTest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
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;
|
slowups = 0;
|
||||||
for (i = 0; i < NCALLBACKS ; i++) {
|
for (i = 0; i < NCALLBACKS ; i++) {
|
||||||
@@ -182,7 +185,8 @@ MAIN(callbackParallelTest)
|
|||||||
}
|
}
|
||||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
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");
|
testDiag("Setup time statistics");
|
||||||
printStats(setupError[0], "LOW");
|
printStats(setupError[0], "LOW");
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
*
|
*
|
||||||
* Two time intervals are measured. The time to queue and run each of
|
* Two time intervals are measured. The time to queue and run each of
|
||||||
* the immediate callbacks, and the actual delay of the delayed callback.
|
* 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
|
#define NCALLBACKS 169
|
||||||
@@ -108,7 +110,7 @@ MAIN(callbackTest)
|
|||||||
for (j = 0; j < 5; j++)
|
for (j = 0; j < 5; j++)
|
||||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||||
|
|
||||||
testPlan(4);
|
testPlan(2);
|
||||||
|
|
||||||
callbackInit();
|
callbackInit();
|
||||||
epicsThreadSleep(1.0);
|
epicsThreadSleep(1.0);
|
||||||
@@ -162,7 +164,8 @@ MAIN(callbackTest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
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;
|
slowups = 0;
|
||||||
for (i = 0; i < NCALLBACKS ; i++) {
|
for (i = 0; i < NCALLBACKS ; i++) {
|
||||||
@@ -179,7 +182,8 @@ MAIN(callbackTest)
|
|||||||
}
|
}
|
||||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
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");
|
testDiag("Setup time statistics");
|
||||||
printStats(setupError[0], "LOW");
|
printStats(setupError[0], "LOW");
|
||||||
|
|||||||
@@ -14,3 +14,8 @@ record(x, "eINST_IO") {
|
|||||||
field(DTYP, "Unit Test INST_IO")
|
field(DTYP, "Unit Test INST_IO")
|
||||||
field(INP, "hello")
|
field(INP, "hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record(x, "eINST_IO2") {
|
||||||
|
field(DTYP, "Unit Test INST_IO")
|
||||||
|
field(INP, "RL @no")
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
/* Declarations from cadef.h and db_access.h which we can't include here */
|
/* Declarations from cadef.h and db_access.h which we can't include here */
|
||||||
typedef void * chid;
|
typedef void * chid;
|
||||||
|
typedef void * evid;
|
||||||
epicsShareExtern const unsigned short dbr_value_size[];
|
epicsShareExtern const unsigned short dbr_value_size[];
|
||||||
epicsShareExtern short epicsShareAPI ca_field_type (chid chan);
|
epicsShareExtern short epicsShareAPI ca_field_type (chid chan);
|
||||||
#define MAX_UNITS_SIZE 8
|
#define MAX_UNITS_SIZE 8
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ static const struct testParseDataT {
|
|||||||
TEST_PV_LINK(" world MSICP", "world", pvlOptMSI|pvlOptCP),
|
TEST_PV_LINK(" world MSICP", "world", pvlOptMSI|pvlOptCP),
|
||||||
|
|
||||||
{"#C14 S145 @testing", {VME_IO, "testing", 0, "CS", {14, 145}}},
|
{"#C14 S145 @testing", {VME_IO, "testing", 0, "CS", {14, 145}}},
|
||||||
|
{"#C14 S145", {VME_IO, "", 0, "CS", {14, 145}}},
|
||||||
{"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}},
|
{"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}},
|
||||||
|
{"#B11 C12 N13 A14 F15", {CAMAC_IO, "", 0, "BCNAF", {11, 12, 13, 14, 15}}},
|
||||||
{" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}},
|
{" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}},
|
||||||
{" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}},
|
{" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}},
|
||||||
{" {\"x\":true} ", {JSON_LINK, "{\"x\":true}", 0, "", /*{}*/}},
|
{" {\"x\":true} ", {JSON_LINK, "{\"x\":true}", 0, "", /*{}*/}},
|
||||||
@@ -87,11 +89,15 @@ static void testLinkParse(void)
|
|||||||
for (;td->str; td++) {
|
for (;td->str; td++) {
|
||||||
int i, N;
|
int i, N;
|
||||||
testDiag("Parsing \"%s\"", td->str);
|
testDiag("Parsing \"%s\"", td->str);
|
||||||
testOk(dbParseLink(td->str, DBF_INLINK, &info, 0) == 0, "Parser returned OK");
|
testOk(dbParseLink(td->str, DBF_INLINK, &info) == 0, "Parser returned OK");
|
||||||
if (!testOk(info.ltype == td->info.ltype, "Link type value"))
|
if (!testOk(info.ltype == td->info.ltype, "Link type value"))
|
||||||
testDiag("Expected %d, got %d", td->info.ltype, info.ltype);
|
testDiag("Expected %d, got %d", td->info.ltype, info.ltype);
|
||||||
if (td->info.target)
|
if (td->info.target && info.target)
|
||||||
testStrcmp(0, info.target, td->info.target);
|
testStrcmp(0, info.target, td->info.target);
|
||||||
|
else if(!!td->info.target ^ !!info.target)
|
||||||
|
testFail("info target NULL mis-match %s %s", info.target, td->info.target);
|
||||||
|
else
|
||||||
|
testPass("info target NULL as expected");
|
||||||
if (info.ltype == td->info.ltype) {
|
if (info.ltype == td->info.ltype) {
|
||||||
switch (info.ltype) {
|
switch (info.ltype) {
|
||||||
case PV_LINK:
|
case PV_LINK:
|
||||||
@@ -125,7 +131,6 @@ static const char *testParseFailData[] = {
|
|||||||
"#A0 B @",
|
"#A0 B @",
|
||||||
"#A0 B C @",
|
"#A0 B C @",
|
||||||
"#R1 M2 D3 E4 @oops", /* RF_IO has no parm */
|
"#R1 M2 D3 E4 @oops", /* RF_IO has no parm */
|
||||||
"#C1 S2", /* VME_IO needs parm */
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -147,7 +152,7 @@ static void testLinkFailParse(void)
|
|||||||
eltc(1);
|
eltc(1);
|
||||||
|
|
||||||
for(;*td; td++) {
|
for(;*td; td++) {
|
||||||
testOk(dbParseLink(*td, DBF_INLINK, &info, 0) == S_dbLib_badField,
|
testOk(dbParseLink(*td, DBF_INLINK, &info) == S_dbLib_badField,
|
||||||
"dbParseLink correctly rejected \"%s\"", *td);
|
"dbParseLink correctly rejected \"%s\"", *td);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,6 +485,13 @@ static void testLinkInitFail(void)
|
|||||||
testOk1(plink->type == INST_IO);
|
testOk1(plink->type == INST_IO);
|
||||||
testOk1(plink->value.instio.string != NULL);
|
testOk1(plink->value.instio.string != NULL);
|
||||||
|
|
||||||
|
testdbGetFieldEqual("eINST_IO2.INP", DBR_STRING, "@");
|
||||||
|
|
||||||
|
prec = (xRecord *) testdbRecordPtr("eINST_IO2");
|
||||||
|
plink = &prec->inp;
|
||||||
|
testOk1(plink->type == INST_IO);
|
||||||
|
testOk1(plink->value.instio.string != NULL);
|
||||||
|
|
||||||
testIocShutdownOk();
|
testIocShutdownOk();
|
||||||
|
|
||||||
testdbCleanup();
|
testdbCleanup();
|
||||||
@@ -684,7 +696,7 @@ void testTSEL(void)
|
|||||||
|
|
||||||
MAIN(dbPutLinkTest)
|
MAIN(dbPutLinkTest)
|
||||||
{
|
{
|
||||||
testPlan(320);
|
testPlan(337);
|
||||||
testLinkParse();
|
testLinkParse();
|
||||||
testLinkFailParse();
|
testLinkFailParse();
|
||||||
testCADBSet();
|
testCADBSet();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
record(x, "testrec") {
|
record(x, "testrec") {
|
||||||
info("A", "B")
|
|
||||||
alias("testalias")
|
alias("testalias")
|
||||||
|
info("A", "B")
|
||||||
}
|
}
|
||||||
|
|
||||||
alias("testrec", "testalias2")
|
alias("testrec", "testalias2")
|
||||||
|
|||||||
@@ -228,6 +228,11 @@ MAIN(dbStressTest)
|
|||||||
|
|
||||||
testPlan(80+nworkers*3);
|
testPlan(80+nworkers*3);
|
||||||
|
|
||||||
|
#if defined(__rtems__)
|
||||||
|
testSkip(80+nworkers*3, "Test assumes time sliced preempting scheduling");
|
||||||
|
return testDone();
|
||||||
|
#endif
|
||||||
|
|
||||||
priv = callocMustSucceed(nworkers, sizeof(*priv), "no memory");
|
priv = callocMustSucceed(nworkers, sizeof(*priv), "no memory");
|
||||||
|
|
||||||
testDiag("lock set stress test");
|
testDiag("lock set stress test");
|
||||||
|
|||||||
@@ -246,7 +246,8 @@ static jlif jlifZ = {
|
|||||||
NULL, /* end child */
|
NULL, /* end child */
|
||||||
&z_lset,
|
&z_lset,
|
||||||
NULL, /* report */
|
NULL, /* report */
|
||||||
NULL /* map child */
|
NULL, /* map child */
|
||||||
|
NULL /* start child */
|
||||||
};
|
};
|
||||||
|
|
||||||
epicsExportAddress(jlif, jlifZ);
|
epicsExportAddress(jlif, jlifZ);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ static void testBasicGet(void)
|
|||||||
|
|
||||||
getter(&addr, scratch, 1, s_input_len, 0);
|
getter(&addr, scratch, 1, s_input_len, 0);
|
||||||
|
|
||||||
testOk1(scratch[0]==s_input[0]);
|
testOk1(scratch[0]==s_input[0] && scratch[1]==0);
|
||||||
|
|
||||||
memset(scratch, 0x42, sizeof(s_input));
|
memset(scratch, 0x42, sizeof(s_input));
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ static void testBasicPut(void)
|
|||||||
|
|
||||||
putter(&addr, s_input, 1, s_input_len, 0);
|
putter(&addr, s_input, 1, s_input_len, 0);
|
||||||
|
|
||||||
testOk1(scratch[0]==s_input[0]);
|
testOk1(scratch[0]==s_input[0] && scratch[1]==0);
|
||||||
|
|
||||||
memset(scratch, 0x42, sizeof(s_input));
|
memset(scratch, 0x42, sizeof(s_input));
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user