Compare commits
413 Commits
stream_2_6
...
master
Author | SHA1 | Date | |
---|---|---|---|
20dde4c1d8 | |||
f61e6404f5 | |||
9080d6ca8e | |||
13e7f2d3dc | |||
e87e093c84 | |||
7debc86514 | |||
668d1d5255 | |||
ae5ca0c45b | |||
b00099973f | |||
5bf5cb9a67 | |||
f6848f0503 | |||
1496089bc8 | |||
a090cd4d8f | |||
2b3e4189c1 | |||
211f689cdf | |||
793675bb12 | |||
922294bf6a | |||
942c4779c9 | |||
8ceee295ae | |||
c30e2a4e31 | |||
fc67fb8721 | |||
c123c5c8f7 | |||
8746dea7cf | |||
2915830b02 | |||
fdfa4d4695 | |||
4d717288da | |||
94721c2b0e | |||
bf0e755913 | |||
51e4a0749d | |||
4cdace3ffe | |||
d19b16d096 | |||
b1e0d63c6b | |||
d1b43b879c | |||
6b0ee5e946 | |||
a0d1b35862 | |||
dfbd308d46 | |||
b615dae9b1 | |||
ac6c96c645 | |||
fe1ac364ab | |||
a06006eade | |||
a4e843cc4c | |||
601d4a3709 | |||
f495dd9853 | |||
6b05e006da | |||
068632326c | |||
a5eb4618b7 | |||
fe7f4a5e1b | |||
0010b8f23f | |||
7e42f6fddf | |||
2b15ae7ac0 | |||
055e141791 | |||
52486ae7a0 | |||
becf7d5585 | |||
132f03fc6c | |||
3978357f17 | |||
a1ec9b99e8 | |||
377d511c67 | |||
849586b7fa | |||
e6b2944c67 | |||
67c205e87b | |||
575c0ffcf8 | |||
e662ebda04 | |||
ea8873becd | |||
cf7e7bd6ee | |||
e36ee60ba7 | |||
e7f36a71af | |||
ce4b14c611 | |||
7c55d7bdfa | |||
6afa4828eb | |||
75bbb1a252 | |||
227bb83f60 | |||
4edff374d0 | |||
9273476135 | |||
8b9359723a | |||
bf55d4c202 | |||
1cace82a70 | |||
85e8632b02 | |||
1994912271 | |||
98fa595753 | |||
f6640b3418 | |||
4747bb5bc7 | |||
bd9ee1c660 | |||
22deae23e5 | |||
7f22d5bdc6 | |||
e4087a9244 | |||
cede631c8d | |||
1c9278812b | |||
2ea014ae46 | |||
9fd345e267 | |||
75aa267875 | |||
7dda6ca773 | |||
1378a9fcbb | |||
4d3672994d | |||
967539c4e1 | |||
f072c217f3 | |||
a60ffd685f | |||
0803c94c79 | |||
b03726903d | |||
afe8cc9a3e | |||
277635c65f | |||
4180bbbdd9 | |||
d683969556 | |||
a62d4d1a40 | |||
aadecf1853 | |||
f172f3d0a0 | |||
08ac900eda | |||
53caf69f3a | |||
3eac2b804d | |||
9b9e7bf722 | |||
7a48a5440e | |||
ef5d0cf3f1 | |||
a5e9ed2d78 | |||
40e937b091 | |||
1bac175c42 | |||
507a8229de | |||
3fd2e8fd31 | |||
f2e9395377 | |||
6669b1c33c | |||
21ce272a65 | |||
2b6a064913 | |||
81a901b386 | |||
cfbc4ac369 | |||
d1b6c8bf1a | |||
491cfa6d4b | |||
a6b11bea0e | |||
a6190c7ddf | |||
4ece622c52 | |||
0e525fc893 | |||
85c9a8b130 | |||
905d8a3b4a | |||
1cc5f3fbd6 | |||
3ad63e04d0 | |||
880a399e4e | |||
592146a648 | |||
e03285b9a9 | |||
fb3d20bfd9 | |||
3363f4f525 | |||
ed300116bd | |||
f912e0b370 | |||
b84655e4de | |||
ece1e01d21 | |||
26877dedbd | |||
7aa1802ec6 | |||
eb9f565aec | |||
04906a5835 | |||
acf7efcff2 | |||
d873d220dc | |||
9ef1653e73 | |||
d1d65344af | |||
a76adc31ab | |||
a2fcbc81c8 | |||
fa51c376c1 | |||
483530f053 | |||
8f34dd2c84 | |||
493dc19d8b | |||
3b64242ffd | |||
280cb7765a | |||
835e68bd76 | |||
92903361d0 | |||
fb937316aa | |||
ae6ebc4106 | |||
0f0dd31a0d | |||
189e61bbe8 | |||
d8f88c340a | |||
2ef5c47f19 | |||
cb4d490fb6 | |||
da281ebf97 | |||
c832efbcb6 | |||
b7b3bc0af0 | |||
4a42c3d43a | |||
624cc0134a | |||
d9d5d5f55d | |||
53ea75dc80 | |||
b1f4c2a7d9 | |||
d87e9cedd2 | |||
32d93d9028 | |||
3d30827798 | |||
b688f14c22 | |||
9e972d3f33 | |||
f5da2ea6b3 | |||
4edd2f2eff | |||
846b884eb5 | |||
3f1918ed2d | |||
1d753366d8 | |||
047f18d113 | |||
26c5b012a7 | |||
4f33600a0f | |||
2077dfb0a6 | |||
1b0e890ddd | |||
eb4e4b08ff | |||
ed00d8eee4 | |||
1bb3614e80 | |||
9bd89318bb | |||
fa122460fd | |||
81ce1dfc62 | |||
53d7129ec3 | |||
bb66a49ec1 | |||
03d6d9672e | |||
9891a75bcd | |||
b011c286aa | |||
fb58a80b0c | |||
9e6f2d593d | |||
2cf0c017e2 | |||
93db87cc07 | |||
dace4e5638 | |||
cd0ab98602 | |||
170298b123 | |||
3d22d2205f | |||
845d8bc1a3 | |||
3f8483eca1 | |||
8e92be073d | |||
57ad547df6 | |||
ca2e6f4a8b | |||
4fc619f9a4 | |||
8e02c65b09 | |||
fe44bf4fde | |||
4b97e4f2df | |||
cad3c25079 | |||
04d0eb6361 | |||
c49fe2e31a | |||
a327714907 | |||
2494f32288 | |||
7de7e48c98 | |||
b18fbeb9ab | |||
bd3e430966 | |||
fe075c3bbd | |||
d22955a1c5 | |||
8679dd543b | |||
b594f94b0c | |||
5c68e117fd | |||
f10514db6b | |||
d5dc15e321 | |||
cfa777d718 | |||
54bc78f7c7 | |||
3b30e9acb9 | |||
77d110de70 | |||
c349c209b0 | |||
19467bd5d5 | |||
d69c74bc8f | |||
e09506c2bb | |||
7b7f319c2f | |||
343eef324b | |||
a798cf2f21 | |||
a9d89cd195 | |||
b98f76ece4 | |||
1f74040f96 | |||
6156260ad4 | |||
774efecd40 | |||
5bb231d8e8 | |||
162fa7b329 | |||
f94e8bc746 | |||
f462a35db3 | |||
1120651daa | |||
3b26bca69a | |||
89d3801a5f | |||
710a442d31 | |||
f7d5cbf5ce | |||
c1144cf277 | |||
9481b95b30 | |||
18a0e54033 | |||
c1b89cb087 | |||
6f4383cd10 | |||
e9db72de72 | |||
827e6eace9 | |||
4d3960c599 | |||
a3d6e9d908 | |||
4e290413d1 | |||
54eb0b215c | |||
6d422c4259 | |||
9d1084cdf8 | |||
cd5811f59d | |||
13cda13ef1 | |||
6ff52fcc94 | |||
ff058547e8 | |||
ded9bd2b4d | |||
8dde86dae7 | |||
0c5227dfc5 | |||
7cdf39d61c | |||
5a23b89087 | |||
7e2d414021 | |||
b91f087736 | |||
136e2ce779 | |||
ed7a537395 | |||
23f3e806e2 | |||
1d6d23b444 | |||
9f6d4ab63f | |||
0dfcc0f511 | |||
90d657c687 | |||
20b3d081e0 | |||
56b6c9a627 | |||
485d2f128f | |||
409c109972 | |||
7156aee723 | |||
f09a304204 | |||
1302db017b | |||
9a5ac6380d | |||
7c8388af2f | |||
0d7cf3074f | |||
3fdca6cf1d | |||
cbc549f355 | |||
099585fa91 | |||
b0c8a14071 | |||
a9e0fb7beb | |||
943787bc0c | |||
0d5ababe55 | |||
2a1f53a07a | |||
7e2305c34d | |||
8000f41de8 | |||
f0a1839548 | |||
76115ae959 | |||
091cfde2a2 | |||
b77ca836b2 | |||
35edb61f9c | |||
a1561af520 | |||
da174b099e | |||
bcbe749d80 | |||
524aad05a0 | |||
ca01ba7c35 | |||
f2ceb71c2b | |||
4feb14ea35 | |||
2830f07324 | |||
abd8daafc3 | |||
489e783872 | |||
10d1fa8b02 | |||
c8bffebfc6 | |||
97f6beb3ae | |||
b80261ba16 | |||
6a114b2c2c | |||
bf29238762 | |||
13d1fb2ca0 | |||
cc1ab5685c | |||
370b3cd8c4 | |||
3a034f843d | |||
2de8e916b2 | |||
6044edfdd9 | |||
836388cd22 | |||
2685a43760 | |||
0eed3ee9c7 | |||
c5e3e89e44 | |||
1f27983505 | |||
146a8c895f | |||
efd5a0cbcd | |||
2968231b60 | |||
ea2238aa53 | |||
d22e1a5f4a | |||
31189ebecf | |||
d42e5a7a9e | |||
e13aa2a96f | |||
ae021ffeab | |||
5a9d89822f | |||
054b0c0e3f | |||
ac07ac3dcf | |||
0195386606 | |||
0026959b1e | |||
450e88d9a9 | |||
a4888634b6 | |||
46a68831c2 | |||
537d573983 | |||
96450e7010 | |||
31e1243eed | |||
0a90eb3d9c | |||
65f46aec36 | |||
37d14caa5b | |||
384474f6fd | |||
17d8592574 | |||
0936ac7840 | |||
704ece6231 | |||
5c6e98127e | |||
8805437c68 | |||
3acf791409 | |||
0ba674a341 | |||
40c33abac7 | |||
bc67317b0b | |||
06e212c66e | |||
7b314ccffd | |||
1d84986ee8 | |||
2ca8a129f7 | |||
126da8c499 | |||
ea110d5047 | |||
b37fad41c6 | |||
74775996db | |||
74426aab66 | |||
690bbb13d4 | |||
871fbed2b0 | |||
85c68d2ae6 | |||
8870611d4d | |||
67af7fc1bf | |||
93bea174e4 | |||
84fc6aabc8 | |||
38c4f5bcb6 | |||
e2af7e3149 | |||
950d75ba43 | |||
e651c99697 | |||
9694628d3f | |||
046582d1a0 | |||
f6f0ea9ae5 | |||
018547cdf3 | |||
d763a64f03 | |||
cefa460a0d | |||
cc5948ad0b | |||
be1943a66d | |||
d9acb47afe | |||
b721d26fb8 | |||
7530c7c67d | |||
824cd4d283 | |||
2e30e7aee6 | |||
3a5a3e22b9 | |||
51bd766ba6 | |||
0ab0d6db07 | |||
a12de614d6 | |||
240abd2788 | |||
e131fcb32f | |||
f88f594e87 |
3
.VERSION
Normal file
@ -0,0 +1,3 @@
|
||||
COMMIT: $Format:%H$
|
||||
REFS: $Format:%D$
|
||||
DATE: $Format:%ci$
|
1
.ci
Submodule
12
.ci-local/defaults.set
Normal file
@ -0,0 +1,12 @@
|
||||
MODULES=calc asyn
|
||||
|
||||
# EPICS Base
|
||||
BASE_DIRNAME=base
|
||||
BASE_REPONAME=epics-base
|
||||
BASE_REPOOWNER=epics-base
|
||||
BASE_VARNAME=EPICS_BASE
|
||||
BASE_RECURSIVE=no
|
||||
|
||||
ASYN_REPOOWNER=epics-modules
|
||||
|
||||
CALC_REPOOWNER=epics-modules
|
7
.cvsignore
Normal file
@ -0,0 +1,7 @@
|
||||
O.*
|
||||
*~
|
||||
bin
|
||||
lib
|
||||
dbd
|
||||
include
|
||||
*.pdf
|
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
GNUmakefile export-ignore
|
||||
.VERSION export-subst
|
164
.github/workflows/ci-scripts-build.yml
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
|
||||
# (see: https://github.com/epics-base/ci-scripts)
|
||||
|
||||
# This is YAML - indentation levels are crucial
|
||||
|
||||
# Workflow name, shared by all branches
|
||||
|
||||
name: StreamDevice
|
||||
|
||||
# Trigger on pushes and PRs to any branch
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/*'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/*'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
env:
|
||||
SETUP_PATH: .ci-local:.ci
|
||||
EPICS_TEST_IMPRECISE_TIMING: YES
|
||||
|
||||
jobs:
|
||||
native:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
# Set environment variables from matrix parameters
|
||||
env:
|
||||
CMP: ${{ matrix.cmp }}
|
||||
BCFG: ${{ matrix.configuration }}
|
||||
BASE: ${{ matrix.base }}
|
||||
WINE: ${{ matrix.wine }}
|
||||
RTEMS: ${{ matrix.rtems }}
|
||||
RTEMS_TARGET: ${{ matrix.rtems_target }}
|
||||
TEST: ${{ matrix.test }}
|
||||
EXTRA: ${{ matrix.extra }}
|
||||
VV: "1"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Native Linux (WError)
|
||||
os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
extra: "CMD_CPPFLAGS=-Werror"
|
||||
pcre: apt
|
||||
|
||||
- name: Cross mingw64 DLL
|
||||
os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
wine: "64"
|
||||
pcre: no
|
||||
|
||||
- name: Cross mingw64 static
|
||||
os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: static
|
||||
base: "7.0"
|
||||
wine: "64"
|
||||
pcre: no
|
||||
|
||||
- name: RTEMS 4.10
|
||||
os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
rtems: "4.10"
|
||||
rtems_target: RTEMS-pc386-qemu
|
||||
pcre: no
|
||||
|
||||
- name: Native Linux with clang
|
||||
os: ubuntu-20.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
pcre: apt
|
||||
|
||||
- name: Native Linux with 3.15
|
||||
os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "3.15"
|
||||
pcre: apt
|
||||
|
||||
- name: Native Linux with 3.14
|
||||
os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "3.14"
|
||||
pcre: apt
|
||||
|
||||
- name: OSX
|
||||
os: macos-latest
|
||||
cmp: clang
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
pcre: no
|
||||
|
||||
- name: vs2019 DLL
|
||||
os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: debug
|
||||
base: "7.0"
|
||||
pcre: no
|
||||
extra: "CMD_CFLAGS=-analysis CMD_CXXFLAGS=-analysis"
|
||||
|
||||
- name: vs2019 static
|
||||
os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: static-debug
|
||||
base: "7.0"
|
||||
pcre: no
|
||||
extra: "CMD_CFLAGS=-analysis CMD_CXXFLAGS=-analysis"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@master
|
||||
- name: "apt-get install"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
- name: Reset RELEASE
|
||||
shell: bash
|
||||
# 'make' on Mac doesn't understand "undefine PCRE"
|
||||
# so replace the whole file
|
||||
run: |
|
||||
cat <<EOF > configure/RELEASE
|
||||
-include \$(TOP)/../RELEASE.local
|
||||
-include \$(TOP)/../RELEASE.\$(EPICS_HOST_ARCH).local
|
||||
-include \$(TOP)/configure/RELEASE.local
|
||||
EOF
|
||||
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
|
||||
- name: "apt-get install pcre"
|
||||
if: matrix.pcre == 'apt'
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get -y install libpcre3-dev
|
||||
cat <<EOF >> configure/CONFIG_SITE.local
|
||||
PCRE_INCLUDE=/usr/include
|
||||
PCRE_LIB=/usr/lib
|
||||
EOF
|
||||
|
||||
- name: Build main module
|
||||
run: python .ci/cue.py build
|
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
O.*
|
||||
*~
|
||||
bin
|
||||
lib
|
||||
dbd
|
||||
include
|
||||
*.pdf
|
||||
*.*log
|
||||
StreamVersion.h
|
||||
*.local
|
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule ".ci"]
|
||||
path = .ci
|
||||
url = https://github.com/epics-base/ci-scripts.git
|
303
CHANGELOG.md
Normal file
@ -0,0 +1,303 @@
|
||||
# Changelog
|
||||
|
||||
## Changes in release 2.8.20
|
||||
|
||||
Fix missing initialization of `inTerminator` and `outTerminator`.
|
||||
Thanks to Krisztián Löki.
|
||||
|
||||
New checksums `%<lrc>` and `%<hexlrc>`.
|
||||
Thanks to Marcio Paduan Donadio.
|
||||
|
||||
Make timestamp output in error and debug messages optional with new
|
||||
iocsh variable `streamMsgTimeStamped`. Default is 1.
|
||||
|
||||
Reduce number of duplicate error messages. Dead time for repeated messages
|
||||
is configurable with new iocsh variable `streamErrorDeadTime`.
|
||||
Thanks to Dominic Oram.
|
||||
|
||||
Shifted some noisy debug messages to `streamDebug` level 2.
|
||||
|
||||
In `STREAM_PROTOCOL_PATH`, allow both `:` and `;` separators on all
|
||||
operating systems to make startup scripts OS independent.
|
||||
On Windows however, an initial single letter followed by a `:` is detected
|
||||
as a drive letter. Thus single letter directories must be separated with
|
||||
`;` or followed by `\` or `/` on Windows.
|
||||
|
||||
Allow absolute path protocol files. Those will not use
|
||||
`STREAM_PROTOCOL_PATH`.
|
||||
Changed the default search path from `"."` to `NULL`.
|
||||
|
||||
Only poll for `I/O Intr` records while `interruptAccept` is true,
|
||||
in particular not between `iocPause` and `iocRun`.
|
||||
|
||||
Added this change log and a document about contributing to StreamDevice.
|
||||
|
||||
## Changes in release 2.8.19
|
||||
|
||||
Make colorization of error and debug messages optional with new
|
||||
iocsh variable `streamDebugColored`. Defaults to 1 when output is a tty
|
||||
and 0 otherwise.
|
||||
|
||||
## Changes in release 2.8.18
|
||||
|
||||
Another format string fix for VxWorks in checksum converter.
|
||||
|
||||
## Changes in release 2.8.17
|
||||
|
||||
Fix format strings for VxWorks 6.9 in checksum converter.
|
||||
|
||||
Fix some compiler warnings on Windows.
|
||||
|
||||
Fix some missing header files installations.
|
||||
|
||||
## Changes in release 2.8.16
|
||||
|
||||
Drop support of upper level `configure/` directory for improved
|
||||
compatibility with SynApps.
|
||||
|
||||
Fix problem with extra spaces after protocol name in record links.
|
||||
|
||||
Make version string generation more robust.
|
||||
|
||||
## Changes in release 2.8.15
|
||||
|
||||
Do not overwrite `HOST_OPT` flag.
|
||||
|
||||
Fix version string generation for zip downloads.
|
||||
|
||||
On Windows use `;` and `\` in `STREAM_PROTOCOL_PATH`.
|
||||
(Was not the case before due to typo in macro name.)
|
||||
|
||||
Link streamApp with `seq` and `pv` libraries when `SNCSEQ` is defined in
|
||||
RELEASE file.
|
||||
|
||||
## Changes in release 2.8.14
|
||||
|
||||
Fix version string generation from git tags.
|
||||
|
||||
## Changes in release 2.8.13
|
||||
|
||||
Fix bug with integer datatype handling in redirectons.
|
||||
|
||||
## Changes in release 2.8.12
|
||||
|
||||
Apply GPL-3.0.
|
||||
|
||||
## Changes in release 2.8.11
|
||||
|
||||
Fix buffer overrun.
|
||||
Thanks to Garth Brown and Bruce Hill.
|
||||
|
||||
Fix bug in 64 bit data type handling in array records (`aai`, `aao`,
|
||||
`waveform`).
|
||||
Thanks to Andrew Johnson.
|
||||
|
||||
Fix Windows linker problem.
|
||||
Thanks to Freddie Akeroyd.
|
||||
|
||||
Allow `(,)` inside protocol parameters. Limitation: Parenthesis must be in
|
||||
matching pairs. Commas within inner parenthesis are consideres part of the
|
||||
argument. Example: `protocol(arg1, (arg2, still arg 2), arg3)`.
|
||||
|
||||
New checksums `%<brksCryo>`, `%<xor8ff>`, `%<nsum8>`, `%<nsum16>`,
|
||||
`%<nsum32>`, `%<notsum>`.
|
||||
Thanks to Mark Davis.
|
||||
|
||||
Some error message cleanup.
|
||||
|
||||
## Changes in release 2.8.10
|
||||
|
||||
Fixes for Windows / Visual Studio 2010.
|
||||
Thanks to Freddie Akeroyd.
|
||||
|
||||
Fix infinite loop in `I/O Intr` scanned records.
|
||||
|
||||
Enable error messages by default and always show error messages too when
|
||||
debug messages are enabled.
|
||||
|
||||
Make sure any console output from StreamDevice can be redirected.
|
||||
|
||||
Fix some problems when building for old EPICS R3.13.
|
||||
|
||||
## Changes in release 2.8.9
|
||||
|
||||
Leave `asynTraceMask` alone. Before, streamDevice had set `setTraceMask`
|
||||
to 0 initially.
|
||||
|
||||
Link with `sscan` module if `SSCAN` is defined in RELEASE file because the
|
||||
`calc` module may need it.
|
||||
|
||||
Fix in regsub converter: Avoid infinite loop if an empty string is matched.
|
||||
Add support for toupper/tolower to regsub converter.
|
||||
|
||||
Fix build problem observed on MacOS related to clash between `wait()`
|
||||
system function and the StreamDevice `wait` command.
|
||||
|
||||
Allow `%%` in addition to `\%` to escape `%` in protocols (compatibility
|
||||
with `printf`/`scanf`).
|
||||
|
||||
Have separate dbd file for applications without scalcout support built in.
|
||||
|
||||
Improved compatibility with SynApps. (fix of the attempt in 2.8.6)
|
||||
|
||||
## Changes in release 2.8.8
|
||||
|
||||
Fix problem with `in` command hanging forever if it is the the first
|
||||
command of the protocol and the device is offline.
|
||||
|
||||
## Changes in release 2.8.7
|
||||
|
||||
Enable colored error/debug output on Windows.
|
||||
|
||||
Changed error/debug hex output highlight from fat to inverse.
|
||||
|
||||
Fix build problem on Windows.
|
||||
|
||||
## Changes in release 2.8.6
|
||||
|
||||
Improved compatibility with SynApps.
|
||||
|
||||
Fix redirection to records with names not starting with a letter or
|
||||
underscore.
|
||||
|
||||
### Fixes/improvements for `mbbo` device support:
|
||||
|
||||
Use `.MASK` and `.SHFT` fields even if no `xxVL` field is defined
|
||||
(and thus `.VAL` is used instead of `.RVAL`).
|
||||
|
||||
Bugfix: Set `mbbo` to unknown state `0xffff` if in readback no state
|
||||
matches.
|
||||
|
||||
Bugfix: Use defined state alarms when `mbbo` is updated by `@init` handler.
|
||||
|
||||
## Changes in release 2.8.5
|
||||
|
||||
A `"\?"` at the end of an input format now matches an empty string.
|
||||
Used to do so unintendedly in earlier versions but had been changed.
|
||||
|
||||
## Changes in release 2.8.4
|
||||
|
||||
Bugfix: After `@init` had been triggered with "magic value" 2 in `.PROC`
|
||||
field, reset the field to 0.
|
||||
|
||||
## Changes in release 2.8.3
|
||||
|
||||
Increase limits on filename, protocolname, busname in record links.
|
||||
|
||||
Bugfix: Fix typo calcout device support that prevented compiling it.
|
||||
|
||||
## Changes in release 2.8.2
|
||||
|
||||
Bugfix: Fix string termination reading into char array records (`waveform`,
|
||||
`aai`, `aao`, `lsi`, `lso`).
|
||||
|
||||
## Changes in release 2.8.1
|
||||
|
||||
Allow empty parameter list `()` in record links.
|
||||
|
||||
## Changes between 2.7 and 2.8.0
|
||||
|
||||
### Build system
|
||||
|
||||
Drop support for (buggy) cygnus-2.7.2 gcc (as used in some old cygwin
|
||||
version).
|
||||
|
||||
Add standard EPICS App build system (`configure/`).
|
||||
|
||||
Some re-ordering of directories.
|
||||
When upgrading from 2.7 or earlier to 2.8, better start with a fresh
|
||||
source directory to avoid problems with files that have moved.
|
||||
|
||||
### New Features
|
||||
|
||||
Support for 64 bit integers. This affects some conversions (e.g. in `ai`
|
||||
and `ao` records).
|
||||
|
||||
Device support for new record types `int64in`, `int64out`, `lsi` and `lso`
|
||||
added.
|
||||
|
||||
Support for new `INT64` and `UINT64` types in `aai`, `aao` and `waveform`
|
||||
records.
|
||||
|
||||
Allow spaces in protocol parameter list in record link.
|
||||
One space after the opening `(`, before and after the separating `,` and
|
||||
before the closing `)` ignored. More spaces are part of the parameter.
|
||||
|
||||
String format `%s` can now pad with 0-bytes instead of spaces using the
|
||||
`0` flag.
|
||||
|
||||
New checksums `%<cpi>` and `%<leybold>`.
|
||||
|
||||
Properly distinguish beween signed and unsigned integers, e.g. when
|
||||
converting to double.
|
||||
Allow signed enums to do this: `%#{backwards=-1|stop=0|forwards=1}`.
|
||||
|
||||
#### New connection handling
|
||||
|
||||
Run `@init` handler each time the device (re-)connects
|
||||
(as long as asynDriver detects connection changes), also at each `iocRun`
|
||||
(after being paused with `iocPause`), and after each `streamReload`.
|
||||
|
||||
Also run `@init` of a record when the "magic value" 2 is written to the
|
||||
`.PROC` field or when new `streamReinitRecord` shell function is called.
|
||||
|
||||
Trigger monitors when `@init` updates output records (after the intial run
|
||||
in `iocInit`).
|
||||
|
||||
Use `"COMM"` error code in `.STAT` when device is disconnected.
|
||||
|
||||
If write fails because device has disconnected, try to re-connect and re-do
|
||||
write once.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix parser bug when command reference was followed by `}` without `;`.
|
||||
|
||||
Fix potential buffer overrun during `streamReload`.
|
||||
After `streamReload`, properly delete handlers and variables that do not
|
||||
exist any longer.
|
||||
|
||||
Fix for waveforms of unsigned integers.
|
||||
|
||||
Several Windows related fixes and support building shared libraries on
|
||||
Windows.
|
||||
|
||||
Fix C++11 warnings.
|
||||
|
||||
Check formatting of `exec` command for errors.
|
||||
|
||||
Fix bug in `dbior` output.
|
||||
|
||||
Fix BCD `%D` format and allow negative values.
|
||||
|
||||
Fix signed hex and octal formats.
|
||||
|
||||
Fix in regsub: Do not run regsub again on substituted string.
|
||||
|
||||
### Shell functions
|
||||
|
||||
New functions `streamReportRecord` and `streamSetLogfile`.
|
||||
|
||||
Support output redirection to file of stream shell functions
|
||||
and protocol dump via `dbior`.
|
||||
|
||||
### Error and debug output
|
||||
|
||||
Cleanup some debug and error messages.
|
||||
|
||||
Hex bytes in debug/error output are now highlighted.
|
||||
|
||||
`StreamError` can now be set before `iocInit`.
|
||||
|
||||
Avoid repeating error messages.
|
||||
Thanks to Ben Franksen.
|
||||
|
||||
### Documentation
|
||||
|
||||
HTML files converted to HTML 5.
|
||||
|
||||
Update and improve several chapters.
|
||||
|
||||
## Changes in releases up to 2.7.14
|
||||
|
||||
Not available. See git log.
|
81
Contributing.md
Normal file
@ -0,0 +1,81 @@
|
||||
# Contributing to StreamDevice
|
||||
|
||||
Contributions from the EPICS community (and others) are welcome.
|
||||
To ease the integration process, please follow the following guidelines.
|
||||
|
||||
All contributions should be done as a pull request to the git repository
|
||||
https://github.com/paulscherrerinstitute/StreamDevice. Make sure to provide
|
||||
meaningful commit messages (no essay but more than "changes").
|
||||
|
||||
For small modifications, a patch file is sufficient. Send it to me or better
|
||||
create an issue on https://github.com/paulscherrerinstitute/StreamDevice/issues
|
||||
and attach the patch file.
|
||||
|
||||
Justify your change requests. Write a short summary for your pull request
|
||||
to explain what the change is about and what it improves or which bug it
|
||||
fixes. Use the issue system on github to report bugs.
|
||||
|
||||
I reserve the right to accept or reject contributions or to request
|
||||
modifications before I accept them.
|
||||
|
||||
Of course, you may as well report bugs without providing a solution yourself.
|
||||
|
||||
## Code compatibility
|
||||
|
||||
All code must compile for any EPICS release from at least R3.14.12 up to the
|
||||
latest one. Likewise the code must be compatible with any operating system
|
||||
supported by EPICS, like Linux, Windows, MacOS, RTEMS and VxWorks.
|
||||
In particular VxWorks 5 compatibility rules out many modern C++ features.
|
||||
But there are also other platforms that for example do not support C++11, so
|
||||
don't use it.
|
||||
There should also be no compiler warning on any OS.
|
||||
|
||||
Avoid compiler dependent features like #pragmas, assumptions on byte order,
|
||||
type size (in particular the size of pointers and long int) and other
|
||||
non-portable things like the availability of certain header files. Make sure
|
||||
non-portable code parts are enclosed in proper compiler branches and provide
|
||||
working implementations for all architectures.
|
||||
|
||||
Make sure that the code in AsynDriverInterface stays compatible with old
|
||||
and new versions of asyn driver.
|
||||
|
||||
The core of StreamDevice does not depend on EPICS. This is on purpose, to be
|
||||
able to use it in other control system frameworks. Modifications should not
|
||||
add EPICS dependencies except to StreamEpics and AsynDriverInterface, or the
|
||||
new dependency must be in a separate file which can be left out of the build
|
||||
without jeopardizing the main functionality of StreamDevice.
|
||||
|
||||
The code must not depend on external libraries that may not be available on
|
||||
all systems, except if provided as a separate file which can be left out of
|
||||
the build on platforms that do not support the library.
|
||||
|
||||
## Language
|
||||
|
||||
Write in English. That includes all identifiers (variables, functions, ...),
|
||||
comments, documentation and commit messages. Check your spelling.
|
||||
|
||||
## File formats
|
||||
|
||||
All files are in Unix format (\n line terminators). Do not change them to
|
||||
any other format (e.g. Windows with \r\n terminators). Do not add new files in
|
||||
other formats.
|
||||
|
||||
The files must contain only ASCII characters. Do not use any Unicode multi-byte
|
||||
characters (including byte order marks) or any pre-Unicode code page dependent
|
||||
characters (e.g. umlaut), not even in comments. Do not use form feed, vertical
|
||||
tab, or other control characters except newline.
|
||||
|
||||
Indents are 4 spaces. Do not use tabs (except in Makefiles). Make sure your
|
||||
editor is set up accordingly.
|
||||
|
||||
Files must end in a newline and there must be no spaces at the end of lines.
|
||||
Do not add excessive amount of newlines at the end of files.
|
||||
|
||||
Do not add any editor configurations (e.g. for emacs) to the files. Also do
|
||||
not add any configuration files or directories for development environments,
|
||||
editors, etc.
|
||||
|
||||
-------
|
||||
|
||||
Dirk Zimoch <dirk.zimoch@psi.ch>, June 2021
|
||||
|
57
GNUmakefile
Normal file
@ -0,0 +1,57 @@
|
||||
ifeq ($(wildcard /ioc/tools/driver.makefile),)
|
||||
$(info If you are not using the PSI build environment, GNUmakefile can be removed.)
|
||||
include Makefile
|
||||
else
|
||||
include /ioc/tools/driver.makefile
|
||||
EXCLUDE_VERSIONS = 3.13.2
|
||||
PROJECT=stream
|
||||
BUILDCLASSES += vxWorks Linux WIN32
|
||||
|
||||
DOCUDIR = docs
|
||||
|
||||
PCRE=1
|
||||
ASYN=1
|
||||
-include ../src/CONFIG_STREAM
|
||||
-include src/CONFIG_STREAM
|
||||
|
||||
SOURCES += $(RECORDTYPES:%=src/dev%Stream.c)
|
||||
SOURCES += $(FORMATS:%=src/%Converter.cc)
|
||||
SOURCES += $(BUSSES:%=src/%Interface.cc)
|
||||
SOURCES += $(STREAM_SRCS:%=src/%)
|
||||
|
||||
HEADERS += src/devStream.h
|
||||
HEADERS += src/StreamFormat.h
|
||||
HEADERS += src/StreamFormatConverter.h
|
||||
HEADERS += src/StreamBuffer.h
|
||||
HEADERS += src/StreamError.h
|
||||
HEADERS += src/StreamProtocol.h
|
||||
HEADERS += src/StreamBusInterface.h
|
||||
HEADERS += src/StreamCore.h
|
||||
HEADERS += src/MacroMagic.h
|
||||
HEADERS += $(COMMON_DIR)/StreamVersion.h
|
||||
|
||||
CPPFLAGS += -DSTREAM_INTERNAL -I$(COMMON_DIR)
|
||||
|
||||
# Update version string each time anything changes
|
||||
StreamVersion$(OBJ) StreamVersion$(DEP): $(COMMON_DIR)/StreamVersion.h $(filter-out StreamVersion$(OBJ) stream_exportAddress$(OBJ),$(LIBOBJS) $(LIBRARY_OBJS))
|
||||
|
||||
$(COMMON_DIR)/StreamVersion.h: $(filter-out StreamVersion.h,$(notdir $(SOURCES) $(HEADERS)))
|
||||
@echo Creating $@
|
||||
$(PERL) ../src/makeStreamVersion.pl $@
|
||||
|
||||
StreamCore$(OBJ) StreamCore$(DEP): streamReferences
|
||||
streamReferences:
|
||||
$(PERL) ../src/makeref.pl Interface $(BUSSES) > $@
|
||||
$(PERL) ../src/makeref.pl Converter $(FORMATS) >> $@
|
||||
|
||||
export DBDFILES = streamSup.dbd
|
||||
streamSup.dbd:
|
||||
@echo Creating $@ from $(RECORDTYPES)
|
||||
$(PERL) ../src/makedbd.pl $(RECORDTYPES) > $@
|
||||
ifdef BASE_3_14
|
||||
ifdef ASYN
|
||||
echo "registrar(AsynDriverInterfaceRegistrar)" >> $@
|
||||
endif
|
||||
endif
|
||||
|
||||
endif
|
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
165
LICENSE.LESSER
Normal file
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
5
MODULE
@ -1,5 +0,0 @@
|
||||
# Please change the following email with yours.
|
||||
Email: dirk.zimoch@psi.ch
|
||||
Module-Name: StreamDevice2
|
||||
Description: StreamDevice2
|
||||
Project-Name:
|
54
Makefile
@ -1,24 +1,38 @@
|
||||
TOP = ..
|
||||
##########################################################################
|
||||
# This is an EPICS Makefile for StreamDevice.
|
||||
# Normally it should not be necessary to modify this file.
|
||||
# All configuration can be done in CONFIG_STREAM
|
||||
#
|
||||
# (C) 2007,2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
#
|
||||
# This file is part of StreamDevice.
|
||||
#
|
||||
# StreamDevice is free software: You can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# StreamDevice is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
#########################################################################/
|
||||
|
||||
DIRS = src
|
||||
streamApp_DEPEND_DIRS = src
|
||||
|
||||
# Look if we have EPICS R3.13 or R3.14
|
||||
ifeq ($(wildcard $(TOP)/configure),)
|
||||
# EPICS R3.13
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
CONFIG = $(TOP)/config
|
||||
else
|
||||
# EPICS R3.14
|
||||
include $(TOP)/configure/CONFIG
|
||||
ifneq ($(words $(CALC) $(SYNAPPS)), 0)
|
||||
# with synApps calc module (contains scalcout)
|
||||
DIRS += srcSynApps
|
||||
srcSynApps_DEPEND_DIRS = src
|
||||
streamApp_DEPEND_DIRS += srcSynApps
|
||||
endif
|
||||
endif
|
||||
TOP = .
|
||||
DIRS = configure
|
||||
src_DEPEND_DIRS := $(DIRS)
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
DIRS += src
|
||||
DIRS += streamApp
|
||||
streamApp_DEPEND_DIRS = src
|
||||
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
include $(CONFIG)/RULES_TOP
|
||||
|
||||
docs/stream.pdf: docs/*.html docs/*.css docs/*.png
|
||||
cd docs; makepdf
|
||||
|
||||
pdf: docs/stream.pdf
|
||||
|
35
README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# StreamDevice
|
||||
|
||||
_StreamDevice_ is a generic [EPICS](https://epics.anl.gov/)
|
||||
device support for devices with a "byte stream" based
|
||||
communication interface.
|
||||
That means devices that can be controlled by sending and receiving
|
||||
strings (in the broadest sense, including non-printable characters
|
||||
and even null-bytes).
|
||||
Examples for this type of communication interface are
|
||||
serial line (RS-232, RS-485, ...),
|
||||
IEEE-488 (also known as GPIB or HP-IB), and telnet-like TCP/IP.
|
||||
|
||||
_StreamDevice_ is not limited to a specific device type or manufacturer
|
||||
nor is it necessary to re-compile anything to support a new device type.
|
||||
Instead, it can be configured for any device type with _protocol files_
|
||||
in plain ASCII text which describes the commands a device understands
|
||||
and the replies it sends.
|
||||
|
||||
For a full documentation see
|
||||
https://paulscherrerinstitute.github.io/StreamDevice.
|
||||
|
||||
## Licensing
|
||||
|
||||
StreamDevice is free software: You can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
StreamDevice is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
12
config/CONFIG_APP
Normal file
@ -0,0 +1,12 @@
|
||||
#CONFIG_APP
|
||||
include $(TOP)/configure/RELEASE
|
||||
-include $(TOP)/configure/RELEASE.$(HOST_ARCH)
|
||||
-include $(EPICS_BASE)/config/CONFIG
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
ifdef INSTALL_LOCATION_APP
|
||||
INSTALL_LOCATION = $(INSTALL_LOCATION_APP)
|
||||
endif
|
||||
|
||||
ifdef T_A
|
||||
-include $(TOP)/config/O.$(T_A)/CONFIG_APP_INCLUDE
|
||||
endif
|
30
config/Makefile
Normal file
@ -0,0 +1,30 @@
|
||||
##########################################################################
|
||||
# This is an EPICS Makefile for StreamDevice.
|
||||
# Normally it should not be necessary to modify this file.
|
||||
# All configuration can be done in CONFIG_STREAM
|
||||
#
|
||||
# (C) 2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
#
|
||||
# This file is part of StreamDevice.
|
||||
#
|
||||
# StreamDevice is free software: You can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# StreamDevice is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
#########################################################################/
|
||||
|
||||
TOP=..
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
ifneq ($(wildcard $(EPICS_BASE)/config),)
|
||||
include $(EPICS_BASE)/config/RULES_ARCHS
|
||||
else
|
||||
build install clean realclean:
|
||||
endif
|
20
config/Makefile.Host
Normal file
@ -0,0 +1,20 @@
|
||||
#
|
||||
# $Id: Makefile.Host,v 1.1.1.1 2000/04/05 07:33:44 janousch Exp $
|
||||
#
|
||||
|
||||
TOP=../..
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
|
||||
TARGETS = CONFIG_APP_INCLUDE
|
||||
|
||||
include $(TOP)/config/RULES.Host
|
||||
|
||||
inc:: $(TARGETS)
|
||||
|
||||
ifeq ($(wildcard $(TOP)/configure/RELEASE.$(HOST_ARCH)),$(TOP)/configure/RELEASE.$(HOST_ARCH))
|
||||
CONFIG_APP_INCLUDE: $(TOP)/configure/RELEASE.$(HOST_ARCH)
|
||||
endif
|
||||
|
||||
CONFIG_APP_INCLUDE: $(TOP)/configure/RELEASE $(TOP)/config/CONFIG_APP
|
||||
$(RM) $@
|
||||
@$(PERL) $(TOP)/config/makeConfigAppInclude.pl $(T_A) $@ $(TOP)
|
15
config/Makefile.Vx
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# Makefile.Vx,v 1.1.2.3 2001/09/14 19:39:15 anj Exp
|
||||
#
|
||||
|
||||
TOP=../..
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
|
||||
TARGETS = CONFIG_APP_INCLUDE
|
||||
|
||||
include $(EPICS_BASE)/config/RULES.Vx
|
||||
|
||||
inc:: $(TARGETS)
|
||||
|
||||
CONFIG_APP_INCLUDE: $(wildcard $(TOP)/config/RELEASE*) $(TOP)/config/CONFIG_APP
|
||||
$(PERL) $(TOP)/config/convertRelease.pl -h $(HOST_ARCH) $@
|
3
config/RULES.Host
Normal file
@ -0,0 +1,3 @@
|
||||
#RULES.Host
|
||||
|
||||
include $(EPICS_BASE)/config/RULES.Host
|
@ -1,12 +1,14 @@
|
||||
MUNCH = $(PERL) $(INSTALL_LOCATION)/bin/$(HOST_ARCH)/munch.pl
|
||||
|
||||
# The original 3.13.10 munching rule does not really work well
|
||||
|
||||
# This is the munch.pl taken from EPICS base 3.14.8.2
|
||||
MUNCH = $(PERL) ../../config/munch.pl
|
||||
|
||||
build:: $(LIBNAME).munch
|
||||
|
||||
buildInstall:: $(INSTALL_BIN)/$(LIBNAME).munch
|
||||
|
||||
%.munch: %
|
||||
@echo "Munching $<"
|
||||
$(RM) $*_ctct.o $*_ctdt.c
|
||||
$(NM) $< | $(MUNCH) > $*_ctdt.c
|
||||
$(GCC) -traditional $(CFLAGS) -fdollars-in-identifiers -c $(SOURCE_FLAG) $*_ctdt.c
|
2
config/RULES_ARCHS
Normal file
@ -0,0 +1,2 @@
|
||||
#RULES_ARCHS
|
||||
include $(EPICS_BASE)/config/RULES_ARCHS
|
2
config/RULES_DIRS
Normal file
@ -0,0 +1,2 @@
|
||||
#RULES_DIRS
|
||||
include $(EPICS_BASE)/config/RULES_DIRS
|
186
config/convertRelease.pl
Normal file
@ -0,0 +1,186 @@
|
||||
eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
|
||||
if $running_under_some_shell; # convertRelease.pl
|
||||
#
|
||||
# convertRelease.pl,v 1.1.2.1 2001/09/14 19:39:15 anj Exp
|
||||
#
|
||||
# Parse config/RELEASE file(s) and generate a derived output file.
|
||||
#
|
||||
# This tool replaces makeConfigAppInclude.pl and makeIocCdCommands.pl
|
||||
# and adds consistency checks for RELEASE files.
|
||||
#
|
||||
|
||||
use Cwd;
|
||||
use Getopt::Std;
|
||||
|
||||
$cwd = cwd();
|
||||
$cwd =~ s/\/tmp_mnt//; # hack for sun4
|
||||
$cwd =~ s/\\/\//g; # hack for win32
|
||||
|
||||
getopt "aht";
|
||||
|
||||
if ($opt_a) {
|
||||
$arch = $opt_a;
|
||||
} else { # Look for O.<arch> in current path
|
||||
$_ = $cwd;
|
||||
($arch) = /.*\/O.([\w-]+)$/;
|
||||
}
|
||||
|
||||
$hostarch = $arch;
|
||||
$hostarch = $opt_h if ($opt_h);
|
||||
|
||||
if ($opt_t) {
|
||||
$top = $opt_t;
|
||||
} else { # Find $top from current path
|
||||
$top = $cwd;
|
||||
$top =~ s/\/iocBoot.*//;
|
||||
$top =~ s/\/config\/O\..*//;
|
||||
}
|
||||
|
||||
unless (@ARGV == 1) {
|
||||
print "Usage: convertRelease.pl [-a arch] [-h hostarch] [-t top] outfile\n";
|
||||
print " where outfile is be one of:\n";
|
||||
print "\tcheckRelease - checks consistency with support apps\n";
|
||||
print "\tcdCommands - generate cd path strings for IOC use\n";
|
||||
print "\tCONFIG_APP_INCLUDE - additional build variables\n";
|
||||
exit 2;
|
||||
}
|
||||
$outfile = $ARGV[0];
|
||||
|
||||
# TOP refers to this application
|
||||
%macros = (TOP => $top);
|
||||
@apps = (TOP); # Provides the order of apps in RELEASE file
|
||||
|
||||
# Read the RELEASE file(s)
|
||||
$relfile = "$top/configure/RELEASE";
|
||||
die "Can't find configure/RELEASE file" unless (-r $relfile);
|
||||
&readRelease($relfile, \%macros, \@apps);
|
||||
|
||||
if ($hostarch) {
|
||||
$relfile .= ".$hostarch";
|
||||
&readRelease($relfile, \%macros, \@apps) if (-r $relfile);
|
||||
}
|
||||
|
||||
# This is a perl switch statement:
|
||||
for ($outfile) {
|
||||
/CONFIG_APP_INCLUDE/ and do { &configAppInclude; last; };
|
||||
/cdCommands/ and do { &cdCommands; last; };
|
||||
/checkRelease/ and do { &checkRelease; last; };
|
||||
die "Output file type \'$outfile\' not supported";
|
||||
}
|
||||
|
||||
sub readRelease {
|
||||
my ($file, $Rmacros, $Rapps) = @_;
|
||||
# $Rmacros is a reference to a hash, $Rapps a ref to an array
|
||||
my ($pre, $macro, $post, $path);
|
||||
local *IN;
|
||||
open(IN, $file) or die "Can't open $file: $!\n";
|
||||
while (<IN>) {
|
||||
chomp;
|
||||
s/\s*#.*$//; # Remove trailing comments
|
||||
next if /^\s*$/; # Skip blank lines
|
||||
|
||||
# Expand all macros in the line:
|
||||
while (($pre,$macro,$post) = /(.*)\$\((\w+)\)(.*)/, $macro ne "") {
|
||||
$_ = $pre . $Rmacros->{$macro} . $post;
|
||||
}
|
||||
|
||||
# Handle "<macro> = <path>"
|
||||
($macro, $path) = /^\s*(\w+)\s*=\s*(.*)/;
|
||||
if ($macro ne "") {
|
||||
$Rmacros->{$macro} = $path;
|
||||
push @$Rapps, $macro;
|
||||
next;
|
||||
}
|
||||
# Handle "include <path>" syntax
|
||||
($path) = /^\s*include\s+(.*)/;
|
||||
&readRelease($path, $Rmacros, $Rapps) if (-r $path);
|
||||
}
|
||||
close IN;
|
||||
}
|
||||
|
||||
sub configAppInclude {
|
||||
@includes = grep !/^(TOP|TEMPLATE_TOP)$/, @apps;
|
||||
|
||||
unlink($outfile);
|
||||
open(OUT,">$outfile") or die "$! creating $outfile";
|
||||
print OUT "# Do not modify this file, changes made here will\n";
|
||||
print OUT "# be lost when the application is next rebuilt.\n\n";
|
||||
|
||||
if ($arch) {
|
||||
foreach $app (@includes) {
|
||||
$path = $macros{$app};
|
||||
next unless (-d "$path/bin/$arch");
|
||||
print OUT "${app}_BIN = \$($app)/bin/$arch\n";
|
||||
}
|
||||
foreach $app (@includes) {
|
||||
$path = $macros{$app};
|
||||
next unless (-d "$path/lib/$arch");
|
||||
print OUT "${app}_LIB = \$($app)/lib/$arch\n";
|
||||
}
|
||||
}
|
||||
foreach $app (@includes) {
|
||||
$path = $macros{$app};
|
||||
next unless (-d "$path/include");
|
||||
print OUT "EPICS_INCLUDES += -I\$($app)/include\n";
|
||||
}
|
||||
foreach $app (@includes) {
|
||||
$path = $macros{$app};
|
||||
next unless (-d "$path/dbd");
|
||||
print OUT "EPICS_DBDFLAGS += -I \$($app)/dbd\n";
|
||||
}
|
||||
close OUT;
|
||||
}
|
||||
|
||||
sub cdCommands {
|
||||
die "Architecture not set (use -a option)" unless ($arch);
|
||||
@includes = grep !/^TEMPLATE_TOP$/, @apps;
|
||||
|
||||
# if -t <top> was given, substitute it in the startup path
|
||||
$startup = $cwd;
|
||||
$startup =~ s/.*(\/iocBoot\/.*)/$top$1/ if ($opt_t);
|
||||
|
||||
unlink($outfile);
|
||||
open(OUT,">$outfile") or die "$! creating $outfile";
|
||||
print OUT "startup = \"$startup\"\n";
|
||||
print OUT "appbin = \"$top/bin/$arch\"\n"; # compatibility with R3.13.1
|
||||
|
||||
foreach $app (@includes) {
|
||||
$path = $macros{$app};
|
||||
$lcapp = lc($app);
|
||||
print OUT "$lcapp = \"$path\"\n" if (-d $path);
|
||||
print OUT "${lcapp}bin = \"$path/bin/$arch\"\n" if (-d "$path/bin/$arch");
|
||||
}
|
||||
close OUT;
|
||||
}
|
||||
|
||||
sub checkRelease {
|
||||
$status = 0;
|
||||
delete $macros{TOP};
|
||||
delete $macros{TEMPLATE_TOP};
|
||||
|
||||
while (($app, $path) = each %macros) {
|
||||
%check = (TOP => $path);
|
||||
@order = ();
|
||||
$relfile = "$path/config/RELEASE";
|
||||
&readRelease($relfile, \%check, \@order) if (-r $relfile);
|
||||
if ($hostarch) {
|
||||
$relfile .= ".$hostarch";
|
||||
&readRelease($relfile, \%check, \@order) if (-r $relfile);
|
||||
}
|
||||
delete $check{TOP};
|
||||
|
||||
while (($parent, $ppath) = each %check) {
|
||||
if (exists $macros{$parent} && ($macros{$parent} ne $ppath)) {
|
||||
print "\n" unless ($status);
|
||||
print "Definition of $parent conflicts with $app support.\n";
|
||||
print "In this application config/RELEASE defines\n";
|
||||
print "\t$parent = $macros{$parent}\n";
|
||||
print "but $app at $path has\n";
|
||||
print "\t$parent = $ppath\n";
|
||||
$status = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
print "\n" if ($status);
|
||||
exit $status;
|
||||
}
|
62
config/makeConfigAppInclude.pl
Normal file
@ -0,0 +1,62 @@
|
||||
# $Id: makeConfigAppInclude.pl,v 1.1.1.1 2000/04/05 07:33:44 janousch Exp $
|
||||
|
||||
eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
|
||||
if $running_under_some_shell; # makeConfigAppInclude.pl
|
||||
|
||||
use Cwd;
|
||||
|
||||
$arch = $ARGV[0];
|
||||
$outfile = $ARGV[1];
|
||||
$top = $ARGV[2];
|
||||
|
||||
unlink("${outfile}");
|
||||
open(OUT,">${outfile}") or die "$! opening ${outfile}";
|
||||
print OUT "#Do not modify this file.\n";
|
||||
print OUT "#This file is created during the build.\n";
|
||||
|
||||
@files =();
|
||||
push(@files,"$top/config/RELEASE");
|
||||
push(@files,"$top/config/RELEASE.${arch}");
|
||||
foreach $file (@files) {
|
||||
if (-r "$file") {
|
||||
open(IN, "$file") or die "Cannot open $file\n";
|
||||
while ($line = <IN>) {
|
||||
next if ( $line =~ /\s*#/ );
|
||||
chomp($line);
|
||||
$_ = $line;
|
||||
#the following looks for
|
||||
# prefix = $(macro)post
|
||||
($prefix,$macro,$post) = /(.*)\s*=\s*\$\((.*)\)(.*)/;
|
||||
if ($macro eq "") { # true if no macro is present
|
||||
# the following looks for
|
||||
# prefix = post
|
||||
($prefix,$post) = /(.*)\s*=\s*(.*)/;
|
||||
} else {
|
||||
$base = $applications{$macro};
|
||||
if ($base eq "") {
|
||||
#print "error: $macro was not previously defined\n";
|
||||
} else {
|
||||
$post = $base . $post;
|
||||
}
|
||||
}
|
||||
$applications{$prefix} = $post;
|
||||
if ( -d "$post") { #check that directory exists
|
||||
print OUT "\n";
|
||||
if ( -d "$post/bin/$arch") { #check that directory exists
|
||||
print OUT "${prefix}_BIN = $post/bin/${arch}\n";
|
||||
}
|
||||
if ( -d "$post/lib/$arch") { #check that directory exists
|
||||
print OUT "${prefix}_LIB = $post/lib/${arch}\n";
|
||||
}
|
||||
if ( -d "$post/include") { #check that directory exists
|
||||
print OUT "EPICS_INCLUDES += -I$post/include\n";
|
||||
}
|
||||
if ( -d "$post/dbd") { #check that directory exists
|
||||
print OUT "EPICS_DBDFLAGS += -I $post/dbd\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
}
|
||||
}
|
||||
close OUT;
|
29
configure/CONFIG
Normal file
@ -0,0 +1,29 @@
|
||||
# CONFIG - Load build configuration data
|
||||
#
|
||||
# Do not make changes to this file!
|
||||
|
||||
# Allow user to override where the build rules come from
|
||||
RULES = $(EPICS_BASE)
|
||||
|
||||
# RELEASE files point to other application tops
|
||||
include $(TOP)/configure/RELEASE
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH)
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
ifdef T_A
|
||||
-include $(TOP)/configure/RELEASE.Common.$(T_A)
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
CONFIG = $(RULES)/configure
|
||||
include $(CONFIG)/CONFIG
|
||||
|
||||
# Override the Base definition:
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
|
||||
# CONFIG_SITE files contain other build configuration settings
|
||||
include $(TOP)/configure/CONFIG_SITE
|
||||
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
|
||||
ifdef T_A
|
||||
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
|
||||
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
40
configure/CONFIG_SITE
Normal file
@ -0,0 +1,40 @@
|
||||
# CONFIG_SITE
|
||||
|
||||
-include $(SUPPORT)/configure/CONFIG_SITE
|
||||
|
||||
# Make any application-specific changes to the EPICS build
|
||||
# configuration variables in this file.
|
||||
#
|
||||
# Host/target specific settings can be specified in files named
|
||||
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
|
||||
# CONFIG_SITE.Common.$(T_A)
|
||||
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
# CHECK_RELEASE controls the consistency checking of the support
|
||||
# applications pointed to by the RELEASE* files.
|
||||
# Normally CHECK_RELEASE should be set to YES.
|
||||
# Set CHECK_RELEASE to NO to disable checking completely.
|
||||
# Set CHECK_RELEASE to WARN to perform consistency checking but
|
||||
# continue building even if conflicts are found.
|
||||
CHECK_RELEASE = YES
|
||||
|
||||
# Set this when you only want to compile this application
|
||||
# for a subset of the cross-compiled target architectures
|
||||
# that Base is built for.
|
||||
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32
|
||||
|
||||
# To install files into a location other than $(TOP) define
|
||||
# INSTALL_LOCATION here.
|
||||
#INSTALL_LOCATION=</absolute/path/to/install/top>
|
||||
|
||||
# Set this when the IOC and build host use different paths
|
||||
# to the install location. This may be needed to boot from
|
||||
# a Microsoft FTP server say, or on some NFS configurations.
|
||||
#IOCS_APPL_TOP = </IOC's/absolute/path/to/install/top>
|
||||
|
||||
# These allow developers to override the CONFIG_SITE variable
|
||||
# settings without having to modify the configure/CONFIG_SITE
|
||||
# file itself.
|
||||
-include $(TOP)/../CONFIG_SITE.local
|
||||
-include $(TOP)/../configure/CONFIG_SITE.local
|
||||
-include $(TOP)/configure/CONFIG_SITE.local
|
11
configure/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# Makefile
|
||||
|
||||
TOP=..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
TARGETS = $(CONFIG_TARGETS)
|
||||
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
31
configure/RELEASE
Normal file
@ -0,0 +1,31 @@
|
||||
#RELEASE Location of external products
|
||||
# Run "gnumake clean uninstall install" in the application
|
||||
# top directory each time this file is changed.
|
||||
#
|
||||
# NOTE: The build does not check dependencies on files
|
||||
# external to this application. Thus you should run
|
||||
# "gnumake clean uninstall install" in the top directory
|
||||
# each time EPICS_BASE, SNCSEQ, or any other external
|
||||
# module defined in the RELEASE file is rebuilt.
|
||||
|
||||
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
||||
|
||||
# If you don't want to install into $(TOP) then
|
||||
# define INSTALL_LOCATION_APP here
|
||||
#INSTALL_LOCATION_APP=<fullpathname>
|
||||
|
||||
SUPPORT=$(TOP)/..
|
||||
-include $(TOP)/../configure/SUPPORT.$(EPICS_HOST_ARCH)
|
||||
|
||||
ASYN=$(SUPPORT)/asyn4-36
|
||||
CALC=$(SUPPORT)/calc-3-7
|
||||
PCRE=$(SUPPORT)/pcre-7-2
|
||||
|
||||
# EPICS_BASE usually appears last so other apps can override stuff:
|
||||
EPICS_BASE=/usr/local/epics/base-7.0.3
|
||||
|
||||
# These lines allow developers to override these RELEASE settings
|
||||
# without having to modify this file directly.
|
||||
-include $(TOP)/../RELEASE.local
|
||||
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
|
||||
-include $(TOP)/configure/RELEASE.local
|
9
configure/RULES
Normal file
@ -0,0 +1,9 @@
|
||||
#CONFIG
|
||||
ifneq ($(wildcard $(EPICS_BASE)/configure),)
|
||||
include $(EPICS_BASE)/configure/RULES
|
||||
else
|
||||
include $(EPICS_BASE)/config/RULES_ARCHS
|
||||
endif
|
||||
|
||||
# Library should be rebuilt because LIBOBJS may have changed.
|
||||
$(LIBNAME): ../Makefile
|
BIN
doc/PSI.gif
Before Width: | Height: | Size: 1.6 KiB |
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>StreamDevice: Operating System API</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Operating System API</h1>
|
||||
|
||||
<h2>Sorry, this documentation is still missing.</h2>
|
||||
|
||||
<hr>
|
||||
<p><small>Dirk Zimoch, 2006</small></p>
|
||||
</body>
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>StreamDevice: Record API</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Record API</h1>
|
||||
|
||||
<h2>Sorry, this documentation is still missing.</h2>
|
||||
|
||||
<hr>
|
||||
<p><small>Dirk Zimoch, 2006</small></p>
|
||||
</body>
|
||||
</html>
|
395
doc/setup.html
@ -1,395 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>StreamDevice: Setup</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Setup</h1>
|
||||
|
||||
<a name="pre"></a>
|
||||
<h2>1. Prerequisites</h2>
|
||||
<p>
|
||||
<em>StreamDevice</em> requires either
|
||||
<a href="http://www.aps.anl.gov/epics/base/R3-14/index.php"
|
||||
target="ex">EPICS base R3.14.6 or higher</a> or
|
||||
<a href="http://www.aps.anl.gov/epics/base/R3-13.php"
|
||||
target="ex">EPICS base R3.13.7 or higher</a>.
|
||||
How to use <em>StreamDevice</em> on EPICS R3.13 is described on a
|
||||
<a href="epics3_13.html">separate page</a>.
|
||||
</p>
|
||||
<h3>Fix required for base R3.14.8.2 and earlier on Windows</h3>
|
||||
<p>
|
||||
Up to release R3.14.8.2, a fix in EPICS base is required to build
|
||||
<em>StreamDevice</em> on Windows (not cygwin).
|
||||
Add the following line to <kbd>src/iocsh/iocsh.h</kbd>
|
||||
and rebuild base.
|
||||
</p>
|
||||
<pre>
|
||||
epicsShareFunc int epicsShareAPI iocshCmd(const char *command);
|
||||
</pre>
|
||||
|
||||
<h3>Configuration</h3>
|
||||
<p>
|
||||
<em>StreamDevice</em> does not come with its own <kbd><top></kbd>
|
||||
location and <kbd><top>/configure</kbd> directory.
|
||||
It expects to be put into an already existing <kbd><top></kbd>
|
||||
directory structure.
|
||||
You can simply create one with <code>makeBaseApp.pl</code>
|
||||
(which is part of EPICS base):
|
||||
</p>
|
||||
<p>
|
||||
<code>mkdir top</code><br>
|
||||
<code>cd top</code><br>
|
||||
<code>makeBaseApp.pl -t support</code>
|
||||
</p>
|
||||
<p>
|
||||
When asked for "Application names" just hit Enter.
|
||||
Then go to the newly created <kbd>configure</kbd> subdirectory and
|
||||
edit the <kbd>RELEASE</kbd> file you find there according to the
|
||||
instructions below.
|
||||
</p>
|
||||
<p>
|
||||
After changing any configuration, you should run <code>make</code>
|
||||
in this directory.
|
||||
</p>
|
||||
<p>
|
||||
For details on <kbd><top></kbd> directories and <kbd>RELEASE</kbd>
|
||||
files please refer to the
|
||||
<a href="http://www.aps.anl.gov/epics/base/R3-14/8-docs/AppDevGuide.pdf"
|
||||
target="ex"><em>IOC Application Developer's Guide</em></a> chapter 4:
|
||||
EPICS Build Facility.
|
||||
</p>
|
||||
|
||||
<h4>Support for <em>asynDriver</em></h4>
|
||||
<p>
|
||||
You most probably want <em>asynDriver</em> support included, because that is the
|
||||
standard way for <em>StreamDevice</em> to talk to hardware.
|
||||
First get and install <a href="http://www.aps.anl.gov/epics/modules/soft/asyn/"
|
||||
target="ex"><em>asynDriver</em></a> version 4-3 or higher before you build <em>StreamDevice</em>.
|
||||
I have tested <em>StreamDevice</em> with <em>asynDriver</em> versions up to 4-17.
|
||||
Make sure that the <em>asyn</em> library can be found by adding the path to the
|
||||
<em><top></em> directory of your <em>asyn</em> installation to the
|
||||
<kbd>RELEASE</kbd> file:
|
||||
<pre>
|
||||
ASYN=/home/epics/asyn4-17
|
||||
</pre>
|
||||
|
||||
<h4>Support for sCalcout record</h4>
|
||||
<p>
|
||||
The <a target="ex"
|
||||
href="http://www.aps.anl.gov/bcda/synApps/calc/R2-8/sCalcoutRecord.html"
|
||||
><em>sCalcout</em></a> record is part of <a target="ex"
|
||||
href="http://www.aps.anl.gov/aod/bcda/synApps/index.php"
|
||||
><em>synApps</em></a>.
|
||||
If <em>streamDevice</em> should be built with support for this record,
|
||||
you have to install the <em>calc</em> module from <em>SynApps</em> first.
|
||||
Add references to the <kbd>RELEASE</kbd> file as shown here:
|
||||
<pre>
|
||||
CALC=/home/epics/synApps/calc-2-8
|
||||
</pre>
|
||||
<p>
|
||||
Up to <em>calc</em> release R2-6 (<em>synApps</em> release R5_1),
|
||||
the <em>sCalcout</em> record needs a fix.
|
||||
(See separate <a href="scalcout.html"><em>scalcout</em> page</a>.)
|
||||
And the <em>calc</em> modue had dependencies on other <em>SynApps</em>
|
||||
modules. Release R2-8 or newer is recommended.
|
||||
</p>
|
||||
<p>
|
||||
Support for the scalcout is optional. <em>StreamDevice</em> works
|
||||
as well without scalcout or SynApps.
|
||||
</p>
|
||||
|
||||
<h4>Support for regular expression matching</h4>
|
||||
<p>
|
||||
If you want to enable regular expression matching, you need the <em>PCRE</em> package.
|
||||
For most Linux systems, it is already installed.
|
||||
In that case add the locations you have to make the locations of the
|
||||
<em>PCRE</em> header file and library known.
|
||||
However, the pre-installed package can only by used for the host architecture.
|
||||
Thus, add them not to <kbd>RELEASE</kbd> but to <kbd>RELEASE.Common.linux-x86</kbd>
|
||||
(if linux-x86 is your EPICS_HOST_ARCH).
|
||||
Note that different Linux distributions may locate the files in different directories.
|
||||
</p>
|
||||
<pre>
|
||||
PCRE_INCLUDE=/usr/include/pcre
|
||||
PCRE_LIB=/usr/lib
|
||||
</pre>
|
||||
<p>
|
||||
A pre-compiled Windows version of <em>PCRE</em> is available at
|
||||
<a href="http://sourceforge.net/projects/gnuwin32/files/pcre/7.0/pcre-7.0.exe/download"
|
||||
target="ex">sourceforge</a>
|
||||
</p>
|
||||
<p>
|
||||
If you want to have <em>PCRE</em> support on platforms that don't support it natively,
|
||||
e.g. vxWorks, it is probably the easiest to build <em>PCRE</em> as an EPICS application.
|
||||
</p>
|
||||
<p>
|
||||
<h4>Building the <em>PCRE</em> package as an EPICS module</h4>
|
||||
<p>
|
||||
<ol>
|
||||
<li>
|
||||
Download the <em>PCRE</em> package from <a target=ex href="http://www.pcre.org">www.pcre.org</a>.
|
||||
</li>
|
||||
<li>
|
||||
Extract the <em>PCRE</em> package in the <kbd><top></kbd> directory of
|
||||
<em>StreamDevice</em> or create a separate <kbd><top></kbd> location using
|
||||
<code>makeBaseApp.pl</code>.
|
||||
</li>
|
||||
<li>
|
||||
Download this <a target=ex href="http://epics.web.psi.ch/software/streamdevice/pcre/Makefile"
|
||||
>Makefile</a> and this
|
||||
<a target=ex href="http://epics.web.psi.ch/software/streamdevice/pcre/fixforvxworks.pl"
|
||||
>fixforvxworks.pl</a> script and save them to the extracted pcre directory.
|
||||
</li>
|
||||
<li>
|
||||
Change into the pcre direcrory and run <code>perl fixforvxworks.pl</code>
|
||||
</li>
|
||||
<li>
|
||||
Run <code>make</code> (or <code>gmake</code>)
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
Define the location of the pcre <kbd><top></kbd> in the RELEASE file for <em>StreamDevice</em>.
|
||||
</p>
|
||||
<pre>
|
||||
PCRE=/home/epics/pcre
|
||||
</pre>
|
||||
<p>
|
||||
Regular expressions are optional. If you don't want them, you don't need this.
|
||||
</p>
|
||||
|
||||
<a name="lib"></a>
|
||||
<h2>2. Build the <em>StreamDevice</em> Library</h2>
|
||||
<p>
|
||||
Unpack the
|
||||
<a href="http://epics.web.psi.ch/software/streamdevice/StreamDevice-2.tgz"
|
||||
><em>StreamDevice</em> package</a> in the <kbd><top></kbd> directory
|
||||
of your application build area.
|
||||
(You might probably have done this already.)
|
||||
Go to the newly created <em>StreamDevice</em> directory
|
||||
and run <code>make</code> (or <code>gmake</code>).
|
||||
This will create and install the <em>stream</em> library and the
|
||||
<kbd>stream.dbd</kbd> file.
|
||||
</p>
|
||||
<a name="app"></a>
|
||||
<h2>3. Build an Application</h2>
|
||||
<p>
|
||||
To use <em>StreamDevice</em>, your application must be built with the
|
||||
<em>asyn</em> and <em>stream</em> libraries and must load
|
||||
<kbd>asyn.dbd</kbd> and <kbd>stream.dbd</kbd>.
|
||||
</p>
|
||||
<p>
|
||||
Include the following lines in your application Makefile:
|
||||
</p>
|
||||
<pre>
|
||||
PROD_LIBS += stream
|
||||
PROD_LIBS += asyn
|
||||
</pre>
|
||||
<p>
|
||||
Include the following lines in your xxxAppInclude.dbd file to use
|
||||
<em>stream</em> and <em>asyn</em> with serial lines, IP sockets,
|
||||
and vxi11 ("GPIB over ethernet") support.
|
||||
</p>
|
||||
<pre>
|
||||
include "base.dbd"
|
||||
include "stream.dbd"
|
||||
include "asyn.dbd"
|
||||
registrar(drvAsynIPPortRegisterCommands)
|
||||
registrar(drvAsynSerialPortRegisterCommands)
|
||||
registrar(vxi11RegisterCommands)
|
||||
</pre>
|
||||
<p>
|
||||
You can find an example application in the <kbd>streamApp</kbd>
|
||||
subdirectory.
|
||||
</p>
|
||||
|
||||
<a name="sta"></a>
|
||||
<h2>4. The Startup Script</h2>
|
||||
<p>
|
||||
<em>StreamDevice</em> is based on <a
|
||||
href="protocol.html"><em>protocol files</em></a>.
|
||||
To tell <em>StreamDevice</em> where to search for protocol files,
|
||||
set the environment variable <code>STREAM_PROTOCOL_PATH</code> to a
|
||||
list of directories to search.
|
||||
On Unix and vxWorks systems, directories are separated by <code>:</code>,
|
||||
on Windows systems by <code>;</code>.
|
||||
The default value is <code>STREAM_PROTOCOL_PATH=.</code>,
|
||||
i.e. the current directory.
|
||||
</p>
|
||||
<p>
|
||||
Also configure the buses (in <em>asynDriver</em> terms: ports) you want
|
||||
to use with <em>StreamDevice</em>.
|
||||
You can give the buses any name you want, like <kbd>COM1</kbd> or
|
||||
<kbd>socket</kbd>, but I recommend to use names related to the
|
||||
connected device.
|
||||
</p>
|
||||
<h3>Example:</h3>
|
||||
<p>
|
||||
A power supply with serial communication (9600 baud, 8N1) is connected to
|
||||
<kbd>/dev/ttyS1</kbd>.
|
||||
The name of the power supply is <tt>PS1</tt>.
|
||||
Protocol files are either in the current working directory or in the
|
||||
<kbd>../protocols</kbd> directory.
|
||||
</p>
|
||||
<p>
|
||||
Then the startup script must contain lines like this:
|
||||
</p>
|
||||
<pre>
|
||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||
|
||||
drvAsynSerialPortConfigure ("PS1","/dev/ttyS1")
|
||||
asynSetOption ("PS1", 0, "baud", "9600")
|
||||
asynSetOption ("PS1", 0, "bits", "8")
|
||||
asynSetOption ("PS1", 0, "parity", "none")
|
||||
asynSetOption ("PS1", 0, "stop", "1")
|
||||
asynSetOption ("PS1", 0, "clocal", "Y")
|
||||
asynSetOption ("PS1", 0, "crtscts", "N")
|
||||
</pre>
|
||||
|
||||
<p>If the power supply was connected via telnet-style TCP/IP
|
||||
at address 192.168.164.10 on port 23,
|
||||
the startupscript would contain:
|
||||
</p>
|
||||
<pre>
|
||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||
|
||||
drvAsynIPPortConfigure ("PS1", "192.168.164.10:23")
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
With a VXI11 (GPIB via TCP/IP) connection, e.g. a
|
||||
HP E2050A on IP address 192.168.164.10, it would look like this:
|
||||
</p>
|
||||
<pre>
|
||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||
|
||||
vxi11Configure ("PS1","192.168.164.10",1,1000,"hpib")
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="pro"></a>
|
||||
<h2>5. The Protocol File</h2>
|
||||
<p>
|
||||
For each different type of hardware, create a protocol file
|
||||
which defines protocols for all needed functions of the device.
|
||||
The file name is arbitrary, but I recommend that it contains
|
||||
the device type.
|
||||
It must not contain spaces and should be short.
|
||||
During <code>iocInit</code>, <em>streamDevice</em> loads and parses
|
||||
the required protocol files.
|
||||
If the files contain errors, they are printed on the IOC shell.
|
||||
Put the protocol file in one of the directories listed in
|
||||
<code>STREAM_PROTOCOL_PATH</code>.
|
||||
</p>
|
||||
<h3>Example:</h3>
|
||||
<p>
|
||||
<tt>PS1</tt> is an <em>ExamplePS</em> power supply.
|
||||
It communicates via ASCII strings which are terminated by
|
||||
<carriage return> <line feed> (ASCII codes 13, 10).
|
||||
The output current can be set by sending a string like
|
||||
<code>"CURRENT 5.13"</code>.
|
||||
When asked with the string <code>"CURRENT?"</code>, the device returns
|
||||
the last set value in a string like <code>"CURRENT 5.13 A"</code>.
|
||||
</p>
|
||||
<p>
|
||||
Normally, an analog output record should write its value to the device.
|
||||
But during startup, the record should be initialized from the the device.
|
||||
The protocol file <kbd>ExamplePS.proto</kbd> defines the protocol
|
||||
<code>setCurrent</code>.
|
||||
</p>
|
||||
<pre>
|
||||
Terminator = CR LF;
|
||||
|
||||
setCurrent {
|
||||
out "CURRENT %.2f";
|
||||
@init {
|
||||
out "CURRENT?";
|
||||
in "CURRENT %f A";
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<a name="reload"></a>
|
||||
<h3>Reloading the Protocol File</h3>
|
||||
<p>
|
||||
During development, the protocol files might change frequently.
|
||||
To prevent restarting the IOC all the time, it is possible to reload
|
||||
the protocol file of one or all records with the shell function
|
||||
<code>streamReload("<var>record</var>")</code>.
|
||||
If <code>"<var>record</var>"</code> is not given, all records using
|
||||
<em>StreamDevice</em> reload their protocols.
|
||||
Furthermore, the <code>streamReloadSub</code> function can be used
|
||||
with a subroutine record to reload all protocols.
|
||||
</p>
|
||||
<p>
|
||||
Reloading the protocol file aborts currently running protocols.
|
||||
This might set <code>SEVR=INVALID</code> and <code>STAT=UDF</code>.
|
||||
If a record can't reload its protocol file (e.g. because of a syntax
|
||||
error), it stays <code>INVALID</code>/<code>UDF</code> until a valid
|
||||
protocol is loaded.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See the <a href="protocol.html">next chapter</a> for protocol files in depth.
|
||||
</p>
|
||||
|
||||
<a name="rec"></a>
|
||||
<h2>6. Configure the Records</h2>
|
||||
<p>
|
||||
To make a record use <em>StreamDevice</em>, set its <code>DTYP</code> field to
|
||||
<code>"stream"</code>.
|
||||
</p>
|
||||
<p>
|
||||
The <code>INP</code> or <code>OUT</code> link has the form
|
||||
<code>"@<var>file protocol bus</var> [<var>address</var> [<var>parameters</var>]]"</code>.
|
||||
</p>
|
||||
<p>
|
||||
Here, <code><var>file</var></code> is the name of the protocol file and
|
||||
<code><var>protocol</var></code> is the name of a protocol defined in this file.
|
||||
(See the <a href="protocol.html">next chapter</a>.)
|
||||
</p>
|
||||
<p>
|
||||
If the protocol requires <a href="protocol.html#argvar">arguments</a>,
|
||||
specify them enclosed in parentheses:
|
||||
<code><var>protocol</var>(<var>arg1,arg2,...</var>)</code>.
|
||||
</p>
|
||||
<p>
|
||||
The communication channel is specified with <code><var>bus</var></code>
|
||||
(aka <em>asynDriver</em> "port") and <code><var>addr</var></code>.
|
||||
If the bus does not have addresses, <code><var>addr</var></code> is dispensable.
|
||||
Optional <code><var>parameters</var></code> are passed to the bus driver.
|
||||
</p>
|
||||
|
||||
<h3>Example:</h3>
|
||||
<p>
|
||||
Create an output record to set the current of <tt>PS1</tt>.
|
||||
Use protocol <em>setCurrent</em> from file <em>ExamplePS.proto</em>.
|
||||
The bus is called <em>PS1</em> like the device.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
record (ao, "PS1:I-set")
|
||||
{
|
||||
field (DESC, "Set current of PS1")
|
||||
<b>field (DTYP, "stream")</b>
|
||||
<b>field (OUT, "@ExamplePS.proto setCurrent PS1")</b>
|
||||
field (EGU, "A")
|
||||
field (PREC, "2")
|
||||
field (DRVL, "0")
|
||||
field (DRVH, "60")
|
||||
field (LOPR, "0")
|
||||
field (HOPR, "60")
|
||||
}
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
<p align="right"><a href="protocol.html">Next: Protocol Files</a></p>
|
||||
<p><small>Dirk Zimoch, 2011</small></p>
|
||||
</body>
|
||||
</html>
|
127
doc/stream.css
@ -1,127 +0,0 @@
|
||||
a:link {color: #0000D0;}
|
||||
a:visited {color: #0000D0;}
|
||||
a:hover {color: #FF0000;}
|
||||
|
||||
body {
|
||||
margin-right:1em;
|
||||
margin-left:15em;
|
||||
margin-top:11ex;
|
||||
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
font-size:14px;
|
||||
background-color:#ffffff;
|
||||
}
|
||||
|
||||
a[name] { position:relative; top:-11ex;}
|
||||
|
||||
pre {
|
||||
background-color:#f4f4f4;
|
||||
padding:1ex;
|
||||
border:1px solid #000000;
|
||||
white-space:pre;
|
||||
margin:2ex;
|
||||
}
|
||||
|
||||
kbd {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-top:0.5ex;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:225%;
|
||||
margin-top:0;
|
||||
font-style:italic;
|
||||
font-family:serif;
|
||||
text-align:center;
|
||||
position:fixed;
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
min-height:60px;
|
||||
height: 4ex;
|
||||
line-height:190%;
|
||||
background-color:white;
|
||||
border-top:6px solid #1b4486;
|
||||
border-bottom:4px solid #1b4486;
|
||||
white-space:nowrap;
|
||||
background-image:url(PSI.gif);
|
||||
background-repeat:no-repeat;
|
||||
background-position:10px 2px;
|
||||
text-shadow: .1em .1em .1em lightgray;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:150%;
|
||||
margin-bottom:0.5ex;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size:120%;
|
||||
margin-bottom:0.25ex;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size:100%;
|
||||
margin-bottom:0.25ex;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top:0.75ex;
|
||||
margin-bottom:0.75ex;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size:75%;
|
||||
}
|
||||
|
||||
code {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.indent {
|
||||
text-indent:-4ex;
|
||||
margin-left:4ex;
|
||||
margin-top:0.5ex;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
#navleft {
|
||||
position:fixed;
|
||||
left:0;
|
||||
top:0;
|
||||
padding-top:9ex;
|
||||
width:14em;
|
||||
height:100%;
|
||||
border-style:solid;
|
||||
border-color:black;
|
||||
border-width:0 1px 0 0;
|
||||
background-color:#e3eaf6;
|
||||
overflow:hidden;
|
||||
z-index:0;
|
||||
}
|
||||
|
||||
.new {
|
||||
background-color: #ffc;
|
||||
}
|
||||
|
||||
a[target=ex]:after {
|
||||
content:" " url(ex.png);
|
||||
}
|
||||
|
||||
a[target=ex]:hover:after {
|
||||
content: " " url(exr.png);
|
||||
}
|
||||
|
||||
@media print {
|
||||
a:link {color: black; text-decoration:none;}
|
||||
a:visited {color: black; text-decoration:none;}
|
||||
a:hover {color: black; text-decoration:none;}
|
||||
a[target=ex] {text-decoration:underline;}
|
||||
a[target=ex]:after {content:" [" attr(href) "]";}
|
||||
code {color: black; }
|
||||
body {margin-left:10px;}
|
||||
h1 {position:absolute;}
|
||||
#navleft {display:none;}
|
||||
}
|
BIN
docs/PSI.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -1,25 +1,24 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: aai Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: aai Records</h1>
|
||||
<h1>aai Records</h1>
|
||||
<p>
|
||||
<b>Note:</b> aai record support is disabled per default.
|
||||
Enable it in <code>src/CONFIG_STREAM</code>.
|
||||
<b>Note:</b> In EPICS versions before 3.14.12, aai records may be disabled.
|
||||
</p>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
With aai records, the format converter is applied to
|
||||
each element. Between the elements, a separator is printed
|
||||
each array element. Between the elements, a separator is printed
|
||||
or expected as specified by the <code>Separator</code>
|
||||
<a href="protocol.html#sysvar">variable</a> in the protocol.
|
||||
When parsing input, a space as the first character of the
|
||||
@ -40,14 +39,19 @@ written.
|
||||
<p>
|
||||
The format data type must be convertible to or from the type
|
||||
specified in the <code>FTVL</code> field.
|
||||
The types <code>"INT64"</code> and <code>"UINT64"</code> are
|
||||
only available in EPICS base version 3.16 or higher.
|
||||
</p>
|
||||
<p>
|
||||
The variable <code><i>x[i]</i></code> stands for one element of
|
||||
the written or read value.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u><code><i>x[i]</i>=double(VAL[i])</code><br>
|
||||
<u>Output:</u> <code><i>x[i]</i>=double(VAL[i])</code><br>
|
||||
<code>FTVL</code> can be <code>"DOUBLE"</code>, <code>"FLOAT"</code>,
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -58,6 +62,7 @@ the written or read value.
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
||||
<code>FTVL</code> can be
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -65,6 +70,7 @@ the written or read value.
|
||||
zero-extended to long before converting them.<br>
|
||||
<u>Input:</u> <code>VAL[i]=FTVL(<i>x[i])</i></code><br>
|
||||
<code>FTVL</code> can be <code>"DOUBLE"</code>, <code>"FLOAT"</code>,
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -105,24 +111,31 @@ the written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2006</small></p>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,25 +1,24 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: aao Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: aao Records</h1>
|
||||
<h1>aao Records</h1>
|
||||
<p>
|
||||
<b>Note:</b> aao record support is disabled per default.
|
||||
Enable it in <code>src/CONFIG_STREAM</code>.
|
||||
<b>Note:</b> In EPICS versions before 3.14.12, aao records may be disabled.
|
||||
</p>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
With aao records, the format converter is applied to
|
||||
each element. Between the elements, a separator is printed
|
||||
each array element. Between the elements, a separator is printed
|
||||
or expected as specified by the <code>Separator</code>
|
||||
<a href="protocol.html#sysvar">variable</a> in the protocol.
|
||||
When parsing input, a space as the first character of the
|
||||
@ -40,14 +39,19 @@ A minimum of one element must be available.
|
||||
<p>
|
||||
The format data type must be convertible to or from the type
|
||||
specified in the <code>FTVL</code> field.
|
||||
The types <code>"INT64"</code> and <code>"UINT64"</code> are
|
||||
only available in EPICS base version 3.16 or higher.
|
||||
</p>
|
||||
<p>
|
||||
The variable <code><i>x[i]</i></code> stands for one element of
|
||||
the written or read value.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u><code><i>x[i]</i>=double(VAL[i])</code><br>
|
||||
<u>Output:</u> <code><i>x[i]</i>=double(VAL[i])</code><br>
|
||||
<code>FTVL</code> can be <code>"DOUBLE"</code>, <code>"FLOAT"</code>,
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -58,6 +62,7 @@ the written or read value.
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
||||
<code>FTVL</code> can be
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -65,6 +70,7 @@ the written or read value.
|
||||
zero-extended to long before converting them.<br>
|
||||
<u>Input:</u> <code>VAL[i]=FTVL(<i>x[i])</i></code><br>
|
||||
<code>FTVL</code> can be <code>"DOUBLE"</code>, <code>"FLOAT"</code>,
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -105,24 +111,31 @@ the written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2006</small></p>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: ai Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: ai Records</h1>
|
||||
<h1>ai Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -41,6 +41,12 @@ written or read value.
|
||||
(=20.0/0xFFFF) maps 0x0000 to -10.0, 0x7FFF to 0.0 and 0xFFFF to 10.0.
|
||||
Using unsigned formats with values ≥ 0x800000 gives different results
|
||||
on 64 bit machines.
|
||||
<p>
|
||||
If <code>LINR=="NO CONVERSION"</code> (the default), <code>VAL</code>
|
||||
is directly converted from and to <code>long</code> without going through
|
||||
<code>RVAL</code>. This allows for more bits on 64 bit machines.
|
||||
To get the old behavior, use <code>LINR=="LINEAR"</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
@ -59,25 +65,31 @@ written or read value.
|
||||
(treated as <code>0.0</code>).
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lan="en">
|
||||
<head>
|
||||
<title>StreamDevice: ao Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" / />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" / />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" / />
|
||||
<meta name="author" content="Dirk Zimoch" / />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: ao Records</h1>
|
||||
<h1>ao Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -31,7 +31,7 @@ written or read value.
|
||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=RVAL</code><br>
|
||||
<u>Input:</u> <code>RBV=<i>x</i></code><br>
|
||||
<u>Input:</u> <code>RBV=RVAL=<i>x</i></code><br>
|
||||
Note that the record calculates
|
||||
<code>RVAL=(((OVAL-EOFF)/ESLO)-AOFF)/ASLO</code> if
|
||||
<code>LINR=="LINEAR"</code>. <code>ESLO</code> and <code>EOFF</code>
|
||||
@ -40,6 +40,12 @@ written or read value.
|
||||
(=20.0/0xFFFF) maps -10.0 to 0x0000, 0.0 to 0x7FFF and 10.0 to 0xFFFF.
|
||||
Using unsigned formats with values ≥ 0x800000 gives different results
|
||||
on 64 bit machines.
|
||||
<p>
|
||||
If <code>LINR=="NO CONVERSION"</code> (the default), <code>OVAL</code>
|
||||
is directly converted to <code>long</code> without going through
|
||||
<code>RVAL</code>. This allows for more bits on 64 bit machines.
|
||||
To get the old behavior, use <code>LINR=="LINEAR"</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
@ -57,28 +63,33 @@ written or read value.
|
||||
present. In contrast to normal operation, output in DOUBLE format uses
|
||||
<code>VAL</code> instead of <code>OVAL</code>. Note that the record
|
||||
initializes <code>VAL</code> from <code>DOL</code> if that is a constant.
|
||||
LONG input is put to <code>RVAL</code> as well as to <code>RBV</code> and
|
||||
converted by the record.
|
||||
</p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: bi Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: bi Records</h1>
|
||||
<h1>bi Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -53,25 +53,31 @@ written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: bo Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: bo Records</h1>
|
||||
<h1>bo Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -52,25 +52,31 @@ written or read value.
|
||||
<code>RVAL</code> as well as to <code>RBV</code> and converted by the record.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,12 +1,12 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Bus API</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
@ -19,7 +19,7 @@
|
||||
href="http://www.aps.anl.gov/epics/modules/soft/asyn/">
|
||||
<em>asynDriver</em></a>.
|
||||
You should first try to implement your bus driver compatible to
|
||||
<em>asynDriver</em>.
|
||||
<em>asynOctet</em>.
|
||||
Then it can be used by <em>StreamDevice</em> automatically.
|
||||
Only if that does not work, write your own bus interface.
|
||||
</p>
|
||||
@ -68,17 +68,13 @@ class MyInterface : StreamBusInterface
|
||||
// StreamBusInterface virtual methods
|
||||
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
|
||||
bool <a href="#lock">unlock</a>();
|
||||
bool <a href="#write">writeRequest</a>(const void* output, size_t size,
|
||||
unsigned long writeTimeout_ms);
|
||||
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms,
|
||||
unsigned long readTimeout_ms,
|
||||
long expectedLength, bool async);
|
||||
bool <a href="#write">writeRequest</a>(const void* output, size_t size, unsigned long writeTimeout_ms);
|
||||
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms, unsigned long readTimeout_ms, ssize_t expectedLength, bool async);
|
||||
bool <a href="#read">supportsAsyncRead</a>();
|
||||
bool <a href="#event">supportsEvent</a>();
|
||||
bool <a href="#event">acceptEvent</a>(unsigned long mask,
|
||||
unsigned long replytimeout_ms);
|
||||
bool <a href="#connect">connectRequest</a>(unsigned long connecttimeout_ms);
|
||||
bool <a href="#connect">disconnect</a>();
|
||||
bool <a href="#event">acceptEvent</a>(unsigned long mask, unsigned long timeout_ms);
|
||||
bool <a href="#connect">connectRequest</a>(unsigned long timeout_ms);
|
||||
bool <a href="#connect">disconnectRequest</a>();
|
||||
void <a href="#lock">finish</a>();
|
||||
|
||||
public:
|
||||
@ -122,7 +118,7 @@ bool <a href="#write">writeRequest</a>(const void* output,
|
||||
<div class="indent"><code>
|
||||
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms,
|
||||
unsigned long readTimeout_ms,
|
||||
long expectedLength, bool async);
|
||||
ssize_t expectedLength, bool async);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool <a href="#read">supportsAsyncRead</a>();
|
||||
@ -132,13 +128,13 @@ bool <a href="#event">supportsEvent</a>();
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool <a href="#event">acceptEvent</a>(unsigned long mask,
|
||||
unsigned long replytimeout_ms);
|
||||
unsigned long timeout_ms);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool <a href="#connect">connectRequest</a>(unsigned long connecttimeout_ms);
|
||||
bool <a href="#connect">connectRequest</a>(unsigned long timeout_ms);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool <a href="#connect">disconnect</a>();
|
||||
bool <a href="#connect">disconnectRequest</a>();
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void <a href="#lock">finish</a>();
|
||||
@ -157,24 +153,24 @@ callback methods which must be called in response to the above request
|
||||
methods (most probably from another thread):
|
||||
</p>
|
||||
<div class="indent"><code>
|
||||
void <a href="#lock">lockCallback</a>(StreamIoStatus status);
|
||||
void <a href="#lock">lockCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void <a href="#write">writeCallback</a>(StreamIoStatus status);
|
||||
void <a href="#write">writeCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
long <a href="#read">readCallback</a>(StreamIoStatus status,
|
||||
const void* input = NULL,
|
||||
long size = 0);
|
||||
ssize_t <a href="#read">readCallback</a>(StreamIoStatus status,
|
||||
const void* buffer = NULL,
|
||||
size_t size = 0);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void <a href="#event">eventCallback</a>(StreamIoStatus status);
|
||||
void <a href="#event">eventCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void <a href="#connect">connectCallback</a>(StreamIoStatus status);
|
||||
void <a href="#connect">connectCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void <a href="#connect">disconnectCallback</a>(StreamIoStatus status);
|
||||
void <a href="#connect">disconnectCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
|
||||
<h3>Other provided methods, attibutes, and types</h3>
|
||||
@ -197,6 +193,9 @@ const char* <a href="#read">getInTerminator</a>(size_t& length);
|
||||
<div class="indent"><code>
|
||||
enum StreamIoStatus {StreamIoSuccess, StreamIoTimeout, StreamIoNoReply, StreamIoEnd, StreamIoFault};
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
const char* ::toStr(StreamIoStatus);
|
||||
</code></div>
|
||||
|
||||
<a name="theory"></a>
|
||||
<h2>Theory of Operation</h2>
|
||||
@ -276,34 +275,47 @@ correct.
|
||||
<a name="connect"></a>
|
||||
<h3>Connecting and disconnecting</h3>
|
||||
<div class="indent"><code>
|
||||
bool connectRequest(unsigned long connecttimeout_ms);
|
||||
bool connectRequest(unsigned long timeout_ms);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool disconnect();
|
||||
bool disconnectRequest();
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void connectCallback(IoStatus status);
|
||||
void connectCallback(IoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void disconnectCallback(IoStatus status);
|
||||
void disconnectCallback(IoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<p>
|
||||
Connection should be handled automatically.
|
||||
If the device is disconnected, each attempt to access the
|
||||
device should try to (re-)connect.
|
||||
Whenever possible connection should be handled automatically.
|
||||
The interface should call <code>connectCallback()</code> when
|
||||
the device has connected and <code>disconnectCallback()</code> when
|
||||
the device has disconnected.
|
||||
These callbacks can be called asynchronously at any time.
|
||||
</p>
|
||||
<p>
|
||||
If the device is disconnected, an attempt to access the
|
||||
device should try to reconnect.
|
||||
Normally, the interface should not try to disconnect unless
|
||||
the device does so.
|
||||
the device does so automatically.
|
||||
</p>
|
||||
<p>
|
||||
However, sometimes the client wants to connect or
|
||||
disconnect explicitely.
|
||||
disconnect explicitly.
|
||||
To connect, the client calls <code>connectRequest()</code>.
|
||||
This function should return <code>true</code> immediately
|
||||
or <code>false</code> if the request cannot be accepted or connection
|
||||
This function should set up things to reconnect but should not block
|
||||
waiting.
|
||||
Instead it should immediately return <code>true</code> if
|
||||
it expects that connection can be established soon, or
|
||||
<code>false</code> if the request cannot be accepted or connection
|
||||
handling is not supported.
|
||||
The interface should call <code>connectCallback(StreamIoSuccess)</code>
|
||||
The interface should call <code>connectCallback()</code>
|
||||
once the bus could be connected.
|
||||
If the bus cannot be connected within <code>connecttimeout_ms</code>
|
||||
If the device can connect immediately without waiting, it may also call
|
||||
<code>connectCallback()</code> directly from <code>connectRequest()</code>.
|
||||
</p>
|
||||
<p>
|
||||
If the bus cannot be connected within <code>timeout_ms</code>
|
||||
milliseconds, the bus interface should call
|
||||
<code>connectCallback(StreamIoTimeout)</code>.
|
||||
</p>
|
||||
@ -313,11 +325,11 @@ something wrong with the I/O hardware,
|
||||
<code>connectCallback(StreamIoFault)</code> may be called.
|
||||
</p>
|
||||
<p>
|
||||
To disconnect, the client calls <code>disconnectRequest()</code>;
|
||||
To disconnect explicitly, the client calls <code>disconnectRequest()</code>;
|
||||
This function should return <code>true</code> immediately or
|
||||
<code>false</code> if the request cannot be accepted or connection
|
||||
handling is not supported.
|
||||
The interface should call <code>connectCallback(StreamIoSuccess)</code>
|
||||
The interface should call <code>connectCallback()</code>
|
||||
once the bus is disconnected. There is no timeout for this operation.
|
||||
If disconnecting is impossible, the interface should call
|
||||
<code>connectCallback(StreamIoFault)</code>.
|
||||
@ -326,10 +338,10 @@ If disconnecting is impossible, the interface should call
|
||||
<a name="lock"></a>
|
||||
<h3>Bus locking</h3>
|
||||
<div class="indent"><code>
|
||||
bool lockRequest(unsigned long lockTimeout_ms);
|
||||
bool lockRequest(unsigned long timeout_ms);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void lockCallback(IoStatus status);
|
||||
void lockCallback(IoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool unlock();
|
||||
@ -348,7 +360,7 @@ or <code>false</code> if the request cannot be accepted.
|
||||
If the device is already locked, the bus interface should add itself to
|
||||
a queue, sorted by <code>priority()</code>.
|
||||
As soon as the device is available, the bus interface should call
|
||||
<code>lockCallback(StreamIoSuccess)</code>.
|
||||
<code>lockCallback()</code>.
|
||||
If the bus cannot be locked within <code>lockTimeout_ms</code>
|
||||
milliseconds, the bus interface should call
|
||||
<code>lockCallback(StreamIoTimeout)</code>.
|
||||
@ -369,7 +381,7 @@ locked the device.
|
||||
When the protocol ends and the device is locked, the client calls
|
||||
<code>unlock()</code>.
|
||||
If other bus interfaces are in the lock queue, the next one should
|
||||
call <code>lockCallback(StreamIoSuccess)</code> now.
|
||||
call <code>lockCallback()</code> now.
|
||||
</p>
|
||||
<p>
|
||||
The client calls <code>finish()</code> when the protocol ends.
|
||||
@ -385,7 +397,7 @@ bool writeRequest(const void* output,
|
||||
size_t size, unsigned long writeTimeout_ms);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void writeCallback(IoStatus status);
|
||||
void writeCallback(IoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
const char* getOutTerminator(size_t& length);
|
||||
@ -404,7 +416,7 @@ The function should arrange transmission of <code>size</code> bytes of
|
||||
or <code>false</code> if the request cannot be accepted.
|
||||
It must not block until output has completed.
|
||||
After all output has been successfully transmitted, but not earlier, the
|
||||
interface should call <code>writeCallback(StreamIoSuccess)</code>.
|
||||
interface should call <code>writeCallback()</code>.
|
||||
</p>
|
||||
<p>
|
||||
If output blocks for <code>writeTimeout_ms</code> milliseconds,
|
||||
@ -417,14 +429,15 @@ something wrong with the I/O hardware,
|
||||
<code>writeCallback(StreamIoFault)</code> may be called.
|
||||
</p>
|
||||
<p>
|
||||
The interface must transmit excactly the <code>size</code> bytes
|
||||
from <code>output</code>.
|
||||
It must not change anything and it should not assume that
|
||||
any bytes have a special meaning.
|
||||
The interface must send excactly the <code>size</code> bytes
|
||||
from <code>output</code>, not less.
|
||||
It should not change anything unless the bus needs some special
|
||||
formatting (e.g. added header, escaped bytes) and it should not
|
||||
assume that any bytes have a special meaning.
|
||||
In particular, a null byte does not terminate <code>output</code>.
|
||||
</p>
|
||||
<p>
|
||||
A call to <code>getOutTerminator</code> tells the interface which
|
||||
A call to <code>getOutTerminator()</code> tells the interface which
|
||||
terminator has already been added to the output.
|
||||
If <code>NULL</code> was returned, the client is not aware of a
|
||||
terminator (no outTerminator was defined in the protocol).
|
||||
@ -447,12 +460,12 @@ The client may request more I/O or call <code>unlock()</code> after
|
||||
<div class="indent"><code>
|
||||
bool readRequest(unsigned long replyTimeout_ms,
|
||||
unsigned long readTimeout_ms,
|
||||
long expectedLength, bool async);
|
||||
ssize_t expectedLength, bool async);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
long readCallback(IoStatus status,
|
||||
const void* input = NULL,
|
||||
long size = 0);
|
||||
ssize_t readCallback(IoStatus status,
|
||||
const void* buffer = NULL,
|
||||
size_t size = 0);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
const char* getInTerminator(size_t& length);
|
||||
@ -487,11 +500,11 @@ The client copies its contents. It does not modify or free it.
|
||||
It is not necessary to wait until all data has been received.
|
||||
The bus interface can call <code>n=readCallback()</code> after
|
||||
any amount of input has been received.
|
||||
If the client needs more input, <code>readCallback()</code>
|
||||
If the client expects more input, <code>readCallback()</code>
|
||||
returns a non-zero value.
|
||||
A positive <code>n</code> means, the client needs another
|
||||
A positive <code>n</code> means, the client expects another
|
||||
<code>n</code> bytes of input.
|
||||
A negative <code>n</code> means, the client needs an unspecified
|
||||
A negative <code>n</code> means, the client expects an unspecified
|
||||
amount of additional input.
|
||||
</p>
|
||||
<p>
|
||||
@ -559,46 +572,43 @@ something wrong with the I/O hardware,
|
||||
<code>readCallback(StreamIoFault)</code> may be called.
|
||||
</p>
|
||||
<p>
|
||||
If the <code>async</code> flag is <code>true</code>, the client
|
||||
wants to read input asyncronously without any timeout.
|
||||
That means, the bus interface should call <code>readCallback()</code>
|
||||
even if the input was requested by another client.
|
||||
</p>
|
||||
<p>
|
||||
If a client wishes to receive asynchonous input, it first calls
|
||||
Sometimes a client wishes to get any input received at any time, even
|
||||
when requested by another client.
|
||||
If a client wishes to receive such asynchronous input, it first calls
|
||||
<code>supportsAsyncRead()</code>.
|
||||
The default implementation of this method always returns
|
||||
<code>false</code>.
|
||||
A bus interface may overwrite this method to return <code>true</code>
|
||||
and eventually prepare for asynchonous input.
|
||||
If a bus interface supports asynchronous input, it should overwrite
|
||||
this method to set up everything needed to receive asynchronous input
|
||||
and then return <code>true</code>.
|
||||
The client is then allowed to call <code>readRequest()</code> with
|
||||
the <code>async==true</code>.
|
||||
This means that the client is interested in any input.
|
||||
This means that the client is now interested in asynchronous input.
|
||||
It should receive a <code>readCallback()</code> of all input which came
|
||||
in response to a synchonous (<code>async==false</code>) request from
|
||||
another client (which of course should receive the input, too).
|
||||
The interface should also receive asynchonous input when no
|
||||
in response to any synchonous (<code>async==false</code>) request from
|
||||
another client (which should receive the input, too).
|
||||
The interface should also receive asynchronous input when no
|
||||
synchonous client is active at the moment.
|
||||
Many asynchonous <code>readRequest()</code> calls from different clients
|
||||
Many asynchronous <code>readRequest()</code> calls from different clients
|
||||
may be active at the same time.
|
||||
All of them should receive the same input.
|
||||
</p>
|
||||
<p>
|
||||
For asynchonous requests, <code>replyTimeout_ms</code> has a different
|
||||
For asynchronous requests, <code>replyTimeout_ms</code> has a different
|
||||
meaning: If the bus interface has to poll the bus for input, it may take
|
||||
<code>replyTimeout_ms</code> as a hint for the poll period.
|
||||
If many asynchonous requests are active at the same time, it should poll
|
||||
If many asynchronous requests are active at the same time, it should poll
|
||||
with the shortest period of all clients.
|
||||
An asynchonous request does not time out.
|
||||
An asynchronous request does not time out.
|
||||
It stays active until the next input arrives.
|
||||
The client may reissue the asynchronous <code>readRequest()</code>
|
||||
from within the <code>readCallback()</code> if it wants to continue
|
||||
receiving asynchonous input.
|
||||
receiving asynchronous input.
|
||||
</p>
|
||||
<p>
|
||||
If the client calls <code>finish()</code> at any time, the bus
|
||||
interface should cancel all outstanding requests, including
|
||||
asynchonous read requests.
|
||||
asynchronous read requests.
|
||||
</p>
|
||||
<a name="event"></a>
|
||||
<h3>Handling events</h3>
|
||||
@ -606,10 +616,10 @@ asynchonous read requests.
|
||||
bool supportsEvent();
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms);
|
||||
bool acceptEvent(unsigned long mask, unsigned long timeout_ms);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
void eventCallback(StreamIoStatus status);
|
||||
void eventCallback(StreamIoStatus status = StreamIoSuccess);
|
||||
</code></div>
|
||||
<p>
|
||||
An event is a sort of input from a device which is not part of
|
||||
@ -627,9 +637,9 @@ If <code>true</code> is returned, the client is allowed to call
|
||||
If <code>mask</code> is illegal, <code>acceptEvent()</code> should
|
||||
return <code>false</code>.
|
||||
The call to <code>acceptEvent()</code> must not block.
|
||||
It should arrange to call <code>eventCallback(StreamIoSuccess)</code>
|
||||
It should arrange to call <code>eventCallback()</code>
|
||||
when the event matching <code>mask</code> arrives within
|
||||
<code>replytimeout_ms</code> milliseconds.
|
||||
<code>timeout_ms</code> milliseconds.
|
||||
If no such event arrives within this time, the bus interface
|
||||
should call <code>eventCallback(StreamIoTimeout)</code>.
|
||||
</p>
|
||||
@ -639,7 +649,9 @@ also report a matching event which occured before the actual call
|
||||
to <code>acceptEvent()</code> but after any previous call of any
|
||||
other request method like <code>writeRequest()</code>.
|
||||
</p>
|
||||
<hr>
|
||||
<p><small>Dirk Zimoch, 2007</small></p>
|
||||
|
||||
<footer>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: calcout Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: calcout Records</h1>
|
||||
<h1>calcout Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> Device support for calcout records is only available for
|
||||
@ -59,25 +59,31 @@ Different record fields are used for output and input. The variable
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Using EPICS 3.13</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Using EPICS 3.13</h1>
|
||||
<h1>Using EPICS 3.13</h1>
|
||||
|
||||
<a name="pre"></a>
|
||||
<h2>1. Prerequisites</h2>
|
||||
@ -218,7 +218,31 @@ asynSetOption ("PS1", 0, "stop", "1")
|
||||
|
||||
<h2>7. <a href="setup.html#pro">Continue as with EPICS 3.14.</a></h2>
|
||||
|
||||
<hr>
|
||||
<p><small>Dirk Zimoch, 2006</small></p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 187 B After Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 187 B After Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Format Converter API</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Format Converter API</h1>
|
||||
<h1>Format Converter API</h1>
|
||||
|
||||
<a name="class"></a>
|
||||
<h2>Converter Class</h2>
|
||||
@ -44,7 +44,7 @@ class MyConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||
int scanLong(const StreamFormat&, const char*, long&);
|
||||
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||
};
|
||||
|
||||
RegisterConverter(MyConverter,"Q");
|
||||
@ -53,7 +53,7 @@ RegisterConverter(MyConverter,"Q");
|
||||
</pre>
|
||||
|
||||
<a name="theory"></a>
|
||||
<h2>Theroy of Operation</h2>
|
||||
<h2>Theory of Operation</h2>
|
||||
|
||||
<a name="registration"></a>
|
||||
<h3>Registration </h3>
|
||||
@ -73,17 +73,17 @@ Provide multiple classes, that's more efficient.
|
||||
<a name="parsing"></a>
|
||||
<h3>Parsing</h3>
|
||||
<div class="indent"><code>
|
||||
int parse (const StreamFormat& fmt, StreamBuffer& info,
|
||||
int parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
struct StreamFormat {
|
||||
char conv;
|
||||
StreamFormatType type;
|
||||
unsigned char flags;
|
||||
short prec;
|
||||
unsigned short width;
|
||||
unsigned short infolen;
|
||||
unsigned short flags;
|
||||
long prec;
|
||||
unsigned long width;
|
||||
unsigned long infolen;
|
||||
const char* info;
|
||||
};
|
||||
</code></div>
|
||||
@ -124,12 +124,12 @@ flags set:
|
||||
</ul>
|
||||
<p>
|
||||
It is not necessary that these flags have exactly the same meaning in your
|
||||
formats, but a similar and intuitive meaning helpful for the user.
|
||||
formats, but a similar and intuitive meaning is helpful for the user.
|
||||
</p>
|
||||
<p>
|
||||
There are two additional flags, <code>default_flag</code> indicating a
|
||||
<code>?</code> and <code>compare_flag</code> indicating a <code>=</code>
|
||||
int the format, that are handled internally by <em>StreamDevice</em> and
|
||||
in the format, that are handled internally by <em>StreamDevice</em> and
|
||||
are not of interest to the converter class.
|
||||
</p>
|
||||
<p>
|
||||
@ -163,13 +163,13 @@ This will probably be necessary if you have parsed additional characters
|
||||
from the format string as in the above example<br>
|
||||
</p>
|
||||
<p>
|
||||
Return <code>long_format</code>, <em>double_format</em>,
|
||||
<em>string_format</em>, or <code>enum_format</code> depending on the
|
||||
Return <code>unsigned_format</code>, <code>signed_format</code>,
|
||||
<code>double_format</code>, <code>string_format</code>, or
|
||||
<code>enum_format</code> depending on the
|
||||
datatype associated with the conversion character.
|
||||
It is not necessary to return the same value for print and for scan
|
||||
formats.
|
||||
You can even return different values depending on the format string,
|
||||
but I can't imagine why anyone should do that.
|
||||
You can even return different values depending on the format string.
|
||||
</p>
|
||||
<p>
|
||||
If the format is not a real data conversion but does other things with
|
||||
@ -178,7 +178,8 @@ return <code>pseudo_format</code>.
|
||||
</p>
|
||||
<p>
|
||||
Return <code>false</code> if there is any parse error or if print or scan
|
||||
is requested but not supported by this conversion.
|
||||
is requested but not supported by this conversion or flags are used that
|
||||
are not supported by this conversion.
|
||||
</p>
|
||||
|
||||
<a name="printing_scanning"></a>
|
||||
@ -191,7 +192,45 @@ That method is called whenever the conversion appears in an output or input,
|
||||
respectively.
|
||||
You only need to implement the flavour of print and/or scan suitable for
|
||||
the datatype returned by <code>parse()</code>.
|
||||
Both <code>unsigned_format</code> and <code>signed_format</code> will use
|
||||
the <code>Long</code> flavour.
|
||||
</p>
|
||||
</p>
|
||||
The possible interface methods are:
|
||||
</p>
|
||||
<div class="indent"><code>
|
||||
bool printLong(const StreamFormat& fmt,
|
||||
StreamBuffer& output, long value);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool printDouble(const StreamFormat& fmt,
|
||||
StreamBuffer& output, double value);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool printString(const StreamFormat& fmt,
|
||||
StreamBuffer& output, const char* value);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
bool printPseudo(const StreamFormat& fmt,
|
||||
StreamBuffer& output);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
ssize_t scanLong(const StreamFormat& fmt,
|
||||
const char* input, long& value);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
ssize_t scanDouble(const StreamFormat& fmt,
|
||||
const char* input, double& value);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
ssize_t scanString(const StreamFormat& fmt,
|
||||
const char* input, char* value, size_t& size);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
ssize_t scanPseudo(const StreamFormat& fmt,
|
||||
StreamBuffer& inputLine, size_t& cursor);
|
||||
</code></div>
|
||||
|
||||
<p>
|
||||
Now, <code>fmt.type</code> contains the value returned by <code>parse()</code>.
|
||||
With <code>fmt.info()</code> get access to the string you have written to
|
||||
@ -203,19 +242,25 @@ The length of the info string can be found in <code>fmt.infolen</code>.
|
||||
<p>
|
||||
In <code>print*()</code>, append the converted value to <code>output</code>.
|
||||
Do not modify what is already in output (unless you really know what you're
|
||||
doing).
|
||||
doing, e.g. some <code>printPseudo</code> methods).
|
||||
Return <code>true</code> on success, <code>false</code> on failure.
|
||||
</p>
|
||||
<p>
|
||||
In <code>scan*()</code>, read the value from input and return the number of
|
||||
consumed bytes.
|
||||
In the string version, don't write more bytes than <code>maxlen</code>!
|
||||
consumed bytes or -1 on failure.
|
||||
If the <code>skip_flag</code> is set, you don't need to write to
|
||||
<code>value</code>, since the value will be discarded anyway.
|
||||
Return <code>-1</code> on failure.
|
||||
In <code>scanString()</code>, don't write more bytes than
|
||||
<code>maxlen</code> to <code>value</code> and set <code>size</code> to the
|
||||
actual string length, which may be different to the number of bytes consumed
|
||||
(e.g. if leading spaces are skipped).
|
||||
In <code>scanPseudo()</code>, <code>cursor</code> is the index of the first
|
||||
byte in <code>inputLine</code> to consider, which may be larger than
|
||||
<code>0</code>.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p><small>Dirk Zimoch, 2007</small></p>
|
||||
<footer>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Format Converters</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Format Converters</h1>
|
||||
<h1>Format Converters</h1>
|
||||
|
||||
<a name="syntax"></a>
|
||||
<h2>1. Format Syntax</h2>
|
||||
@ -28,8 +28,8 @@ A format converter consists of
|
||||
</p>
|
||||
<ul>
|
||||
<li>The <code>%</code> character</li>
|
||||
<li>Optionally a field <span class="new">or record</span> name in <code>()</code></li>
|
||||
<li>Optionally flags out of the characters <code>*# +0-<span class="new">?=</span></code></li>
|
||||
<li>Optionally a field or record name in <code>()</code></li>
|
||||
<li>Optionally flags out of the characters <code>*# +0-?=!</code></li>
|
||||
<li>Optionally an integer <em>width</em> field</li>
|
||||
<li>Optionally a period character (<code>.</code>) followed
|
||||
by an integer <em>precision</em> field (input ony for most formats)</li>
|
||||
@ -37,10 +37,18 @@ A format converter consists of
|
||||
<li>Additional information required by some converters</li>
|
||||
</ul>
|
||||
|
||||
<p class="new">
|
||||
An exception is the sequence <code>%%</code> which stands for a single
|
||||
literal <code>%</code>.
|
||||
This has been added for compatibility with the C functions
|
||||
<em>printf()</em> and <em>scanf()</em>.
|
||||
It behaves the same as the escaped percent <code>\%</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The flags <code>*# +0-</code> work like in the C functions
|
||||
<em>printf()</em> and <em>scanf()</em>.
|
||||
The flags <code>?</code> and <code>=</code> are extensions.
|
||||
The flags <code>?</code>, <code>=</code> and <code>!</code> are extensions.
|
||||
</p>
|
||||
<p>
|
||||
The <code>*</code> flag skips data in input formats.
|
||||
@ -55,58 +63,74 @@ The <code>#</code> flag may alter the format, depending on the
|
||||
converter (see below).
|
||||
</p>
|
||||
<p>
|
||||
The '<code> </code>' (space) and <code>+</code> flags print a space
|
||||
or a <code>+</code> sign before positive numbers, where negative
|
||||
The '<code> </code>' (space) and <code>+</code> flags usually print a
|
||||
space or a <code>+</code> sign before positive numbers, where negative
|
||||
numbers would have a <code>-</code>.
|
||||
Some converters may redefine the meaning of these flags (see below).
|
||||
</p>
|
||||
<p>
|
||||
The <code>0</code> flag says that numbers should be left padded with
|
||||
<code>0</code> if <em>width</em> is larger than required.
|
||||
The <code>0</code> flag usually says that numbers should be left padded
|
||||
with <code>0</code> if <em>width</em> is larger than required.
|
||||
Some converters may redefine the meaning of this flag (see below).
|
||||
<p>
|
||||
The <code>-</code> flag usually specifies that output is left justified
|
||||
if <em>width</em> is larger than required.
|
||||
Some converters may redefine the meaning of this flag (see below).
|
||||
</p>
|
||||
<p>
|
||||
The <code>-</code> flag specifies that output is left justified if
|
||||
<em>width</em> is larger than required.
|
||||
</p>
|
||||
<p class="new">
|
||||
The <code>?</code> flag makes failing input conversions succeed with
|
||||
a default zero value (0, 0.0, or "", depending on the format type).
|
||||
</p>
|
||||
<p class="new">
|
||||
<p>
|
||||
The <code>=</code> flag allows to compare input with current values.
|
||||
It is only allowed in input formats.
|
||||
Instead of reading a new value from input, the current value is
|
||||
formatted (like for output) and then compared to the input.
|
||||
</p>
|
||||
<p>
|
||||
The <code>!</code> flag demands that input is exactly <em>width</em>
|
||||
bytes long (normally <em>width</em> defines the maximum number of
|
||||
bytes read in many formats).
|
||||
This feature has been added by Klemen Vodopivec, SNS.
|
||||
</p>
|
||||
|
||||
<h3>Examples:</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>in "%f";</code></td>
|
||||
<td>float</td>
|
||||
<td>Read a float value</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>out "%(HOPR)7.4f";</code></td>
|
||||
<td>the HOPR field as 7 char float with precision 4</td>
|
||||
<td>Write the HOPR field as 7 char float with precision 4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>out "%#010x";</code></td>
|
||||
<td>0-padded 10 char alternate hex (with leading 0x)</td>
|
||||
<td>Write a 0-padded 10 char hex integer using the alternative format (with leading 0x)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>in "%[_a-zA-Z0-9]";</code></td>
|
||||
<td>string of chars out of a charset</td>
|
||||
<td>Read a string of alphanumerical chars or underscores</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>in "%*i";</code></td>
|
||||
<td>skipped integer number</td>
|
||||
<td>Skip over an integer number</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>in "%?d";</code></td>
|
||||
<td>decimal number or nothing (read as 0)</td>
|
||||
<td>Read a decimal number or if that fails pretend that value was 0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>in "%=.3f";</code></td>
|
||||
<td>compare input to the current value formatted as a float with precision 3</td>
|
||||
<td>Assure that the input is equal to the current value formatted as a float with precision 3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>in "%!5d";</code></td>
|
||||
<td>Expect exactly 5 decimal digits. Fewer digits are considered loss of data and make the format fail.
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>in "%d%%";</code></td>
|
||||
<td>Read a decimal number followed by a % sign</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -115,9 +139,9 @@ formatted (like for output) and then compared to the input.
|
||||
<h3>Default fields</h3>
|
||||
<p>
|
||||
Every conversion character corresponds to one of the data types DOUBLE,
|
||||
LONG, ENUM, or STRING.
|
||||
In opposite to to <em>printf()</em> and <em>scanf()</em>, it is not
|
||||
required to specify a variable for the conversion.
|
||||
LONG, ULONG, ENUM, or STRING.
|
||||
In contrast to to the C functions <em>printf()</em> and <em>scanf()</em>,
|
||||
it is not required to specify a variable for the conversion.
|
||||
The variable is typically the <code>VAL</code> or <code>RVAL</code> field
|
||||
of the record, selected automatically depending on the data type.
|
||||
Not all data types make sense for all record types.
|
||||
@ -133,42 +157,72 @@ exist in <em>StreamDevice</em> formats.
|
||||
</p>
|
||||
|
||||
<a name="redirection"></a>
|
||||
<h3>Redirection</h3>
|
||||
<h3>I/O Redirection to other records or fields</h3>
|
||||
<p>
|
||||
To use other fields of the record or even fields of other records on the
|
||||
same IOC for the conversion, write the field name in parentheses directly
|
||||
after the <code>%</code>.
|
||||
For example <code>out "%(EGU)s";</code> outputs the <code>EGU</code>
|
||||
field formatted as a string.
|
||||
Use <code>in "%(<i>otherrecord</i>.RVAL)f";</code> to write the floating
|
||||
point input value into the <code>RVAL</code> field of
|
||||
<code><i>otherrecord</i></code>.
|
||||
<span class="new">
|
||||
If no field is given for an other record .VAL is assumed.
|
||||
When a record name conflicts with a field name use .VAL explicitly.
|
||||
</span>
|
||||
|
||||
To use formats with other than the default fields of a record or even with
|
||||
fields of other records on the same IOC, use the syntax
|
||||
<code>%(<var>record</var>.<var>FIEL</var>D)</code>.
|
||||
If only a field name but no record is given, the active record is assumed.
|
||||
If only a record name but no field name is given, the <code>VAL</code>
|
||||
field is assumed.
|
||||
</p>
|
||||
<p>
|
||||
This feature is very useful when one line of input contains many values that should
|
||||
be distributed to many records.
|
||||
If <code><i>otherrecord</i></code> is passive and the field has the PP
|
||||
<b>Example 1:</b> <code>out "%(EGU)s";</code> outputs the
|
||||
<code>EGU</code> field of the active record.
|
||||
</p>
|
||||
<p>
|
||||
<b>Example 2:</b> <code>in "%(<var>otherrecord</var>.RVAL)i";</code>
|
||||
stores the received integer value in the <code>RVAL</code> field of the
|
||||
other record and then processes that record.
|
||||
The other record should probably use <code>DTYP="Raw Soft Channel"</code>
|
||||
in order to convert <code>RVAL</code> to <code>VAL</code>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Example 3:</b> <code>in "%(<var>otherrecord</var>)f";</code>
|
||||
stores the received floating point value in the <code>VAL</code> field
|
||||
of the other record and then processes that record.
|
||||
The other record should probably use <code>DTYP="Soft Channel"</code>.
|
||||
In the unlikely case that the name of the other record is the same as a field
|
||||
of the active record (e.g. if you name a record "DESC"), then use <code>.VAL</code>
|
||||
explicitly to refer to the record rather than the field of the active record.
|
||||
</p>
|
||||
<p>
|
||||
This feature is quite useful in the case that one line of input contains more
|
||||
than one value that need to be stored in multiple records or if one line of
|
||||
output needs to be contructed from values of multiple records.
|
||||
In order to avoid using full record names in the protocol file, it is recommended
|
||||
to pass the name or part of the name (e.g. the device prefix) of the other
|
||||
record as a <a href="protocol.html#argvar">protocol argument</a>.
|
||||
In that case the redirection usually looks like this:
|
||||
<code>in "%(\$1<var>recordpart</var>)f"</code> and the record calls the protocol
|
||||
like this:
|
||||
<code>field(INP, "@<var>protocolfile</var> <var>protocol</var>($(PREFIX)) $(PORT)")</code>
|
||||
using a macro for the prefix part which is then used for <code>\$1</code>.
|
||||
</p>
|
||||
<p>
|
||||
If the other record is passive and the field has the PP
|
||||
attribute (see
|
||||
<a href="http://www.aps.anl.gov/asd/controls/epics/EpicsDocumentation/AppDevManuals/RecordRef/Recordref-1.html"
|
||||
target="ex">Record Reference Manual</a>), the record will be processed.
|
||||
It is your responsibility that the data type of the record field is
|
||||
compatible to the the data type of the converter.
|
||||
Note that using this syntax is by far not as efficient as using the
|
||||
STRING formats are compatible with arrays of CHAR or UCHAR.
|
||||
</p>
|
||||
<p>
|
||||
Be aware that using this syntax is by far not as efficient as using the
|
||||
default field.
|
||||
At the moment it is not possible to set <code>otherrecord</code> to an alarm
|
||||
state when anything fails.
|
||||
At the moment it is not possible to set the other record to an alarm
|
||||
state if anything fails. It will simply not be processed if the fault
|
||||
happens before or while handling it and it will already have been
|
||||
processed if the fault happens later.
|
||||
</p>
|
||||
|
||||
<h3>Pseudo-converters</h3>
|
||||
<p>
|
||||
Some formats are not actually converters.
|
||||
They format data which is not stored in a record field, such as a
|
||||
<a href="#chksum">checksum</a>.
|
||||
<a href="#chksum">checksum</a> or
|
||||
<a href="#regsub">regular expression substitution</a>.
|
||||
No data type corresponds to those <em>pseudo-converters</em> and the
|
||||
<code>%(<em>FIELD</em>)</code> syntax cannot be used.
|
||||
</p>
|
||||
@ -189,17 +243,17 @@ With the <code>#</code> flag, output always contains a period character.
|
||||
<p>
|
||||
<b>Input:</b> All these formats are equivalent. Leading whitespaces are skipped.
|
||||
</p>
|
||||
<p class="new">
|
||||
<p>
|
||||
With the <code>#</code> flag additional whitespace between sign and number
|
||||
is accepted.
|
||||
</p>
|
||||
<p class="new">
|
||||
<p>
|
||||
When a maximum field width is given, leading whitespace only counts to the
|
||||
field witdth when the space flag is given.
|
||||
field witdth when the space flag is used.
|
||||
</p>
|
||||
|
||||
<a name="stdl"></a>
|
||||
<h2>4. Standard LONG Converters (<code>%d</code>, <code>%i</code>,
|
||||
<h2>4. Standard LONG and ULONG Converters (<code>%d</code>, <code>%i</code>,
|
||||
<code>%u</code>, <code>%o</code>, <code>%x</code>, <code>%X</code>)</h2>
|
||||
<p>
|
||||
<b>Output</b>: <code>%d</code> and <code>%i</code> print signed decimal,
|
||||
@ -210,6 +264,10 @@ field witdth when the space flag is given.
|
||||
<p>
|
||||
With the <code>#</code> flag, octal values are prefixed with <code>0</code>
|
||||
and hexadecimal values with <code>0x</code> or <code>0X</code>.
|
||||
<p>
|
||||
Unlike printf, <code>%x</code> and <code>%X</code> truncate the
|
||||
output to the the given width (number of least significant half bytes).
|
||||
</p>
|
||||
</p>
|
||||
<p>
|
||||
<b>Input:</b> <code>%d</code> matches signed decimal, <code>%u</code> matches
|
||||
@ -221,16 +279,16 @@ Octal and hexadecimal values can optionally be prefixed.
|
||||
hexadecimal notation.
|
||||
Leading whitespaces are skipped.
|
||||
</p>
|
||||
<p class="new">
|
||||
<p>
|
||||
With the <code>-</code> negative octal and hexadecimal values are accepted.
|
||||
</p>
|
||||
<p class="new">
|
||||
<p>
|
||||
With the <code>#</code> flag additional whitespace between sign and number
|
||||
is accepted.
|
||||
</p>
|
||||
<p class="new">
|
||||
<p>
|
||||
When a maximum field width is given, leading whitespace only counts to the
|
||||
field witdth when the space flag is given.
|
||||
field witdth when the space flag is used.
|
||||
</p>
|
||||
|
||||
<a name="stds"></a>
|
||||
@ -246,16 +304,19 @@ and <code>%c</code> matches a sequence of not-null characters.
|
||||
The maximum string length is given by <em>width</em>.
|
||||
The default <em>width</em> is infinite for <code>%s</code> and
|
||||
1 for <code>%c</code>.
|
||||
Leading whitespaces are skipped with <code>%s</code>
|
||||
<span class="new">
|
||||
except when the space flag is given</span>
|
||||
but not with <code>%c</code>.
|
||||
Leading whitespaces are skipped with <code>%s</code> except when
|
||||
the space flag is used but not with <code>%c</code>.
|
||||
The empty string matches.
|
||||
</p>
|
||||
<p class="new">
|
||||
<p>
|
||||
With the <code>#</code> flag <code>%s</code> matches a sequence of not-null
|
||||
characters instead of non-whitespace characters.
|
||||
</p>
|
||||
<p>
|
||||
With the <code>0</code> flag <code>%s</code> pads with 0 bytes instead of
|
||||
spaces.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="cset"></a>
|
||||
<h2>6. Standard Charset STRING Converter (<code>%[<em>charset</em>]</code>)</h2>
|
||||
@ -286,9 +347,21 @@ to the value 0, <code>STANDBY</code> to 1 and <code>ON</code> to 2.
|
||||
<p>
|
||||
When using the <code>#</code> flag it is allowed to assign integer values
|
||||
to the strings using <code>=</code>.
|
||||
Unassigned strings increment their values by 1 as usual.
|
||||
</p>
|
||||
<p>
|
||||
Example: <code>%#{neg=-1|stop=0|pos=1|fast=10}</code>.
|
||||
If one string is the initial substing of another, the substing must come
|
||||
later to ensure correct matching.
|
||||
In particular if one string is the emptry string, it must be the last one
|
||||
because it always matches.
|
||||
Use <code>#</code> and <code>=</code> to renumber if necessary.
|
||||
</p>
|
||||
<p>
|
||||
Use the assignment <code>=?</code> for the last string to make it the
|
||||
default value for output formats.
|
||||
</p>
|
||||
<p>
|
||||
Example: <code>%#{neg=-1|stop|pos|fast=10|rewind=-10}</code>.
|
||||
</p>
|
||||
<p>
|
||||
If one of the strings contains <code>|</code> or <code>}</code>
|
||||
@ -296,14 +369,15 @@ If one of the strings contains <code>|</code> or <code>}</code>
|
||||
a <code>\</code> must be used to escape the character.
|
||||
</p>
|
||||
<p>
|
||||
In output, depending on the value, one of the strings is printed.
|
||||
<b>Output:</b> Depending on the value, one of the strings is printed,
|
||||
or the default if given and no value matches.
|
||||
</p>
|
||||
<p>
|
||||
In input, if any of the strings matches the value is set accordingly.
|
||||
<b>Input:</b> If any of the strings matches, the value is set accordingly.
|
||||
</p>
|
||||
|
||||
<a name="bin"></a>
|
||||
<h2>8. Binary LONG Converter (<code>%b</code>, <code>%B<em>zo</em></code>)</h2>
|
||||
<h2>8. Binary LONG or ULONG Converter (<code>%b</code>, <code>%B<em>zo</em></code>)</h2>
|
||||
<p>
|
||||
This format prints or scans an unsigned integer represented as a binary
|
||||
string (one character per bit).
|
||||
@ -333,7 +407,7 @@ one character.
|
||||
</p>
|
||||
|
||||
<a name="raw"></a>
|
||||
<h2>9. Raw LONG Converter (<code>%r</code>)</h2>
|
||||
<h2>9. Raw LONG or ULONG Converter (<code>%r</code>)</h2>
|
||||
<p>
|
||||
The raw converter does not really "convert".
|
||||
A signed or unsigned integer value is written or read in the internal
|
||||
@ -345,9 +419,12 @@ endian</em>, i.e. least significant byte first.
|
||||
With the <code>0</code> flag, the value is unsigned, otherwise signed.
|
||||
</p>
|
||||
<p>
|
||||
In output, the <em>prec</em> (or sizeof(long) whatever is less) least
|
||||
In output, the <em>precision</em> (or sizeof(long) whatever is less) least
|
||||
significant bytes of the value are sign extended or zero extended
|
||||
(depending on the <code>0</code> flag) to <em>width</em> bytes.
|
||||
The default for <em>precision</em> is 1. Thus if you do not specify
|
||||
the <em>precision</em>, only the least significant byte is written!
|
||||
It is common error to write <code>out "%2r";</code> instead of <code>out "%.2r";</code>.
|
||||
</p>
|
||||
<p>
|
||||
In input, <em>width</em> bytes are read and put into the value.
|
||||
@ -358,7 +435,7 @@ the value is sign extended or zero extended, depending on the
|
||||
<code>0</code> flag.
|
||||
</p>
|
||||
<p>
|
||||
Example: <code>out "%.2r"</code>
|
||||
Examples: <code>out "%.2r"; in "%02r";</code>
|
||||
</p>
|
||||
|
||||
<a name="rawdouble"></a>
|
||||
@ -375,7 +452,7 @@ The <em>width</em> must be 4 (float) or 8 (double). The default is 4.
|
||||
</p>
|
||||
|
||||
<a name="bcd"></a>
|
||||
<h2>11. Packed BCD (Binary Coded Decimal) LONG Converter (<code>%D</code>)</h2>
|
||||
<h2>11. Packed BCD (Binary Coded Decimal) LONG or ULONG Converter (<code>%D</code>)</h2>
|
||||
<p>
|
||||
Packed BCD is a format where each byte contains two binary coded
|
||||
decimal digits (<code>0</code> ... <code>9</code>).
|
||||
@ -408,11 +485,17 @@ than 9.
|
||||
<p>
|
||||
This is not a normal "converter", because no user data is converted.
|
||||
Instead, a checksum is calculated from the input or output.
|
||||
<span class="new">
|
||||
Any pre-processing of input, e.g. by the <a href="#regsub">regsub</a> converter
|
||||
is ignored for the calculation of the checksum.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
The <em>width</em> field is the byte number from which to start
|
||||
calculating the checksum.
|
||||
Default is 0, i.e. the first byte of the input or output of the current
|
||||
command.
|
||||
The last byte is <em>prec</em> bytes before the checksum (default 0).
|
||||
The last byte is <em>precision</em> bytes before the checksum (default 0).
|
||||
For example in <code>"abcdefg%<xor>"</code> the checksum is calculated
|
||||
from <code>abcdefg</code>,
|
||||
but in <code>"abcdefg%2.1<xor>"</code> only from <code>cdef</code>.
|
||||
@ -424,8 +507,17 @@ With the <code>#</code> flag, the byte order is changed to <em>little
|
||||
endian</em>, i.e. least significant byte first.
|
||||
</p>
|
||||
<p>
|
||||
The <code>0</code> flag changes the checksum representation from
|
||||
binary to hexadecimal ASCII (2 bytes per checksum byte).
|
||||
The <code>0</code> flag changes the checksum representation to
|
||||
hexadecimal ASCII (2 chars per checksum byte).
|
||||
</p>
|
||||
<p>
|
||||
The <code>-</code> flag changes the checksum representation to
|
||||
"poor man's hex": 0x30 ... 0x3f (2 chars per checksum byte).
|
||||
</p>
|
||||
<p>
|
||||
The <code>+</code> flag changes the checksum representation to
|
||||
decimal ASCII (formatted with %d).
|
||||
</p>
|
||||
<!--
|
||||
In output, the case of the ASCII checksum matches the case of first
|
||||
letter of the function name.
|
||||
@ -466,21 +558,24 @@ In input, the next byte or bytes must match the checksum.
|
||||
(poly=0x07, init=0x00, xorout=0x00).</dd>
|
||||
<dt><code>%<ccitt8></code></dt>
|
||||
<dd>One byte. The CCITT standard 8 bit crc checksum
|
||||
(poly=0x31, init=0x00, xorout=0x00).</dd>
|
||||
(poly=0x31, init=0x00, xorout=0x00, reflected).</dd>
|
||||
<dt><code>%<crc16></code></dt>
|
||||
<dd>Two bytes. An often used 16 bit crc checksum
|
||||
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
|
||||
<dt><code>%<crc16r></code></dt>
|
||||
<dd>Two bytes. An often used reflected 16 bit crc checksum
|
||||
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
|
||||
(poly=0x8005, init=0x0000, xorout=0x0000, reflected).</dd>
|
||||
<dt><code>%<modbus></code></dt>
|
||||
<dd>Two bytes. The modbus 16 bit crc checksum
|
||||
(poly=0x8005, init=0xffff, xorout=0x0000, reflected)</dd>
|
||||
<dt><code>%<ccitt16></code></dt>
|
||||
<dd>Two bytes. The usual (but <a target="ex"
|
||||
href="http://www.joegeluso.com/software/articles/ccitt.htm">wrong?</a>)
|
||||
href="http://srecord.sourceforge.net/crc16-ccitt.html">wrong?</a>)
|
||||
implementation of the CCITT standard 16 bit crc checksum
|
||||
(poly=0x1021, init=0xFFFF, xorout=0x0000).</dd>
|
||||
<dt><code>%<ccitt16a></code></dt>
|
||||
<dd>Two bytes. The unusual (but <a target="ex"
|
||||
href="http://www.joegeluso.com/software/articles/ccitt.htm">correct?</a>)
|
||||
href="http://srecord.sourceforge.net/crc16-ccitt.html">correct?</a>)
|
||||
implementation of the CCITT standard 16 bit crc checksum with augment.
|
||||
(poly=0x1021, init=0x1D0F, xorout=0x0000).</dd>
|
||||
<dt><code>%<ccitt16x></code> or <code>%<crc16c></code> or <code>%<xmodem></code></dt>
|
||||
@ -491,53 +586,78 @@ In input, the next byte or bytes must match the checksum.
|
||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
||||
<dt><code>%<crc32r></code></dt>
|
||||
<dd>Four bytes. The standard reflected 32 bit crc checksum.
|
||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF, reflected).</dd>
|
||||
<dt><code>%<jamcrc></code></dt>
|
||||
<dd>Four bytes. Another reflected 32 bit crc checksum.
|
||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0x00000000).</dd>
|
||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0x00000000, reflected).</dd>
|
||||
<dt><code>%<adler32></code></dt>
|
||||
<dd>Four bytes. The Adler32 checksum according to <a target="ex"
|
||||
href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950</a>.</dd>
|
||||
<dt><code>%<hexsum8></code></dt>
|
||||
<dd>One byte. The sum of all hex digits. (Other characters are ignored.)</dd>
|
||||
<dt><code>%<lrc></code></dt>
|
||||
<dd>One byte. The Longitudinal Redundancy Check according to <a target="ex"
|
||||
href="https://en.wikipedia.org/wiki/Longitudinal_redundancy_check">Wikipedia</a>.</dd>
|
||||
<dt><code>%<hexlrc></code></dt>
|
||||
<dd>One byte. The LRC for the hex digits. (Other characters are ignored.)</dd>
|
||||
<dt><code>%<leybold></code></dt>
|
||||
<dd>One byte. Used by some Leybold products. 255-bytesum%255 (+32 if result would be <32)</dd>
|
||||
<dt><code>%<brksCryo></code></dt>
|
||||
<dd>One byte. Used by Brooks Cryopumps.</dd>
|
||||
<dt><code>%<CPI></code></dt>
|
||||
<dd>One byte. Used by TRIUMF CPI RF amplifier.</dd>
|
||||
<dt><code>%<bitsum></code> or <code>%<bitsum8></code></dt>
|
||||
<dd>One byte. Number of 1 bits in all characters.</dd>
|
||||
<dt><code>%<bitsum16></code></dt>
|
||||
<dd>Two bytes. Number of 1 bits in all characters.</dd>
|
||||
<dt><code>%<bitsum32></code></dt>
|
||||
<dd>Four bytes. Number of 1 bits in all characters.</dd>
|
||||
</dl>
|
||||
|
||||
<a name="regex"></a>
|
||||
<h2>12. Regular Expresion STRING Converter (<code>%/<em>regex</em>/</code>)</h2>
|
||||
<h2>13. Regular Expresion STRING Converter (<code>%/<em>regex</em>/</code>)</h2>
|
||||
<p>
|
||||
This input-only format matches <a target="ex"
|
||||
href="http://www.pcre.org/" >Perl compatible regular expressions (PCRE)</a>.
|
||||
It is only available if a PCRE library is installed.
|
||||
</p>
|
||||
<div class="box">
|
||||
<p>
|
||||
If PCRE is not available for your host or cross architecture, download
|
||||
the sourcecode from <a target="ex" href="http://www.pcre.org/">www.pcre.org</a>
|
||||
the sourcecode from <a target="ex" href="https://www.pcre.org/">www.pcre.org</a>
|
||||
and try my EPICS compatible <a target="ex"
|
||||
href="http://epics.web.psi.ch/software/streamdevice/pcre/Makefile">Makefile</a>
|
||||
to compile it like a normal EPICS application.
|
||||
to compile it like a normal EPICS support module.
|
||||
The Makefile is known to work with EPICS 3.14.8 and PCRE 7.2.
|
||||
In your RELEASE file define the variable <code>PCRE</code> so that
|
||||
it points to the install location of PCRE.
|
||||
</p>
|
||||
<p>
|
||||
If PCRE is already installed on your system, use the variables
|
||||
<code>PCRE_INCLUDE</code> and <code>PCRE_LIB</code> instead to provide
|
||||
the install directories of <code>pcre.h</code> and the library.
|
||||
</p>
|
||||
<p>
|
||||
If you have PCRE installed in different locations for different (cross)
|
||||
architectures, define the variables in RELEASE.Common.<architecture>
|
||||
instead of the global RELEASE file.
|
||||
If PCRE is already installed on (some of) your systems, you may add
|
||||
architectures where PCRE can be found in standard include and library
|
||||
locations to the variable <code>WITH_SYSTEM_PCRE</code>.
|
||||
If either the header file or the library are in a non-standard place,
|
||||
set in your RELEASE file the variables <code>PCRE_INCLUDE_<em>arch</em></code>
|
||||
and/or <code>PCRE_LIB_<em>arch</em></code> for the respective architectures
|
||||
to the correct directories or set
|
||||
<code>PCRE_INCLUDE</code> and/or <code>PCRE_LIB</code>
|
||||
in architecture specific RELEASE.Common.<em>arch</em> files.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
If the regular expression is not anchored, i.e. does not start with
|
||||
<code>^</code>, leading non-matching input is skipped.
|
||||
<code>^</code>, leading non-matching input is skipped.
|
||||
To match in multiline mode (across newlines) add <code>(?m)</code>
|
||||
at the beginning of the pattern.
|
||||
To match case insensitive, add <code>(?i)</code>.
|
||||
</p>
|
||||
<p>
|
||||
A maximum of <em>width</em> bytes is matched, if specified.
|
||||
If <em>prec</em> is given, it specifies the sub-expression whose match
|
||||
is retuned.
|
||||
If <em>precision</em> is given, it specifies the sub-expression in <code>()</code>
|
||||
whose match is returned.
|
||||
Otherwise the complete match is returned.
|
||||
In any case, the complete match is consumed from the input buffer.
|
||||
If the expression contains a <code>/</code> it must be escaped.
|
||||
If the expression contains a <code>/</code> it must be escaped like <code>\/</code>.
|
||||
</p>
|
||||
<p>
|
||||
Example: <code>%.1/<title>(.*)<\/title>/</code> returns
|
||||
@ -545,8 +665,102 @@ the title of an HTML page, skipps anything before the
|
||||
<code><title></code> tag and leaves anything after the
|
||||
<code></title></code> tag in the input buffer.
|
||||
</p>
|
||||
<a name="regsub"></a>
|
||||
<h2>14. Regular Expresion Substitution Pseudo-Converter (<code>%#/<em>regex</em>/<em>subst</em>/</code>)</h2>
|
||||
<p>
|
||||
This is a variant of the previous converter (note the <code>#</code>)
|
||||
but instead of returning the matching string,
|
||||
it can be used as a pre-processor for input or
|
||||
as a post-processor for output.
|
||||
</p>
|
||||
<p>
|
||||
Matches of the <em>regex</em> are replaced by the string <em>subst</em> with all
|
||||
<code>&</code> in <em>subst</em> replaced with the match itself and all
|
||||
<code>\1</code> through <code>\9</code> replaced with the match of the corresponding
|
||||
sub-expression <span class="new"> if such a sub-expression exists.
|
||||
|
||||
Occurrences of <code>\U<i>n</i></code>, <code>\L<i>n</i></code>, <code>\u<i>n</i></code>,
|
||||
or <code>\l<i>n</i></code> with <code><i>n</i></code> being a number <code>0</code>
|
||||
through <code>9</code> or <code>&</code> are replaced with the corresponding sub-expression
|
||||
converted to all upper case, all lower case, first letter upper case, or first letter lower
|
||||
case, respectively.</span>
|
||||
</p>
|
||||
<p><span class="new">
|
||||
Due to limitations of the parser, <code>\1</code> and <code>\x01</code> are the same
|
||||
which makes it difficult to use literal bytes with values lower than 10 in <em>subst</em>.
|
||||
Therefore <code>\0</code> aways means a literal byte (incompatible change from earlier version!)
|
||||
and <code>\1</code> through <code>\9</code> mean literal bytes if they are larger than
|
||||
the number of sub-expressions.
|
||||
</span>
|
||||
|
||||
To get a literal <code>&</code> or <code>\</code> or <code>/</code> in the substitution write
|
||||
<code>\&</code> or <code>\\</code> or <code>\/</code>.
|
||||
</p>
|
||||
<p>
|
||||
If <em>width</em> is specified, it limits the number of characters processed.
|
||||
If the <code>-</code> flag is used (i.e. <em>width</em> looks like a negative number)
|
||||
only the last <em>width</em> characters are processed, else the first.
|
||||
Without <em>width</em> (or 0) all available characters are processed.
|
||||
</p>
|
||||
<p>
|
||||
If <em>precision</em> is specified, it indicates which matches to replace.
|
||||
With the <code>+</code> flag given, <em>precision</em> is the maximum
|
||||
number of matches to replace.
|
||||
Otherwise <em>precision</em> is the index (counting from 1) of the match to replace.
|
||||
Without <em>precision</em> (or 0), all matches are replaced.
|
||||
</p>
|
||||
<p>
|
||||
When replacing multiple matches, the next match is searched directly after the currently
|
||||
replaced string, so that the <em>subst</em> string itself will never be modified recursively.
|
||||
<span class="new">
|
||||
However if an empty string is matched, searching advances by 1 character in order to
|
||||
avoid matching the same empty string again.</span>
|
||||
</p>
|
||||
<p>
|
||||
In input, this converter pre-processes data received from the device before
|
||||
following converters read it.
|
||||
Converters preceding this one will read unmodified input.
|
||||
Thus place this converter before those whose input should be pre-processed.
|
||||
<span class="new">
|
||||
However, <a href="#chksum">checksum</a> converters will always use the unmodified
|
||||
input as sent by the device because the modified input would not match the checksum.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
In output it post-processes data already formatted by preceding converters
|
||||
before sending it to the device.
|
||||
Converters following this one will send their output unmodified.
|
||||
Thus place this converter after those whose output should be post-processed.
|
||||
</p>
|
||||
<p>
|
||||
Examples:
|
||||
<div class="indent">
|
||||
<code>%#+-10.2/ab/X/</code> replaces the string <code>ab</code> with <code>X</code>
|
||||
maximal 2 times in the last 10 characters.
|
||||
(<code>abcabcabcabc</code> becomes <code>abcXcXcabc</code>)
|
||||
</div>
|
||||
<div class="indent">
|
||||
<code>%#/\\/\//</code> replaces all <code>\</code> with <code>/</code>
|
||||
(<code>\dir\file</code> becomes <code>/dir/file</code>)
|
||||
</div>
|
||||
<div class="indent">
|
||||
<code>%#/..\B/&:/</code> inserts <code>:</code> after every second character
|
||||
which is not at the end of a word.
|
||||
(<code>0b19353134</code> becomes <code>0b:19:35:31:34</code>)
|
||||
</div>
|
||||
<div class="indent">
|
||||
<code>%#/://</code> removes all <code>:</code> characters.
|
||||
(<code>0b:19:35:31:34</code> becomes <code>0b19353134</code>)
|
||||
</div>
|
||||
<div class="indent">
|
||||
<code>%#/([^+-])*([+-])/\2\1/</code> moves a postfix sign to the front.
|
||||
(<code>1.23-</code> becomes <code>-1.23</code>)<br>
|
||||
</div>
|
||||
<div class="indent">
|
||||
<code>%#-2/.*/\U0/</code> converts the previous 2 characters to upper case.
|
||||
</div>
|
||||
<a name="mantexp"></a>
|
||||
<h2>13. MantissaExponent DOUBLE converter (<code>%m</code>)</h2>
|
||||
<h2>15. MantissaExponent DOUBLE converter (<code>%m</code>)</h2>
|
||||
<p>
|
||||
This exotic and experimental format matches numbers in the format
|
||||
<i>[sign] mantissa sign exponent</i>, e.g <code>+123-4</code> meaning
|
||||
@ -565,9 +779,8 @@ Format flags <code>+</code>, <code>-</code>, and space are supported in
|
||||
the usual way (always sign, left justified, space instead of + sign).
|
||||
Flags <code>#</code> and <code>0</code> are unsupported.
|
||||
</p>
|
||||
<div class="new">
|
||||
<a name="timestamp"></a>
|
||||
<h2>14. Timestamp DOUBLE converter (<code>%T(<em>timeformat</em>)</code>)</h2>
|
||||
<h2>16. Timestamp DOUBLE converter (<code>%T(<em>timeformat</em>)</code>)</h2>
|
||||
<p>
|
||||
This format reads or writes timestamps and converts them to a double number.
|
||||
The value represents the number of seconds since 1970 (the UNIX epoch).
|
||||
@ -604,7 +817,7 @@ In output, the system function <em>strftime()</em> is used to format the time.
|
||||
There may be differences in the implementation between operating systems.
|
||||
</p>
|
||||
<p>
|
||||
In input, <em>StreamDevice</em> used its own implementation because many
|
||||
In input, <em>StreamDevice</em> uses its own implementation because many
|
||||
systems are missing the <em>strptime()</em> function and additional formats
|
||||
are supported.
|
||||
</p>
|
||||
@ -618,9 +831,10 @@ Because of the complexity of the problem, locales are not supported.
|
||||
Thus, only the English month names can be used (week day names are
|
||||
ignored anyway).
|
||||
</p>
|
||||
</div>
|
||||
<hr>
|
||||
<p align="right"><a href="processing.html">Next: Record Processing</a></p>
|
||||
<p><small>Dirk Zimoch, 2011</small></p>
|
||||
|
||||
<footer>
|
||||
<a href="processing.html">Next: Record Processing</a>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,12 +1,12 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
@ -15,7 +15,7 @@
|
||||
<h2>What is <em>StreamDevice</em>?</h2>
|
||||
<p>
|
||||
<em>StreamDevice</em> is a generic
|
||||
<a href="http://www.aps.anl.gov/epics" target="ex">EPICS</a>
|
||||
<a href="https://epics.anl.gov/" target="ex">EPICS</a>
|
||||
device support for devices with a "byte stream" based
|
||||
communication interface.
|
||||
That means devices that can be controlled by sending and
|
||||
@ -52,7 +52,7 @@ It does not provide loops or branches.
|
||||
</p>
|
||||
<p>
|
||||
<em>StreamDevice</em> comes with an interface to<a target="ex"
|
||||
href="http://www.aps.anl.gov/epics/modules/soft/asyn/">
|
||||
href="https://www.aps.anl.gov/epics/modules/soft/asyn/">
|
||||
<em>asynDriver</em></a>
|
||||
but can be extended to
|
||||
<a href="businterface.html">support other bus drivers</a>.
|
||||
@ -82,14 +82,26 @@ primitive commands.
|
||||
</p>
|
||||
<p>
|
||||
It is not a block oriented device support.
|
||||
It is not possible to send or receive huge blocks of data that contain
|
||||
It is not intended for huge binary blocks of data that contain
|
||||
many process variables distributed over many records.
|
||||
Consider <a href="https://github.com/paulscherrerinstitute/regdev"
|
||||
target="ex"><em>regDev</em></a>
|
||||
for that.
|
||||
</p>
|
||||
<p>
|
||||
It is not a very flexible html, xml, json, etc. parser. Data needs to
|
||||
come in a predictible order to be parsable by <em>StreamDevice</em>.
|
||||
</p>
|
||||
|
||||
<h2>Recommended Readings</h2>
|
||||
<p>
|
||||
<a href="http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide"
|
||||
target="ex">IOC Application Developer's Guide</a>
|
||||
IOC Application Developer's Guide:
|
||||
<a href="https://epics.anl.gov/base/R3-14/12-docs/AppDevGuide/"
|
||||
target="ex">R3.14.12</a>,
|
||||
<a href="https://epics.anl.gov/base/R3-15/6-docs/AppDevGuide/AppDevGuide.html"
|
||||
target="ex">R3.15.6</a>,
|
||||
<a href="https://epics.anl.gov/base/R3-16/2-docs/AppDevGuide/AppDevGuide.html"
|
||||
target="ex">R3.16.2</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://wiki-ext.aps.anl.gov/epics/index.php/RRM_3-14"
|
||||
@ -104,13 +116,31 @@ This marks text you typically type in configuration files etc.
|
||||
<pre>
|
||||
Longer code segments are often set in a box.
|
||||
</pre>
|
||||
<p>
|
||||
Important modifications and new features are
|
||||
<span class="new">highlighted with a yellow background</span>.
|
||||
Obsolete features are <strike class="new">highlighted and crossed out</strike>.
|
||||
</p>
|
||||
<hr>
|
||||
<p align="right"><a href="setup.html">Next: Setup</a></p>
|
||||
<p><small>Dirk Zimoch, 2011</small></p>
|
||||
|
||||
<h2>Changes in Version 2.8</h2>
|
||||
<ul>
|
||||
<li>Support standard EPICS module build system.
|
||||
<li>Compatible with EPICS 7.
|
||||
<ul>
|
||||
<li>Support for new record types: int64in, int64out, lsi, lso.
|
||||
<li>Support for INT64 and UINT64 in aai, aao, waveform.
|
||||
</ul>
|
||||
<li>Run @init more often (e.g. when device re-connects or paused IOC is resumed).
|
||||
<li>Use "COMM" error code in .STAT when device is disconnected.
|
||||
<li>Allow spaces in protocol parameter list.
|
||||
<li>Support output redirect of all shell functions.
|
||||
<li>Fix building shared libraries on Windows.
|
||||
<li>Fix some C++11 warnings.
|
||||
<li>Fix several signed/unsigned problems.
|
||||
<li>Dropped support for cygnus-2.7.2 gcc (used by some old cygwin).
|
||||
<li>Several bug fixes.
|
||||
<li>Several documentation updates.
|
||||
</ul>
|
||||
|
||||
|
||||
<footer>
|
||||
<a href="setup.html">Next: Setup</a>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
78
docs/int64in.html
Normal file
@ -0,0 +1,78 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: int64in Records</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>int64in Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> The int64in (integer 64 bit input) record is only available from EPICS base R3.16 on.
|
||||
</p>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
The variable <code><i>x</i></code> stands for the
|
||||
written or read value.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code>
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code>
|
||||
</dd>
|
||||
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Initialization</h2>
|
||||
<p>
|
||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
78
docs/int64out.html
Normal file
@ -0,0 +1,78 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: int64out Records</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>int64out Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> The int64out (integer 64 bit output) record is only available from EPICS base R3.16 on.
|
||||
</p>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
The variable <code><i>x</i></code> stands for the
|
||||
written or read value.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code>
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code>
|
||||
</dd>
|
||||
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Initialization</h2>
|
||||
<p>
|
||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: longin Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: longin Records</h1>
|
||||
<h1>longin Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -46,25 +46,31 @@ written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: longout Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: longout Records</h1>
|
||||
<h1>longout Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -46,25 +46,31 @@ written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
79
docs/lsi.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: lsi Records</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>lsi Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> The lsi (long string in) record is only available from EPICS base R3.15 on.
|
||||
</p>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
The variable <code><i>x</i></code> stands for the
|
||||
written or read value.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code><br>
|
||||
Also the <code>LEN</code> field is set to the length of the input
|
||||
including possible null bytes.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Initialization</h2>
|
||||
<p>
|
||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
79
docs/lso.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: lso Records</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>lso Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> The lso (long string out) record is only available from EPICS base R3.15 on.
|
||||
</p>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
The variable <code><i>x</i></code> stands for the
|
||||
written or read value.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code><br>
|
||||
Also the <code>LEN</code> field is set to the length of the input
|
||||
including possible null bytes.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Initialization</h2>
|
||||
<p>
|
||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
59
docs/makepdf
Executable file
@ -0,0 +1,59 @@
|
||||
#/bin/sh
|
||||
wkhtmltopdf --enable-local-file-access -V >/dev/null 2>&1
|
||||
case $? in
|
||||
127)
|
||||
echo "wkhtmltopdf not installed." >&2
|
||||
echo "See https://wkhtmltopdf.org" >&2
|
||||
exit 1
|
||||
;;
|
||||
0)
|
||||
# have (and need) --enable-local-file-access
|
||||
ENABLE_FILE_ACCESS=--enable-local-file-access
|
||||
;;
|
||||
1)
|
||||
# have no (and need no) --enable-local-file-access
|
||||
;;
|
||||
*)
|
||||
# Some error but I don't know what it means. Try anyway.
|
||||
;;
|
||||
esac
|
||||
|
||||
PAGES="
|
||||
index.html
|
||||
setup.html
|
||||
epics3_13.html
|
||||
protocol.html
|
||||
formats.html
|
||||
processing.html
|
||||
recordtypes.html
|
||||
aai.html
|
||||
aao.html
|
||||
ai.html
|
||||
ao.html
|
||||
bi.html
|
||||
bo.html
|
||||
calcout.html
|
||||
int64in.html
|
||||
int64out.html
|
||||
longin.html
|
||||
longout.html
|
||||
lsi.html
|
||||
lso.html
|
||||
mbbiDirect.html
|
||||
mbboDirect.html
|
||||
mbbi.html
|
||||
mbbo.html
|
||||
scalcout.html
|
||||
stringin.html
|
||||
stringout.html
|
||||
waveform.html
|
||||
tipsandtricks.html
|
||||
recordinterface.html
|
||||
businterface.html
|
||||
formatconverter.html
|
||||
osinterface.html
|
||||
"
|
||||
|
||||
rm -f stream.pdf
|
||||
wkhtmltopdf --print-media-type --page-size Letter \
|
||||
$ENABLE_FILE_ACCESS $PAGES stream.pdf
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: mbbi Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbbi Records</h1>
|
||||
<h1>mbbi Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -70,25 +70,31 @@ written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: mbbiDirect Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbbiDirect Records</h1>
|
||||
<h1>mbbiDirect Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -56,25 +56,31 @@ written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">calcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: mbbo Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbbo Records</h1>
|
||||
<h1>mbbo Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -23,7 +23,7 @@ written or read value.
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||
<dt>LONG <span class=new>or ENUM</span> format (e.g. <code>%i</code>):</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>If any of <code>ZRVL</code> ... <code>FFVL</code> is set
|
||||
@ -33,25 +33,20 @@ written or read value.
|
||||
Note that the record calculates <code>RVAL</code> by choosing one of
|
||||
<code>ZRVL</code> ... <code>FFVL</code> depending on <code>VAL</code>
|
||||
and by shifting it left by <code>SHFT</code> bits.<br>
|
||||
<u>Input:</u> <code>RBV=<i>x</i>&MASK</code><br>
|
||||
<u>Input:</u> <code>RBV=RVAL=<i>x</i>&MASK</code><br>
|
||||
<code>MASK</code> is initialized to <code>NOBT</code> 1-bits shifted
|
||||
left by <code>SHFT</code>. If <code>MASK==0</code> (because
|
||||
<code>NOBT</code> was not set) it is ignored, i.e.
|
||||
<code><i>x</i>=RVAL</code> and <code>RBV=<i>x</i></code>.
|
||||
<code><i>x</i>=RVAL</code> and <code>RBV=RVAL=<i>x</i></code>.
|
||||
</dd>
|
||||
<dt>If none of <code>ZRVL</code> ... <code>FFVL</code> is set
|
||||
(all are <code>0</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code><br>
|
||||
<dd class=new>
|
||||
<u>Output:</u> <code><i>x</i>=(VAL<<SHFT)&MASK</code><br>
|
||||
<u>Input:</u> <code>VAL=(RBV=(<i>x</i>&MASK))>>SHFT</code><br>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code><br>
|
||||
</dd>
|
||||
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> Depending on <code>VAL</code>, one of <code>ZRST</code>
|
||||
@ -66,30 +61,34 @@ written or read value.
|
||||
<h2>Initialization</h2>
|
||||
<p>
|
||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
||||
present. In contrast to normal operation, LONG input is put to
|
||||
<code>RVAL</code> as well as to <code>RBV</code> and converted by the
|
||||
record.
|
||||
present.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: mbboDirect Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: mbboDirect Records</h1>
|
||||
<h1>mbboDirect Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -23,26 +23,23 @@ written or read value.
|
||||
<dd>
|
||||
Not allowed.
|
||||
</dd>
|
||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||
<dt>LONG or ENUM format (e.g. <code>%i</code>):</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>If <code>MASK==0</code> (because <code>NOBT</code> is not set):</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
||||
<u>Input:</u> <code>VAL=<i>x</i></code><br>
|
||||
<u>Output:</u> <code><i>x</i>=RVAL</code><br>
|
||||
<u>Input:</u> <code>RAL=<i>x</i></code>, <code>VAL=RVAL>>SHFT</code><br>
|
||||
</dd>
|
||||
<dt>If <code>MASK!=0</code>:</dt>
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x</i>=RVAL&MASK</code><br>
|
||||
<u>Input:</u> <code>RBV=<i>x</i>&MASK</code><br>
|
||||
<u>Input:</u> <code>RBV=RVAL=<i>x</i>&MASK</code>, <code>VAL=RVAL>>SHFT</code><br>
|
||||
</dd>
|
||||
</dl>
|
||||
<code>MASK</code> is initialized to <code>NOBT</code> 1-bits shifted
|
||||
left by <code>SHFT</code>.
|
||||
</dd>
|
||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
||||
<dd>
|
||||
Not allowed.
|
||||
left by <code>SHFT</code> (<code>((2^NOBT)-1)<<SHFT</code>).
|
||||
The record calculates <code>RVAL=VAL<<SHFT</code>.
|
||||
</dd>
|
||||
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
||||
<dd>
|
||||
@ -53,30 +50,34 @@ written or read value.
|
||||
<h2>Initialization</h2>
|
||||
<p>
|
||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
||||
present. In contrast to normal operation, input is put to
|
||||
<code>RVAL</code> as well as to <code>RBV</code> and converted by the
|
||||
record if <code>MASK!=0</code>.
|
||||
present.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,10 +1,10 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Navbar</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
<style type="text/css">
|
||||
<!--
|
||||
body {margin:0 0 13ex 1em;
|
||||
@ -95,6 +95,7 @@ div div div a {list-style-type:circle;}
|
||||
<div>
|
||||
<a target="_parent" href="setup.html#reload">Reloading</a>
|
||||
</div>
|
||||
<a target="_parent" href="setup.html#debug">Debugging</a>
|
||||
<a target="_parent" href="setup.html#rec">Records</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -132,6 +133,7 @@ div div div a {list-style-type:circle;}
|
||||
<a target="_parent" href="formats.html#bcd" title="Binary coded decimal LONG converter">%D</a>
|
||||
<a target="_parent" href="formats.html#chksum" title="Checksum pseudo converter">%<<em>checksum</em>></a>
|
||||
<a target="_parent" href="formats.html#regex" title="Perl regular expression STRING converter">%/<em>regex</em>/</a>
|
||||
<a target="_parent" href="formats.html#regsub" title="Perl regular expression substitution pseudo converter">%#/<em>regex</em>/<em>subst</em>/</a>
|
||||
<a target="_parent" href="formats.html#mantexp" title="MantissaExponent DOUBLE converter">%m</a>
|
||||
<a target="_parent" href="formats.html#timestamp" title="Timestamp DOUBLE converter">%T</a>
|
||||
</div>
|
||||
@ -155,17 +157,21 @@ div div div a {list-style-type:circle;}
|
||||
<a target="_parent" href="ao.html">ao</a>
|
||||
<a target="_parent" href="bi.html">bi</a>
|
||||
<a target="_parent" href="bo.html">bo</a>
|
||||
<a target="_parent" href="mbbi.html">mbbi</a>
|
||||
<a target="_parent" href="mbbo.html">mbbo</a>
|
||||
<a target="_parent" href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a target="_parent" href="mbboDirect.html">mbboDirect</a>
|
||||
<a target="_parent" href="stringin.html">stringin</a>
|
||||
<a target="_parent" href="stringout.html">stringout</a>
|
||||
<a target="_parent" href="calcout.html">calcout</a>
|
||||
<a target="_parent" href="int64in.html">int64in</a>
|
||||
<a target="_parent" href="int64out.html">int64out</a>
|
||||
<a target="_parent" href="longin.html">longin</a>
|
||||
<a target="_parent" href="longout.html">longout</a>
|
||||
<a target="_parent" href="waveform.html">waveform</a>
|
||||
<a target="_parent" href="calcout.html">calcout</a>
|
||||
<a target="_parent" href="lsi.html">lsi</a>
|
||||
<a target="_parent" href="lso.html">lso</a>
|
||||
<a target="_parent" href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a target="_parent" href="mbboDirect.html">mbboDirect</a>
|
||||
<a target="_parent" href="mbbi.html">mbbi</a>
|
||||
<a target="_parent" href="mbbo.html">mbbo</a>
|
||||
<a target="_parent" href="scalcout.html">scalcout</a>
|
||||
<a target="_parent" href="stringin.html">stringin</a>
|
||||
<a target="_parent" href="stringout.html">stringout</a>
|
||||
<a target="_parent" href="waveform.html">waveform</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@ -205,6 +211,15 @@ div div div a {list-style-type:circle;}
|
||||
</div>
|
||||
<div>
|
||||
<a target="_parent" href="formatconverter.html">Format Converter API</a>
|
||||
<div>
|
||||
<a target="_parent" href="formatconverter.html#class">Converter Class</a>
|
||||
<a target="_parent" href="formatconverter.html#theory">Theory of Operation</a>
|
||||
<div>
|
||||
<a target="_parent" href="formatconverter.html#registration">Registration</a>
|
||||
<a target="_parent" href="formatconverter.html#parsing">Parsing</a>
|
||||
<a target="_parent" href="formatconverter.html#printing_scanning">Printing and Scanning</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a target="_parent" href="osinterface.html">Operating System API</a>
|
22
docs/osinterface.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Operating System API</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>Operating System API</h1>
|
||||
|
||||
<h2>Sorry, this documentation is still missing.</h2>
|
||||
|
||||
|
||||
<footer>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,22 +1,22 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Record Processing</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Record Processing</h1>
|
||||
<h1>Record Processing</h1>
|
||||
|
||||
<a name="proc"></a>
|
||||
<h2>1. Normal Processing</h2>
|
||||
<p>
|
||||
<em>StreamDevice</em> is an asynchronous device support
|
||||
(see <a href="http://www.aps.anl.gov/epics/base/R3-14/8-docs/AppDevGuide.pdf"
|
||||
(see <a href="http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide.pdf"
|
||||
target="ex">IOC Application Developer's Guide</a> chapter 12:
|
||||
Device Support).
|
||||
Whenever the record is processed, the <a href="protocol.html">protocol</a>
|
||||
@ -54,22 +54,23 @@ its <code>SEVR</code> field set to <code>INVALID</code> and its
|
||||
<dl>
|
||||
<dt><code>TIMEOUT</code></dt>
|
||||
<dd>
|
||||
The device could not be locked (<code>LockTimeout</code>) or the
|
||||
device did not reply (<code>ReplyTimeout</code>).
|
||||
The device could not be locked (<code>LockTimeout</code>) because
|
||||
other records are keeping the device busy or the device did not reply
|
||||
in time (<a href="protocol.html#sysvar"><code>ReplyTimeout</code></a>).
|
||||
</dd>
|
||||
<dt><code>WRITE</code></dt>
|
||||
<dd>
|
||||
Output could not be written to the device (<code>WriteTimeout</code>).
|
||||
Output could not be written to the device in time
|
||||
(<a href="protocol.html#sysvar"><code>WriteTimeout</code></a>).
|
||||
</dd>
|
||||
<dt><code>READ</code></dt>
|
||||
<dd>
|
||||
Input from the device started but stopped unexpectedly
|
||||
(<code>ReadTimeout</code>).
|
||||
(<a href="protocol.html#sysvar"><code>ReadTimeout</code></a>).
|
||||
</dd>
|
||||
<dt><code>COMM</code></dt>
|
||||
<dd>
|
||||
The device driver reported some other communication error (e.g.
|
||||
unplugged cable).
|
||||
The device driver reported that the device is disconnected.
|
||||
</dd>
|
||||
<dt><code>CALC</code></dt>
|
||||
<dd>
|
||||
@ -95,13 +96,14 @@ will be set according to the original error.
|
||||
<a name="init"></a>
|
||||
<h2>2. Initialization</h2>
|
||||
<p>
|
||||
Often, it is required to initialize records from the hardware after
|
||||
Often, it is useful to initialize records from the hardware after
|
||||
booting the IOC, especially output records.
|
||||
For this purpose, initialization is formally handled as an
|
||||
<a href="protocol.html#except">exception</a>.
|
||||
The <code>@init</code> handler is called as part of the
|
||||
<code>initRecord()</code> function during <code>iocInit</code>
|
||||
before any scan task starts.
|
||||
before any scan task starts <span class="new">and may be re-run
|
||||
later under circumstances listed below</span>.
|
||||
</p>
|
||||
<p>
|
||||
In contrast to <a href="#proc">normal processing</a>, the protocol
|
||||
@ -119,7 +121,7 @@ If the handler fails, the record remains uninitialized:
|
||||
The <code>@init</code> handler has nothing to do with the
|
||||
<code>PINI</code> field.
|
||||
The handler does <u>not</u> process the record nor does it trigger
|
||||
forward links or other PP links.
|
||||
forward links or any links with the <code>PP</code> flag.
|
||||
It runs <u>before</u> <code>PINI</code> is handled.
|
||||
If the record has <code>PINI=YES</code>, the <code>PINI</code>
|
||||
processing is a <a href="#proc">normal processing</a> after the
|
||||
@ -146,6 +148,33 @@ read from a constant <code>INP</code> or <code>DOL</code> field,
|
||||
or restored from a bump-less reboot system
|
||||
(e.g. <em>autosave</em> from the <em>synApps</em> package).
|
||||
</p>
|
||||
<p>
|
||||
The <code>@init</code> handler is called in the following situations:
|
||||
<ul>
|
||||
<li>At startup by <code>iocInit</code> during record initialization
|
||||
as described above.
|
||||
<li class="new">When the IOC is resumed with <code>iocRun</code> (after
|
||||
beeing paused with <code>iocPause</code>) before the scan tasks
|
||||
restart and before records with <code>PINI=RUN</code> are processed.
|
||||
<li class="new">When the protocol is
|
||||
<a href="setup.html#reload">reloaded</a></span> for example with
|
||||
<code>streamReload ["<var>recordname</var>"]</code>.
|
||||
<li class="new">When <em>StreamDevice</em> detects that the device has
|
||||
reconnected (after being disconnected). This includes the case that
|
||||
the device was disconnected when the IOC started.
|
||||
Be aware that some drivers test the connection only periodically,
|
||||
e.g. the <em>asynIPPort</em> driver tests it every few seconds.
|
||||
Thus there may be a small delay between the device being online
|
||||
and the record re-initializing.
|
||||
<li class="new">When <code>streamReinit
|
||||
"<var>asynPortname</var>"[,<var>addr</var>]</code> is called
|
||||
(if using an <em>asynDriver</em> port).
|
||||
<li class="new">When the "magic value" <code>2</code> is written to the
|
||||
<code>.PROC</code> field of the record.
|
||||
In this case the record is processed and thus its <code>FLNK</code>
|
||||
and links with the <code>PP</code> flag are triggered.
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<a name="iointr"></a>
|
||||
<h2>3. I/O Intr</h2>
|
||||
@ -237,8 +266,10 @@ Even though the <code>getROIend</code> protocol may receive input
|
||||
from other requests, it silently ignores every message that does not start
|
||||
with "<code>ROI</code>", followed by two floating point numbers.
|
||||
</p>
|
||||
<hr>
|
||||
<p align="right"><a href="recordtypes.html">Next: Supported Record Types</a></p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
|
||||
<footer>
|
||||
<a href="recordtypes.html">Next: Supported Record Types</a>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Protocol Files</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Protocol Files</h1>
|
||||
<h1>Protocol Files</h1>
|
||||
<a name="gen"></a>
|
||||
<h2>1. General Information</h2>
|
||||
<p>
|
||||
@ -390,6 +390,9 @@ what they influence.
|
||||
the moment.
|
||||
How many milliseconds to wait after last poll or last received
|
||||
input before polling again?
|
||||
A good value is about half the time of the expected input period.
|
||||
Longer values cause latency and shorter values may increase CPU
|
||||
consumption.
|
||||
If not set the same value as for <code>ReplyTimeout</code> is
|
||||
used.
|
||||
</dd>
|
||||
@ -479,12 +482,63 @@ To make this easier, <em>protocol arguments</em> can be used:
|
||||
move { out "\$1 GOTO %d"; }
|
||||
</pre>
|
||||
<p>
|
||||
Now, the protocol can be references in the <code>OUT</code> link
|
||||
Now the same protocol can be used in the <code>OUT</code> link
|
||||
of three different records as <code>move(X)</code>,
|
||||
<code>move(Y)</code> and <code>move(Z)</code>.
|
||||
Up to 9 parameters, referenced as <code>$1</code> ... <code>$9</code>
|
||||
can be specified in parentheses, separated by comma.
|
||||
The variable <code>$0</code> is replaced by the name of the protocol.
|
||||
</p>
|
||||
<p>
|
||||
Up to 9 parameters can be specified in parentheses, separated by comma.
|
||||
In the protocol, they are referenced as <code>$1</code> ...
|
||||
<code>$9</code> outside quotes or <code>\$1</code> ... <code>\$9</code>
|
||||
within quotes. The parameter <code>$0</code> resolves to the protocol name.
|
||||
</p>
|
||||
<div class="new">
|
||||
<p>
|
||||
To make links more readable, one space is allowed before and after each comma
|
||||
and the enclosing parentheses. This space is not part of the parameter string.
|
||||
Any additional space is part of the parameter.
|
||||
</p>
|
||||
<p>
|
||||
If a parameter contains matching pairs of parentheses, these and all commas
|
||||
inside are part of the parameter.
|
||||
This allows to pass parameter strings like <code>(1,2)</code> easily without
|
||||
much escaping.
|
||||
</p>
|
||||
<p>
|
||||
Unmatched parentheses must be escaped with double backslash <code>\\</code>
|
||||
as well as must be commas outside pairs of parentheses.
|
||||
Double backslash is necessary because one backslash is already consumed by
|
||||
the db file parser.
|
||||
To pass a literal backslash in a parameter string use 4 backslashes
|
||||
<code>\\\\</code>.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
Note that macros can be used in parameters. That makes it possible to
|
||||
pass part of the record name to the protocol to be used in
|
||||
<a href="formats.html#redirection">redirections</a>.
|
||||
</p>
|
||||
|
||||
<h4>Example:</h3>
|
||||
<pre>
|
||||
record(ai, "$(PREFIX)recX5") {
|
||||
field(DTYP, "stream")
|
||||
field(INP, "@$(PROTOCOLFILE) read(5, X\\,Y $(PREFIX)) $(PORT)")
|
||||
}
|
||||
record(ai, "$(PREFIX)recY5") {}
|
||||
|
||||
read { out 0x8$1 "READ \$2"; in "%f,%(\$3recY\$1)f" }
|
||||
</pre>
|
||||
<p>
|
||||
The protocol resolves to:
|
||||
</p>
|
||||
<pre>
|
||||
read { out 0x85 "READ X,Y"; in "%f,%($(PREFIX)recY5)f" }
|
||||
</pre>
|
||||
<p>
|
||||
Here <code>$(PREFIX)</code> is replaced with its macro value.
|
||||
But be aware that the macro is actually replaced before the link is parsed so
|
||||
that macro values containing comma or parentheses may have unintended effects.
|
||||
</p>
|
||||
|
||||
<a name="usrvar"></a>
|
||||
@ -556,14 +610,13 @@ There is a fixed set of exception handler names starting with
|
||||
<dt><code>@init</code></dt>
|
||||
<dd>
|
||||
Not really an exception but formally specified in the same syntax.
|
||||
This handler is called from <code>iocInit</code> during record
|
||||
initialization.
|
||||
It can be used to initialize an output record with a value read from
|
||||
This handler can be used to initialize an output record with a value read from
|
||||
the device.
|
||||
Also see chapter <a href="processing.html#init">Record Processing</a>.
|
||||
See also chapter <a href="processing.html#init">Record Processing</a>.
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Example:</h3>
|
||||
<h4>Example:</h3>
|
||||
<pre>
|
||||
setPosition {
|
||||
out "POS %f";
|
||||
@ -577,8 +630,10 @@ is called but the protocol terminates immediately.
|
||||
An exception handler uses all <a href="#sysvar">system variable</a>
|
||||
settings from the protocol in which the exception occurred.
|
||||
</p>
|
||||
<hr>
|
||||
<p align="right"><a href="formats.html">Next: Format Converters</a></p>
|
||||
<p><small>Dirk Zimoch, 2011</small></p>
|
||||
|
||||
<footer>
|
||||
<a href="formats.html">Next: Format Converters</a>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
328
docs/recordinterface.html
Normal file
@ -0,0 +1,328 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Record API</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>Record API</h1>
|
||||
|
||||
<a name="theory"></a>
|
||||
<h2>Theory of Operation</h2>
|
||||
<p>
|
||||
<em>StreamDevice</em> implements the generic part of an EPICS device support.
|
||||
However it cannot know the internals of a specific record type, such as the
|
||||
.VAL or .RVAL fields or the .INP or .OUT links. It can only access a record
|
||||
as dbCommon. Thus it is necessary to write an interface for each record type
|
||||
which takes care of these details.
|
||||
</p>
|
||||
<p>
|
||||
A record interface consists of three functions, <code>readData()</code> and
|
||||
<code>writeData()</code> and <code>initRecord()</code>.
|
||||
</p>
|
||||
The record interface also implements the device support structure for this
|
||||
record type. Most of its functions will be generic <em>StreamDevice</em>
|
||||
functions. The exception is <code>initRecord()</code>.
|
||||
</p>
|
||||
<p>
|
||||
The name of the device support structure must have the form
|
||||
<code>dev<var>recordtype</var>Stream</code> and the name of the record
|
||||
interface source code file must be
|
||||
<code>dev<var>recordtype</var>Stream.c</code> to work seamlessly with the
|
||||
build system implemented in the Makefile of <em>StreamDevice</em>.
|
||||
</p>
|
||||
<p>
|
||||
Finally add <code><var>recordtype</var></code> to the
|
||||
<code>RECORDTYPES</code> variable in the file src/CONFIG_STREAM
|
||||
and rebuild.
|
||||
</p>
|
||||
<a name="headers"></a>
|
||||
<h3>Headers to Include</h2>
|
||||
<p>
|
||||
A record interface typically <code>#include</code>s the header file
|
||||
for the supported record type, <code>"<var>recordtype</var>Record.h"</code>
|
||||
and <code>"devStream.h"</code>.
|
||||
For many record interfaces this is sufficient, but sometimes additional
|
||||
header files may be needed.
|
||||
</p>
|
||||
|
||||
<a name="functions"></a>
|
||||
<h3>Functions to Implement</h2>
|
||||
<p>
|
||||
A record interface has to implement three functions:
|
||||
</p>
|
||||
<div class="indent"><code>
|
||||
static long readData(dbCommon *record, format_t *format);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
static long writeData(dbCommon *record, format_t *format);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
static long initRecord(dbCommon *record);
|
||||
</code></div>
|
||||
|
||||
<h4>writeData</h4>
|
||||
<p>
|
||||
The function <code>writeData()</code> is called whenever a
|
||||
<a href="protocol.html#proto">protocol</a> needs
|
||||
to handle a prining <a href="formats.html">format converter</a>
|
||||
(without <a href="formats.html#redirection">redirection</a>),
|
||||
typically in an <code>out</code> command.
|
||||
It is also possible that <code>writeData()</code> is called for an input
|
||||
record, e.g. when the <a href="formats.html#syntax"><code>=</code> flag</a>
|
||||
is used in an <code>in</code> command.
|
||||
Thus implement this function for input records as well.
|
||||
</p>
|
||||
<p>
|
||||
The functions is called with a <code>dbCommon *record</code> argument,
|
||||
which the function should cast to the specific record type to get
|
||||
access to the record specific fields, in particular .VAL and .RVAL.
|
||||
</p>
|
||||
<p>
|
||||
The second argument, <code>format_t *format</code>, contains information
|
||||
about the format converter. The only field of interest in this argument
|
||||
is <code>format->type</code> which specifies the data type of the format
|
||||
conversion. Its value is one of <code>DBF_ULONG</code>,
|
||||
<code>DBF_ULONG</code>, <code>DBF_ENUM</code>, <code>DBF_DOUBLE</code>,
|
||||
or <code>DBF_STRING</code>.
|
||||
</p>
|
||||
<p>
|
||||
The <code>writeData()</code> function may access different fields depending
|
||||
on <code>format->type</code>, e.g. .VAL for <code>DBF_DOUBLE</code> but
|
||||
.RVAL for <code>DBF_LONG</code>.
|
||||
It also may interpret the fields in a different way, e.g. cast to
|
||||
<code>long</code> for <code>DBF_LONG</code> but to <code>unsigned long</code>
|
||||
for <code>DBF_ULONG</code>.
|
||||
This is typically done with a <code>switch(format->type)</code> statement.
|
||||
</p>
|
||||
<p>
|
||||
The function may refuse to handle <code>format->type</code> values
|
||||
that make no sense for the record type, e.g. <code>DBF_STRING</code> for a
|
||||
record type that cannot handle strings. In that case the function should
|
||||
return <code>ERROR</code>. It is a good idea to return <code>ERROR</code>
|
||||
in the <code>default</code> part of the <code>switch</code> statement.
|
||||
</p>
|
||||
<p>
|
||||
<em>StreamDevice</em> provides a function to output a value from the record:
|
||||
</p>
|
||||
<div class="indent"><code>
|
||||
long streamPrintf(dbCommon *record, format_t *format, ...);
|
||||
</code></div>
|
||||
<p>
|
||||
Once the correct record field and type cast has been chosen, the
|
||||
<code>writeData()</code> function calls
|
||||
<code>return streamPrintf(record, format, value)</code> where the type of
|
||||
value should match <code>field->type</code> (<code>long</code>,
|
||||
<code>unsigned long</code>, <code>double</code>, or <code>char*</code>),
|
||||
returning the result of that call.
|
||||
</p>
|
||||
<p>
|
||||
<b>Example:</b>
|
||||
</p>
|
||||
<pre>
|
||||
static long writeData(dbCommon *record, format_t *format)
|
||||
{
|
||||
<var>recordtype</var>Record *rec = (<var>recordtype</var>Record *)record;
|
||||
|
||||
switch (format->type)
|
||||
{
|
||||
case DBF_ULONG:
|
||||
case DBF_ENUM:
|
||||
return streamPrintf(record, format, (unsigned long)rec->rval);
|
||||
case DBF_LONG:
|
||||
return streamPrintf(record, format, (long)rec->rval);
|
||||
case DBF_DOUBLE:
|
||||
return streamPrintf(record, format, rec->val);
|
||||
default:
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h4>readData</h4>
|
||||
<p>
|
||||
The arguments of this function are the same as for <code>writeData()</code>.
|
||||
But this function stores a value into record fields depending on
|
||||
<code>format->type</code>.
|
||||
</p>
|
||||
<p>
|
||||
<em>StreamDevice</em> provides two functions to receive a value;
|
||||
</p>
|
||||
<div class="indent"><code>
|
||||
ssize_t streamScanf(dbCommon *record, format_t *format, void* value);
|
||||
</code></div>
|
||||
<div class="indent"><code>
|
||||
ssize_t streamScanfN(dbCommon *record, format_t *format, void* value, size_t maxStringSize);
|
||||
</code></div>
|
||||
<p>
|
||||
The argument <code>value</code> is a pointer to the variable where the value
|
||||
is to be stored. Its type must match <code>field->type</code>
|
||||
(<code>long*</code>, <code>unsigned long*</code>, <code>double*</code>, or
|
||||
<code>char*</code>).
|
||||
</p>
|
||||
<p>
|
||||
The <code>streamScanfN()</code> function is meant for strings and gets the
|
||||
additional argument <code>maxStringSize</code> to specify the size of the
|
||||
string buffer.
|
||||
</p>
|
||||
<p>
|
||||
The <code>streamScanf()</code> function is actually a macro calling
|
||||
<code>streamScanfN()</code> with <code>MAX_STRING_SIZE</code> (=40) for
|
||||
the last argument. For <code>field->type</code> values other than
|
||||
<code>DBF_STRING</code>, this argument is ignored.
|
||||
</p>
|
||||
<p>
|
||||
In case of strings, these functions return the number of characters
|
||||
actually stored (which may be less than <code>maxStringSize</code>).
|
||||
Some record types may want to store this value into a field of the record.
|
||||
</p>
|
||||
<p>
|
||||
The functions return <code>ERROR</code> on failure. In this case the
|
||||
<code>readData()</code> function should return <code>ERROR</code> as well.
|
||||
Otherwise the function should store the value received into the appropriate
|
||||
record field.
|
||||
</p>
|
||||
<p>
|
||||
If <code>record->pact</code> is <code>true</code>, the function
|
||||
should now return <code>OK</code> or <code>DO_NOT_CONVERT</code> (=2),
|
||||
depending on wheter conversion from .RVAL to .VAL should be left to the
|
||||
record or not.
|
||||
</p>
|
||||
<p>
|
||||
If <code>record->pact</code> is <code>false</code>, the record is curretly
|
||||
executing the <code>@init</code> handler.
|
||||
This typically only affects output records.
|
||||
As the record is not processed by EPICS at this time, changes in fields would
|
||||
not trigger monitor updates.
|
||||
</p>
|
||||
<p>
|
||||
Also the record will not convert .RVAL to .VAL in this case, thus the
|
||||
<code>readData()</code> function should now convert .RVAL
|
||||
to .VAL as usually done by the record.
|
||||
</p>
|
||||
<p>
|
||||
In order to make monitors work properly, the <code>readData()</code> function
|
||||
should then first call <code>recGblResetAlarms()</code> and then call
|
||||
<code>db_post_events()</code> as needed. Usually the code
|
||||
from the record support function <code>monitor()</code> needs to be copied.
|
||||
Unfortunately the <code>monitor()</code> function of the record cannot be
|
||||
called directly because it is <code>static</code>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Example:</b>
|
||||
</p>
|
||||
<pre>
|
||||
static long readData(dbCommon *record, format_t *format)
|
||||
{
|
||||
<var>recordtype</var>Record *rec = (<var>recordtype</var>Record *)record;
|
||||
unsigned long rval;
|
||||
unsigned short monitor_mask;
|
||||
|
||||
switch (format->type)
|
||||
{
|
||||
case DBF_ULONG:
|
||||
case DBF_LONG:
|
||||
case DBF_ENUM:
|
||||
if (streamScanf(record, format, &rval) == ERROR) return ERROR;
|
||||
rec->rval = rval;
|
||||
if (record->pact) return OK;
|
||||
/* emulate convertion to val */
|
||||
rec->val = rval * rec->eslo + rec->eoff;
|
||||
break;
|
||||
case DBF_DOUBLE:
|
||||
if (streamScanf(record, format, &rec->val) == ERROR) return ERROR;
|
||||
break;
|
||||
if (record->pact) return DO_NOT_CONVERT;
|
||||
default:
|
||||
return ERROR;
|
||||
}
|
||||
/* In @init handler, no processing, enforce monitor updates. */
|
||||
monitor_mask = recGblResetAlarms(record);
|
||||
if (rec->oraw != rec->rval)
|
||||
{
|
||||
db_post_events(record, &rec->rval, monitor_mask | DBE_VALUE | DBE_LOG);
|
||||
rec->oraw = rec->rval;
|
||||
}
|
||||
if (!(fabs(rec->mlst - rec->val) <= rec->mdel))
|
||||
{
|
||||
monitor_mask |= DBE_VALUE;
|
||||
ao->mlst = rec->val;
|
||||
}
|
||||
if (!(fabs(rec->alst - rec->val) <= rec->adel))
|
||||
{
|
||||
monitor_mask |= DBE_VALUE;
|
||||
ao->alst = rec->val;
|
||||
}
|
||||
if (monitor_mask)
|
||||
db_post_events(record, &rec->val, monitor_mask);
|
||||
return OK;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h4>initRecord</h4>
|
||||
<p>
|
||||
The main purpose of this function is to pass the .INP or .OUT link to
|
||||
<em>StreamDevice</em> for parsing and to make the two functions
|
||||
<code>readData</code> and <code>writeData</code> known.
|
||||
Often the only thing the <code>initRecord()</code> function does is to call
|
||||
<code>streamInitRecord()</code> and return its result.
|
||||
</p>
|
||||
<div class="indent"><code>
|
||||
long streamInitRecord(dbCommon *record, const struct link *ioLink,
|
||||
streamIoFunction readData, streamIoFunction writeData);
|
||||
</code></div>
|
||||
<pre>
|
||||
static long initRecord(dbCommon *record)
|
||||
{
|
||||
<var>recordtype</var>Record *rec = (<var>recordtype</var>Record *)record;
|
||||
|
||||
return streamInitRecord(record, &rec->out, readData, writeData);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3>Device Support Structure</h3>
|
||||
<p>
|
||||
For most record types the device support structure contains 5 functions,
|
||||
<code>report</code>, <code>init</code>, <code>init_record</code>,
|
||||
<code>get_ioint_info</code>, and <code>read</code> or <code>write</code>.
|
||||
Few other record typess, for examle ai and ao may have additional functions.
|
||||
For most of these functions simply pass one of the provided
|
||||
<em>StreamDevice</em> functions <code>streamReport</code>,
|
||||
<code>streamInit</code>, <code>streamGetIoInitInfo</code>, and
|
||||
<code>streamRead</code> or <code>streamWrite</code>.
|
||||
Only for <code>init_record</code> pass your own
|
||||
<code>initRecord</code> function. Then export the structure.
|
||||
</p>
|
||||
<pre>
|
||||
struct {
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record;
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN write;
|
||||
} dev<var>recordtype</var>Stream = {
|
||||
5,
|
||||
streamReport,
|
||||
streamInit,
|
||||
initRecord,
|
||||
streamGetIointInfo,
|
||||
streamWrite
|
||||
};
|
||||
|
||||
epicsExportAddress(dset,dev<var>recordtype</var>Stream);
|
||||
|
||||
</pre>
|
||||
|
||||
|
||||
<footer>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Record Types</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Record Types</h1>
|
||||
<h1>Record Types</h1>
|
||||
|
||||
<h2>Supported Record Types</h2>
|
||||
<p>
|
||||
@ -18,25 +18,32 @@
|
||||
in EPICS base which can have device support.
|
||||
</p>
|
||||
<p>
|
||||
There is a separate page for each supported record type:<br>
|
||||
There is a separate page for each supported record type:
|
||||
</p>
|
||||
<p>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Each page describes which record fields are used in input and output
|
||||
for different <a href="formats.html#types">format data types</a>
|
||||
@ -48,7 +55,8 @@ It is also possible to
|
||||
<a href="recordinterface.html">write support for other recordtypes</a>.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
<footer>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,21 +1,21 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: scalcout Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: scalcout Records</h1>
|
||||
<h1>scalcout Records</h1>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> The scalcout record is part of the <i>calc</i> module of
|
||||
the <a target="ex"
|
||||
href="http://www.aps.anl.gov/aod/bcda/synApps/index.php"
|
||||
href="https://www.aps.anl.gov/BCDA/synApps"
|
||||
><em>synApps</em></a> package.
|
||||
Device support for scalcout records is only available for <i>calc</i>
|
||||
module release 2-4 or higher.
|
||||
@ -29,7 +29,7 @@ before the final <code>return(0)</code>:
|
||||
</p>
|
||||
<pre class="box">
|
||||
if(pscalcoutDSET->init_record ) {
|
||||
return (*pscalcoutDSET->init_record)(pcalc);
|
||||
return (*pscalcoutDSET->init_record)(pcalc);
|
||||
}
|
||||
</pre>
|
||||
|
||||
@ -77,25 +77,31 @@ Different record fields are used for output and input. The variable
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
526
docs/setup.html
Normal file
@ -0,0 +1,526 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Setup</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>Setup</h1>
|
||||
|
||||
<a name="pre"></a>
|
||||
<h2>1. Prerequisites</h2>
|
||||
<p>
|
||||
<em>StreamDevice</em> works with
|
||||
<a href="https://epics.anl.gov/base/index.php">EPICS base</a>
|
||||
versions from R3.14.6 on, tested up to 7.0.3.
|
||||
It also works (with limitations) with older
|
||||
<a href="https://epics.anl.gov/base/R3-13.php">R3.13</a>
|
||||
versions from R3.13.7 on.
|
||||
How to use <em>StreamDevice</em> with EPICS R3.13 is described on a
|
||||
<a href="epics3_13.html">separate page</a>.
|
||||
<p>
|
||||
Download and build the EPICS version of your choice first before continuing.
|
||||
</p>
|
||||
</p>
|
||||
<h3>Fix required for base R3.14.8.2 and earlier on Windows</h3>
|
||||
<p>
|
||||
Up to release R3.14.8.2, a fix in EPICS base is required to build
|
||||
<em>StreamDevice</em> on Windows (not cygwin).
|
||||
Add the following line to <kbd>src/iocsh/iocsh.h</kbd>
|
||||
and rebuild base.
|
||||
</p>
|
||||
<pre>
|
||||
epicsShareFunc int epicsShareAPI iocshCmd(const char *command);
|
||||
</pre>
|
||||
|
||||
<h3>Downloading <em>StreamDevice</em></h3>
|
||||
The latest version of StreamDevice can be found on github:
|
||||
<a href="https://github.com/paulscherrerinstitute/StreamDevice"
|
||||
>https://github.com/paulscherrerinstitute/StreamDevice</a>.
|
||||
|
||||
Either download a <a
|
||||
href="https://github.com/paulscherrerinstitute/StreamDevice/archive/master.zip
|
||||
">zip file</a> or clone the git repo:
|
||||
<pre>
|
||||
git clone https://github.com/paulscherrerinstitute/StreamDevice.git
|
||||
</pre>
|
||||
|
||||
<h3>Configuration</h3>
|
||||
<p class="new">
|
||||
<em>StreamDevice</em> now comes with a standard
|
||||
<kbd>configure</kbd> directory.
|
||||
<del>But it can still be built in an external <em><top></em>
|
||||
directory as in previous versions.
|
||||
It will automatically detect <em><top></em> locations
|
||||
from the presence of <kbd>../configure</kbd> or <kbd>../config</kbd>
|
||||
directories.</del> Using an upper level <kbd>../configure</kbd> is
|
||||
no longer supported due to compatibility issues with <em>SynApps</em>.
|
||||
</p>
|
||||
<p class="new">
|
||||
Edit the <kbd>configure/RELEASE</kbd> file to specify the install location
|
||||
of EPICS base and of additional software modules or add a
|
||||
<kbd>configure/RELEASE.local</kbd> file to overwrite, for example:
|
||||
<pre>
|
||||
EPICS_BASE=/home/epics/base-3.16.1
|
||||
</pre>
|
||||
|
||||
<h4>Support for <em>asynDriver</em></h4>
|
||||
<p>
|
||||
You most probably want to have <em>asynDriver</em> support included, because
|
||||
that is the standard way for <em>StreamDevice</em> to talk to hardware.
|
||||
First get and install
|
||||
<a href="https://www.aps.anl.gov/epics/modules/soft/asyn/"
|
||||
><em>asynDriver</em></a> version 4-3 or higher before you build
|
||||
<em>StreamDevice</em>.
|
||||
I have tested <em>StreamDevice</em> with <em>asynDriver</em> versions up to 4-30.
|
||||
Make sure that the <em>asyn</em> library can be found by adding the path to the
|
||||
<em><top></em> directory of your <em>asyn</em> installation to the
|
||||
<kbd>configure/RELEASE</kbd> file:
|
||||
<pre>
|
||||
ASYN=/home/epics/asyn4-30
|
||||
</pre>
|
||||
|
||||
<h4 id="scalcout">Support for <em>sCalcout</em> record</h4>
|
||||
<p>
|
||||
The <a
|
||||
href="https://htmlpreview.github.io/?https://raw.githubusercontent.com/epics-modules/calc/R3-6-1/documentation/sCalcoutRecord.html"
|
||||
><em>sCalcout</em></a> record is part of <a
|
||||
href="https://www.aps.anl.gov/BCDA/synApps"
|
||||
><em>synApps</em></a>.
|
||||
If <em>streamDevice</em> should be built with support for this record,
|
||||
you have to install at least the <a
|
||||
href="https://epics.anl.gov/bcda/synApps/calc/calc.html"
|
||||
><em>calc</em> module</a> from <em>SynApps</em> first.
|
||||
Add references to the <kbd>RELEASE</kbd> file as shown here:
|
||||
<pre>
|
||||
CALC=/home/epics/synApps/calc-R3-6-1
|
||||
</pre>
|
||||
<p>
|
||||
Up to <em>calc</em> release R2-6 (<em>synApps</em> release R5_1),
|
||||
the <em>sCalcout</em> record needs a fix.
|
||||
(See separate <a href="scalcout.html"><em>scalcout</em> page</a>.)
|
||||
And the <em>calc</em> module had dependencies on other <em>SynApps</em>
|
||||
modules. Release R2-8 or newer is recommended.
|
||||
</p>
|
||||
<p>
|
||||
Support for the <em>sCalcout</em> is optional. <em>StreamDevice</em> works
|
||||
as well without <em>sCalcout</em> or <em>SynApps</em>. If your application does
|
||||
not need this record support, you may load <kbd>stream-base.dbd</kbd> instead of
|
||||
<kbd>stream.dbd</kbd>, making it optional to include <em>calc</em> as an
|
||||
application dependency.
|
||||
</p>
|
||||
|
||||
<h4>Support for regular expression matching</h4>
|
||||
<p>
|
||||
If you want to enable regular expression matching, you need the <em>PCRE</em> package.
|
||||
For most Linux systems, it is already installed.
|
||||
In that case tell <em>StreamDevice</em> the locations of the
|
||||
<em>PCRE</em> header file and library.
|
||||
However, the pre-installed package can only by used for the host architecture.
|
||||
Thus, add them not to <kbd>RELEASE</kbd> but to
|
||||
<kbd>RELEASE.Common.linux-x86</kbd> (if linux-x86 is your EPICS_HOST_ARCH).
|
||||
Be aware that different Linux distributions may locate the files in different
|
||||
directories.
|
||||
</p>
|
||||
<pre>
|
||||
PCRE_INCLUDE=/usr/include/pcre
|
||||
PCRE_LIB=/usr/lib
|
||||
</pre>
|
||||
<p>
|
||||
For 64 bit installations, the path to the library may be different:
|
||||
</p>
|
||||
<pre>
|
||||
PCRE_INCLUDE=/usr/include/pcre
|
||||
PCRE_LIB=/usr/lib64
|
||||
</pre>
|
||||
<p>
|
||||
A pre-compiled Windows version of <em>PCRE</em> is available at
|
||||
<a href="https://sourceforge.net/projects/gnuwin32/files/pcre/7.0/pcre-7.0.exe/download"
|
||||
>sourceforge</a>
|
||||
</p>
|
||||
<p>
|
||||
If you want to have <em>PCRE</em> support on platforms that don't support it natively,
|
||||
e.g. vxWorks, it is probably the easiest to build <em>PCRE</em> as an EPICS module.
|
||||
</p>
|
||||
<p>
|
||||
<h4>Building the <em>PCRE</em> package as an EPICS module</h4>
|
||||
<p>
|
||||
<ol>
|
||||
<li>
|
||||
Download the <em>PCRE</em> package from <a href="https://www.pcre.org">www.pcre.org</a>.
|
||||
</li>
|
||||
<li>
|
||||
Extract the <em>PCRE</em> package in the <kbd><top></kbd> directory of
|
||||
<em>StreamDevice</em> or create a separate <kbd><top></kbd> location using
|
||||
<code>makeBaseApp.pl</code>.
|
||||
</li>
|
||||
<li>
|
||||
Download this <a href="http://epics.web.psi.ch/software/streamdevice/pcre/Makefile"
|
||||
>Makefile</a> and this
|
||||
<a href="http://epics.web.psi.ch/software/streamdevice/pcre/fixforvxworks.pl"
|
||||
>fixforvxworks.pl</a> script and save them to the extracted pcre directory.
|
||||
</li>
|
||||
<li>
|
||||
Change into the pcre direcrory and run <code>perl fixforvxworks.pl</code>
|
||||
</li>
|
||||
<li>
|
||||
Run <code>make</code> (or <code>gmake</code>)
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
Define the location of the pcre <kbd><top></kbd> in the RELEASE file for <em>StreamDevice</em>.
|
||||
</p>
|
||||
<pre>
|
||||
PCRE=/home/epics/pcre
|
||||
</pre>
|
||||
<p>
|
||||
Regular expressions are optional. If you don't want them, you don't need this.
|
||||
</p>
|
||||
|
||||
<a name="lib"></a>
|
||||
<h2>2. Building <em>StreamDevice</em></h2>
|
||||
<p>
|
||||
Go to the <em>StreamDevice</em> directory
|
||||
and run <code>make</code> (or <code>gmake</code>).
|
||||
This will create and install the <em>stream</em> library and the
|
||||
<em>StreamDevice</em> database definition files and an example IOC application.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To use <em>StreamDevice</em>, your own application must be built with the
|
||||
<em>stream</em> and <em>asyn</em> (and optionally <em>pcre</em>) libraries
|
||||
and must load <kbd>asyn.dbd</kbd> and <kbd>stream.dbd</kbd> (or alternatively
|
||||
<kbd>stream-base.dbd</kbd>; see <a href="#scalcout">Support for sCalcout record</a>).
|
||||
</p>
|
||||
<p>
|
||||
Include the following lines in your application <kbd>Makefile</kbd>:
|
||||
</p>
|
||||
<pre>
|
||||
PROD_LIBS += stream
|
||||
PROD_LIBS += asyn
|
||||
PROD_LIBS += pcre
|
||||
</pre>
|
||||
<p>
|
||||
Include the following lines in your <kbd>xxxAppInclude.dbd</kbd> file to use
|
||||
<em>stream</em> and <em>asyn</em> with serial lines, IP sockets,
|
||||
and vxi11 ("GPIB over ethernet") support.
|
||||
</p>
|
||||
<pre>
|
||||
include "base.dbd"
|
||||
include "stream.dbd"
|
||||
include "asyn.dbd"
|
||||
registrar(drvAsynIPPortRegisterCommands)
|
||||
registrar(drvAsynSerialPortRegisterCommands)
|
||||
registrar(vxi11RegisterCommands)
|
||||
</pre>
|
||||
<p>
|
||||
You can find an example application in the <kbd>streamApp</kbd>
|
||||
subdirectory.
|
||||
</p>
|
||||
|
||||
<a name="sta"></a>
|
||||
<h2>3. The Startup Script</h2>
|
||||
<p>
|
||||
<em>StreamDevice</em> is based on <a
|
||||
href="protocol.html"><em>protocol files</em></a>.
|
||||
To tell <em>StreamDevice</em> where to search for protocol files,
|
||||
set the environment variable <code>STREAM_PROTOCOL_PATH</code> to a
|
||||
list of directories to search.
|
||||
On Unix and vxWorks systems, directories are separated by <code>:</code>,
|
||||
on Windows systems by <code>;</code>.
|
||||
The default value is <code>STREAM_PROTOCOL_PATH=.</code>,
|
||||
i.e. the current directory.
|
||||
</p>
|
||||
<p>
|
||||
Also configure the buses (in <em>asynDriver</em> terms: ports) you want
|
||||
to use with <em>StreamDevice</em>.
|
||||
You can give the buses any name you want, like <kbd>COM1</kbd> or
|
||||
<kbd>socket</kbd>, but I recommend to use names related to the
|
||||
connected device.
|
||||
</p>
|
||||
<h3>Example:</h3>
|
||||
<p>
|
||||
A device with serial communication (9600 baud, 8N1, no flow control) is
|
||||
connected to <kbd>/dev/ttyS1</kbd>.
|
||||
The name of the device shall be <tt>PS1</tt>.
|
||||
Protocol files are either in the current working directory or in the
|
||||
<kbd>../protocols</kbd> directory.
|
||||
</p>
|
||||
<p>
|
||||
Then the startup script may look like this:
|
||||
</p>
|
||||
<pre>
|
||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||
|
||||
drvAsynSerialPortConfigure ("PS1","/dev/ttyS1")
|
||||
asynSetOption ("PS1", 0, "baud", "9600")
|
||||
asynSetOption ("PS1", 0, "bits", "8")
|
||||
asynSetOption ("PS1", 0, "parity", "none")
|
||||
asynSetOption ("PS1", 0, "stop", "1")
|
||||
asynSetOption ("PS1", 0, "clocal", "Y")
|
||||
asynSetOption ("PS1", 0, "crtscts", "N")
|
||||
</pre>
|
||||
|
||||
<p>All above options are the defaults.
|
||||
Thus their usage in optional in this case.
|
||||
</p>
|
||||
<p>
|
||||
If the device uses hardware flow control, change the last two lines to:
|
||||
</p>
|
||||
<pre>
|
||||
asynSetOption ("PS1", 0, "clocal", "N")
|
||||
asynSetOption ("PS1", 0, "crtscts", "Y")
|
||||
</pre>
|
||||
<p>
|
||||
Newer versions of <em>asyn</em> also support software flow control
|
||||
(CTRL-S,CTRL-Q). If the device uses this, you may want to set:
|
||||
</p>
|
||||
<pre>
|
||||
asynSetOption ("PS1", 0, "ixon", "Y")
|
||||
asynSetOption ("PS1", 0, "ixany", "Y")
|
||||
</pre>
|
||||
|
||||
<p>If the device was instead connected via telnet-style TCP/IP
|
||||
at address 192.168.164.10 on port 23,
|
||||
the startup script would contain:
|
||||
</p>
|
||||
<pre>
|
||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||
|
||||
drvAsynIPPortConfigure ("PS1", "192.168.164.10:23")
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
With a VXI11 (GPIB via TCP/IP) connection, e.g. a
|
||||
HP E2050A on IP address 192.168.164.10, it would look like this:
|
||||
</p>
|
||||
<pre>
|
||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||
|
||||
vxi11Configure ("PS1","192.168.164.10",1,1000,"hpib")
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="pro"></a>
|
||||
<h2>4. The Protocol File</h2>
|
||||
<p>
|
||||
For each different type of hardware, create a protocol file
|
||||
which defines protocols for all needed functions of the device.
|
||||
The file name is arbitrary, but I recommend that it contains
|
||||
the device type.
|
||||
It must not contain spaces and should be short.
|
||||
During <code>iocInit</code>, <em>streamDevice</em> loads and parses
|
||||
the required protocol files.
|
||||
If the files contain errors, they are printed on the IOC shell.
|
||||
Put the protocol file in one of the directories listed in
|
||||
<code>STREAM_PROTOCOL_PATH</code>.
|
||||
</p>
|
||||
<h3>Example:</h3>
|
||||
<p>
|
||||
<tt>PS1</tt> is an <em>ExamplePS</em> power supply.
|
||||
It communicates via ASCII strings which are terminated by
|
||||
<carriage return> <line feed> (ASCII codes 13, 10).
|
||||
The output current can be set by sending a string like
|
||||
<code>"CURRENT 5.13"</code>.
|
||||
When asked with the string <code>"CURRENT?"</code>, the device returns
|
||||
the last set value in a string like <code>"CURRENT 5.13 A"</code>.
|
||||
</p>
|
||||
<p>
|
||||
Normally, an analog output record should write its value to the device.
|
||||
But during startup, the record should be initialized from the the device.
|
||||
The protocol file <kbd>ExamplePS.proto</kbd> defines the protocols
|
||||
<code>getCurrent</code> and <code>setCurrent</code>.
|
||||
</p>
|
||||
<pre>
|
||||
Terminator = CR LF;
|
||||
|
||||
getCurent {
|
||||
out "CURRENT?";
|
||||
in "CURRENT %f A";
|
||||
}
|
||||
|
||||
setCurrent {
|
||||
out "CURRENT %.2f";
|
||||
@init {
|
||||
getCurent;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<a name="reload"></a>
|
||||
<h3>Reloading the Protocol File</h3>
|
||||
<p>
|
||||
During development, the protocol files might change frequently.
|
||||
To prevent restarting the IOC all the time, it is possible to reload
|
||||
the protocol file of one or all records with the shell function
|
||||
<code>streamReload("<var>record</var>")</code>.
|
||||
If <code>"<var>record</var>"</code> is not given
|
||||
<span class="new">or empty</span>, all records using
|
||||
<em>StreamDevice</em> reload their protocols.
|
||||
<span class="new">In EPICS 3.14 or higher,
|
||||
<code><var>record</var></code> can be a glob pattern.</span>
|
||||
</p>
|
||||
<p>
|
||||
Furthermore, the <code>streamReloadSub</code> function can be used
|
||||
with a subroutine record to reload all protocols.
|
||||
</p>
|
||||
<p>
|
||||
Reloading the protocol file aborts currently running protocols.
|
||||
This might set <code>SEVR=INVALID</code> and <code>STAT=UDF</code>.
|
||||
If a record can't reload its protocol file (e.g. because of a syntax
|
||||
error), it stays <code>INVALID</code>/<code>UDF</code> until a valid
|
||||
protocol is loaded.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<span class="new">Reloading triggers an <code>@init</code>
|
||||
<a href="protocol.html#except">handler</a>.</span>
|
||||
See the <a href="protocol.html">next chapter</a> for protocol files in depth.
|
||||
</p>
|
||||
|
||||
<a name="debug"></a>
|
||||
<h2>5. Debug and Error Messages</h2>
|
||||
<p>
|
||||
Generation of debug and error messages is controlled with two shell variables,
|
||||
<code>streamDebug</code> and <code>streamError</code>.
|
||||
Setting those variables to 1 (actually to any number but 0) enables the
|
||||
messages. A few noisy and rarely useful debug messages are only enabled when
|
||||
setting <code>streamDebug</code> to 2.
|
||||
Per default debug messages are switched off and error messages are switched on.
|
||||
Errors occuring while loading protocol files are always shown.
|
||||
</p>
|
||||
<p>
|
||||
Warning: Enabling debug messages this way can create a lot of output!
|
||||
Therefore, some limited debugging can be enabled per record, independent of
|
||||
the <code>streamDebug</code> variable using the <code>.TPRO</code> field of
|
||||
the record. Currently, setting <code>.TPRO</code> to 1 or 2 enables some
|
||||
basic information about the processing of a record and its i/o.
|
||||
</p>
|
||||
<p>
|
||||
Debug output can be redirected to a file with the command
|
||||
<code>streamSetLogfile("<var>filename</var>")</code>.
|
||||
If the file already exists, it will be overwritten, not appended to.
|
||||
While debug messages are only written to the defined log file, error messages
|
||||
are still printed to <var>stderr</var> too.
|
||||
Calling <code>streamSetLogfile</code> without a filename directs debug output
|
||||
back to <var>stderr</var> and closes the log file.
|
||||
</p>
|
||||
<p>
|
||||
By default, error messages to the console are printed in red color if
|
||||
<var>stderr</var> is a tty at startup time, using ANSI color codes. Some
|
||||
terminals may not support this properly.
|
||||
The variable <code>streamDebugColored</code> can be set to 0 or 1 to
|
||||
disable or enable colored error messages explicitly.
|
||||
Error messages written to a log file do not use colors.
|
||||
</p>
|
||||
<p>
|
||||
Error and debug messages are prefixed with a time stamp unless the variable
|
||||
<code>streamMsgTimeStamped</code> is set to 0.
|
||||
</p>
|
||||
<p>
|
||||
when a device is unresponsive, StreamDevice may produce many repeated timeout
|
||||
messages. To reduce this, you can set <code>streamErrorDeadTime</code>
|
||||
to an integer number of seconds. In this case, repeated timeout messages
|
||||
will not be printed during the specified dead time after the last printed
|
||||
message. The default dead time is 0, resulting in every message being printed.
|
||||
</p>
|
||||
|
||||
<h3>Example (vxWorks):</h3>
|
||||
<pre>
|
||||
streamError=1
|
||||
streamDebug=1
|
||||
streamDebugColored=1
|
||||
streamErrorDeadTime=30
|
||||
streamMsgTimeStamped=1
|
||||
streamSetLogfile("logfile.txt")
|
||||
</pre>
|
||||
|
||||
<h3>Example (iocsh):</h3>
|
||||
<pre>
|
||||
var streamError 1
|
||||
var streamDebug 1
|
||||
var streamDebugColored 1
|
||||
var streamErrorDeadTime 30
|
||||
var streamMsgTimeStamped 1
|
||||
streamSetLogfile("logfile.txt")
|
||||
</pre>
|
||||
|
||||
<a name="rec"></a>
|
||||
<h2>6. Configuring the Records</h2>
|
||||
<p>
|
||||
To tell a record to use <em>StreamDevice</em>, set its <code>DTYP</code> field to
|
||||
<code>"stream"</code>.
|
||||
</p>
|
||||
<p>
|
||||
The <code>INP</code> or <code>OUT</code> link has the form
|
||||
<code>"@<var>filename protocol</var>[(<var>arg1</var>,<var>arg2</var>,...)] </var>bus</var> [<var>address</var> [<var>parameters</var>]]"</code>.
|
||||
</p>
|
||||
<p>
|
||||
(Elements in <code>[]</code> are optional. Do not type the <code>[]</code>).
|
||||
</p>
|
||||
<p>
|
||||
Here, <code><var>filename</var></code> is the name of the protocol file and
|
||||
<code><var>protocol</var></code> is the name of a protocol defined in this file.
|
||||
(See the <a href="protocol.html">next chapter</a>.)
|
||||
</p>
|
||||
<p>
|
||||
If the protocol requires <a href="protocol.html#argvar">arguments</a>,
|
||||
specify them enclosed in parentheses:
|
||||
<code><var>protocol</var>(<var>arg1,arg2,...</var>)</code>.
|
||||
<span class="new">Spaces in the argument list are now allowed.
|
||||
The first space before and after an argument is ignored. Further spaces are
|
||||
considered part of the argument.</span>
|
||||
</p>
|
||||
<p>
|
||||
The communication channel is specified with <code><var>bus</var></code>
|
||||
(aka <em>asynDriver</em> "port") and <code><var>addr</var></code>.
|
||||
If the bus does not have addresses, <code><var>addr</var></code> may be skipped.
|
||||
Optional <code><var>parameters</var></code> are passed to the bus driver.
|
||||
(At the moment, no bus driver supports parameters.)
|
||||
</p>
|
||||
|
||||
<h3>Example:</h3>
|
||||
<p>
|
||||
Create an input record to read and an output record to set the current of <tt>PS1</tt>.
|
||||
Use protocols <em>getCurrent</em> and <em>setCurrent</em> from file <em>ExamplePS.proto</em>.
|
||||
The bus is called <em>PS1</em> like the device.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
record (ai, "PS1:I-get")
|
||||
{
|
||||
field (DESC, "Read current of PS1")
|
||||
<b>field (DTYP, "stream")</b>
|
||||
<b>field (INP, "@ExamplePS.proto getCurrent PS1")</b>
|
||||
field (EGU, "A")
|
||||
field (PREC, "2")
|
||||
field (LOPR, "0")
|
||||
field (HOPR, "60")
|
||||
field (PINI, "YES")
|
||||
field (SCAN, "10 second")
|
||||
}
|
||||
record (ao, "PS1:I-set")
|
||||
{
|
||||
field (DESC, "Set current of PS1")
|
||||
<b>field (DTYP, "stream")</b>
|
||||
<b>field (OUT, "@ExamplePS.proto setCurrent PS1")</b>
|
||||
field (EGU, "A")
|
||||
field (PREC, "2")
|
||||
field (DRVL, "0")
|
||||
field (DRVH, "60")
|
||||
field (LOPR, "0")
|
||||
field (HOPR, "60")
|
||||
}
|
||||
</pre>
|
||||
|
||||
<footer>
|
||||
<a href="protocol.html">Next: Protocol Files</a>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
169
docs/stream.css
Normal file
@ -0,0 +1,169 @@
|
||||
a:link { color: #0000D0; }
|
||||
a:visited { color: #0000D0; }
|
||||
a:hover { color: #FF0000; }
|
||||
|
||||
body {
|
||||
margin-right: 1em;
|
||||
margin-left: 15em;
|
||||
margin-top: 75px;
|
||||
padding-top: 1px;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 100%;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
a[name] {
|
||||
position: relative;
|
||||
top: -11ex;
|
||||
}
|
||||
|
||||
pre, tt, kbd, code {
|
||||
font-size: 95%;
|
||||
font-family: Mono, "Lucida Console", Courier, monospace;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #f4f4f4;
|
||||
padding: 1ex;
|
||||
border: 1px solid #000000;
|
||||
white-space: pre;
|
||||
margin: 2ex;
|
||||
page-break-inside: avoid;
|
||||
font-size: 85%;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
kbd {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
code {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-top: 0.5ex;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 250%;
|
||||
margin-top: 0;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
font-family: "Times New Roman", Times, serif;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
line-height: 190%;
|
||||
background-color: white;
|
||||
border-width: 0;
|
||||
border-bottom: 3px solid #1b4486;
|
||||
white-space: nowrap;
|
||||
background-image: url(PSI.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px 5px;
|
||||
text-shadow: .1em .1em .1em lightgray;
|
||||
box-shadow: 0 .3em .1em -.2em darkgray;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 140%;
|
||||
margin-bottom: 0.5ex;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 120%;
|
||||
margin-bottom: 0.25ex;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 100%;
|
||||
margin-bottom: 0.25ex;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0.75ex;
|
||||
margin-bottom: 0.75ex;
|
||||
}
|
||||
|
||||
body h1 + p {
|
||||
margin-top: 1.5ex;
|
||||
margin-bottom: 0.75ex;
|
||||
}
|
||||
|
||||
footer {
|
||||
font-size: 75%;
|
||||
margin-top: 1em;
|
||||
border-top: 1px solid darkgray;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
footer a:only-of-type {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.indent {
|
||||
text-indent: -4ex;
|
||||
margin-left: 4ex;
|
||||
margin-top: 0.5ex;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.box {
|
||||
margin-left: 1ex;
|
||||
margin-right: 1ex;
|
||||
margin-top: 0.5ex;
|
||||
padding: 0 1ex;
|
||||
border: thin solid black;
|
||||
text-align: left;
|
||||
background-color: #f0f0f0;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
#navleft {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding-top: 70px;
|
||||
width: 14em;
|
||||
height: 100%;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width: 0 1px 0 0;
|
||||
background-color: #e3eaf6;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.new {
|
||||
background-color: #ffc;
|
||||
}
|
||||
|
||||
a[target=ex]:after {
|
||||
content: " " url(ex.png);
|
||||
}
|
||||
|
||||
a[target=ex]:hover:after {
|
||||
content: " " url(exr.png);
|
||||
}
|
||||
|
||||
@media print {
|
||||
a:link { text-decoration: none; }
|
||||
a[target=ex]:after { content:" [" attr(href) "]"; font-size: 75%; }
|
||||
body { margin: 0 4em; }
|
||||
h1 { position: relative; background-position: 0 0; }
|
||||
#navleft { display: none; }
|
||||
footer { display: none; }
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: stringin Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: stringin Records</h1>
|
||||
<h1>stringin Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -43,25 +43,31 @@ written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: stringout Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: stringout Records</h1>
|
||||
<h1>stringout Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
@ -43,25 +43,31 @@ written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: Tips and Tricks</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: Tips and Tricks</h1>
|
||||
<h1>Tips and Tricks</h1>
|
||||
|
||||
<a name="argvar"></a>
|
||||
<h2>I have many almost identical protocols</h2>
|
||||
@ -260,7 +260,7 @@ When asked "<code>CURRENT?</code>", the device send something like
|
||||
</p>
|
||||
<p>
|
||||
<code>
|
||||
read_current {out "CURRENT?"; in "CURRENT %f A"; @mismatch {in "%(\1)39c";}}
|
||||
read_current {out "CURRENT?"; in "CURRENT %f A"; @mismatch {in "%(\$1)39c";}}
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
@ -281,7 +281,7 @@ With some more records, you can clean the message record if SEVR is not INVALID.
|
||||
<code>
|
||||
record (calcout, "$(DEVICE):clean_1") {<br>
|
||||
field (INPA, "$(DEVICE):readcurrent.SEVR CP")<br>
|
||||
field (CALC, "A!=2")<br>
|
||||
field (CALC, "A#3")<br>
|
||||
field (OOPT, "When Non-zero")<br>
|
||||
field (OUT, "$(DEVICE):clean_2.PROC")<br>
|
||||
}<br>
|
||||
@ -293,9 +293,10 @@ record (stringout, "$(DEVICE):clean_2") {<br>
|
||||
<a name="web"></a>
|
||||
<h2>I need to read a web page</h2>
|
||||
<p>
|
||||
First you have to send a correctly formatted HTML request.
|
||||
Note that this request must contain the full URL like
|
||||
"http://server/page" and must be terminated with <u>two</u> newlines.
|
||||
First you have to send a correctly formatted HTML header for a GET request.
|
||||
Note that this header must contain the full URL like
|
||||
"http://server/page" and must be terminated with <u>two</u>
|
||||
CR LF sequences (<code>"\r\n\r\n"</code> or <code>CR LF CR LF</code>).
|
||||
The server should be the same as in the
|
||||
<a href="setup.html#sta"><code>drvAsynIPPortConfigure</code></a>
|
||||
command (if not using a http proxy).
|
||||
@ -313,17 +314,18 @@ Read the title of a web page.
|
||||
get_title {<br>
|
||||
extrainput = ignore;<br>
|
||||
replyTimeout = 1000;<br>
|
||||
out "GET http://\$1\n\n";<br>
|
||||
out "GET http://\$1\r\n\r\n";<br>
|
||||
in "%+.1/(?im)<title>(.*)<\/title>/";<br>
|
||||
}
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Terminate the request with two newlines, either explicit like here
|
||||
<u>or</u> using an
|
||||
Terminate the request with two carriage return + newlines, either explicit
|
||||
like here <u>or</u> using an
|
||||
<a href="protocol.html#sysvar"><code>outTerminator</code></a>.
|
||||
The URI (without http:// but including the web server host name)
|
||||
is passed as <a href="protocol.html#argvar">argument</a> 1 to <code>\$1</code>.
|
||||
is passed as <a href="protocol.html#argvar">argument</a> 1 to <code>\$1</code>
|
||||
in this example.
|
||||
Note that web servers may be slow, so allow some
|
||||
<a href="protocol.html#argvar"><code>replyTimeout</code></a>.
|
||||
</p>
|
||||
@ -390,7 +392,7 @@ Then we read the number.
|
||||
get_title {<br>
|
||||
extrainput = ignore;<br>
|
||||
replyTimeout = 1000;<br>
|
||||
out "GET http://\$1\n\n";<br>
|
||||
out "GET http://\$1\r\n\r\n";<br>
|
||||
in "%*/Interesting value:/%f more text";<br>
|
||||
}
|
||||
</code>
|
||||
@ -406,7 +408,9 @@ and <a href="formats.html#redirection">redirections</a>.
|
||||
But this only works if the order of the values is predictible.
|
||||
<i>StreamDevice</i> is not an XML parser! It always reads sequentially.
|
||||
</p>
|
||||
<hr>
|
||||
<p><small>Dirk Zimoch, 2012</small></p>
|
||||
|
||||
<footer>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,21 +1,21 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>StreamDevice: waveform Records</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta name="author" content="Dirk Zimoch">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="author" content="Dirk Zimoch" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="nav.html" id="navleft"></iframe>
|
||||
<h1>StreamDevice: waveform Records</h1>
|
||||
<h1>waveform Records</h1>
|
||||
|
||||
<h2>Normal Operation</h2>
|
||||
<p>
|
||||
With waveform records, the format converter is applied to
|
||||
each element. Between the elements, a separator is printed
|
||||
each array element. Between the elements, a separator is printed
|
||||
or expected as specified by the <code>Separator</code>
|
||||
<a href="protocol.html#sysvar">variable</a> in the
|
||||
protocol.
|
||||
@ -37,14 +37,19 @@ written.
|
||||
<p>
|
||||
The format data type must be convertible to or from the type
|
||||
specified in the <code>FTVL</code> field.
|
||||
The types <code>"INT64"</code> and <code>"UINT64"</code> are
|
||||
only available in EPICS base version 3.16 or higher.
|
||||
</p>
|
||||
<p>
|
||||
The variable <code><i>x[i]</i></code> stands for one element of
|
||||
the written or read value.
|
||||
</p>
|
||||
<dl>
|
||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||
<dd>
|
||||
<u>Output:</u><code><i>x[i]</i>=double(VAL[i])</code><br>
|
||||
<u>Output:</u> <code><i>x[i]</i>=double(VAL[i])</code><br>
|
||||
<code>FTVL</code> can be <code>"DOUBLE"</code>, <code>"FLOAT"</code>,
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -55,6 +60,7 @@ the written or read value.
|
||||
<dd>
|
||||
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
||||
<code>FTVL</code> can be
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -62,6 +68,7 @@ the written or read value.
|
||||
zero-extended to long before converting them.<br>
|
||||
<u>Input:</u> <code>VAL[i]=FTVL(<i>x[i])</i></code><br>
|
||||
<code>FTVL</code> can be <code>"DOUBLE"</code>, <code>"FLOAT"</code>,
|
||||
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||
@ -102,25 +109,31 @@ the written or read value.
|
||||
present. All format converters work like in normal operation.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<footer>
|
||||
<nav>
|
||||
<a href="aai.html">aai</a>
|
||||
<a href="aao.html">aao</a>
|
||||
<a href="ai.html">ai</a>
|
||||
<a href="ao.html">ao</a>
|
||||
<a href="bi.html">bi</a>
|
||||
<a href="bo.html">bo</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="int64in.html">int64in</a>
|
||||
<a href="int64out.html">int64out</a>
|
||||
<a href="longin.html">longin</a>
|
||||
<a href="longout.html">longout</a>
|
||||
<a href="lsi.html">lsi</a>
|
||||
<a href="lso.html">lso</a>
|
||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
||||
<a href="mbboDirect.html">mbboDirect</a>
|
||||
<a href="mbbi.html">mbbi</a>
|
||||
<a href="mbbo.html">mbbo</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
<a href="stringin.html">stringin</a>
|
||||
<a href="stringout.html">stringout</a>
|
||||
<a href="calcout.html">calcout</a>
|
||||
<a href="scalcout.html">scalcout</a>
|
||||
</p>
|
||||
<p><small>Dirk Zimoch, 2005</small></p>
|
||||
<a href="waveform.html">waveform</a>
|
||||
</nav>
|
||||
Dirk Zimoch, 2018
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
58
makefile
@ -1,58 +0,0 @@
|
||||
include /ioc/tools/driver.makefile
|
||||
EXCLUDE_VERSIONS = 3.13.2
|
||||
PROJECT=stream2
|
||||
BUILDCLASSES += Linux
|
||||
|
||||
#DOCUDIR = doc
|
||||
|
||||
DBDS = stream.dbd
|
||||
|
||||
BUSSES += AsynDriver
|
||||
BUSSES += Dummy
|
||||
|
||||
FORMATS += Enum
|
||||
FORMATS += BCD
|
||||
FORMATS += Raw
|
||||
FORMATS += RawFloat
|
||||
FORMATS += Binary
|
||||
FORMATS += Checksum
|
||||
FORMATS += Regexp
|
||||
FORMATS += MantissaExponent
|
||||
FORMATS += Timestamp
|
||||
|
||||
RECORDTYPES += aai aao
|
||||
RECORDTYPES += ao ai
|
||||
RECORDTYPES += bo bi
|
||||
RECORDTYPES += mbbo mbbi
|
||||
RECORDTYPES += mbboDirect mbbiDirect
|
||||
RECORDTYPES += longout longin
|
||||
RECORDTYPES += stringout stringin
|
||||
RECORDTYPES += waveform
|
||||
|
||||
SOURCES += $(RECORDTYPES:%=src/dev%Stream.c)
|
||||
SOURCES += $(FORMATS:%=src/%Converter.cc)
|
||||
SOURCES += $(BUSSES:%=src/%Interface.cc)
|
||||
SOURCES += $(wildcard src/Stream*.cc)
|
||||
SOURCES += src/StreamVersion.c
|
||||
|
||||
HEADERS += devStream.h
|
||||
HEADERS += StreamFormat.h
|
||||
HEADERS += StreamFormatConverter.h
|
||||
HEADERS += StreamBuffer.h
|
||||
HEADERS += StreamError.h
|
||||
|
||||
ifeq (${EPICS_BASETYPE},3.13)
|
||||
USR_INCLUDES += -include $(INSTALL_INCLUDE)/compat3_13.h
|
||||
endif
|
||||
ifeq (${EPICS_BASETYPE},3.14)
|
||||
RECORDTYPES += calcout
|
||||
endif
|
||||
|
||||
StreamCore.o: streamReferences
|
||||
|
||||
streamReferences:
|
||||
perl ../src/makeref.pl Interface $(BUSSES) > $@
|
||||
perl ../src/makeref.pl Converter $(FORMATS) >> $@
|
||||
|
||||
stream.dbd:
|
||||
perl ../src/makedbd.pl $(RECORDTYPES) > $@
|
@ -1,22 +1,24 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the BCD format converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the BCD format converter of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
@ -27,76 +29,67 @@ class BCDConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||
int scanLong(const StreamFormat&, const char*, long&);
|
||||
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||
};
|
||||
|
||||
int BCDConverter::
|
||||
parse(const StreamFormat&, StreamBuffer&, const char*&, bool)
|
||||
parse(const StreamFormat& fmt, StreamBuffer&, const char*&, bool)
|
||||
{
|
||||
return long_format;
|
||||
return (fmt.flags & sign_flag) ? signed_format : unsigned_format;
|
||||
}
|
||||
|
||||
bool BCDConverter::
|
||||
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
{
|
||||
unsigned char bcd[6]={0,0,0,0,0,0}; // sufficient for 2^32
|
||||
int i;
|
||||
int prec = fmt.prec; // number of nibbles
|
||||
if (prec == -1)
|
||||
{
|
||||
prec = 2 * sizeof (value);
|
||||
}
|
||||
int width = (prec + (fmt.flags & sign_flag ? 2 : 1)) / 2;
|
||||
unsigned char bcd;
|
||||
long i, d, s;
|
||||
unsigned long prec = fmt.prec < 0 ? 2 * sizeof(value) : fmt.prec; // number of nibbles
|
||||
unsigned long width = (prec + (fmt.flags & sign_flag ? 2 : 1)) / 2;
|
||||
unsigned long val = value;
|
||||
|
||||
output.append('\0', width);
|
||||
if (fmt.width > width) width = fmt.width;
|
||||
if (fmt.flags & sign_flag && value < 0)
|
||||
{
|
||||
// negative BCD value, I hope "F" as "-" is OK
|
||||
bcd[5] = 0xF0;
|
||||
value = -value;
|
||||
}
|
||||
if (prec > 10) prec = 10;
|
||||
for (i = 0; i < prec; i++)
|
||||
{
|
||||
bcd[i/2] |= (value % 10) << (4 * (i & 1));
|
||||
value /= 10;
|
||||
}
|
||||
val = -value;
|
||||
if (fmt.flags & alt_flag)
|
||||
{
|
||||
// least significant byte first (little endian)
|
||||
for (i = 0; i < (prec + 1) / 2; i++)
|
||||
{
|
||||
output.append(bcd[i]);
|
||||
}
|
||||
for (; i < width; i++)
|
||||
{
|
||||
output.append('\0');
|
||||
}
|
||||
output[-1] |= bcd[5];
|
||||
i = -(long)width;
|
||||
d = 1;
|
||||
s = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// most significant byte first (big endian)
|
||||
int firstbyte = output.length();
|
||||
for (i = 0; i < width - (prec + 1) / 2; i++)
|
||||
i = -1;
|
||||
d = -1;
|
||||
s = -(long)width;
|
||||
}
|
||||
while (width && prec)
|
||||
{
|
||||
width--;
|
||||
bcd = val%10;
|
||||
if (--prec)
|
||||
{
|
||||
output.append('\0');
|
||||
--prec;
|
||||
val /= 10;
|
||||
bcd |= (val%10)<<4;
|
||||
val /= 10;
|
||||
}
|
||||
for (i = (prec - 1) / 2; i >= 0; i--)
|
||||
{
|
||||
output.append(bcd[i]);
|
||||
}
|
||||
output[firstbyte] |= bcd[5];
|
||||
output[i] = bcd;
|
||||
i += d;
|
||||
}
|
||||
if (fmt.flags & sign_flag && value < 0) {
|
||||
output[s] |= 0xf0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int BCDConverter::
|
||||
ssize_t BCDConverter::
|
||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
{
|
||||
int length = 0;
|
||||
int val = 0;
|
||||
ssize_t consumed = 0;
|
||||
long val = 0;
|
||||
unsigned char bcd1, bcd10;
|
||||
int width = fmt.width;
|
||||
long width = fmt.width;
|
||||
if (width == 0) width = 1;
|
||||
if (fmt.flags & alt_flag)
|
||||
{
|
||||
@ -104,7 +97,8 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
int shift = 1;
|
||||
while (width--)
|
||||
{
|
||||
bcd1 = bcd10 = (unsigned char) input[length++];
|
||||
bcd1 = input[consumed++];
|
||||
bcd10 = bcd1>>4;
|
||||
bcd1 &= 0x0F;
|
||||
bcd10 >>= 4;
|
||||
if (bcd1 > 9 || shift * bcd1 < bcd1) break;
|
||||
@ -127,10 +121,10 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
while (width--)
|
||||
{
|
||||
long temp;
|
||||
bcd1 = bcd10 = (unsigned char) input[length];
|
||||
bcd1 = input[consumed];
|
||||
bcd10 = bcd1>>4;
|
||||
bcd1 &= 0x0F;
|
||||
bcd10 >>= 4;
|
||||
if (length == 0 && fmt.flags & sign_flag && bcd10)
|
||||
if (consumed == 0 && fmt.flags & sign_flag && bcd10)
|
||||
{
|
||||
sign = -1;
|
||||
bcd10 = 0;
|
||||
@ -139,17 +133,17 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
temp = val * 100 + (bcd1 + 10 * bcd10);
|
||||
if (temp < val)
|
||||
{
|
||||
length = 0;
|
||||
consumed = 0;
|
||||
break;
|
||||
}
|
||||
val = temp;
|
||||
length++;
|
||||
consumed++;
|
||||
}
|
||||
val *= sign;
|
||||
}
|
||||
if (length == 0) return -1;
|
||||
if (consumed == 0) return -1;
|
||||
value = val;
|
||||
return length;
|
||||
return consumed;
|
||||
}
|
||||
|
||||
RegisterConverter (BCDConverter, "D");
|
||||
|
@ -1,24 +1,28 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the binary format converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the binary format converter of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
|
||||
@ -28,58 +32,66 @@ class BinaryConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||
int scanLong(const StreamFormat&, const char*, long&);
|
||||
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||
};
|
||||
|
||||
int BinaryConverter::
|
||||
parse(const StreamFormat& format, StreamBuffer& info,
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool)
|
||||
{
|
||||
if (format.conv == 'B')
|
||||
if (fmt.conv == 'b')
|
||||
{
|
||||
// user defined characters for %B (next 2 in source)
|
||||
// default characters 0 and 1 for %b
|
||||
info.append("01");
|
||||
return unsigned_format;
|
||||
}
|
||||
|
||||
// user defined characters for %B (next 2 in source)
|
||||
if (*source)
|
||||
{
|
||||
if (*source == esc) source++;
|
||||
info.append(*source++);
|
||||
if (*source)
|
||||
{
|
||||
if (*source == esc) source++;
|
||||
info.append(*source++);
|
||||
if (*source)
|
||||
{
|
||||
if (*source == esc) source++;
|
||||
info.append(*source++);
|
||||
return long_format;
|
||||
}
|
||||
return unsigned_format;
|
||||
}
|
||||
error("Missing characters after %%B format conversion\n");
|
||||
return false;
|
||||
}
|
||||
// default characters for %b
|
||||
info.append("01");
|
||||
return long_format;
|
||||
error("Missing characters after %%B format conversion\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BinaryConverter::
|
||||
printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
{
|
||||
int prec = format.prec;
|
||||
int prec = fmt.prec;
|
||||
if (prec == -1)
|
||||
{
|
||||
// find number of significant bits
|
||||
prec = sizeof (value) * 8;
|
||||
while (prec && (value & (1L << (prec - 1))) == 0) prec--;
|
||||
// Find number of significant bits is nothing is specified.
|
||||
unsigned long x = (unsigned long) value;
|
||||
prec = 32;
|
||||
#if (LONG_BIT > 32)
|
||||
if (x > 0xFFFFFFFF) { prec = 64; x >>=32; }
|
||||
#endif
|
||||
if (x <= 0x0000FFFF) { prec -= 16; x <<=16; }
|
||||
if (x <= 0x00FFFFFF) { prec -= 8; x <<=8; }
|
||||
if (x <= 0x0FFFFFFF) { prec -= 4; x <<=4; }
|
||||
if (x <= 0x3FFFFFFF) { prec -= 2; x <<=2; }
|
||||
if (x <= 0x7FFFFFFF) { prec -= 1; }
|
||||
}
|
||||
if (prec == 0) prec++; // print at least one bit
|
||||
int width = prec;
|
||||
if (format.width > width) width = format.width;
|
||||
char zero = format.info[0];
|
||||
char one = format.info[1];
|
||||
char fill = (format.flags & zero_flag) ? zero : ' ';
|
||||
if (format.flags & alt_flag)
|
||||
unsigned long width = prec;
|
||||
if (fmt.width > width) width = fmt.width;
|
||||
char zero = fmt.info[0];
|
||||
char one = fmt.info[1];
|
||||
char fill = (fmt.flags & zero_flag) ? zero : ' ';
|
||||
if (fmt.flags & alt_flag)
|
||||
{
|
||||
// little endian (least significant bit first)
|
||||
if (!(format.flags & left_flag))
|
||||
if (!(fmt.flags & left_flag))
|
||||
{
|
||||
// pad left
|
||||
while (width > prec)
|
||||
while (width > (unsigned int)prec)
|
||||
{
|
||||
output.append(' ');
|
||||
width--;
|
||||
@ -100,10 +112,10 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
else
|
||||
{
|
||||
// big endian (most significant bit first)
|
||||
if (!(format.flags & left_flag))
|
||||
if (!(fmt.flags & left_flag))
|
||||
{
|
||||
// pad left
|
||||
while (width > prec)
|
||||
while (width > (unsigned int)prec)
|
||||
{
|
||||
output.append(fill);
|
||||
width--;
|
||||
@ -123,39 +135,39 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
return true;
|
||||
}
|
||||
|
||||
int BinaryConverter::
|
||||
scanLong(const StreamFormat& format, const char* input, long& value)
|
||||
ssize_t BinaryConverter::
|
||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
{
|
||||
long val = 0;
|
||||
int width = format.width;
|
||||
long width = fmt.width;
|
||||
if (width == 0) width = -1;
|
||||
int length = 0;
|
||||
char zero = format.info[0];
|
||||
char one = format.info[1];
|
||||
size_t consumed = 0;
|
||||
char zero = fmt.info[0];
|
||||
char one = fmt.info[1];
|
||||
if (!isspace(zero) && !isspace(one))
|
||||
while (isspace(input[length])) length++; // skip whitespaces
|
||||
if (input[length] != zero && input[length] != one) return -1;
|
||||
if (format.flags & alt_flag)
|
||||
while (isspace(input[consumed])) consumed++; // skip whitespaces
|
||||
if (input[consumed] != zero && input[consumed] != one) return -1;
|
||||
if (fmt.flags & alt_flag)
|
||||
{
|
||||
// little endian (least significan bit first)
|
||||
long mask = 1;
|
||||
while (width-- && (input[length] == zero || input[length] == one))
|
||||
while (width-- && (input[consumed] == zero || input[consumed] == one))
|
||||
{
|
||||
if (input[length++] == one) val |= mask;
|
||||
if (input[consumed++] == one) val |= mask;
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// big endian (most significan bit first)
|
||||
while (width-- && (input[length] == zero || input[length] == one))
|
||||
while (width-- && (input[consumed] == zero || input[consumed] == one))
|
||||
{
|
||||
val <<= 1;
|
||||
if (input[length++] == one) val |= 1;
|
||||
if (input[consumed++] == one) val |= 1;
|
||||
}
|
||||
}
|
||||
value = val;
|
||||
return length;
|
||||
return consumed;
|
||||
}
|
||||
|
||||
RegisterConverter (BinaryConverter, "bB");
|
||||
|
@ -1,29 +1,59 @@
|
||||
# Want debugging?
|
||||
# HOST_OPT = NO
|
||||
##########################################################################
|
||||
# This is the build configuration file of StreamDevice.
|
||||
#
|
||||
# (C) 2007,2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
#
|
||||
# This file is part of StreamDevice.
|
||||
#
|
||||
# StreamDevice is free software: You can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# StreamDevice is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
#########################################################################/
|
||||
|
||||
# You may add more record interfaces
|
||||
# This requires the naming conventions
|
||||
# dev$(RECORD)Stream.c
|
||||
# dev$(RECORDTYPE)Stream.c
|
||||
|
||||
RECORDS += ao ai
|
||||
RECORDS += bo bi
|
||||
RECORDS += mbbo mbbi
|
||||
RECORDS += mbboDirect mbbiDirect
|
||||
RECORDS += longout longin
|
||||
RECORDS += stringout stringin
|
||||
RECORDS += waveform
|
||||
RECORDS += calcout
|
||||
RECORDS += aai aao
|
||||
RECORDTYPES += ao ai
|
||||
RECORDTYPES += bo bi
|
||||
RECORDTYPES += mbbo mbbi
|
||||
RECORDTYPES += mbboDirect mbbiDirect
|
||||
RECORDTYPES += longout longin
|
||||
RECORDTYPES += stringout stringin
|
||||
RECORDTYPES += waveform
|
||||
RECORDTYPES += aai aao
|
||||
|
||||
ifdef BASE_3_14
|
||||
RECORDTYPES += calcout
|
||||
endif
|
||||
|
||||
ifdef BASE_3_15
|
||||
RECORDTYPES += lsi lso
|
||||
endif
|
||||
|
||||
ifdef BASE_3_16
|
||||
RECORDTYPES += int64in int64out
|
||||
endif
|
||||
|
||||
# Do you have synApps and want support for scalcout?
|
||||
# Then define CALC or SYNAPPS in your RELEASE file
|
||||
# pointing to the 'calc' module of synApps.
|
||||
# Due to strange cross dependencies in synApps
|
||||
# you have to build the 'sscan' and 'genSub'
|
||||
# modules before building 'calc'.
|
||||
# See doc/scalcout.html for a required fix in scalcout.
|
||||
|
||||
SYNAPPS_RECORDS += scalcout
|
||||
# Older 'calc' versions have a cross reference on
|
||||
# 'sscan' and/or 'genSub', so you may have to build them first.
|
||||
# Up to version 2-6 (synApps 5-1) the 'calc' module needs a fix.
|
||||
# See doc/scalcout.html for details.
|
||||
ifneq ($(words $(CALC) $(SYNAPPS)), 0)
|
||||
RECORDTYPES += scalcout
|
||||
endif
|
||||
|
||||
# You may add more bus interfaces
|
||||
# This requires the naming convention
|
||||
@ -33,6 +63,9 @@ SYNAPPS_RECORDS += scalcout
|
||||
|
||||
BUSSES += Debug
|
||||
BUSSES += Dummy
|
||||
ifdef ASYN
|
||||
BUSSES += AsynDriver
|
||||
endif
|
||||
|
||||
# You may add more format converters
|
||||
# This requires the naming convention
|
||||
@ -63,7 +96,7 @@ ifneq ($(words $(PCRE) $(PCRE_LIB) $(PCRE_INCLUDE)),0)
|
||||
FORMATS += Regexp
|
||||
endif
|
||||
|
||||
# Want a loadable module?
|
||||
# Want a loadable module?
|
||||
# For Tornado 2.0.2, a fix is needed in the
|
||||
# registerRecordDeviceDriver.pl script in base:
|
||||
# at the end replace the line "IoccrfReg iocshReg;"
|
||||
|
@ -1,35 +1,86 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the checksum pseudo-converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the checksum pseudo-converter of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2006,2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <version.h>
|
||||
/* VxWorks has strncasecmp since version 6
|
||||
but availability depends on configuration.
|
||||
We cannot know.
|
||||
*/
|
||||
#define NEED_strncasecmp
|
||||
/* VxWorks does not have inttypes.h and uint32_t differs between versions */
|
||||
#if defined(_WRS_VXWORKS_MAJOR) && (_WRS_VXWORKS_MAJOR > 6 || (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 9))
|
||||
#define PRIX32 "X"
|
||||
#define PRIu32 "u"
|
||||
#else
|
||||
#define PRIX32 "lX"
|
||||
#define PRIu32 "lu"
|
||||
#endif
|
||||
#define PRIX8 "X"
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1700
|
||||
/* Visual Studio 2010 does not have inttypes.h */
|
||||
#define PRIX32 "X"
|
||||
#define PRIu32 "u"
|
||||
#define PRIX8 "X"
|
||||
#else
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__rtems__)
|
||||
#include <rtems.h>
|
||||
#if __RTEMS_MAJOR__ < 5
|
||||
/* RTEMS has strncasecmp since version 5 */
|
||||
#define NEED_strncasecmp
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Windows strncasecmp has a different name. */
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
#ifdef NEED_strncasecmp
|
||||
// Have no strncasecmp but avoid compiler errors in case it exists in future versions
|
||||
extern "C" {
|
||||
static int mystrncasecmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
int r=0;
|
||||
while (n && (r = toupper(*s1)-toupper(*s2)) == 0) { n--; s1++; s2++; };
|
||||
return r;
|
||||
}
|
||||
}
|
||||
#define strncasecmp mystrncasecmp
|
||||
#endif
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
#if defined(__vxworks) || defined(vxWorks) || defined(_WIN32) || defined(__rtems__)
|
||||
// These systems have no strncasecmp
|
||||
#include <epicsString.h>
|
||||
#define strncasecmp epicsStrnCaseCmp
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
typedef unsigned int (*checksumFunc)(const unsigned char* data, unsigned int len, unsigned int init);
|
||||
typedef uint32_t (*checksumFunc)(const uint8_t* data, size_t len, uint32_t init);
|
||||
|
||||
static unsigned int sum(const unsigned char* data, unsigned int len, unsigned int sum)
|
||||
static uint32_t sum(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
@ -38,7 +89,7 @@ static unsigned int sum(const unsigned char* data, unsigned int len, unsigned in
|
||||
return sum;
|
||||
}
|
||||
|
||||
static unsigned int xor8(const unsigned char* data, unsigned int len, unsigned int sum)
|
||||
static uint32_t xor8(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
@ -47,15 +98,42 @@ static unsigned int xor8(const unsigned char* data, unsigned int len, unsigned i
|
||||
return sum;
|
||||
}
|
||||
|
||||
static unsigned int xor7(const unsigned char* data, unsigned int len, unsigned int sum)
|
||||
static uint32_t xor7(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
return xor8(data, len, sum) & 0x7F;
|
||||
}
|
||||
|
||||
static unsigned int crc_0x07(const unsigned char* data, unsigned int len, unsigned int crc)
|
||||
static uint32_t bitsum(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
// number of set bits in each byte
|
||||
const uint8_t table[256] = {
|
||||
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
|
||||
while (len--)
|
||||
{
|
||||
sum += table[*data++];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static uint32_t crc_0x07(const uint8_t* data, size_t len, uint32_t crc)
|
||||
{
|
||||
// x^8 + x^2 + x^1 + x^0 (0x07)
|
||||
const static unsigned char table[256] = {
|
||||
const uint8_t table[256] = {
|
||||
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
|
||||
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
|
||||
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
||||
@ -93,10 +171,10 @@ static unsigned int crc_0x07(const unsigned char* data, unsigned int len, unsign
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned int crc_0x31(const unsigned char* data, unsigned int len, unsigned int crc)
|
||||
static uint32_t crc_0x31(const uint8_t* data, size_t len, uint32_t crc)
|
||||
{
|
||||
// x^8 + x^5 + x^4 + x^0 (0x31)
|
||||
const static unsigned char table[256] = {
|
||||
const uint8_t table[256] = {
|
||||
0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83,
|
||||
0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41,
|
||||
0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e,
|
||||
@ -134,93 +212,93 @@ static unsigned int crc_0x31(const unsigned char* data, unsigned int len, unsign
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned int crc_0x8005(const unsigned char* data, unsigned int len, unsigned int crc)
|
||||
static uint32_t crc_0x8005(const uint8_t* data, size_t len, uint32_t crc)
|
||||
{
|
||||
// x^16 + x^15 + x^2 + x^0 (0x8005)
|
||||
const static unsigned short table[256] = {
|
||||
0x0000,0x8005,0x800f,0x000a,0x801b,0x001e,0x0014,0x8011,
|
||||
0x8033,0x0036,0x003c,0x8039,0x0028,0x802d,0x8027,0x0022,
|
||||
0x8063,0x0066,0x006c,0x8069,0x0078,0x807d,0x8077,0x0072,
|
||||
0x0050,0x8055,0x805f,0x005a,0x804b,0x004e,0x0044,0x8041,
|
||||
0x80c3,0x00c6,0x00cc,0x80c9,0x00d8,0x80dd,0x80d7,0x00d2,
|
||||
0x00f0,0x80f5,0x80ff,0x00fa,0x80eb,0x00ee,0x00e4,0x80e1,
|
||||
0x00a0,0x80a5,0x80af,0x00aa,0x80bb,0x00be,0x00b4,0x80b1,
|
||||
0x8093,0x0096,0x009c,0x8099,0x0088,0x808d,0x8087,0x0082,
|
||||
0x8183,0x0186,0x018c,0x8189,0x0198,0x819d,0x8197,0x0192,
|
||||
0x01b0,0x81b5,0x81bf,0x01ba,0x81ab,0x01ae,0x01a4,0x81a1,
|
||||
0x01e0,0x81e5,0x81ef,0x01ea,0x81fb,0x01fe,0x01f4,0x81f1,
|
||||
0x81d3,0x01d6,0x01dc,0x81d9,0x01c8,0x81cd,0x81c7,0x01c2,
|
||||
0x0140,0x8145,0x814f,0x014a,0x815b,0x015e,0x0154,0x8151,
|
||||
0x8173,0x0176,0x017c,0x8179,0x0168,0x816d,0x8167,0x0162,
|
||||
0x8123,0x0126,0x012c,0x8129,0x0138,0x813d,0x8137,0x0132,
|
||||
0x0110,0x8115,0x811f,0x011a,0x810b,0x010e,0x0104,0x8101,
|
||||
0x8303,0x0306,0x030c,0x8309,0x0318,0x831d,0x8317,0x0312,
|
||||
0x0330,0x8335,0x833f,0x033a,0x832b,0x032e,0x0324,0x8321,
|
||||
0x0360,0x8365,0x836f,0x036a,0x837b,0x037e,0x0374,0x8371,
|
||||
0x8353,0x0356,0x035c,0x8359,0x0348,0x834d,0x8347,0x0342,
|
||||
0x03c0,0x83c5,0x83cf,0x03ca,0x83db,0x03de,0x03d4,0x83d1,
|
||||
0x83f3,0x03f6,0x03fc,0x83f9,0x03e8,0x83ed,0x83e7,0x03e2,
|
||||
0x83a3,0x03a6,0x03ac,0x83a9,0x03b8,0x83bd,0x83b7,0x03b2,
|
||||
0x0390,0x8395,0x839f,0x039a,0x838b,0x038e,0x0384,0x8381,
|
||||
0x0280,0x8285,0x828f,0x028a,0x829b,0x029e,0x0294,0x8291,
|
||||
0x82b3,0x02b6,0x02bc,0x82b9,0x02a8,0x82ad,0x82a7,0x02a2,
|
||||
0x82e3,0x02e6,0x02ec,0x82e9,0x02f8,0x82fd,0x82f7,0x02f2,
|
||||
0x02d0,0x82d5,0x82df,0x02da,0x82cb,0x02ce,0x02c4,0x82c1,
|
||||
0x8243,0x0246,0x024c,0x8249,0x0258,0x825d,0x8257,0x0252,
|
||||
0x0270,0x8275,0x827f,0x027a,0x826b,0x026e,0x0264,0x8261,
|
||||
0x0220,0x8225,0x822f,0x022a,0x823b,0x023e,0x0234,0x8231,
|
||||
0x8213,0x0216,0x021c,0x8219,0x0208,0x820d,0x8207,0x0202 };
|
||||
const uint16_t table[256] = {
|
||||
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
|
||||
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
|
||||
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
|
||||
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
|
||||
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
|
||||
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
|
||||
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
|
||||
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
|
||||
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
|
||||
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
|
||||
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
|
||||
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
|
||||
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
|
||||
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
|
||||
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
|
||||
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
|
||||
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
|
||||
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
|
||||
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
|
||||
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 };
|
||||
|
||||
while (len--) crc = table[((crc>>8) ^ *data++) & 0xFF] ^ (crc << 8);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned int crc_0x8005_r(const unsigned char* data, unsigned int len, unsigned int crc)
|
||||
static uint32_t crc_0x8005_r(const uint8_t* data, size_t len, uint32_t crc)
|
||||
{
|
||||
// x^16 + x^15 + x^2 + x^0 (0x8005)
|
||||
// reflected
|
||||
const static unsigned short table[256] = {
|
||||
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
|
||||
0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
|
||||
0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
|
||||
0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
|
||||
0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
|
||||
0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
|
||||
0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
|
||||
0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
|
||||
0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
|
||||
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
|
||||
0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
|
||||
0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
|
||||
0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
|
||||
0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
|
||||
0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
|
||||
0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
|
||||
0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
|
||||
0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
|
||||
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
|
||||
0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
|
||||
0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
|
||||
0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
|
||||
0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
|
||||
0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
|
||||
0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
|
||||
0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
|
||||
0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
|
||||
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
|
||||
0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
|
||||
0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
|
||||
0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
|
||||
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040 };
|
||||
const uint16_t table[256] = {
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 };
|
||||
|
||||
while (len--) crc = table[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned int crc_0x1021(const unsigned char* data, unsigned int len, unsigned int crc)
|
||||
static uint32_t crc_0x1021(const uint8_t* data, size_t len, uint32_t crc)
|
||||
{
|
||||
// x^16 + x^12 + x^5 + x^0 (0x1021)
|
||||
const static unsigned short table[256] = {
|
||||
const uint16_t table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||
@ -258,11 +336,11 @@ static unsigned int crc_0x1021(const unsigned char* data, unsigned int len, unsi
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned int crc_0x04C11DB7(const unsigned char* data, unsigned int len, unsigned int crc)
|
||||
static uint32_t crc_0x04C11DB7(const uint8_t* data, size_t len, uint32_t crc)
|
||||
{
|
||||
// x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 +
|
||||
// x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + x^0 (0x04C11DB7)
|
||||
const static unsigned int table[] = {
|
||||
const uint32_t table[] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
@ -332,12 +410,12 @@ static unsigned int crc_0x04C11DB7(const unsigned char* data, unsigned int len,
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned int crc_0x04C11DB7_r(const unsigned char* data, unsigned int len, unsigned int crc)
|
||||
static uint32_t crc_0x04C11DB7_r(const uint8_t* data, size_t len, uint32_t crc)
|
||||
{
|
||||
// x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 +
|
||||
// x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + x^0 (0x04C11DB7)
|
||||
// reflected
|
||||
const static unsigned int table[] = {
|
||||
const uint32_t table[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
@ -407,13 +485,13 @@ static unsigned int crc_0x04C11DB7_r(const unsigned char* data, unsigned int len
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned int adler32(const unsigned char* data, unsigned int len, unsigned int init)
|
||||
static uint32_t adler32(const uint8_t* data, size_t len, uint32_t init)
|
||||
{
|
||||
unsigned int a = init & 0xFFFF;
|
||||
unsigned int b = (init >> 16) & 0xFFFF;
|
||||
uint32_t a = init & 0xFFFF;
|
||||
uint32_t b = (init >> 16) & 0xFFFF;
|
||||
|
||||
while (len) {
|
||||
unsigned int tlen = len > 5550 ? 5550 : len;
|
||||
size_t tlen = len > 5550 ? 5550 : len;
|
||||
len -= tlen;
|
||||
do {
|
||||
a += *data++;
|
||||
@ -421,17 +499,17 @@ static unsigned int adler32(const unsigned char* data, unsigned int len, unsigne
|
||||
} while (--tlen);
|
||||
a = (a & 0xFFFF) + (a >> 16) * 15;
|
||||
b = (b & 0xFFFF) + (b >> 16) * 15;
|
||||
}
|
||||
if (a >= 65521) a -= 65521;
|
||||
b = (b & 0xFFFF) + (b >> 16) * 15;
|
||||
if (b >= 65521) b -= 65521;
|
||||
return b << 16 | a;
|
||||
}
|
||||
if (a >= 65521) a -= 65521;
|
||||
b = (b & 0xFFFF) + (b >> 16) * 15;
|
||||
if (b >= 65521) b -= 65521;
|
||||
return b << 16 | a;
|
||||
}
|
||||
|
||||
static unsigned int hexsum(const unsigned char* data, unsigned int len, unsigned int sum)
|
||||
static uint32_t hexsum(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
// Add all hex digits, ignore all other bytes.
|
||||
unsigned int d;
|
||||
uint32_t d;
|
||||
while (len--)
|
||||
{
|
||||
d = toupper(*data++);
|
||||
@ -445,13 +523,116 @@ static unsigned int hexsum(const unsigned char* data, unsigned int len, unsigned
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Special TRIUMF version for the CPI RF Amplifier
|
||||
static uint32_t CPI(const uint8_t * data, size_t len, uint32_t init)
|
||||
{
|
||||
init -= (uint32_t)len<<5;
|
||||
while (len--)
|
||||
{
|
||||
init += *data++;
|
||||
}
|
||||
init %= 95;
|
||||
init += 32;
|
||||
return init;
|
||||
}
|
||||
|
||||
// Leybold Graphix uses a strange sum (= notsum + fix):
|
||||
// "CRC = 255 - [(Byte sum of all preceding characters) mod 256]
|
||||
// If this value is lower than 32 (control character of the ASCII code),
|
||||
// then 32 must be added."
|
||||
|
||||
static uint32_t leybold(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
sum += *data++;
|
||||
}
|
||||
sum = ~sum;
|
||||
sum &= 0xff;
|
||||
if (sum < 32) sum+=32;
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Checksum used by Brooks Cryopumps
|
||||
static uint32_t brksCryo(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
uint32_t xsum;
|
||||
while (len--) {
|
||||
sum += (*data++) & 0x7F;
|
||||
}
|
||||
xsum = (((sum >> 6) ^ sum) & 0x3F) + 0x30;
|
||||
return xsum;
|
||||
}
|
||||
|
||||
// Longitudinal Redundancy Check
|
||||
static uint32_t lrc(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
while (len--) {
|
||||
sum = (sum + (*data++)) & 0xFF;
|
||||
}
|
||||
|
||||
sum = ((sum ^ 0xFF) + 1) & 0xFF;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Longitudinal Redundancy Check using ASCII representation of numbers, 2-by-2
|
||||
static uint32_t hexlrc(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
uint32_t d;
|
||||
uint32_t final_digit = 0;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
d = toupper(*data++);
|
||||
|
||||
// Convert all hex digits, ignore all other bytes
|
||||
if (isxdigit(d))
|
||||
{
|
||||
// Convert digits from ASCII to number
|
||||
if (isdigit(d)) {
|
||||
d -= '0';
|
||||
}
|
||||
else {
|
||||
d -= 'A' - 0x0A;
|
||||
}
|
||||
|
||||
// For the most significant bits, shift 4 bits
|
||||
if (len % 2) {
|
||||
final_digit = d << 4;
|
||||
// Least significant bits are summed to previous converted digit
|
||||
} else {
|
||||
d += final_digit;
|
||||
final_digit = 0;
|
||||
// Apply lrc rule
|
||||
sum = (sum + d) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply lrc rule
|
||||
sum = ((sum ^ 0xFF) + 1) & 0xFF;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Checksum used by Spellman High Voltage Supplies MPS
|
||||
static uint32_t hv_mps(const uint8_t* data, size_t len, uint32_t sum)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
sum += *data++;
|
||||
}
|
||||
return (~sum & 0x7F) | 0x40;
|
||||
}
|
||||
|
||||
struct checksum
|
||||
{
|
||||
const char* name;
|
||||
checksumFunc func;
|
||||
unsigned int init;
|
||||
unsigned int xorout;
|
||||
signed char bytes;
|
||||
uint32_t init;
|
||||
uint32_t xorout;
|
||||
uint8_t bytes;
|
||||
};
|
||||
|
||||
static checksum checksumMap[] =
|
||||
@ -462,13 +643,19 @@ static checksum checksumMap[] =
|
||||
{"sum8", sum, 0x00, 0x00, 1}, // 0xDD
|
||||
{"sum16", sum, 0x0000, 0x0000, 2}, // 0x01DD
|
||||
{"sum32", sum, 0x00000000, 0x00000000, 4}, // 0x000001DD
|
||||
{"nsum8", sum, 0xFF, 0xFF, 1}, // 0x23
|
||||
{"nsum16", sum, 0xFFFF, 0xFFFF, 2}, // 0xFE23
|
||||
{"nsum32", sum, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xFFFFFE23
|
||||
{"notsum", sum, 0x00, 0xFF, 1}, // 0x22
|
||||
{"xor", xor8, 0x00, 0x00, 1}, // 0x31
|
||||
{"xor8", xor8, 0x00, 0x00, 1}, // 0x31
|
||||
{"xor8ff", xor8, 0x00, 0xFF, 1}, // 0xCE
|
||||
{"xor7", xor7, 0x00, 0x00, 1}, // 0x31
|
||||
{"crc8", crc_0x07, 0x00, 0x00, 1}, // 0xF4
|
||||
{"ccitt8", crc_0x31, 0x00, 0x00, 1}, // 0xA1
|
||||
{"crc16", crc_0x8005, 0x0000, 0x0000, 2}, // 0xFEE8
|
||||
{"crc16r", crc_0x8005_r, 0x0000, 0x0000, 2}, // 0xBB3D
|
||||
{"modbus", crc_0x8005_r, 0xFFFF, 0x0000, 2}, // 0x4B37
|
||||
{"ccitt16", crc_0x1021, 0xFFFF, 0x0000, 2}, // 0x29B1
|
||||
{"ccitt16a",crc_0x1021, 0x1D0F, 0x0000, 2}, // 0xE5CC
|
||||
{"ccitt16x",crc_0x1021, 0x0000, 0x0000, 2}, // 0x31C3
|
||||
@ -478,20 +665,30 @@ static checksum checksumMap[] =
|
||||
{"crc32r", crc_0x04C11DB7_r, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xCBF43926
|
||||
{"jamcrc", crc_0x04C11DB7_r, 0xFFFFFFFF, 0x00000000, 4}, // 0x340BC6D9
|
||||
{"adler32", adler32, 0x00000001, 0x00000000, 4}, // 0x091E01DE
|
||||
{"hexsum8", hexsum, 0x00, 0x00, 1} // 0x2D
|
||||
{"hexsum8", hexsum, 0x00, 0x00, 1}, // 0x2D
|
||||
{"cpi", CPI, 0x00, 0x00, 1}, // 0x7E
|
||||
{"leybold", leybold, 0x00, 0x00, 1}, // 0x22
|
||||
{"brksCryo",brksCryo, 0x00, 0x00, 1}, // 0x4A
|
||||
{"lrc", lrc, 0x00, 0x00, 1}, // 0x23
|
||||
{"hexlrc", hexlrc, 0x00, 0x00, 1}, // 0xA7
|
||||
{"bitsum", bitsum, 0x00, 0x00, 1}, // 0x21
|
||||
{"bitsum8", bitsum, 0x00, 0x00, 1}, // 0x21
|
||||
{"bitsum16",bitsum, 0x0000, 0x0000, 2}, // 0x0021
|
||||
{"bitsum32",bitsum, 0x00000000, 0x00000000, 4}, // 0x00000021
|
||||
{"hv_mps", hv_mps, 0xFF, 0x00, 1} // 0x63
|
||||
};
|
||||
|
||||
static unsigned int mask[5] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF};
|
||||
static uint32_t mask[5] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF};
|
||||
|
||||
class ChecksumConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool scanFormat);
|
||||
bool printPseudo(const StreamFormat&, StreamBuffer&);
|
||||
int scanPseudo(const StreamFormat&, StreamBuffer&, long& cursor);
|
||||
ssize_t scanPseudo(const StreamFormat&, StreamBuffer&, size_t& cursor);
|
||||
};
|
||||
|
||||
int ChecksumConverter::
|
||||
parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
|
||||
parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool scanFormat)
|
||||
{
|
||||
const char* p = strchr(source, '>');
|
||||
if (!p)
|
||||
@ -522,9 +719,9 @@ parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
|
||||
source+=3;
|
||||
notflag = true;
|
||||
}
|
||||
unsigned fnum;
|
||||
int len = p-source;
|
||||
unsigned int init, xorout;
|
||||
uint8_t fnum;
|
||||
size_t len = p-source;
|
||||
uint32_t init, xorout;
|
||||
for (fnum = 0; fnum < sizeof(checksumMap)/sizeof(checksum); fnum++)
|
||||
{
|
||||
if ((strncasecmp(source, checksumMap[fnum].name, len) == 0) ||
|
||||
@ -545,58 +742,63 @@ parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
|
||||
info.append(&xorout, sizeof(xorout));
|
||||
info.append(fnum);
|
||||
source = p+1;
|
||||
return pseudo_format;
|
||||
return scanFormat ? needs_original_format : pseudo_format;
|
||||
}
|
||||
}
|
||||
|
||||
error ("Unknown checksum algorithm \"%.*s\"\n", len, source);
|
||||
error ("Unknown checksum algorithm \"%.*s\"\n", (int)len, source);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChecksumConverter::
|
||||
printPseudo(const StreamFormat& format, StreamBuffer& output)
|
||||
{
|
||||
unsigned int sum;
|
||||
uint32_t sum;
|
||||
const char* info = format.info;
|
||||
unsigned int init = extract<unsigned int>(info);
|
||||
unsigned int xorout = extract<unsigned int>(info);
|
||||
int fnum = extract<char>(info);
|
||||
uint32_t init = extract<uint32_t>(info);
|
||||
uint32_t xorout = extract<uint32_t>(info);
|
||||
uint8_t fnum = extract<uint8_t>(info);
|
||||
|
||||
int start = format.width;
|
||||
int length = output.length()-format.width;
|
||||
if (format.prec > 0) length -= format.prec;
|
||||
size_t start = format.width;
|
||||
size_t length = output.length();
|
||||
if (length >= start) length -= start;
|
||||
else length = 0;
|
||||
if (format.prec > 0) {
|
||||
if (length >= (size_t)format.prec) length -= format.prec;
|
||||
else length = 0;
|
||||
}
|
||||
|
||||
debug("ChecksumConverter %s: output to check: \"%s\"\n",
|
||||
checksumMap[fnum].name, output.expand(start,length)());
|
||||
|
||||
|
||||
sum = (xorout ^ checksumMap[fnum].func(
|
||||
reinterpret_cast<unsigned char*>(output(start)), length, init))
|
||||
reinterpret_cast<uint8_t*>(output(start)), length, init))
|
||||
& mask[checksumMap[fnum].bytes];
|
||||
|
||||
debug("ChecksumConverter %s: output checksum is 0x%X\n",
|
||||
debug("ChecksumConverter %s: output checksum is 0x%" PRIX32 "\n",
|
||||
checksumMap[fnum].name, sum);
|
||||
|
||||
int i;
|
||||
unsigned outchar;
|
||||
|
||||
uint8_t i;
|
||||
uint8_t outchar;
|
||||
|
||||
if (format.flags & sign_flag) // decimal
|
||||
{
|
||||
// get number of decimal digits from number of bytes: ceil(xbytes*2.5)
|
||||
// get number of decimal digits from number of bytes: ceil(bytes*2.5)
|
||||
i = (checksumMap[fnum].bytes+1)*25/10-2;
|
||||
output.print("%0*d", i, sum);
|
||||
debug("ChecksumConverter %s: decimal appending %0*d\n",
|
||||
output.print("%0*" PRIu32, i, sum);
|
||||
debug("ChecksumConverter %s: decimal appending %0*" PRIu32 "\n",
|
||||
checksumMap[fnum].name, i, sum);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (format.flags & alt_flag) // lsb first (little endian)
|
||||
{
|
||||
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
||||
{
|
||||
outchar = sum & 0xff;
|
||||
debug("ChecksumConverter %s: little endian appending 0x%X\n",
|
||||
debug("ChecksumConverter %s: little endian appending 0x%02" PRIX8 "\n",
|
||||
checksumMap[fnum].name, outchar);
|
||||
if (format.flags & zero_flag) // ASCII
|
||||
output.print("%02X", outchar);
|
||||
output.print("%02" PRIX8, outchar);
|
||||
else
|
||||
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
||||
output.print("%c%c",
|
||||
@ -612,10 +814,10 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
|
||||
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
||||
{
|
||||
outchar = (sum >> 24) & 0xff;
|
||||
debug("ChecksumConverter %s: big endian appending 0x%X\n",
|
||||
debug("ChecksumConverter %s: big endian appending 0x02%" PRIX8 "\n",
|
||||
checksumMap[fnum].name, outchar);
|
||||
if (format.flags & zero_flag) // ASCII
|
||||
output.print("%02X", outchar);
|
||||
output.print("%02" PRIX8, outchar);
|
||||
else
|
||||
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
||||
output.print("%c%c",
|
||||
@ -628,48 +830,53 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
|
||||
return true;
|
||||
}
|
||||
|
||||
int ChecksumConverter::
|
||||
scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
||||
ssize_t ChecksumConverter::
|
||||
scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
|
||||
{
|
||||
unsigned int sum;
|
||||
uint32_t sum;
|
||||
const char* info = format.info;
|
||||
unsigned int init = extract<unsigned int>(info);
|
||||
unsigned int xorout = extract<unsigned int>(info);
|
||||
int start = format.width;
|
||||
int fnum = extract<char>(info);
|
||||
int length = cursor-format.width;
|
||||
uint32_t init = extract<uint32_t>(info);
|
||||
uint32_t xorout = extract<uint32_t>(info);
|
||||
size_t start = format.width;
|
||||
uint8_t fnum = extract<uint8_t>(info);
|
||||
size_t length = cursor;
|
||||
if (length >= start) length -= start;
|
||||
else length = 0;
|
||||
if (format.prec > 0) {
|
||||
if (length >= (size_t)format.prec) length -= format.prec;
|
||||
else length = 0;
|
||||
}
|
||||
|
||||
if (format.prec > 0) length -= format.prec;
|
||||
|
||||
debug("ChecksumConverter %s: input to check: \"%s\n",
|
||||
debug("ChecksumConverter %s: input to check: \"%s\"\n",
|
||||
checksumMap[fnum].name, input.expand(start,length)());
|
||||
|
||||
int expectedLength =
|
||||
uint8_t nDigits =
|
||||
// get number of decimal digits from number of bytes: ceil(bytes*2.5)
|
||||
format.flags & sign_flag ? (checksumMap[fnum].bytes + 1) * 25 / 10 - 2 :
|
||||
format.flags & (zero_flag|left_flag) ? 2 * checksumMap[fnum].bytes :
|
||||
checksumMap[fnum].bytes;
|
||||
|
||||
if (input.length() - cursor < expectedLength)
|
||||
ssize_t expectedLength = nDigits;
|
||||
|
||||
if ((ssize_t)( input.length() - cursor ) < expectedLength)
|
||||
{
|
||||
debug("ChecksumConverter %s: Input '%s' too short for checksum\n",
|
||||
checksumMap[fnum].name, input.expand(cursor)());
|
||||
debug("ChecksumConverter %s: Input '%s' too short (%zu-%zu<%zu) for checksum\n",
|
||||
checksumMap[fnum].name, input.expand(cursor)(), input.length(), cursor, expectedLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sum = (xorout ^ checksumMap[fnum].func(
|
||||
reinterpret_cast<unsigned char*>(input(start)), length, init))
|
||||
(uint8_t*)input(start), length, init))
|
||||
& mask[checksumMap[fnum].bytes];
|
||||
|
||||
debug("ChecksumConverter %s: input checksum is 0x%0*X\n",
|
||||
debug("ChecksumConverter %s: input checksum is 0x%0*" PRIX32 "\n",
|
||||
checksumMap[fnum].name, 2*checksumMap[fnum].bytes, sum);
|
||||
|
||||
int i, j;
|
||||
unsigned inchar;
|
||||
|
||||
unsigned int inchar;
|
||||
|
||||
if (format.flags & sign_flag) // decimal
|
||||
{
|
||||
unsigned int sumin = 0;
|
||||
uint32_t sumin = 0;
|
||||
ssize_t i;
|
||||
for (i = 0; i < expectedLength; i++)
|
||||
{
|
||||
inchar = input[cursor+i];
|
||||
@ -678,21 +885,22 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
||||
}
|
||||
if (sumin != sum)
|
||||
{
|
||||
debug("ChecksumConverter %s: Input %0*u does not match checksum %0*u\n",
|
||||
checksumMap[fnum].name, i, sumin, expectedLength, sum);
|
||||
debug("ChecksumConverter %s: Input %0*" PRIu32 " does not match checksum %0*" PRIu32 "\n",
|
||||
checksumMap[fnum].name, (int)i, sumin, (int)expectedLength, sum);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
if (format.flags & alt_flag) // lsb first (little endian)
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
||||
{
|
||||
if (format.flags & zero_flag) // ASCII
|
||||
{
|
||||
if (sscanf(input(cursor+2*i), "%2X", &inchar) != 1)
|
||||
if (sscanf(input(cursor+2*i), "%2x", &inchar) != 1)
|
||||
{
|
||||
debug("ChecksumConverter %s: Input byte '%s' is not a hex byte\n",
|
||||
debug("ChecksumConverter %s: Input byte '%s' is not a hex byte\n",
|
||||
checksumMap[fnum].name, input.expand(cursor+2*i,2)());
|
||||
return -1;
|
||||
}
|
||||
@ -702,13 +910,13 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
||||
{
|
||||
if ((input[cursor+2*i] & 0xf0) != 0x30)
|
||||
{
|
||||
debug("ChecksumConverter %s: Input byte 0x%02X is not in range 0x30 - 0x3F\n",
|
||||
debug("ChecksumConverter %s: Input byte 0x%02" PRIX8 " is not in range 0x30 - 0x3F\n",
|
||||
checksumMap[fnum].name, input[cursor+2*i]);
|
||||
return -1;
|
||||
}
|
||||
if ((input[cursor+2*i+1] & 0xf0) != 0x30)
|
||||
{
|
||||
debug("ChecksumConverter %s: Input byte 0x%02X is not in range 0x30 - 0x3F\n",
|
||||
debug("ChecksumConverter %s: Input byte 0x%02" PRIX8 " is not in range 0x30 - 0x3F\n",
|
||||
checksumMap[fnum].name, input[cursor+2*i+1]);
|
||||
return -1;
|
||||
}
|
||||
@ -720,7 +928,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
||||
}
|
||||
if (inchar != ((sum >> 8*i) & 0xff))
|
||||
{
|
||||
debug("ChecksumConverter %s: Input byte 0x%02X does not match checksum 0x%0*X\n",
|
||||
debug("ChecksumConverter %s: Input byte 0x%02" PRIX8 " does not match checksum 0x%0*" PRIX32 "\n",
|
||||
checksumMap[fnum].name, inchar, 2*checksumMap[fnum].bytes, sum);
|
||||
return -1;
|
||||
}
|
||||
@ -728,6 +936,8 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
||||
}
|
||||
else // msb first (big endian)
|
||||
{
|
||||
int8_t i;
|
||||
uint8_t j;
|
||||
for (i = checksumMap[fnum].bytes-1, j = 0; i >= 0; i--, j++)
|
||||
{
|
||||
if (format.flags & zero_flag) // ASCII
|
||||
@ -739,13 +949,13 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
||||
{
|
||||
if ((input[cursor+2*i] & 0xf0) != 0x30)
|
||||
{
|
||||
debug("ChecksumConverter %s: Input byte 0x%02X is not in range 0x30 - 0x3F\n",
|
||||
debug("ChecksumConverter %s: Input byte 0x%02" PRIX8 " is not in range 0x30 - 0x3F\n",
|
||||
checksumMap[fnum].name, input[cursor+2*i]);
|
||||
return -1;
|
||||
}
|
||||
if ((input[cursor+2*i+1] & 0xf0) != 0x30)
|
||||
{
|
||||
debug("ChecksumConverter %s: Input byte 0x%02X is not in range 0x30 - 0x3F\n",
|
||||
debug("ChecksumConverter %s: Input byte 0x%02" PRIX8 " is not in range 0x30 - 0x3F\n",
|
||||
checksumMap[fnum].name, input[cursor+2*i+1]);
|
||||
return -1;
|
||||
}
|
||||
@ -757,7 +967,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
||||
}
|
||||
if (inchar != ((sum >> 8*j) & 0xff))
|
||||
{
|
||||
debug("ChecksumConverter %s: Input byte 0x%02X does not match checksum 0x%0*X\n",
|
||||
debug("ChecksumConverter %s: Input byte 0x%02" PRIX8 " does not match checksum 0x%0*" PRIX32 "\n",
|
||||
checksumMap[fnum].name, inchar, 2*checksumMap[fnum].bytes, sum);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,26 +1,31 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the interface to a debug and example bus drivers for *
|
||||
* StreamDevice. Please refer to the HTML files in ../doc/ for *
|
||||
* a detailed documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is a debug and example bus interface for StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include "StreamBusInterface.h"
|
||||
#include "StreamError.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
#define Z PRINTF_SIZE_T_PREFIX
|
||||
|
||||
// This is a non-blocking bus interface for debugging purpose.
|
||||
// Normally, a bus interface will use blocking I/O and thus require
|
||||
// a separate thread.
|
||||
@ -35,7 +40,7 @@ class DebugInterface : StreamBusInterface
|
||||
bool writeRequest(const void* output, size_t size,
|
||||
unsigned long writeTimeout_ms);
|
||||
bool readRequest(unsigned long replyTimeout_ms,
|
||||
unsigned long readTimeout_ms, long expectedLength, bool async);
|
||||
unsigned long readTimeout_ms, ssize_t expectedLength, bool async);
|
||||
|
||||
protected:
|
||||
~DebugInterface();
|
||||
@ -167,9 +172,9 @@ writeRequest(const void* output, size_t size, unsigned long writeTimeout_ms)
|
||||
// Return false if the read request cannot be accepted.
|
||||
bool DebugInterface::
|
||||
readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
||||
long expectedLength, bool async)
|
||||
ssize_t expectedLength, bool async)
|
||||
{
|
||||
debug("DebugInterface::readRequest(%s, %ld msec reply, %ld msec read, expect %ld bytes, asyn=%s)\n",
|
||||
debug("DebugInterface::readRequest(%s, %ld msec reply, %ld msec read, expect %" Z "d bytes, asyn=%s)\n",
|
||||
clientName(), replyTimeout_ms, readTimeout_ms, expectedLength, async?"yes":"no");
|
||||
|
||||
// Debug interface does not support async mode.
|
||||
|
@ -1,20 +1,25 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 2011 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the interface to a "dummy" bus driver for *
|
||||
* StreamDevice. It does not provide any I/O functionality. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is a debug and example bus interface for StreamDevice.
|
||||
* It does not provide any I/O functionality.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include "StreamBusInterface.h"
|
||||
#include "StreamError.h"
|
||||
|
@ -1,27 +1,30 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the enum format converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the enum format converter of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
#include "StreamProtocol.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// Enum %{string0|string1|...}
|
||||
|
||||
@ -29,14 +32,14 @@ class EnumConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||
int scanLong(const StreamFormat&, const char*, long&);
|
||||
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||
};
|
||||
|
||||
// info format: <numEnums><index><string>0<index><string>0...
|
||||
|
||||
int EnumConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool)
|
||||
const char*& source, bool scanFormat)
|
||||
{
|
||||
if (fmt.flags & (left_flag|sign_flag|space_flag|zero_flag))
|
||||
{
|
||||
@ -45,10 +48,10 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
return false;
|
||||
}
|
||||
long numEnums = 0;
|
||||
int n = info.length(); // put numEnums here later
|
||||
size_t n = info.length(); // put numEnums here later
|
||||
info.append(&numEnums, sizeof(numEnums));
|
||||
long index = 0;
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
i = info.length(); // put index here later
|
||||
info.append(&index, sizeof(index));
|
||||
while (*source)
|
||||
@ -56,7 +59,30 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
if (*source == '=' && (fmt.flags & alt_flag))
|
||||
{
|
||||
char* p;
|
||||
index = strtol(++source, &p, 0);
|
||||
|
||||
if (*++source == '?')
|
||||
{
|
||||
// default choice
|
||||
if (scanFormat)
|
||||
{
|
||||
error("Default value only allowed in output formats\n");
|
||||
return false;
|
||||
}
|
||||
if (*++source != '}')
|
||||
{
|
||||
error("Default value must be last\n");
|
||||
return false;
|
||||
}
|
||||
source++;
|
||||
numEnums = -(numEnums+1);
|
||||
info.append('\0');
|
||||
memcpy(info(n), &numEnums, sizeof(numEnums));
|
||||
debug2("EnumConverter::parse %ld choices with default: %s\n",
|
||||
-numEnums, info.expand()());
|
||||
return enum_format;
|
||||
}
|
||||
|
||||
index = strtol(source, &p, 0);
|
||||
if (p == source || (*p != '|' && *p != '}'))
|
||||
{
|
||||
error("Integer expected after '=' "
|
||||
@ -70,15 +96,15 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
{
|
||||
numEnums++;
|
||||
info.append('\0');
|
||||
|
||||
|
||||
if (*source++ == '}')
|
||||
{
|
||||
memcpy(info(n), &numEnums, sizeof(numEnums));
|
||||
debug("EnumConverter::parse %ld choices: %s\n",
|
||||
debug2("EnumConverter::parse %ld choices: %s\n",
|
||||
numEnums, info.expand()());
|
||||
return enum_format;
|
||||
}
|
||||
index ++;
|
||||
index++;
|
||||
i = info.length();
|
||||
info.append(&index, sizeof(index));
|
||||
}
|
||||
@ -99,9 +125,12 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
const char* s = fmt.info;
|
||||
long numEnums = extract<long>(s);
|
||||
long index = extract<long>(s);
|
||||
bool noDefault = numEnums >= 0;
|
||||
|
||||
if (numEnums < 0) numEnums=-numEnums-1;
|
||||
while (numEnums-- && (value != index))
|
||||
{
|
||||
while(*s)
|
||||
while (*s)
|
||||
{
|
||||
if (*s == esc) s++;
|
||||
s++;
|
||||
@ -109,12 +138,12 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
s++;
|
||||
index = extract<long>(s);
|
||||
}
|
||||
if (numEnums == -1)
|
||||
if (numEnums == -1 && noDefault)
|
||||
{
|
||||
error("Value %li not found in enum set\n", value);
|
||||
return false;
|
||||
}
|
||||
while(*s)
|
||||
while (*s)
|
||||
{
|
||||
if (*s == esc) s++;
|
||||
output.append(*s++);
|
||||
@ -122,7 +151,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
return true;
|
||||
}
|
||||
|
||||
int EnumConverter::
|
||||
ssize_t EnumConverter::
|
||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
{
|
||||
debug("EnumConverter::scanLong(%%%c, \"%s\")\n",
|
||||
@ -130,31 +159,31 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
const char* s = fmt.info;
|
||||
long numEnums = extract<long>(s);
|
||||
long index;
|
||||
int length;
|
||||
|
||||
ssize_t consumed;
|
||||
bool match;
|
||||
|
||||
while (numEnums--)
|
||||
{
|
||||
index = extract<long>(s);
|
||||
debug("EnumConverter::scanLong: check #%ld \"%s\"\n", index, s);
|
||||
length = 0;
|
||||
consumed = 0;
|
||||
match = true;
|
||||
while(*s)
|
||||
while (*s)
|
||||
{
|
||||
if (*s == StreamProtocolParser::skip)
|
||||
{
|
||||
s++;
|
||||
length++;
|
||||
consumed++;
|
||||
continue;
|
||||
}
|
||||
if (*s == esc) s++;
|
||||
if (*s++ != input[length++]) match = false;
|
||||
if (*s++ != input[consumed++]) match = false;
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
debug("EnumConverter::scanLong: value %ld matches\n", index);
|
||||
value = index;
|
||||
return length;
|
||||
return consumed;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
101
src/MacroMagic.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*************************************************************************
|
||||
* This header provides macros for enum to string conversions.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef _MacroMagic_h
|
||||
#define _MacroMagic_h
|
||||
|
||||
#if defined __GNUC__ && __GNUC__ < 3
|
||||
|
||||
/* Using old GCC variadic macros */
|
||||
|
||||
#define _NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, N, args...) N
|
||||
|
||||
#define _fe_0(_call, args...)
|
||||
#define _fe_1(_call, x) _call(x)
|
||||
#define _fe_2(_call, x, args...) _call(x) _fe_1(_call, args)
|
||||
#define _fe_3(_call, x, args...) _call(x) _fe_2(_call, args)
|
||||
#define _fe_4(_call, x, args...) _call(x) _fe_3(_call, args)
|
||||
#define _fe_5(_call, x, args...) _call(x) _fe_4(_call, args)
|
||||
#define _fe_6(_call, x, args...) _call(x) _fe_5(_call, args)
|
||||
#define _fe_7(_call, x, args...) _call(x) _fe_6(_call, args)
|
||||
#define _fe_8(_call, x, args...) _call(x) _fe_7(_call, args)
|
||||
#define _fe_9(_call, x, args...) _call(x) _fe_8(_call, args)
|
||||
#define _fe_10(_call, x, args...) _call(x) _fe_9(_call, args)
|
||||
|
||||
#define MACRO_FOR_EACH(x, args...) \
|
||||
_NTH_ARG(_, ##args, \
|
||||
_fe_10, _fe_9, _fe_8, _fe_7, _fe_6, _fe_5, _fe_4, _fe_3, _fe_2, _fe_1, _fe_0) \
|
||||
(x, ##args)
|
||||
|
||||
/* Enum to string magic */
|
||||
|
||||
#define ENUM(type, args...) \
|
||||
enum type { args }; \
|
||||
static inline const char* type##ToStr(int x) {switch(x) {MACRO_FOR_EACH(_CASE_LINE,args)default: return "invalid";}}\
|
||||
_ENUM_CAST(type)
|
||||
|
||||
#else
|
||||
|
||||
/* Using ISO C variadic macros */
|
||||
|
||||
#define _NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, N, ...) N
|
||||
|
||||
/*
|
||||
* we need to use _EXPAND below to work around a problem in Visual Studio 2010
|
||||
* where __VA_ARGS__ is treated as a single argument
|
||||
* See https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
|
||||
*/
|
||||
#define _EXPAND( x ) x
|
||||
|
||||
#define _fe_0(_call, ...)
|
||||
#define _fe_1(_call, x) _call(x)
|
||||
#define _fe_2(_call, x, ...) _call(x) _EXPAND(_fe_1(_call, __VA_ARGS__))
|
||||
#define _fe_3(_call, x, ...) _call(x) _EXPAND(_fe_2(_call, __VA_ARGS__))
|
||||
#define _fe_4(_call, x, ...) _call(x) _EXPAND(_fe_3(_call, __VA_ARGS__))
|
||||
#define _fe_5(_call, x, ...) _call(x) _EXPAND(_fe_4(_call, __VA_ARGS__))
|
||||
#define _fe_6(_call, x, ...) _call(x) _EXPAND(_fe_5(_call, __VA_ARGS__))
|
||||
#define _fe_7(_call, x, ...) _call(x) _EXPAND(_fe_6(_call, __VA_ARGS__))
|
||||
#define _fe_8(_call, x, ...) _call(x) _EXPAND(_fe_7(_call, __VA_ARGS__))
|
||||
#define _fe_9(_call, x, ...) _call(x) _EXPAND(_fe_8(_call, __VA_ARGS__))
|
||||
#define _fe_10(_call, x, ...) _call(x) _EXPAND(_fe_9(_call, __VA_ARGS__))
|
||||
|
||||
#define MACRO_FOR_EACH(x, ...) \
|
||||
_EXPAND(_NTH_ARG(_, ##__VA_ARGS__, \
|
||||
_fe_10, _fe_9, _fe_8, _fe_7, _fe_6, _fe_5, _fe_4, _fe_3, _fe_2, _fe_1, _fe_0) \
|
||||
(x, ##__VA_ARGS__))
|
||||
|
||||
/* Enum to string magic */
|
||||
|
||||
#define ENUM(type,...) \
|
||||
enum type { __VA_ARGS__ }; \
|
||||
static inline const char* type##ToStr(int x) {switch(x) {_EXPAND(MACRO_FOR_EACH(_CASE_LINE,__VA_ARGS__)) default: return "invalid";}} \
|
||||
_ENUM_CAST(type)
|
||||
#endif
|
||||
|
||||
#define _CASE_LINE(x) case x: return #x;
|
||||
#ifdef __cplusplus
|
||||
#define _ENUM_CAST(type) ; static inline const char* toStr(type x) {return type##ToStr(x);}
|
||||
#else
|
||||
#define _ENUM_CAST(type)
|
||||
#endif
|
||||
|
||||
#endif
|
131
src/Makefile
@ -1,60 +1,52 @@
|
||||
################################################################
|
||||
# StreamDevice Support #
|
||||
# #
|
||||
# (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) #
|
||||
# (C) 2007 Dirk Zimoch (dirk.zimoch@psi.ch) #
|
||||
# #
|
||||
# This is the EPICS 3.14 Makefile of StreamDevice. #
|
||||
# Normally it should not be necessary to modify this file. #
|
||||
# All configuration can be done in CONFIG_STREAM #
|
||||
# #
|
||||
# If you do any changes in this file, you are not allowed to #
|
||||
# redistribute it any more. If there is a bug or a missing #
|
||||
# feature, send me an email and/or your patch. If I accept #
|
||||
# your changes, they will go to the next release. #
|
||||
# #
|
||||
# DISCLAIMER: If this software breaks something or harms #
|
||||
# someone, it's your problem. #
|
||||
# #
|
||||
################################################################
|
||||
##########################################################################
|
||||
# This is the EPICS 3.14+ Makefile for StreamDevice.
|
||||
# Normally it should not be necessary to modify this file.
|
||||
# All configuration can be done in CONFIG_STREAM
|
||||
#
|
||||
# (C) 2007,2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
#
|
||||
# This file is part of StreamDevice.
|
||||
#
|
||||
# StreamDevice is free software: You can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# StreamDevice is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
#########################################################################/
|
||||
|
||||
TOP=../..
|
||||
|
||||
# Look if we have EPICS R3.13 or R3.14
|
||||
ifeq ($(wildcard $(TOP)/configure),)
|
||||
# EPICS R3.13
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
# The real work is in Makefile.Vx
|
||||
include $(TOP)/config/RULES_ARCHS
|
||||
else
|
||||
|
||||
# EPICS R3.14
|
||||
TOP= ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
-include CONFIG_STREAM
|
||||
-include ../CONFIG_STREAM
|
||||
|
||||
LIBRARY_DEFAULT = stream
|
||||
LIBRARY_IOC = stream
|
||||
|
||||
DBD += $(LIBRARY_DEFAULT).dbd
|
||||
DBD += stream.dbd
|
||||
DBD += stream-base.dbd
|
||||
ifneq ($(words $(CALC) $(SYNAPPS)), 0)
|
||||
DBD += stream-scalcout.dbd
|
||||
endif
|
||||
|
||||
ifdef ASYN
|
||||
LIB_LIBS += asyn
|
||||
BUSSES += AsynDriver
|
||||
endif
|
||||
|
||||
ifdef T_A
|
||||
ifndef BUSSES
|
||||
$(error No bus interface defined! Didn't you set ASYN in your RELEASE file?)
|
||||
endif
|
||||
else
|
||||
$(warning Asyn not included! Didn't you set ASYN in your RELEASE file?)
|
||||
endif
|
||||
|
||||
ifeq ($(LOADABLE_MODULE),YES)
|
||||
SRCS += $(LIBRARY_DEFAULT)_registerRecordDeviceDriver.cpp
|
||||
endif
|
||||
SRCS += stream_registerRecordDeviceDriver.cpp
|
||||
endif
|
||||
SRCS += $(BUSSES:%=%Interface.cc)
|
||||
SRCS += $(FORMATS:%=%Converter.cc)
|
||||
SRCS += $(RECORDS:%=dev%Stream.c)
|
||||
SRCS += $(RECORDTYPES:%=dev%Stream.c)
|
||||
SRCS += $(STREAM_SRCS)
|
||||
|
||||
# find system wide or local PCRE header and library
|
||||
@ -68,18 +60,37 @@ ifneq ($(words $(PCRE_LIB) $(PCRE_INCLUDE)),0)
|
||||
LIB_SYS_LIBS_DEFAULT += pcre
|
||||
LIB_SYS_LIBS_WIN32 += $(PCRE_LIB)\\pcre
|
||||
SHRLIB_DEPLIB_DIRS += $(PCRE_LIB)
|
||||
ifdef ENABLE_STATIC
|
||||
CPPFLAGS += -DPCRE_STATIC
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
LIB_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
INC += devStream.h
|
||||
INC += StreamFormat.h
|
||||
INC += StreamFormatConverter.h
|
||||
INC += StreamBuffer.h
|
||||
INC += StreamError.h
|
||||
INC += StreamVersion.h
|
||||
INC += StreamProtocol.h
|
||||
INC += StreamBusInterface.h
|
||||
INC += StreamCore.h
|
||||
INC += MacroMagic.h
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
# switch off annoying rset warnings in 3.16+
|
||||
CPPFLAGS += -DUSE_TYPED_RSET
|
||||
|
||||
# Update version string (contains __DATE__ and __TIME__)
|
||||
# each time make runs.
|
||||
StreamVersion$(OBJ): ../*.c ../*.h ../*.cc ../CONFIG_STREAM ../Makefile
|
||||
CPPFLAGS += -DSTREAM_INTERNAL
|
||||
|
||||
-include $(TOP)/configure/RULES
|
||||
|
||||
# Update version string whenever something changed.
|
||||
StreamVersion$(OBJ): $(COMMON_DIR)/StreamVersion.h $(filter-out StreamVersion$(OBJ),$(LIBOBJS) $(LIBRARY_OBJS)) ../CONFIG_STREAM
|
||||
$(COMMON_DIR)/StreamVersion.h: ../../.VERSION $(SRCS) $(filter-out StreamVersion.h, $(INC))
|
||||
@echo Creating $@
|
||||
$(PERL) ../makeStreamVersion.pl $@
|
||||
|
||||
# Add references to all registrars to main file to avoid
|
||||
# missing initialization.
|
||||
@ -89,11 +100,29 @@ streamReferences: ../CONFIG_STREAM
|
||||
$(PERL) ../makeref.pl Interface $(BUSSES) > $@
|
||||
$(PERL) ../makeref.pl Converter $(FORMATS) >> $@
|
||||
|
||||
# create stream.dbd from all RECORDS
|
||||
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM
|
||||
$(PERL) ../makedbd.pl $(RECORDS) > $@
|
||||
# create stream-base.dbd from all RECORDTYPES except scalcout record
|
||||
$(COMMON_DIR)/stream-base.dbd: ../CONFIG_STREAM
|
||||
$(PERL) ../makedbd.pl $(if $(ASYN),--with-asyn) $(if $(BASE_3_14),,-3.13) $(filter-out scalcout, $(RECORDTYPES)) > $@
|
||||
|
||||
$(LIBRARY_DEFAULT).dbd$(DEP): ../CONFIG_STREAM
|
||||
echo $(LIBRARY_DEFAULT).dbd: $< > $@
|
||||
stream-base.dbd$(DEP): ../CONFIG_STREAM
|
||||
echo stream-base.dbd: $< > $@
|
||||
|
||||
STREAM_DBD_FILES = stream-base.dbd
|
||||
|
||||
ifneq ($(words $(CALC) $(SYNAPPS)), 0)
|
||||
# create stream-scalcout.dbd for scalcout record
|
||||
$(COMMON_DIR)/stream-scalcout.dbd: ../CONFIG_STREAM
|
||||
$(PERL) ../makedbd.pl --rec-only scalcout > $@
|
||||
|
||||
stream-scalcout.dbd$(DEP): ../CONFIG_STREAM
|
||||
echo stream-scalcout.dbd: $< > $@
|
||||
|
||||
STREAM_DBD_FILES += stream-scalcout.dbd
|
||||
endif
|
||||
|
||||
# create stream.dbd for all record types
|
||||
$(COMMON_DIR)/stream.dbd: ../CONFIG_STREAM
|
||||
$(PERL) ../makedbd.pl $(if $(ASYN),--with-asyn) $(if $(BASE_3_14),,-3.13) $(RECORDTYPES) > $@
|
||||
|
||||
stream.dbd$(DEP): ../CONFIG_STREAM
|
||||
echo stream.dbd: $< > $@
|
||||
|
@ -1,42 +1,32 @@
|
||||
################################################################
|
||||
# StreamDevice Support #
|
||||
# #
|
||||
# (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) #
|
||||
# (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) #
|
||||
# #
|
||||
# This is the EPICS 3.13 Makefile of StreamDevice. #
|
||||
# Normally it should not be necessary to modify this file. #
|
||||
# All configuration can be done in CONFIG_STREAM #
|
||||
# #
|
||||
# If you do any changes in this file, you are not allowed to #
|
||||
# redistribute it any more. If there is a bug or a missing #
|
||||
# feature, send me an email and/or your patch. If I accept #
|
||||
# your changes, they will go to the next release. #
|
||||
# #
|
||||
# DISCLAIMER: If this software breaks something or harms #
|
||||
# someone, it's your problem. #
|
||||
# #
|
||||
################################################################
|
||||
##########################################################################
|
||||
# This is an EPICS 3.13 Makefile for StreamDevice.
|
||||
# Normally it should not be necessary to modify this file.
|
||||
# All configuration can be done in CONFIG_STREAM
|
||||
#
|
||||
# (C) 2007,2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
#
|
||||
# This file is part of StreamDevice.
|
||||
#
|
||||
# StreamDevice is free software: You can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# StreamDevice is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
#########################################################################/
|
||||
|
||||
TOP = ../..
|
||||
ifneq ($(wildcard ../../../config),)
|
||||
TOP = ../../..
|
||||
endif
|
||||
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
include ../CONFIG_STREAM
|
||||
|
||||
# In 3.13, calcout has no device support
|
||||
RECORDS_3_13 = $(filter-out calcout,$(RECORDS))
|
||||
|
||||
DBDNAME = stream.dbd
|
||||
|
||||
INC += devStream.h
|
||||
|
||||
# This is the munch.pl taken from EPICS 3.14.8.2
|
||||
# Install script and rule.
|
||||
CONFIGS = RULES.munch
|
||||
SCRIPTS = munch.pl
|
||||
|
||||
include $(TOP)/config/RULES.Host
|
||||
|
||||
# create stream.dbd from all RECORDS
|
||||
stream.dbd: ../CONFIG_STREAM
|
||||
$(PERL) ../makedbd.pl -3.13 $(RECORDS_3_13) > $@
|
||||
include $(EPICS_BASE)/config/RULES.Host
|
||||
|
@ -1,58 +1,78 @@
|
||||
################################################################
|
||||
# StreamDevice Support #
|
||||
# #
|
||||
# (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) #
|
||||
# (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) #
|
||||
# #
|
||||
# This is the EPICS 3.13 Makefile of StreamDevice. #
|
||||
# Normally it should not be necessary to modify this file. #
|
||||
# All configuration can be done in CONFIG_STREAM #
|
||||
# #
|
||||
# If you do any changes in this file, you are not allowed to #
|
||||
# redistribute it any more. If there is a bug or a missing #
|
||||
# feature, send me an email and/or your patch. If I accept #
|
||||
# your changes, they will go to the next release. #
|
||||
# #
|
||||
# DISCLAIMER: If this software breaks something or harms #
|
||||
# someone, it's your problem. #
|
||||
# #
|
||||
################################################################
|
||||
##########################################################################
|
||||
# This is an EPICS 3.13 Makefile for StreamDevice.
|
||||
# Normally it should not be necessary to modify this file.
|
||||
# All configuration can be done in CONFIG_STREAM
|
||||
#
|
||||
# (C) 2007,2018 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
#
|
||||
# This file is part of StreamDevice.
|
||||
#
|
||||
# StreamDevice is free software: You can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# StreamDevice is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
#########################################################################/
|
||||
|
||||
TOP = ../..
|
||||
ifneq ($(wildcard ../../../config),)
|
||||
TOP = ../../..
|
||||
endif
|
||||
|
||||
include $(TOP)/config/CONFIG_APP
|
||||
include ../CONFIG_STREAM
|
||||
|
||||
CXXCMPLR=NORMAL
|
||||
G++_NORMAL = $(G++)
|
||||
|
||||
LIBNAME = streamLib
|
||||
|
||||
# In 3.13, calcout has no device support
|
||||
RECORDS_3_13 = $(filter-out calcout,$(RECORDS))
|
||||
|
||||
ifdef ASYN
|
||||
BUSSES += AsynDriver
|
||||
endif
|
||||
|
||||
SRCS.cc += $(patsubst %,../%,$(filter %.cc,$(STREAM_SRCS)))
|
||||
SRCS.cc += $(BUSSES:%=../%Interface.cc)
|
||||
SRCS.cc += $(FORMATS:%=../%Converter.cc)
|
||||
SRCS.c += $(patsubst %,../%,$(filter %.c,$(STREAM_SRCS)))
|
||||
SRCS.c += $(RECORDS_3_13:%=../dev%Stream.c)
|
||||
SRCS.cc += $(filter %.cc,$(STREAM_SRCS:%=%../%))
|
||||
SRCS.c += $(RECORDTYPES:%=../dev%Stream.c)
|
||||
SRCS.c += $(filter %.c,$(STREAM_SRCS:%=%../%))
|
||||
|
||||
LIBOBJS = $(patsubst ../%,%.o,$(basename $(SRCS.cc) $(SRCS.c)))
|
||||
|
||||
include $(TOP)/config/RULES.Vx
|
||||
include $(TOP)/config/RULES.munch
|
||||
DBDNAME = stream.dbd
|
||||
|
||||
build:: depends
|
||||
INC += devStream.h
|
||||
INC += StreamFormat.h
|
||||
INC += StreamFormatConverter.h
|
||||
INC += StreamBuffer.h
|
||||
INC += StreamError.h
|
||||
INC += StreamVersion.h
|
||||
|
||||
include $(EPICS_BASE)/config/RULES.Vx
|
||||
include ../../config/RULES.munch
|
||||
|
||||
DEPENDS: depends
|
||||
-include DEPENDS
|
||||
|
||||
# Update version string (contains __DATE__ and __TIME__)
|
||||
# each time make runs.
|
||||
StreamVersion.o: FORCE
|
||||
FORCE:
|
||||
CPPFLAGS += -DSTREAM_INTERNAL
|
||||
|
||||
# Update version string whenever something changes
|
||||
$(LIBNAME): StreamVersion.o
|
||||
|
||||
StreamVersion.o: StreamVersion.h $(filter-out StreamVersion.o,$(LIBOBJS)) ../CONFIG_STREAM
|
||||
StreamVersion.h: $(SRCS.cc) $(SRCS.c) $(add-prefix ../,$(filter-out StreamVersion.h, $(INC)))
|
||||
@echo Creating $@ from git tag
|
||||
$(PERL) ../makeStreamVersion.pl > $@
|
||||
|
||||
StreamCore.o: streamReferences
|
||||
|
||||
streamReferences:
|
||||
touch $@
|
||||
|
||||
# create stream.dbd from all RECORDTYPES
|
||||
stream.dbd: ../CONFIG_STREAM
|
||||
$(PERL) ../makedbd.pl -3.13 $(RECORDTYPES) > $@
|
||||
|
||||
|
@ -1,28 +1,31 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 2008 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is a custom exponential format converter for *
|
||||
* StreamDevice. *
|
||||
* The number is represented as two signed integers, mantissa *
|
||||
* and exponent, like in +00011-01 *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is a custom exponential format converter for StreamDevice.
|
||||
* A number is represented as two signed integers, mantissa and exponent,
|
||||
* like in "+00011-01" (without an "E")
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2008 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
#include <math.h>
|
||||
|
||||
// Exponential Converter %m
|
||||
// Eric Berryman requested a double format that reads
|
||||
@ -39,7 +42,7 @@
|
||||
class MantissaExponentConverter : public StreamFormatConverter
|
||||
{
|
||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
virtual int scanDouble(const StreamFormat&, const char*, double&);
|
||||
virtual ssize_t scanDouble(const StreamFormat&, const char*, double&);
|
||||
virtual bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||
};
|
||||
|
||||
@ -50,13 +53,13 @@ parse(const StreamFormat&, StreamBuffer&,
|
||||
return double_format;
|
||||
}
|
||||
|
||||
int MantissaExponentConverter::
|
||||
ssize_t MantissaExponentConverter::
|
||||
scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
||||
{
|
||||
int mantissa;
|
||||
int exponent;
|
||||
int length = -1;
|
||||
|
||||
|
||||
sscanf(input, "%d%d%n", &mantissa, &exponent, &length);
|
||||
if (fmt.flags & skip_flag) return length;
|
||||
if (length == -1) return -1;
|
||||
@ -70,15 +73,15 @@ printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
|
||||
// Have to divide value into mantissa and exponent
|
||||
// precision field is number of characters in mantissa
|
||||
// number of characters in exponent is at least 2
|
||||
int spaces;
|
||||
ssize_t spaces;
|
||||
StreamBuffer buf;
|
||||
int prec = fmt.prec;
|
||||
|
||||
|
||||
if (prec < 1) prec = 6;
|
||||
buf.print("%.*e", prec-1, fabs(value)/pow(10.0, prec-1));
|
||||
buf.remove(1,1);
|
||||
buf.remove(buf.find('e'),1);
|
||||
|
||||
|
||||
spaces = fmt.width-buf.length();
|
||||
if (fmt.flags & (space_flag|sign_flag) || value < 0.0) spaces--;
|
||||
if (spaces < 0) spaces = 0;
|
||||
|
@ -1,22 +1,24 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the raw format converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the raw integer format converter of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
@ -27,27 +29,26 @@ class RawConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||
int scanLong(const StreamFormat&, const char*, long&);
|
||||
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||
};
|
||||
|
||||
int RawConverter::
|
||||
parse(const StreamFormat&, StreamBuffer&,
|
||||
parse(const StreamFormat& fmt, StreamBuffer&,
|
||||
const char*&, bool)
|
||||
{
|
||||
return long_format;
|
||||
return (fmt.flags & zero_flag) ? unsigned_format : signed_format;
|
||||
}
|
||||
|
||||
bool RawConverter::
|
||||
printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
{
|
||||
int prec = format.prec; // number of bytes from value
|
||||
if (prec == -1) prec = 1; // default: 1 byte
|
||||
int width = prec; // number of bytes in output
|
||||
if (prec > (int)sizeof(long)) prec=sizeof(long);
|
||||
if (format.width > width) width = format.width;
|
||||
|
||||
unsigned int prec = fmt.prec < 0 ? 1 : fmt.prec; // number of bytes from value, default 1
|
||||
unsigned long width = prec; // number of bytes in output
|
||||
if (prec > sizeof(long)) prec=sizeof(long);
|
||||
if (fmt.width > width) width = fmt.width;
|
||||
|
||||
char byte = 0;
|
||||
if (format.flags & alt_flag) // little endian (lsb first)
|
||||
if (fmt.flags & alt_flag) // little endian (lsb first)
|
||||
{
|
||||
while (prec--)
|
||||
{
|
||||
@ -56,7 +57,7 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
value >>= 8;
|
||||
width--;
|
||||
}
|
||||
if (format.flags & zero_flag)
|
||||
if (fmt.flags & zero_flag)
|
||||
{
|
||||
// fill with zero
|
||||
byte = 0;
|
||||
@ -73,7 +74,7 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
}
|
||||
else // big endian (msb first)
|
||||
{
|
||||
if (format.flags & zero_flag)
|
||||
if (fmt.flags & zero_flag)
|
||||
{
|
||||
// fill with zero
|
||||
byte = 0;
|
||||
@ -96,62 +97,62 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
return true;
|
||||
}
|
||||
|
||||
int RawConverter::
|
||||
scanLong(const StreamFormat& format, const char* input, long& value)
|
||||
ssize_t RawConverter::
|
||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
{
|
||||
long length = 0;
|
||||
ssize_t consumed = 0;
|
||||
long val = 0;
|
||||
int width = format.width;
|
||||
unsigned long width = fmt.width;
|
||||
if (width == 0) width = 1; // default: 1 byte
|
||||
if (format.flags & skip_flag)
|
||||
if (fmt.flags & skip_flag)
|
||||
{
|
||||
return width; // just skip input
|
||||
}
|
||||
if (format.flags & alt_flag)
|
||||
if (fmt.flags & alt_flag)
|
||||
{
|
||||
// little endian (lsb first)
|
||||
unsigned int shift = 0;
|
||||
while (--width && shift < sizeof(long)*8)
|
||||
{
|
||||
val |= ((unsigned char) input[length++]) << shift;
|
||||
val |= (unsigned long)((unsigned char)input[consumed++]) << shift;
|
||||
shift += 8;
|
||||
}
|
||||
if (width == 0)
|
||||
{
|
||||
if (format.flags & zero_flag)
|
||||
if (fmt.flags & zero_flag)
|
||||
{
|
||||
// fill with zero
|
||||
val |= ((unsigned char) input[length++]) << shift;
|
||||
val |= (unsigned long)((unsigned char)input[consumed++]) << shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fill with sign
|
||||
val |= ((signed char) input[length++]) << shift;
|
||||
val |= ((long)(signed char)input[consumed++]) << shift;
|
||||
}
|
||||
}
|
||||
length += width; // ignore upper bytes not fitting in long
|
||||
consumed += width; // ignore upper bytes not fitting in long
|
||||
}
|
||||
else
|
||||
{
|
||||
// big endian (msb first)
|
||||
if (format.flags & zero_flag)
|
||||
if (fmt.flags & zero_flag)
|
||||
{
|
||||
// fill with zero
|
||||
val = (unsigned char) input[length++];
|
||||
val = (unsigned char)input[consumed++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// fill with sign
|
||||
val = (signed char) input[length++];
|
||||
val = (signed char)input[consumed++];
|
||||
}
|
||||
while (--width)
|
||||
{
|
||||
val <<= 8;
|
||||
val |= (unsigned char) input[length++];
|
||||
val |= (unsigned char)input[consumed++];
|
||||
}
|
||||
}
|
||||
value = val;
|
||||
return length;
|
||||
return consumed;
|
||||
}
|
||||
|
||||
RegisterConverter (RawConverter, "r");
|
||||
|
@ -1,22 +1,24 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the raw format converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the raw floating point format converter of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
@ -29,7 +31,7 @@ class RawFloatConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||
int scanDouble(const StreamFormat&, const char*, double&);
|
||||
ssize_t scanDouble(const StreamFormat&, const char*, double&);
|
||||
};
|
||||
|
||||
int RawFloatConverter::
|
||||
@ -77,20 +79,20 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
||||
if (!(format.flags & alt_flag) ^ (endian == 4321))
|
||||
{
|
||||
// swap if byte orders differ
|
||||
for (n = nbOfBytes-1; n >= 0; n--)
|
||||
{
|
||||
for (n = nbOfBytes-1; n >= 0; n--)
|
||||
{
|
||||
output.append(buffer.bytes[n]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (n = 0; n < nbOfBytes; n++)
|
||||
{
|
||||
for (n = 0; n < nbOfBytes; n++)
|
||||
{
|
||||
output.append(buffer.bytes[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int RawFloatConverter::
|
||||
ssize_t RawFloatConverter::
|
||||
scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
{
|
||||
int nbOfBytes;
|
||||
@ -114,15 +116,15 @@ scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
if (!(format.flags & alt_flag) ^ (endian == 4321))
|
||||
{
|
||||
// swap if byte orders differ
|
||||
for (n = nbOfBytes-1, i = 0; n >= 0; n--, i++)
|
||||
{
|
||||
for (n = nbOfBytes-1, i = 0; n >= 0; n--, i++)
|
||||
{
|
||||
buffer.bytes[n] = input[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (n = 0; n < nbOfBytes; n++)
|
||||
{
|
||||
for (n = 0; n < nbOfBytes; n++)
|
||||
{
|
||||
buffer.bytes[n] = input[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nbOfBytes == 4)
|
||||
|
@ -1,29 +1,37 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2007 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the regexp format converter of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the regular expression format converter of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2007 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "pcre.h"
|
||||
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
#include "string.h"
|
||||
#include "pcre.h"
|
||||
|
||||
// Perl regular expressions (PCRE) %/regexp/
|
||||
#define Z PRINTF_SIZE_T_PREFIX
|
||||
|
||||
// Perl regular expressions (PCRE) %/regexp/ and %#/regexp/subst/
|
||||
|
||||
/* Notes:
|
||||
- Memory for compiled regexp is allocated in parse but never freed.
|
||||
@ -32,94 +40,279 @@
|
||||
run-time leak.
|
||||
- A maximum of 9 subexpressions is supported. Only one of them can
|
||||
be the result of the match.
|
||||
- vxWorks and maybe other OS don't have a PCRE library. Provide one?
|
||||
*/
|
||||
|
||||
class RegexpConverter : public StreamFormatConverter
|
||||
{
|
||||
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
int scanString(const StreamFormat&, const char*, char*, size_t);
|
||||
int parse (const StreamFormat& fmt, StreamBuffer&, const char*&, bool);
|
||||
ssize_t scanString(const StreamFormat& fmt, const char*, char*, size_t&);
|
||||
ssize_t scanPseudo(const StreamFormat& fmt, StreamBuffer& input, size_t& cursor);
|
||||
bool printPseudo(const StreamFormat& fmt, StreamBuffer& output);
|
||||
};
|
||||
|
||||
int RegexpConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat)
|
||||
{
|
||||
if (!scanFormat)
|
||||
if (!scanFormat && !(fmt.flags & alt_flag))
|
||||
{
|
||||
error("Format conversion %%/regexp/ is only allowed in input formats\n");
|
||||
return false;
|
||||
}
|
||||
if (fmt.prec > 9)
|
||||
{
|
||||
error("Subexpression index %d too big (>9)\n", fmt.prec);
|
||||
return false;
|
||||
}
|
||||
if (fmt.flags & (left_flag|space_flag|zero_flag|alt_flag))
|
||||
{
|
||||
error("Use of modifiers '-', ' ', '0', '#'"
|
||||
"not allowed with %%/regexp/ conversion\n");
|
||||
error("Sub-expression index %ld too big (>9)\n", fmt.prec);
|
||||
return false;
|
||||
}
|
||||
|
||||
StreamBuffer pattern;
|
||||
while (*source != '/')
|
||||
{
|
||||
if (!*source) {
|
||||
error("Missing closing '/' after %%/ format conversion\n");
|
||||
error("Missing closing '/' after %%/%s format conversion\n", pattern());
|
||||
return false;
|
||||
}
|
||||
if (*source == esc) {
|
||||
source++;
|
||||
pattern.print("\\x%02x", *source++ & 0xFF);
|
||||
continue;
|
||||
if (*source == esc) { // handle escaped chars
|
||||
if (*++source != '/') // just un-escape /
|
||||
{
|
||||
pattern.append('\\');
|
||||
if ((*source & 0x7f) < 0x30) // handle control chars
|
||||
{
|
||||
pattern.print("x%02x", *source++);
|
||||
continue;
|
||||
}
|
||||
// fall through for PCRE codes like \B
|
||||
}
|
||||
}
|
||||
pattern.append(*source++);
|
||||
}
|
||||
source++;
|
||||
debug("regexp = \"%s\"\n", pattern());
|
||||
debug("regexp = \"%s\"\n", pattern.expand()());
|
||||
|
||||
const char* errormsg;
|
||||
int eoffset;
|
||||
pcre* code = pcre_compile(pattern(), 0,
|
||||
&errormsg, &eoffset, NULL);
|
||||
int nsubexpr;
|
||||
|
||||
pcre* code = pcre_compile(pattern(), 0, &errormsg, &eoffset, NULL);
|
||||
if (!code)
|
||||
{
|
||||
error("%s after \"%s\"\n", errormsg, pattern.expand(0, eoffset)());
|
||||
return false;
|
||||
}
|
||||
pcre_fullinfo(code, NULL, PCRE_INFO_CAPTURECOUNT, &nsubexpr);
|
||||
if (fmt.prec > nsubexpr)
|
||||
{
|
||||
error("Sub-expression index is %ld but pattern has only %d sub-expression\n", fmt.prec, nsubexpr);
|
||||
return false;
|
||||
}
|
||||
info.append(&code, sizeof(code));
|
||||
|
||||
if (fmt.flags & alt_flag)
|
||||
{
|
||||
StreamBuffer subst;
|
||||
|
||||
debug("check for subst in \"%s\"\n", StreamBuffer(source).expand()());
|
||||
while (*source != '/')
|
||||
{
|
||||
if (!*source) {
|
||||
error("Missing closing '/' after %%#/%s/%s format conversion\n", pattern(), subst());
|
||||
return false;
|
||||
}
|
||||
if (*source == esc)
|
||||
subst.append(*source++);
|
||||
subst.append(*source++);
|
||||
}
|
||||
source++;
|
||||
debug("subst = \"%s\"\n", subst.expand()());
|
||||
info.append(subst).append('\0');
|
||||
return pseudo_format;
|
||||
}
|
||||
return string_format;
|
||||
}
|
||||
|
||||
int RegexpConverter::
|
||||
ssize_t RegexpConverter::
|
||||
scanString(const StreamFormat& fmt, const char* input,
|
||||
char* value, size_t maxlen)
|
||||
char* value, size_t& size)
|
||||
{
|
||||
pcre* code;
|
||||
size_t len;
|
||||
int ovector[30];
|
||||
int rc;
|
||||
int subexpr = 0;
|
||||
|
||||
memcpy (&code, fmt.info, sizeof(code));
|
||||
|
||||
len = fmt.width > 0 ? fmt.width : strlen(input);
|
||||
subexpr = fmt.prec > 0 ? fmt.prec : 0;
|
||||
rc = pcre_exec(code, NULL, input, len, 0, 0, ovector, 30);
|
||||
if (rc < 1) return -1;
|
||||
if (fmt.flags & skip_flag) return ovector[1];
|
||||
len = ovector[subexpr*2+1] - ovector[subexpr*2];
|
||||
if (len >= maxlen) {
|
||||
size_t l;
|
||||
const char* info = fmt.info;
|
||||
pcre* code = extract<pcre*>(info);
|
||||
size_t length = fmt.width > 0 ? fmt.width : strlen(input);
|
||||
int subexpr = fmt.prec > 0 ? fmt.prec : 0;
|
||||
|
||||
if (length > INT_MAX)
|
||||
length = INT_MAX;
|
||||
debug("input = \"%s\"\n", input);
|
||||
debug("length=%" Z "u\n", length);
|
||||
|
||||
rc = pcre_exec(code, NULL, input, (int)length, 0, 0, ovector, 30);
|
||||
debug("pcre_exec match \"%.*s\" result = %d\n", (int)length, input, rc);
|
||||
if ((subexpr && rc <= subexpr) || rc < 0)
|
||||
{
|
||||
// error or no match or not enough sub-expressions
|
||||
return -1;
|
||||
}
|
||||
if (fmt.flags & skip_flag) return ovector[subexpr*2+1];
|
||||
|
||||
l = ovector[subexpr*2+1] - ovector[subexpr*2];
|
||||
if (l >= size) {
|
||||
if (!(fmt.flags & sign_flag)) {
|
||||
error("Regexp: Matching string \"%s\" too long (%d>%d bytes). You may want to try the + flag: \"%%+/.../\"\n",
|
||||
StreamBuffer(input+ovector[subexpr*2], len).expand()(),
|
||||
(int)len, (int)maxlen-1);
|
||||
error("Regexp: Matching string \"%s\" too long (%" Z "u>%" Z "u bytes). You may want to try the + flag: \"%%+/.../\"\n",
|
||||
StreamBuffer(input + ovector[subexpr*2],l).expand()(),
|
||||
l, size-1);
|
||||
return -1;
|
||||
}
|
||||
len = maxlen-1;
|
||||
l = size-1;
|
||||
}
|
||||
memcpy(value, input+ovector[subexpr*2], len);
|
||||
value[len]=0;
|
||||
return ovector[1];
|
||||
memcpy(value, input + ovector[subexpr*2], l);
|
||||
value[l] = '\0';
|
||||
size = l+1; // update number of bytes written to value
|
||||
return ovector[1]; // consume input until end of match
|
||||
}
|
||||
|
||||
static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, size_t start)
|
||||
{
|
||||
const char* subst = fmt.info;
|
||||
pcre* code = extract<pcre*>(subst);
|
||||
size_t length, c;
|
||||
int rc, l, r, rl, n;
|
||||
int ovector[30];
|
||||
StreamBuffer s;
|
||||
|
||||
length = buffer.length() - start;
|
||||
if (fmt.width && fmt.width < length)
|
||||
length = fmt.width;
|
||||
if (length > INT_MAX)
|
||||
length = INT_MAX;
|
||||
if (fmt.flags & left_flag)
|
||||
start = buffer.length() - length;
|
||||
|
||||
debug("regsubst buffer=\"%s\", start=%" Z "u, length=%" Z "u, subst = \"%s\"\n",
|
||||
buffer.expand()(), start, length, StreamBuffer(subst).expand()());
|
||||
|
||||
for (c = 0, n = 1; c < length; n++)
|
||||
{
|
||||
rc = pcre_exec(code, NULL, buffer(start+c), (int)(length-c), 0, 0, ovector, 30);
|
||||
debug("pcre_exec match \"%s\" result = %d\n", buffer.expand(start+c, length-c)(), rc);
|
||||
|
||||
if (rc < 0) // no match
|
||||
{
|
||||
debug("pcre_exec: no match\n");
|
||||
break;
|
||||
}
|
||||
l = ovector[1] - ovector[0];
|
||||
|
||||
// no prec: replace all matches
|
||||
// prec with + flag: replace first prec matches
|
||||
// prec without + flag: replace only match number prec
|
||||
|
||||
if ((fmt.flags & sign_flag) || n >= fmt.prec)
|
||||
{
|
||||
// replace subexpressions
|
||||
debug("before [%d]= \"%s\"\n", ovector[0], buffer.expand(start+c,ovector[0])());
|
||||
debug("match [%d]= \"%s\"\n", l, buffer.expand(start+c+ovector[0],l)());
|
||||
for (r = 1; r < rc; r++)
|
||||
debug("sub%d = \"%s\"\n", r, buffer.expand(start+c+ovector[r*2], ovector[r*2+1]-ovector[r*2])());
|
||||
debug("after = \"%s\"\n", buffer.expand(start+c+ovector[1])());
|
||||
s = subst;
|
||||
debug("subs = \"%s\"\n", s.expand()());
|
||||
for (r = 0; r < (int)s.length(); r++)
|
||||
{
|
||||
debug("check \"%s\"\n", s.expand(r)());
|
||||
if (s[r] == esc)
|
||||
{
|
||||
unsigned char ch = s[r+1];
|
||||
if (strchr("ulUL", ch))
|
||||
{
|
||||
unsigned char br = s[r+2] - '0';
|
||||
if (br == (unsigned char)('&'-'0')) br = 0;
|
||||
debug("found case conversion \\%c%u\n", ch, br);
|
||||
if (br >= rc)
|
||||
{
|
||||
s.remove(r, 1);
|
||||
continue;
|
||||
}
|
||||
br *= 2;
|
||||
rl = ovector[br+1] - ovector[br];
|
||||
s.replace(r, 3, buffer(start+c+ovector[br]), rl);
|
||||
switch (ch)
|
||||
{
|
||||
case 'u':
|
||||
if (islower(s[r])) s[r] = toupper(s[r]);
|
||||
break;
|
||||
case 'l':
|
||||
if (isupper(s[r])) s[r] = tolower(s[r]);
|
||||
break;
|
||||
case 'U':
|
||||
for (int i = 0; i < rl; i++)
|
||||
if (islower(s[r+i])) s[r+i] = toupper(s[r+i]);
|
||||
break;
|
||||
case 'L':
|
||||
for (int i = 0; i < rl; i++)
|
||||
if (isupper(s[r+i])) s[r+i] = tolower(s[r+i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ch != 0 && ch < rc) // escaped 1 - 9 : replace with subexpr
|
||||
{
|
||||
debug("found escaped \\%u\n", ch);
|
||||
ch *= 2;
|
||||
rl = ovector[ch+1] - ovector[ch];
|
||||
debug("yes, replace \\%d: \"%s\"\n", ch/2, buffer.expand(start+c+ovector[ch], rl)());
|
||||
s.replace(r, 2, buffer(start+c+ovector[ch]), rl);
|
||||
r += rl - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("use literal \\%u\n", ch);
|
||||
s.remove(r, 1); // just remove escape
|
||||
}
|
||||
}
|
||||
else if (s[r] == '&') // unescaped & : replace with match
|
||||
{
|
||||
debug("replace &: \"%s\"\n", buffer.expand(start+c+ovector[0], l)());
|
||||
s.replace(r, 1, buffer(start+c+ovector[0]), l);
|
||||
r += l - 1;
|
||||
}
|
||||
else continue;
|
||||
debug("subs = \"%s\"\n", s.expand()());
|
||||
}
|
||||
buffer.replace(start+c+ovector[0], l, s);
|
||||
length -= l;
|
||||
length += s.length();
|
||||
c += s.length();
|
||||
}
|
||||
c += ovector[0];
|
||||
if (l == 0)
|
||||
{
|
||||
debug("pcre_exec: empty match\n");
|
||||
c++; // Empty strings may lead to an endless loop. Match them only once.
|
||||
}
|
||||
if (n == fmt.prec) // max match reached
|
||||
{
|
||||
debug("pcre_exec: max match %d reached\n", n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug("pcre_exec converted string: %s\n", buffer.expand()());
|
||||
}
|
||||
|
||||
ssize_t RegexpConverter::
|
||||
scanPseudo(const StreamFormat& fmt, StreamBuffer& input, size_t& cursor)
|
||||
{
|
||||
/* re-write input buffer */
|
||||
regsubst(fmt, input, cursor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RegexpConverter::
|
||||
printPseudo(const StreamFormat& fmt, StreamBuffer& output)
|
||||
{
|
||||
/* re-write output buffer */
|
||||
regsubst(fmt, output, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterConverter (RegexpConverter, "/");
|
||||
|
@ -1,34 +1,79 @@
|
||||
/***************************************************************
|
||||
* StreamBuffer *
|
||||
* *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is a buffer class used in StreamDevice for I/O. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is a buffer class used in StreamDevice for I/O.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamError.h"
|
||||
// Make sure that vsnprintf is available
|
||||
#ifndef _BSD_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__vxworks) || defined(vxWorks) || defined(_WIN32) || defined(__rtems__)
|
||||
// These systems have no vsnprintf
|
||||
#include <epicsStdio.h>
|
||||
#define vsnprintf epicsVsnprintf
|
||||
#endif
|
||||
#ifdef vxWorks
|
||||
#include <version.h>
|
||||
#ifndef _WRS_VXWORKS_MAJOR
|
||||
// VxWorks 5 has no vsnprintf
|
||||
// Implementation taken from EPICS 3.14
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <fioLib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct outStr_s {
|
||||
char *str;
|
||||
int free;
|
||||
};
|
||||
|
||||
static STATUS outRoutine(char *buffer, int nchars, int outarg) {
|
||||
struct outStr_s *poutStr = (struct outStr_s *) outarg;
|
||||
int free = poutStr->free;
|
||||
int len;
|
||||
|
||||
if (free < 1) { /*let fioFormatV continue to count length*/
|
||||
return OK;
|
||||
} else if (free > 1) {
|
||||
len = min(free-1, nchars);
|
||||
strncpy(poutStr->str, buffer, len);
|
||||
poutStr->str += len;
|
||||
poutStr->free -= len;
|
||||
}
|
||||
/*make sure final string is null terminated*/
|
||||
*poutStr->str = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list ap) {
|
||||
struct outStr_s outStr;
|
||||
|
||||
outStr.str = str;
|
||||
outStr.free = size;
|
||||
return fioFormatV(format, ap, (FUNCPTR)outRoutine, (int)&outStr);
|
||||
}
|
||||
#endif // ! _WRS_VXWORKS_MAJOR
|
||||
#endif // vxWorks
|
||||
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamError.h"
|
||||
|
||||
#define P PRINTF_SIZE_T_PREFIX
|
||||
|
||||
@ -57,7 +102,7 @@ init(const void* s, ssize_t minsize)
|
||||
}
|
||||
|
||||
// How the buffer looks like:
|
||||
// |----free-----|####used####|--------00--------|
|
||||
// |----junk-----|####used####|--------00--------|
|
||||
///|<--- offs -->|<-- len --->|<- cap-offs-len ->|
|
||||
// 0 offs offs+len cap
|
||||
// |<-------------- minsize --------------->
|
||||
@ -209,39 +254,71 @@ replace(ssize_t remstart, ssize_t remlen, const void* ins, ssize_t inslen)
|
||||
if (inslen < 0) inslen = 0;
|
||||
size_t remend = remstart+remlen;
|
||||
size_t newlen = len+inslen-remlen;
|
||||
|
||||
// How the buffer looks like before and after:
|
||||
// |---junk---|##content_start##|/////////remove_this////////|##content_end##|0000|
|
||||
// |<- offs ->|<-- remstart --->|<--------- remlen --------->| | |
|
||||
// | |<--------------------- len ---------------------------------->| |
|
||||
// 0 offs offs+remstart offs+remend offs+len cap
|
||||
//
|
||||
// If content size stays the same, no need to move old content:
|
||||
// |---junk---|##content_start##|+++++++inserted_text++++++++|##content_end##|0000|
|
||||
// |<----- inslen==remlen ----->| newlen==len
|
||||
//
|
||||
// If content shrinks (need to clear end of buffer): |< clear this >|
|
||||
// |---junk---|##content_start##|inserted_text|##content_end##|00000000000000|0000|
|
||||
// 0 offs |<- inslen -->| |< len-newlen >|
|
||||
// offs+newlen offs+len
|
||||
//
|
||||
// If content grows but still fits (make sure to keep at least one 0 byte at end):
|
||||
// |---junk---|##content_start##|++++++++inserted_text++++++++++|##content_end##|0|
|
||||
// |<- offs ->|<--------------------- newlen ---------------------------------->| |
|
||||
// 0 offs offs+newlen<cap
|
||||
//
|
||||
// If content would overflow, moving to offs 0 may help:
|
||||
// May need to clear end if newlen < offs+len: |<clear>|
|
||||
// |##content_start##|++++++++inserted_text++++++++++|##content_end##|0000000|0000|
|
||||
// |<--------------------- newlen ---------------------------------->| |
|
||||
// newlen offs+len
|
||||
//
|
||||
// Otherwise we need to copy to a new buffer.
|
||||
|
||||
|
||||
if (cap <= newlen)
|
||||
{
|
||||
// buffer too short
|
||||
// buffer too short, copy to new buffer
|
||||
size_t newcap;
|
||||
for (newcap = sizeof(local)*2; newcap <= newlen; newcap *= 2);
|
||||
char* newbuffer = new char[newcap];
|
||||
memcpy(newbuffer, buffer+offs, remstart);
|
||||
memcpy(newbuffer+remstart, ins, inslen);
|
||||
memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend);
|
||||
memset(newbuffer+newlen, 0, newcap-newlen);
|
||||
memcpy(newbuffer, buffer+offs, remstart); // copy content start
|
||||
memcpy(newbuffer+remstart, ins, inslen); // insert
|
||||
memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend); // copy content end
|
||||
memset(newbuffer+newlen, 0, newcap-newlen); // clear buffer end
|
||||
if (buffer != local)
|
||||
{
|
||||
delete [] buffer;
|
||||
}
|
||||
delete[] buffer;
|
||||
buffer = newbuffer;
|
||||
cap = newcap;
|
||||
offs = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newlen+offs<=cap)
|
||||
if (offs+newlen < cap)
|
||||
{
|
||||
// move to start of buffer
|
||||
memmove(buffer+offs+remstart+inslen, buffer+offs+remend, len-remend);
|
||||
memcpy(buffer+offs+remstart, ins, inslen);
|
||||
if (newlen<len) memset(buffer+offs+newlen, 0, len-newlen);
|
||||
// modified content still fits with current offs, just move content end
|
||||
if (newlen != len)
|
||||
memmove(buffer+offs+remstart+inslen, buffer+offs+remend, len-remend); // move old content end if necessary
|
||||
memcpy(buffer+offs+remstart, ins, inslen); // insert before
|
||||
if (newlen < len)
|
||||
memset(buffer+offs+newlen, 0, len-newlen); // clear buffer end if content shrunk
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(buffer,buffer+offs,remstart);
|
||||
memmove(buffer+remstart+inslen, buffer+offs+remend, len-remend);
|
||||
memcpy(buffer+remstart, ins, inslen);
|
||||
if (newlen<len) memset(buffer+newlen, 0, len-newlen);
|
||||
// move content to start of buffer
|
||||
memmove(buffer, buffer+offs, remstart); // move content start to 0 offs
|
||||
memmove(buffer+remstart+inslen, buffer+offs+remend, len-remend); // move content end
|
||||
memcpy(buffer+remstart, ins, inslen); // insert in between
|
||||
if (newlen < offs+len)
|
||||
memset(buffer+newlen, 0, offs+len-newlen); // clear buffer end if necessary
|
||||
offs = 0;
|
||||
}
|
||||
}
|
||||
@ -265,7 +342,7 @@ print(const char* fmt, ...)
|
||||
return *this;
|
||||
}
|
||||
if (printed > -1) grow(len+printed);
|
||||
else grow(len);
|
||||
else grow(cap*2-1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +365,7 @@ StreamBuffer StreamBuffer::expand(ssize_t start, ssize_t length) const
|
||||
}
|
||||
end = start+length;
|
||||
if (end > len) end = len;
|
||||
StreamBuffer result((end-start)*2);
|
||||
StreamBuffer result;
|
||||
start += offs;
|
||||
end += offs;
|
||||
size_t i;
|
||||
@ -296,14 +373,13 @@ StreamBuffer StreamBuffer::expand(ssize_t start, ssize_t length) const
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
c = buffer[i];
|
||||
if ((c & 0x7f) < 0x20 || (c & 0x7f) == 0x7f)
|
||||
{
|
||||
result.print("<%02x>", c & 0xff);
|
||||
}
|
||||
if (c < 0x20 || c >= 0x7f)
|
||||
result.print("%s<%02x>%s",
|
||||
ansiEscape(ANSI_REVERSE_VIDEO),
|
||||
c & 0xff,
|
||||
ansiEscape(ANSI_NOT_REVERSE_VIDEO));
|
||||
else
|
||||
{
|
||||
result.append(c);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -311,28 +387,24 @@ StreamBuffer StreamBuffer::expand(ssize_t start, ssize_t length) const
|
||||
StreamBuffer StreamBuffer::
|
||||
dump() const
|
||||
{
|
||||
StreamBuffer result(256+cap*5);
|
||||
result.append("\033[0m");
|
||||
StreamBuffer result;
|
||||
size_t i;
|
||||
result.print("%"P"d,%"P"d,%"P"d:\033[37m", offs, len, cap);
|
||||
result.print("%" P "d,%" P "d,%" P "d:", offs, len, cap);
|
||||
if (offs) result.print("%s", ansiEscape(ANSI_BG_WHITE));
|
||||
char c;
|
||||
for (i = 0; i < cap; i++)
|
||||
{
|
||||
if (i == offs) result.append("\033[34m[\033[0m");
|
||||
if ((buffer[i] & 0x7f) < 0x20 || (buffer[i] & 0x7f) == 0x7f)
|
||||
{
|
||||
if (i < offs || i >= offs+len)
|
||||
result.print(
|
||||
"<%02x>", buffer[i] & 0xff);
|
||||
else
|
||||
result.print(
|
||||
"\033[34m<%02x>\033[37m", buffer[i] & 0xff);
|
||||
}
|
||||
c = buffer[i];
|
||||
if (offs && i == offs) result.append(ansiEscape(ANSI_RESET));
|
||||
if (c < 0x20 || c >= 0x7f)
|
||||
result.print("%s<%02x>%s",
|
||||
ansiEscape(ANSI_REVERSE_VIDEO),
|
||||
c & 0xff,
|
||||
ansiEscape(ANSI_NOT_REVERSE_VIDEO));
|
||||
else
|
||||
{
|
||||
result.append(buffer[i]);
|
||||
}
|
||||
if (i == offs+len-1) result.append("\033[34m]\033[37m");
|
||||
result.append(c);
|
||||
if (i == offs+len-1) result.append(ansiEscape(ANSI_BG_WHITE));
|
||||
}
|
||||
result.append("\033[0m");
|
||||
result.append(ansiEscape(ANSI_RESET));
|
||||
return result;
|
||||
}
|
||||
|
@ -1,34 +1,38 @@
|
||||
/***************************************************************
|
||||
* StreamBuffer *
|
||||
* *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is a buffer class used in StreamDevice for I/O. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is a buffer class used in StreamDevice for I/O.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef StreamBuffer_h
|
||||
#define StreamBuffer_h
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ssize_t ptrdiff_t
|
||||
#if defined(_WIN32)
|
||||
typedef ptrdiff_t ssize_t;
|
||||
#endif
|
||||
|
||||
class StreamBuffer
|
||||
@ -72,7 +76,7 @@ public:
|
||||
{init(NULL, size);}
|
||||
|
||||
~StreamBuffer()
|
||||
{if (buffer != local) delete buffer;}
|
||||
{if (buffer != local) delete [] buffer;}
|
||||
|
||||
// operator (): get char* pointing to index
|
||||
const char* operator()(ssize_t index=0) const
|
||||
@ -93,11 +97,11 @@ public:
|
||||
{return len>0;}
|
||||
|
||||
// length: get current data length
|
||||
ssize_t length() const
|
||||
size_t length() const
|
||||
{return len;}
|
||||
|
||||
// capacity: get current max data length (spare one byte for end)
|
||||
ssize_t capacity() const
|
||||
size_t capacity() const
|
||||
{return cap-1;}
|
||||
|
||||
// end: get pointer to byte after last data byte
|
||||
@ -129,7 +133,7 @@ public:
|
||||
|
||||
StreamBuffer& append(const StreamBuffer& s)
|
||||
{return append(s.buffer+s.offs, s.len);}
|
||||
|
||||
|
||||
// operator += alias for append
|
||||
StreamBuffer& operator+=(char c)
|
||||
{return append(c);}
|
||||
@ -194,15 +198,14 @@ public:
|
||||
{return replace(pos, 0, &c, 1);}
|
||||
|
||||
StreamBuffer& print(const char* fmt, ...)
|
||||
__attribute__ ((format(printf,2,3)));
|
||||
__attribute__((__format__(__printf__,2,3)));
|
||||
|
||||
// find: get index of data in buffer or -1
|
||||
ssize_t find(char c, ssize_t start=0) const
|
||||
{char* p;
|
||||
{if (start < 0 && (start -= len) < 0) start = 0;
|
||||
char* p;
|
||||
return (p = static_cast<char*>(
|
||||
memchr(buffer+offs+(start<0?start+len:start),
|
||||
c, start<0?-start:len-start)))?
|
||||
p-(buffer+offs) : -1;}
|
||||
memchr(buffer+offs+start, c, len-start)))? p-(buffer+offs) : -1;}
|
||||
|
||||
ssize_t find(const void* s, size_t size, ssize_t start=0) const;
|
||||
|
||||
@ -223,7 +226,7 @@ public:
|
||||
// expand: create copy of StreamBuffer where all nonprintable characters
|
||||
// are replaced by <xx> with xx being the hex code of the characters
|
||||
StreamBuffer expand(ssize_t start, ssize_t length) const;
|
||||
|
||||
|
||||
StreamBuffer expand(ssize_t start=0) const
|
||||
{return expand(start, len);}
|
||||
|
||||
|
@ -1,27 +1,30 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the interface to bus drivers for StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the interface to bus (I/O) drivers for StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "StreamBusInterface.h"
|
||||
#include "StreamError.h"
|
||||
|
||||
StreamIoStatusStrClass StreamIoStatusStr;
|
||||
|
||||
StreamBusInterfaceRegistrarBase* StreamBusInterfaceRegistrarBase::first;
|
||||
|
||||
StreamBusInterfaceRegistrarBase::
|
||||
@ -70,7 +73,20 @@ find(Client* client, const char* busname, int addr, const char* param)
|
||||
bus = r->find(client, busname, addr, param);
|
||||
debug("StreamBusInterface::find %s %s\n",
|
||||
r->name, bus ? "matches" : "does not match");
|
||||
if (bus) return bus;
|
||||
if (bus)
|
||||
{
|
||||
if (addr >= 0)
|
||||
{
|
||||
bus->_name = new char[strlen(busname) + sizeof(int)*2 + sizeof(int)/2 + 2];
|
||||
sprintf(bus->_name, "%s %d", busname, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
bus->_name = new char[strlen(busname) + 1];
|
||||
strcpy(bus->_name, busname);
|
||||
}
|
||||
return bus;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -106,7 +122,7 @@ writeRequest(const void*, size_t, unsigned long)
|
||||
}
|
||||
|
||||
bool StreamBusInterface::
|
||||
readRequest(unsigned long, unsigned long, long, bool)
|
||||
readRequest(unsigned long, unsigned long, ssize_t, bool)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -126,8 +142,8 @@ writeCallback(StreamIoStatus)
|
||||
{
|
||||
}
|
||||
|
||||
long StreamBusInterface::Client::
|
||||
readCallback(StreamIoStatus, const void*, long)
|
||||
ssize_t StreamBusInterface::Client::
|
||||
readCallback(StreamIoStatus, const void*, size_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,46 +1,35 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the interface to bus drivers for StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the interface to bus (I/O) drivers for StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef StreamBusInterface_h
|
||||
#define StreamBusInterface_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <StreamBuffer.h>
|
||||
#include "StreamBuffer.h"
|
||||
#include "MacroMagic.h"
|
||||
|
||||
enum StreamIoStatus {
|
||||
ENUM (StreamIoStatus,
|
||||
StreamIoSuccess, StreamIoTimeout, StreamIoNoReply,
|
||||
StreamIoEnd, StreamIoFault
|
||||
};
|
||||
|
||||
class StreamIoStatusStrClass {
|
||||
public:
|
||||
const char* operator [] (int index) {
|
||||
switch (index) {
|
||||
case StreamIoSuccess: return "StreamIoSuccess";
|
||||
case StreamIoTimeout: return "StreamIoTimeout";
|
||||
case StreamIoNoReply: return "StreamIoNoReply";
|
||||
case StreamIoEnd: return "StreamIoEnd";
|
||||
case StreamIoFault: return "StreamIoFault";
|
||||
default: return "illegal status";
|
||||
}
|
||||
}
|
||||
} extern StreamIoStatusStr;
|
||||
StreamIoEnd, StreamIoFault);
|
||||
|
||||
class StreamBusInterface
|
||||
{
|
||||
@ -48,11 +37,13 @@ public:
|
||||
|
||||
class Client
|
||||
{
|
||||
private:
|
||||
friend class StreamBusInterface;
|
||||
|
||||
virtual void lockCallback(StreamIoStatus status) = 0;
|
||||
virtual void writeCallback(StreamIoStatus status);
|
||||
virtual long readCallback(StreamIoStatus status,
|
||||
const void* input, long size);
|
||||
virtual ssize_t readCallback(StreamIoStatus status,
|
||||
const void* input, size_t size);
|
||||
virtual void eventCallback(StreamIoStatus status);
|
||||
virtual void connectCallback(StreamIoStatus status);
|
||||
virtual void disconnectCallback(StreamIoStatus status);
|
||||
@ -88,7 +79,7 @@ public:
|
||||
return businterface && businterface->writeRequest(output, size, timeout_ms);
|
||||
}
|
||||
bool busReadRequest(unsigned long replytimeout_ms,
|
||||
unsigned long readtimeout_ms, long expectedLength,
|
||||
unsigned long readtimeout_ms, ssize_t expectedLength,
|
||||
bool async) {
|
||||
return businterface && businterface->readRequest(replytimeout_ms,
|
||||
readtimeout_ms, expectedLength, async);
|
||||
@ -110,27 +101,29 @@ public:
|
||||
private:
|
||||
friend class StreamBusInterfaceClass; // the iterator
|
||||
friend class Client;
|
||||
char* _name;
|
||||
|
||||
public:
|
||||
Client* client;
|
||||
virtual ~StreamBusInterface() {};
|
||||
const char* name() { return _name; }
|
||||
|
||||
protected:
|
||||
StreamBusInterface(Client* client);
|
||||
|
||||
|
||||
// map client functions into StreamBusInterface namespace
|
||||
void lockCallback(StreamIoStatus status)
|
||||
void lockCallback(StreamIoStatus status = StreamIoSuccess)
|
||||
{ client->lockCallback(status); }
|
||||
void writeCallback(StreamIoStatus status)
|
||||
void writeCallback(StreamIoStatus status = StreamIoSuccess)
|
||||
{ client->writeCallback(status); }
|
||||
long readCallback(StreamIoStatus status,
|
||||
const void* input = NULL, long size = 0)
|
||||
ssize_t readCallback(StreamIoStatus status,
|
||||
const void* input = NULL, size_t size = 0)
|
||||
{ return client->readCallback(status, input, size); }
|
||||
void eventCallback(StreamIoStatus status)
|
||||
void eventCallback(StreamIoStatus status = StreamIoSuccess)
|
||||
{ client->eventCallback(status); }
|
||||
void connectCallback(StreamIoStatus status)
|
||||
void connectCallback(StreamIoStatus status = StreamIoSuccess)
|
||||
{ client->connectCallback(status); }
|
||||
void disconnectCallback(StreamIoStatus status)
|
||||
void disconnectCallback(StreamIoStatus status = StreamIoSuccess)
|
||||
{ client->disconnectCallback(status); }
|
||||
const char* getInTerminator(size_t& length)
|
||||
{ return client->getInTerminator(length); }
|
||||
@ -143,7 +136,7 @@ protected:
|
||||
virtual bool writeRequest(const void* output, size_t size,
|
||||
unsigned long timeout_ms);
|
||||
virtual bool readRequest(unsigned long replytimeout_ms,
|
||||
unsigned long readtimeout_ms, long expectedLength,
|
||||
unsigned long readtimeout_ms, ssize_t expectedLength,
|
||||
bool async);
|
||||
virtual bool supportsEvent(); // defaults to false
|
||||
virtual bool supportsAsyncRead(); // defaults to false
|
||||
@ -178,7 +171,7 @@ protected:
|
||||
StreamBusInterfaceRegistrarBase(const char* name);
|
||||
virtual ~StreamBusInterfaceRegistrarBase();
|
||||
};
|
||||
|
||||
|
||||
template <class C>
|
||||
class StreamBusInterfaceRegistrar : protected StreamBusInterfaceRegistrarBase
|
||||
{
|
||||
|
128
src/StreamCore.h
@ -1,22 +1,24 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is the kernel of StreamDevice. *
|
||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
||||
* documentation. *
|
||||
* *
|
||||
* If you do any changes in this file, you are not allowed to *
|
||||
* redistribute it any more. If there is a bug or a missing *
|
||||
* feature, send me an email and/or your patch. If I accept *
|
||||
* your changes, they will go to the next release. *
|
||||
* *
|
||||
* DISCLAIMER: If this software breaks something or harms *
|
||||
* someone, it's your problem. *
|
||||
* *
|
||||
***************************************************************/
|
||||
/*************************************************************************
|
||||
* This is the core of StreamDevice.
|
||||
* Please see ../docs/ for detailed documentation.
|
||||
*
|
||||
* (C) 1999,2005 Dirk Zimoch (dirk.zimoch@psi.ch)
|
||||
*
|
||||
* This file is part of StreamDevice.
|
||||
*
|
||||
* StreamDevice is free software: You can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* StreamDevice is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with StreamDevice. If not, see https://www.gnu.org/licenses/.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef StreamCore_h
|
||||
#define StreamCore_h
|
||||
@ -70,25 +72,31 @@ void acceptEvent(unsigned short mask, unsigned short timeout)
|
||||
|
||||
***************************************/
|
||||
|
||||
enum Flags {
|
||||
// 0x00FFFFFF reserved for StreamCore
|
||||
None = 0x0000,
|
||||
IgnoreExtraInput = 0x0001,
|
||||
InitRun = 0x0002,
|
||||
AsyncMode = 0x0004,
|
||||
GotValue = 0x0008,
|
||||
BusOwner = 0x0010,
|
||||
Separator = 0x0020,
|
||||
ScanTried = 0x0040,
|
||||
AcceptInput = 0x0100,
|
||||
AcceptEvent = 0x0200,
|
||||
LockPending = 0x0400,
|
||||
WritePending = 0x0800,
|
||||
WaitPending = 0x1000,
|
||||
BusPending = LockPending|WritePending|WaitPending,
|
||||
ClearOnStart = InitRun|AsyncMode|GotValue|BusOwner|Separator|ScanTried|
|
||||
AcceptInput|AcceptEvent|BusPending
|
||||
};
|
||||
#include "MacroMagic.h"
|
||||
#include "time.h"
|
||||
|
||||
// Flags: 0x00FFFFFF reserved for StreamCore
|
||||
const unsigned long None = 0x0000;
|
||||
const unsigned long IgnoreExtraInput = 0x0001;
|
||||
const unsigned long InitRun = 0x0002;
|
||||
const unsigned long AsyncMode = 0x0004;
|
||||
const unsigned long GotValue = 0x0008;
|
||||
const unsigned long BusOwner = 0x0010;
|
||||
const unsigned long Separator = 0x0020;
|
||||
const unsigned long ScanTried = 0x0040;
|
||||
const unsigned long AcceptInput = 0x0100;
|
||||
const unsigned long AcceptEvent = 0x0200;
|
||||
const unsigned long LockPending = 0x0400;
|
||||
const unsigned long WritePending = 0x0800;
|
||||
const unsigned long WaitPending = 0x1000;
|
||||
const unsigned long Aborted = 0x2000;
|
||||
const unsigned long BusPending = LockPending|WritePending|WaitPending;
|
||||
const unsigned long ClearOnStart = InitRun|AsyncMode|GotValue|Aborted|
|
||||
BusOwner|Separator|ScanTried|
|
||||
AcceptInput|AcceptEvent|BusPending;
|
||||
|
||||
// The amount of time to wait before printing duplicated messages
|
||||
extern int streamErrorDeadTime;
|
||||
|
||||
struct StreamFormat;
|
||||
|
||||
@ -97,14 +105,15 @@ class StreamCore :
|
||||
StreamBusInterface::Client
|
||||
{
|
||||
protected:
|
||||
enum ProtocolResult {
|
||||
Success, LockTimeout, WriteTimeout, ReplyTimeout, ReadTimeout,
|
||||
ScanError, FormatError, Abort, Fault
|
||||
};
|
||||
|
||||
enum StartMode {
|
||||
StartNormal, StartInit, StartAsync
|
||||
};
|
||||
ENUM(ProtocolResult,
|
||||
Success, LockTimeout, WriteTimeout, ReplyTimeout, ReadTimeout, ScanError, FormatError, Abort, Fault, Offline);
|
||||
|
||||
ENUM(StartMode,
|
||||
StartNormal, StartInit, StartAsync);
|
||||
|
||||
ENUM (Commands,
|
||||
end, in, out, wait, event, exec, connect, disconnect);
|
||||
|
||||
class MutexLock
|
||||
{
|
||||
@ -135,10 +144,10 @@ protected:
|
||||
bool printValue(const StreamFormat& format, long value);
|
||||
bool printValue(const StreamFormat& format, double value);
|
||||
bool printValue(const StreamFormat& format, char* value);
|
||||
long scanValue(const StreamFormat& format, long& value);
|
||||
long scanValue(const StreamFormat& format, double& value);
|
||||
long scanValue(const StreamFormat& format, char* value, long maxlen);
|
||||
long scanValue(const StreamFormat& format);
|
||||
ssize_t scanValue(const StreamFormat& format, long& value);
|
||||
ssize_t scanValue(const StreamFormat& format, double& value);
|
||||
ssize_t scanValue(const StreamFormat& format, char* value, size_t& size);
|
||||
ssize_t scanValue(const StreamFormat& format);
|
||||
|
||||
StreamBuffer protocolname;
|
||||
unsigned long lockTimeout;
|
||||
@ -159,14 +168,19 @@ protected:
|
||||
StreamBuffer onReadTimeout; // error handler (optional)
|
||||
StreamBuffer onMismatch; // error handler (optional)
|
||||
const char* commandIndex; // current position
|
||||
const char* activeCommand; // start of current command
|
||||
char activeCommand; // current command
|
||||
StreamBuffer outputLine;
|
||||
StreamBuffer inputBuffer;
|
||||
StreamBuffer inputLine;
|
||||
long consumedInput;
|
||||
size_t consumedInput;
|
||||
ProtocolResult runningHandler;
|
||||
StreamBuffer fieldAddress;
|
||||
|
||||
// Keep track of errors to reduce logging frequencies
|
||||
ProtocolResult previousResult;
|
||||
time_t lastErrorTime;
|
||||
int numberOfErrors;
|
||||
|
||||
StreamIoStatus lastInputStatus;
|
||||
bool unparsedInput;
|
||||
|
||||
@ -194,8 +208,8 @@ protected:
|
||||
// StreamBusInterface::Client methods
|
||||
void lockCallback(StreamIoStatus status);
|
||||
void writeCallback(StreamIoStatus status);
|
||||
long readCallback(StreamIoStatus status,
|
||||
const void* input, long size);
|
||||
ssize_t readCallback(StreamIoStatus status,
|
||||
const void* input, size_t size);
|
||||
void eventCallback(StreamIoStatus status);
|
||||
void execCallback(StreamIoStatus status);
|
||||
void connectCallback(StreamIoStatus status);
|
||||
@ -205,6 +219,7 @@ protected:
|
||||
|
||||
// virtual methods
|
||||
virtual void protocolStartHook() {}
|
||||
virtual void inputHook(const void* input, size_t size) {};
|
||||
virtual void protocolFinishHook(ProtocolResult) {}
|
||||
virtual void startTimer(unsigned long timeout) = 0;
|
||||
virtual bool formatValue(const StreamFormat&, const void* fieldaddress) = 0;
|
||||
@ -217,9 +232,14 @@ public:
|
||||
StreamCore();
|
||||
virtual ~StreamCore();
|
||||
bool parse(const char* filename, const char* protocolname);
|
||||
void printProtocol();
|
||||
void printProtocol(FILE* = stdout);
|
||||
const char* name() { return streamname; }
|
||||
void printStatus(StreamBuffer& buffer);
|
||||
static const char* license(void);
|
||||
|
||||
private:
|
||||
char* printCommands(StreamBuffer& buffer, const char* c);
|
||||
bool checkShouldPrint(ProtocolResult newErrorType);
|
||||
};
|
||||
|
||||
#endif
|
||||
|