Compare commits
183 Commits
stream_2_7
...
2.8.2
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
65f46aec36 | |||
37d14caa5b | |||
384474f6fd | |||
17d8592574 |
7
.cvsignore
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
O.*
|
||||||
|
*~
|
||||||
|
bin
|
||||||
|
lib
|
||||||
|
dbd
|
||||||
|
include
|
||||||
|
*.pdf
|
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
O.*
|
||||||
|
*~
|
||||||
|
bin
|
||||||
|
lib
|
||||||
|
dbd
|
||||||
|
include
|
||||||
|
*.pdf
|
||||||
|
*.*log
|
63
GNUmakefile
@ -1,38 +1,27 @@
|
|||||||
# Remove this file if not using the PSI build system
|
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
|
include /ioc/tools/driver.makefile
|
||||||
EXCLUDE_VERSIONS = 3.13.2
|
EXCLUDE_VERSIONS = 3.13.2
|
||||||
PROJECT=stream
|
PROJECT=stream
|
||||||
BUILDCLASSES += Linux
|
BUILDCLASSES += Linux
|
||||||
|
|
||||||
#DOCUDIR = doc
|
DOCUDIR = docs
|
||||||
|
|
||||||
BUSSES += AsynDriver
|
PCRE=1
|
||||||
BUSSES += Dummy
|
ASYN=1
|
||||||
|
ifdef EPICSVERSION
|
||||||
FORMATS += Enum
|
ifndef RECORDTYPES
|
||||||
FORMATS += BCD
|
include src/CONFIG_STREAM
|
||||||
FORMATS += Raw
|
export RECORDTYPES BUSSES FORMATS
|
||||||
FORMATS += RawFloat
|
endif
|
||||||
FORMATS += Binary
|
endif
|
||||||
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 += $(RECORDTYPES:%=src/dev%Stream.c)
|
||||||
SOURCES += $(FORMATS:%=src/%Converter.cc)
|
SOURCES += $(FORMATS:%=src/%Converter.cc)
|
||||||
SOURCES += $(BUSSES:%=src/%Interface.cc)
|
SOURCES += $(BUSSES:%=src/%Interface.cc)
|
||||||
SOURCES += $(wildcard src/Stream*.cc)
|
SOURCES += $(STREAM_SRCS:%=src/%)
|
||||||
SOURCES += src/StreamVersion.c
|
|
||||||
|
|
||||||
HEADERS += devStream.h
|
HEADERS += devStream.h
|
||||||
HEADERS += StreamFormat.h
|
HEADERS += StreamFormat.h
|
||||||
@ -40,17 +29,25 @@ HEADERS += StreamFormatConverter.h
|
|||||||
HEADERS += StreamBuffer.h
|
HEADERS += StreamBuffer.h
|
||||||
HEADERS += StreamError.h
|
HEADERS += StreamError.h
|
||||||
|
|
||||||
ifneq (${EPICS_BASETYPE},3.13)
|
StreamCore.o StreamCore.d: streamReferences
|
||||||
RECORDTYPES += calcout
|
|
||||||
endif
|
|
||||||
|
|
||||||
StreamCore.o: streamReferences
|
# Update version string (contains __DATE__ and __TIME__)
|
||||||
|
# each time make runs.
|
||||||
|
StreamVersion.o: FORCE
|
||||||
|
FORCE:
|
||||||
|
|
||||||
streamReferences:
|
streamReferences:
|
||||||
perl ../src/makeref.pl Interface $(BUSSES) > $@
|
$(PERL) ../src/makeref.pl Interface $(BUSSES) > $@
|
||||||
perl ../src/makeref.pl Converter $(FORMATS) >> $@
|
$(PERL) ../src/makeref.pl Converter $(FORMATS) >> $@
|
||||||
|
|
||||||
export DBDFILES = streamSup.dbd
|
export DBDFILES = streamSup.dbd
|
||||||
streamSup.dbd:
|
streamSup.dbd:
|
||||||
@echo Creating $@
|
@echo Creating $@ from $(RECORDTYPES)
|
||||||
perl ../src/makedbd.pl $(RECORDTYPES) > $@
|
$(PERL) ../src/makedbd.pl $(RECORDTYPES) > $@
|
||||||
|
ifdef BASE_3_14
|
||||||
|
ifdef ASYN
|
||||||
|
echo "registrar(AsynDriverInterfaceRegistrar)" >> $@
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
38
Makefile
@ -1,24 +1,26 @@
|
|||||||
TOP = ..
|
TOP = ..
|
||||||
|
ifneq ($(wildcard ../configure),)
|
||||||
DIRS = src
|
# We are in an EPICS R3.14+ <TOP> location
|
||||||
streamApp_DEPEND_DIRS = src
|
include $(TOP)/configure/CONFIG
|
||||||
|
else ifneq ($(wildcard ../config),)
|
||||||
# Look if we have EPICS R3.13 or R3.14
|
# We are in an EPICS R3.13 <TOP> location
|
||||||
ifeq ($(wildcard $(TOP)/configure),)
|
CONFIG = $(TOP)/config
|
||||||
# EPICS R3.13
|
include $(TOP)/config/CONFIG_APP
|
||||||
include $(TOP)/config/CONFIG_APP
|
else
|
||||||
CONFIG = $(TOP)/config
|
# Using our own local configuration
|
||||||
else
|
TOP = .
|
||||||
# EPICS R3.14
|
DIRS = config configure
|
||||||
|
src_DEPEND_DIRS := $(DIRS)
|
||||||
include $(TOP)/configure/CONFIG
|
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
|
endif
|
||||||
|
|
||||||
|
DIRS += src
|
||||||
DIRS += streamApp
|
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
|
||||||
|
20
README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# StreamDevice
|
||||||
|
|
||||||
|
_StreamDevice_ is a generic [EPICS](https://www.aps.anl.gov/epics)
|
||||||
|
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.
|
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
|
7
config/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
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
|
# 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
|
build:: $(LIBNAME).munch
|
||||||
|
|
||||||
buildInstall:: $(INSTALL_BIN)/$(LIBNAME).munch
|
buildInstall:: $(INSTALL_BIN)/$(LIBNAME).munch
|
||||||
|
|
||||||
%.munch: %
|
%.munch: %
|
||||||
|
@echo "Munching $<"
|
||||||
$(RM) $*_ctct.o $*_ctdt.c
|
$(RM) $*_ctct.o $*_ctdt.c
|
||||||
$(NM) $< | $(MUNCH) > $*_ctdt.c
|
$(NM) $< | $(MUNCH) > $*_ctdt.c
|
||||||
$(GCC) -traditional $(CFLAGS) -fdollars-in-identifiers -c $(SOURCE_FLAG) $*_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;
|
14
configure/CONFIG
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#CONFIG
|
||||||
|
include $(TOP)/configure/CONFIG_APP
|
||||||
|
# Add any changes to make definitions here
|
||||||
|
|
||||||
|
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040
|
||||||
|
#CROSS_COMPILER_TARGET_ARCHS =
|
||||||
|
|
||||||
|
# Use this when your IOC and the host use different paths
|
||||||
|
# to access the application. Typically this will be
|
||||||
|
# used with the Microsoft FTP server or with NFS mounts. Use
|
||||||
|
# is indicated by failure of the cdCommands script on
|
||||||
|
# vxWorks. You must rebuild in the iocBoot directory
|
||||||
|
# before this takes effect.
|
||||||
|
#IOCS_APPL_TOP = <the top of the application as seen by the IOC>
|
27
configure/CONFIG_APP
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# CONFIG_APP
|
||||||
|
|
||||||
|
include $(TOP)/configure/RELEASE
|
||||||
|
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH)
|
||||||
|
-include $(TOP)/configure/RELEASE.Common.$(T_A)
|
||||||
|
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||||
|
|
||||||
|
ifneq ($(wildcard $(EPICS_BASE)/configure),)
|
||||||
|
CONFIG=$(EPICS_BASE)/configure
|
||||||
|
else
|
||||||
|
CONFIG=$(EPICS_BASE)/config
|
||||||
|
DIRS += config
|
||||||
|
endif
|
||||||
|
include $(CONFIG)/CONFIG
|
||||||
|
|
||||||
|
INSTALL_LOCATION = $(TOP)
|
||||||
|
ifdef INSTALL_LOCATION_APP
|
||||||
|
INSTALL_LOCATION = $(INSTALL_LOCATION_APP)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef T_A
|
||||||
|
-include $(TOP)/configure/O.$(T_A)/CONFIG_APP_INCLUDE
|
||||||
|
endif
|
||||||
|
|
||||||
|
# dbst based database optimization (default: NO)
|
||||||
|
DB_OPT = NO
|
||||||
|
HOST_OPT=NO
|
15
configure/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Makefile
|
||||||
|
|
||||||
|
TOP=..
|
||||||
|
|
||||||
|
include $(TOP)/configure/CONFIG_APP
|
||||||
|
|
||||||
|
# Set the following to NO to disable consistency checking of
|
||||||
|
# the support applications defined in $(TOP)/configure/RELEASE
|
||||||
|
CHECK_RELEASE = YES
|
||||||
|
|
||||||
|
TARGETS = $(CONFIG_TARGETS)
|
||||||
|
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||||
|
|
||||||
|
include $(TOP)/configure/RULES
|
||||||
|
|
43
configure/RELEASE
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#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>
|
||||||
|
|
||||||
|
|
||||||
|
EPICS_BASE=/usr/local/epics/base-3.16.1
|
||||||
|
ASYN=~/top-3.16/asyn4-30
|
||||||
|
CALC=~/top-3.16/SynApps/calc-2-8
|
||||||
|
PCRE=~/top-3.16/pcre-7-2
|
||||||
|
PCRE_INCLUDE_SL6-x86=/usr/include
|
||||||
|
PCRE_INCLUDE_SL6-x86_64=/usr/include
|
||||||
|
PCRE_INCLUDE_SL6-x86_64-clang=/usr/include
|
||||||
|
|
||||||
|
#EPICS_BASE=/usr/local/epics/base-3.15.5
|
||||||
|
#ASYN=~/top-3.15/asyn4-30
|
||||||
|
#CALC=~/top-3.15/SynApps/calc-2-8
|
||||||
|
#PCRE=~/top-3.15/pcre-7-2
|
||||||
|
|
||||||
|
#EPICS_BASE=/usr/local/epics/base-3.14.12
|
||||||
|
#ASYN=~/top/asyn4-30
|
||||||
|
#CALC=~/top/SynApps/calc-2-8
|
||||||
|
#PCRE=~/top/pcre-7-2
|
||||||
|
|
||||||
|
#3.14.8 does not understand ~
|
||||||
|
#EPICS_BASE=/usr/local/epics/base-3.14.8
|
||||||
|
#ASYN=/afs/psi.ch/user/z/zimoch/top/asyn-4.10
|
||||||
|
|
||||||
|
##Example 3.13 build
|
||||||
|
#EPICS_BASE=/usr/local/epics/base-3.13.10
|
||||||
|
#ASYN=/afs/psi.ch/user/z/zimoch/top_3.13/4-6
|
||||||
|
#COMPAT=/afs/psi.ch/user/z/zimoch/top_3.13
|
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
|
@ -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>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>Record API</h1>
|
|
||||||
|
|
||||||
<h2>Sorry, this documentation is still missing.</h2>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<p><small>Dirk Zimoch, 2006</small></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@ -1,25 +1,24 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: aai Records</title>
|
<title>StreamDevice: aai Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
<h1>aai Records</h1>
|
<h1>aai Records</h1>
|
||||||
<p>
|
<p>
|
||||||
<b>Note:</b> aai record support is disabled per default.
|
<b>Note:</b> In EPICS versions before 3.14.12, aai records may be disabled.
|
||||||
Enable it in <code>src/CONFIG_STREAM</code>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Normal Operation</h2>
|
<h2>Normal Operation</h2>
|
||||||
<p>
|
<p>
|
||||||
With aai records, the format converter is applied to
|
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>
|
or expected as specified by the <code>Separator</code>
|
||||||
<a href="protocol.html#sysvar">variable</a> in the protocol.
|
<a href="protocol.html#sysvar">variable</a> in the protocol.
|
||||||
When parsing input, a space as the first character of the
|
When parsing input, a space as the first character of the
|
||||||
@ -40,14 +39,19 @@ written.
|
|||||||
<p>
|
<p>
|
||||||
The format data type must be convertible to or from the type
|
The format data type must be convertible to or from the type
|
||||||
specified in the <code>FTVL</code> field.
|
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 variable <code><i>x[i]</i></code> stands for one element of
|
||||||
the written or read value.
|
the written or read value.
|
||||||
</p>
|
</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||||
<dd>
|
<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>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>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||||
@ -58,6 +62,7 @@ the written or read value.
|
|||||||
<dd>
|
<dd>
|
||||||
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
||||||
<code>FTVL</code> can be
|
<code>FTVL</code> can be
|
||||||
|
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
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>
|
zero-extended to long before converting them.<br>
|
||||||
<u>Input:</u> <code>VAL[i]=FTVL(<i>x[i])</i></code><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>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>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
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.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="calcout.html">calcout</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="scalcout.html">scalcout</a>
|
</nav>
|
||||||
</p>
|
Dirk Zimoch, 2018
|
||||||
<p><small>Dirk Zimoch, 2006</small></p>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,25 +1,24 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: aao Records</title>
|
<title>StreamDevice: aao Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
<h1>aao Records</h1>
|
<h1>aao Records</h1>
|
||||||
<p>
|
<p>
|
||||||
<b>Note:</b> aao record support is disabled per default.
|
<b>Note:</b> In EPICS versions before 3.14.12, aao records may be disabled.
|
||||||
Enable it in <code>src/CONFIG_STREAM</code>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Normal Operation</h2>
|
<h2>Normal Operation</h2>
|
||||||
<p>
|
<p>
|
||||||
With aao records, the format converter is applied to
|
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>
|
or expected as specified by the <code>Separator</code>
|
||||||
<a href="protocol.html#sysvar">variable</a> in the protocol.
|
<a href="protocol.html#sysvar">variable</a> in the protocol.
|
||||||
When parsing input, a space as the first character of the
|
When parsing input, a space as the first character of the
|
||||||
@ -40,14 +39,19 @@ A minimum of one element must be available.
|
|||||||
<p>
|
<p>
|
||||||
The format data type must be convertible to or from the type
|
The format data type must be convertible to or from the type
|
||||||
specified in the <code>FTVL</code> field.
|
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 variable <code><i>x[i]</i></code> stands for one element of
|
||||||
the written or read value.
|
the written or read value.
|
||||||
</p>
|
</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||||
<dd>
|
<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>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>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||||
@ -58,6 +62,7 @@ the written or read value.
|
|||||||
<dd>
|
<dd>
|
||||||
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
||||||
<code>FTVL</code> can be
|
<code>FTVL</code> can be
|
||||||
|
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
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>
|
zero-extended to long before converting them.<br>
|
||||||
<u>Input:</u> <code>VAL[i]=FTVL(<i>x[i])</i></code><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>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>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
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.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="calcout.html">calcout</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="scalcout.html">scalcout</a>
|
</nav>
|
||||||
</p>
|
Dirk Zimoch, 2018
|
||||||
<p><small>Dirk Zimoch, 2006</small></p>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: ai Records</title>
|
<title>StreamDevice: ai Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -65,25 +65,31 @@ written or read value.
|
|||||||
(treated as <code>0.0</code>).
|
(treated as <code>0.0</code>).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2015</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lan="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: ao Records</title>
|
<title>StreamDevice: ao Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" / />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" / />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" / />
|
||||||
|
<meta name="author" content="Dirk Zimoch" / />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -31,7 +31,7 @@ written or read value.
|
|||||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<u>Output:</u> <code><i>x</i>=RVAL</code><br>
|
<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
|
Note that the record calculates
|
||||||
<code>RVAL=(((OVAL-EOFF)/ESLO)-AOFF)/ASLO</code> if
|
<code>RVAL=(((OVAL-EOFF)/ESLO)-AOFF)/ASLO</code> if
|
||||||
<code>LINR=="LINEAR"</code>. <code>ESLO</code> and <code>EOFF</code>
|
<code>LINR=="LINEAR"</code>. <code>ESLO</code> and <code>EOFF</code>
|
||||||
@ -63,28 +63,33 @@ written or read value.
|
|||||||
present. In contrast to normal operation, output in DOUBLE format uses
|
present. In contrast to normal operation, output in DOUBLE format uses
|
||||||
<code>VAL</code> instead of <code>OVAL</code>. Note that the record
|
<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.
|
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>
|
</p>
|
||||||
<hr>
|
|
||||||
<p>
|
<footer>
|
||||||
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2015</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: bi Records</title>
|
<title>StreamDevice: bi Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -53,25 +53,31 @@ written or read value.
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: bo Records</title>
|
<title>StreamDevice: bo Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -52,25 +52,31 @@ written or read value.
|
|||||||
<code>RVAL</code> as well as to <code>RBV</code> and converted by the record.
|
<code>RVAL</code> as well as to <code>RBV</code> and converted by the record.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Bus API</title>
|
<title>StreamDevice: Bus API</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
href="http://www.aps.anl.gov/epics/modules/soft/asyn/">
|
href="http://www.aps.anl.gov/epics/modules/soft/asyn/">
|
||||||
<em>asynDriver</em></a>.
|
<em>asynDriver</em></a>.
|
||||||
You should first try to implement your bus driver compatible to
|
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.
|
Then it can be used by <em>StreamDevice</em> automatically.
|
||||||
Only if that does not work, write your own bus interface.
|
Only if that does not work, write your own bus interface.
|
||||||
</p>
|
</p>
|
||||||
@ -68,17 +68,13 @@ class MyInterface : StreamBusInterface
|
|||||||
// StreamBusInterface virtual methods
|
// StreamBusInterface virtual methods
|
||||||
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
|
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
|
||||||
bool <a href="#lock">unlock</a>();
|
bool <a href="#lock">unlock</a>();
|
||||||
bool <a href="#write">writeRequest</a>(const void* output, size_t size,
|
bool <a href="#write">writeRequest</a>(const void* output, size_t size, unsigned long writeTimeout_ms);
|
||||||
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="#read">readRequest</a>(unsigned long replyTimeout_ms,
|
|
||||||
unsigned long readTimeout_ms,
|
|
||||||
long expectedLength, bool async);
|
|
||||||
bool <a href="#read">supportsAsyncRead</a>();
|
bool <a href="#read">supportsAsyncRead</a>();
|
||||||
bool <a href="#event">supportsEvent</a>();
|
bool <a href="#event">supportsEvent</a>();
|
||||||
bool <a href="#event">acceptEvent</a>(unsigned long mask,
|
bool <a href="#event">acceptEvent</a>(unsigned long mask, unsigned long timeout_ms);
|
||||||
unsigned long replytimeout_ms);
|
bool <a href="#connect">connectRequest</a>(unsigned long timeout_ms);
|
||||||
bool <a href="#connect">connectRequest</a>(unsigned long connecttimeout_ms);
|
bool <a href="#connect">disconnectRequest</a>();
|
||||||
bool <a href="#connect">disconnect</a>();
|
|
||||||
void <a href="#lock">finish</a>();
|
void <a href="#lock">finish</a>();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -132,13 +128,13 @@ bool <a href="#event">supportsEvent</a>();
|
|||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool <a href="#event">acceptEvent</a>(unsigned long mask,
|
bool <a href="#event">acceptEvent</a>(unsigned long mask,
|
||||||
unsigned long replytimeout_ms);
|
unsigned long timeout_ms);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<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>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool <a href="#connect">disconnect</a>();
|
bool <a href="#connect">disconnectRequest</a>();
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void <a href="#lock">finish</a>();
|
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):
|
methods (most probably from another thread):
|
||||||
</p>
|
</p>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void <a href="#lock">lockCallback</a>(StreamIoStatus status);
|
void <a href="#lock">lockCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void <a href="#write">writeCallback</a>(StreamIoStatus status);
|
void <a href="#write">writeCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
long <a href="#read">readCallback</a>(StreamIoStatus status,
|
ssize_t <a href="#read">readCallback</a>(StreamIoStatus status,
|
||||||
const void* input = NULL,
|
const void* buffer = NULL,
|
||||||
long size = 0);
|
size_t size = 0);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void <a href="#event">eventCallback</a>(StreamIoStatus status);
|
void <a href="#event">eventCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void <a href="#connect">connectCallback</a>(StreamIoStatus status);
|
void <a href="#connect">connectCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void <a href="#connect">disconnectCallback</a>(StreamIoStatus status);
|
void <a href="#connect">disconnectCallback</a>(StreamIoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
|
|
||||||
<h3>Other provided methods, attibutes, and types</h3>
|
<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>
|
<div class="indent"><code>
|
||||||
enum StreamIoStatus {StreamIoSuccess, StreamIoTimeout, StreamIoNoReply, StreamIoEnd, StreamIoFault};
|
enum StreamIoStatus {StreamIoSuccess, StreamIoTimeout, StreamIoNoReply, StreamIoEnd, StreamIoFault};
|
||||||
</code></div>
|
</code></div>
|
||||||
|
<div class="indent"><code>
|
||||||
|
const char* ::toStr(StreamIoStatus);
|
||||||
|
</code></div>
|
||||||
|
|
||||||
<a name="theory"></a>
|
<a name="theory"></a>
|
||||||
<h2>Theory of Operation</h2>
|
<h2>Theory of Operation</h2>
|
||||||
@ -276,34 +275,47 @@ correct.
|
|||||||
<a name="connect"></a>
|
<a name="connect"></a>
|
||||||
<h3>Connecting and disconnecting</h3>
|
<h3>Connecting and disconnecting</h3>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool connectRequest(unsigned long connecttimeout_ms);
|
bool connectRequest(unsigned long timeout_ms);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool disconnect();
|
bool disconnectRequest();
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void connectCallback(IoStatus status);
|
void connectCallback(IoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void disconnectCallback(IoStatus status);
|
void disconnectCallback(IoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<p>
|
<p>
|
||||||
Connection should be handled automatically.
|
Whenever possible connection should be handled automatically.
|
||||||
If the device is disconnected, each attempt to access the
|
The interface should call <code>connectCallback()</code> when
|
||||||
device should try to (re-)connect.
|
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
|
Normally, the interface should not try to disconnect unless
|
||||||
the device does so.
|
the device does so automatically.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
However, sometimes the client wants to connect or
|
However, sometimes the client wants to connect or
|
||||||
disconnect explicitely.
|
disconnect explicitly.
|
||||||
To connect, the client calls <code>connectRequest()</code>.
|
To connect, the client calls <code>connectRequest()</code>.
|
||||||
This function should return <code>true</code> immediately
|
This function should set up things to reconnect but should not block
|
||||||
or <code>false</code> if the request cannot be accepted or connection
|
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.
|
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.
|
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
|
milliseconds, the bus interface should call
|
||||||
<code>connectCallback(StreamIoTimeout)</code>.
|
<code>connectCallback(StreamIoTimeout)</code>.
|
||||||
</p>
|
</p>
|
||||||
@ -313,11 +325,11 @@ something wrong with the I/O hardware,
|
|||||||
<code>connectCallback(StreamIoFault)</code> may be called.
|
<code>connectCallback(StreamIoFault)</code> may be called.
|
||||||
</p>
|
</p>
|
||||||
<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
|
This function should return <code>true</code> immediately or
|
||||||
<code>false</code> if the request cannot be accepted or connection
|
<code>false</code> if the request cannot be accepted or connection
|
||||||
handling is not supported.
|
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.
|
once the bus is disconnected. There is no timeout for this operation.
|
||||||
If disconnecting is impossible, the interface should call
|
If disconnecting is impossible, the interface should call
|
||||||
<code>connectCallback(StreamIoFault)</code>.
|
<code>connectCallback(StreamIoFault)</code>.
|
||||||
@ -326,10 +338,10 @@ If disconnecting is impossible, the interface should call
|
|||||||
<a name="lock"></a>
|
<a name="lock"></a>
|
||||||
<h3>Bus locking</h3>
|
<h3>Bus locking</h3>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool lockRequest(unsigned long lockTimeout_ms);
|
bool lockRequest(unsigned long timeout_ms);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void lockCallback(IoStatus status);
|
void lockCallback(IoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool unlock();
|
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
|
If the device is already locked, the bus interface should add itself to
|
||||||
a queue, sorted by <code>priority()</code>.
|
a queue, sorted by <code>priority()</code>.
|
||||||
As soon as the device is available, the bus interface should call
|
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>
|
If the bus cannot be locked within <code>lockTimeout_ms</code>
|
||||||
milliseconds, the bus interface should call
|
milliseconds, the bus interface should call
|
||||||
<code>lockCallback(StreamIoTimeout)</code>.
|
<code>lockCallback(StreamIoTimeout)</code>.
|
||||||
@ -369,7 +381,7 @@ locked the device.
|
|||||||
When the protocol ends and the device is locked, the client calls
|
When the protocol ends and the device is locked, the client calls
|
||||||
<code>unlock()</code>.
|
<code>unlock()</code>.
|
||||||
If other bus interfaces are in the lock queue, the next one should
|
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>
|
||||||
<p>
|
<p>
|
||||||
The client calls <code>finish()</code> when the protocol ends.
|
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);
|
size_t size, unsigned long writeTimeout_ms);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void writeCallback(IoStatus status);
|
void writeCallback(IoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
const char* getOutTerminator(size_t& length);
|
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.
|
or <code>false</code> if the request cannot be accepted.
|
||||||
It must not block until output has completed.
|
It must not block until output has completed.
|
||||||
After all output has been successfully transmitted, but not earlier, the
|
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>
|
||||||
<p>
|
<p>
|
||||||
If output blocks for <code>writeTimeout_ms</code> milliseconds,
|
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.
|
<code>writeCallback(StreamIoFault)</code> may be called.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The interface must transmit excactly the <code>size</code> bytes
|
The interface must send excactly the <code>size</code> bytes
|
||||||
from <code>output</code>.
|
from <code>output</code>, not less.
|
||||||
It must not change anything and it should not assume that
|
It should not change anything unless the bus needs some special
|
||||||
any bytes have a special meaning.
|
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>.
|
In particular, a null byte does not terminate <code>output</code>.
|
||||||
</p>
|
</p>
|
||||||
<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.
|
terminator has already been added to the output.
|
||||||
If <code>NULL</code> was returned, the client is not aware of a
|
If <code>NULL</code> was returned, the client is not aware of a
|
||||||
terminator (no outTerminator was defined in the protocol).
|
terminator (no outTerminator was defined in the protocol).
|
||||||
@ -450,9 +463,9 @@ bool readRequest(unsigned long replyTimeout_ms,
|
|||||||
long expectedLength, bool async);
|
long expectedLength, bool async);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
long readCallback(IoStatus status,
|
ssize_t readCallback(IoStatus status,
|
||||||
const void* input = NULL,
|
const void* buffer = NULL,
|
||||||
long size = 0);
|
size_t size = 0);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
const char* getInTerminator(size_t& length);
|
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.
|
It is not necessary to wait until all data has been received.
|
||||||
The bus interface can call <code>n=readCallback()</code> after
|
The bus interface can call <code>n=readCallback()</code> after
|
||||||
any amount of input has been received.
|
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.
|
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.
|
<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.
|
amount of additional input.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@ -559,46 +572,43 @@ something wrong with the I/O hardware,
|
|||||||
<code>readCallback(StreamIoFault)</code> may be called.
|
<code>readCallback(StreamIoFault)</code> may be called.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If the <code>async</code> flag is <code>true</code>, the client
|
Sometimes a client wishes to get any input received at any time, even
|
||||||
wants to read input asyncronously without any timeout.
|
when requested by another client.
|
||||||
That means, the bus interface should call <code>readCallback()</code>
|
If a client wishes to receive such asynchronous input, it first calls
|
||||||
even if the input was requested by another client.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If a client wishes to receive asynchonous input, it first calls
|
|
||||||
<code>supportsAsyncRead()</code>.
|
<code>supportsAsyncRead()</code>.
|
||||||
The default implementation of this method always returns
|
The default implementation of this method always returns
|
||||||
<code>false</code>.
|
<code>false</code>.
|
||||||
A bus interface may overwrite this method to return <code>true</code>
|
If a bus interface supports asynchronous input, it should overwrite
|
||||||
and eventually prepare for asynchonous input.
|
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 client is then allowed to call <code>readRequest()</code> with
|
||||||
the <code>async==true</code>.
|
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
|
It should receive a <code>readCallback()</code> of all input which came
|
||||||
in response to a synchonous (<code>async==false</code>) request from
|
in response to any synchonous (<code>async==false</code>) request from
|
||||||
another client (which of course should receive the input, too).
|
another client (which should receive the input, too).
|
||||||
The interface should also receive asynchonous input when no
|
The interface should also receive asynchronous input when no
|
||||||
synchonous client is active at the moment.
|
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.
|
may be active at the same time.
|
||||||
All of them should receive the same input.
|
All of them should receive the same input.
|
||||||
</p>
|
</p>
|
||||||
<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
|
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.
|
<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.
|
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.
|
It stays active until the next input arrives.
|
||||||
The client may reissue the asynchronous <code>readRequest()</code>
|
The client may reissue the asynchronous <code>readRequest()</code>
|
||||||
from within the <code>readCallback()</code> if it wants to continue
|
from within the <code>readCallback()</code> if it wants to continue
|
||||||
receiving asynchonous input.
|
receiving asynchronous input.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If the client calls <code>finish()</code> at any time, the bus
|
If the client calls <code>finish()</code> at any time, the bus
|
||||||
interface should cancel all outstanding requests, including
|
interface should cancel all outstanding requests, including
|
||||||
asynchonous read requests.
|
asynchronous read requests.
|
||||||
</p>
|
</p>
|
||||||
<a name="event"></a>
|
<a name="event"></a>
|
||||||
<h3>Handling events</h3>
|
<h3>Handling events</h3>
|
||||||
@ -606,10 +616,10 @@ asynchonous read requests.
|
|||||||
bool supportsEvent();
|
bool supportsEvent();
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms);
|
bool acceptEvent(unsigned long mask, unsigned long timeout_ms);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
void eventCallback(StreamIoStatus status);
|
void eventCallback(StreamIoStatus status = StreamIoSuccess);
|
||||||
</code></div>
|
</code></div>
|
||||||
<p>
|
<p>
|
||||||
An event is a sort of input from a device which is not part of
|
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
|
If <code>mask</code> is illegal, <code>acceptEvent()</code> should
|
||||||
return <code>false</code>.
|
return <code>false</code>.
|
||||||
The call to <code>acceptEvent()</code> must not block.
|
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
|
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
|
If no such event arrives within this time, the bus interface
|
||||||
should call <code>eventCallback(StreamIoTimeout)</code>.
|
should call <code>eventCallback(StreamIoTimeout)</code>.
|
||||||
</p>
|
</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
|
to <code>acceptEvent()</code> but after any previous call of any
|
||||||
other request method like <code>writeRequest()</code>.
|
other request method like <code>writeRequest()</code>.
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
|
||||||
<p><small>Dirk Zimoch, 2007</small></p>
|
<footer>
|
||||||
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: calcout Records</title>
|
<title>StreamDevice: calcout Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -59,25 +59,31 @@ Different record fields are used for output and input. The variable
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="scalcout.html">scalcout</a>
|
</nav>
|
||||||
</p>
|
Dirk Zimoch, 2018
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Using EPICS 3.13</title>
|
<title>StreamDevice: Using EPICS 3.13</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -218,7 +218,31 @@ asynSetOption ("PS1", 0, "stop", "1")
|
|||||||
|
|
||||||
<h2>7. <a href="setup.html#pro">Continue as with EPICS 3.14.</a></h2>
|
<h2>7. <a href="setup.html#pro">Continue as with EPICS 3.14.</a></h2>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p><small>Dirk Zimoch, 2006</small></p>
|
<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>
|
</body>
|
||||||
</html>
|
</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,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Format Converter API</title>
|
<title>StreamDevice: Format Converter API</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -44,7 +44,7 @@ class MyConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||||
int scanLong(const StreamFormat&, const char*, long&);
|
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||||
};
|
};
|
||||||
|
|
||||||
RegisterConverter(MyConverter,"Q");
|
RegisterConverter(MyConverter,"Q");
|
||||||
@ -73,17 +73,17 @@ Provide multiple classes, that's more efficient.
|
|||||||
<a name="parsing"></a>
|
<a name="parsing"></a>
|
||||||
<h3>Parsing</h3>
|
<h3>Parsing</h3>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
int parse (const StreamFormat& fmt, StreamBuffer& info,
|
int parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||||
const char*& source, bool scanFormat);
|
const char*& source, bool scanFormat);
|
||||||
</code></div>
|
</code></div>
|
||||||
<div class="indent"><code>
|
<div class="indent"><code>
|
||||||
struct StreamFormat {
|
struct StreamFormat {
|
||||||
char conv;
|
char conv;
|
||||||
StreamFormatType type;
|
StreamFormatType type;
|
||||||
unsigned char flags;
|
unsigned short flags;
|
||||||
short prec;
|
long prec;
|
||||||
unsigned short width;
|
unsigned long width;
|
||||||
unsigned short infolen;
|
unsigned long infolen;
|
||||||
const char* info;
|
const char* info;
|
||||||
};
|
};
|
||||||
</code></div>
|
</code></div>
|
||||||
@ -124,12 +124,12 @@ flags set:
|
|||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
It is not necessary that these flags have exactly the same meaning in your
|
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>
|
||||||
<p>
|
<p>
|
||||||
There are two additional flags, <code>default_flag</code> indicating a
|
There are two additional flags, <code>default_flag</code> indicating a
|
||||||
<code>?</code> and <code>compare_flag</code> indicating a <code>=</code>
|
<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.
|
are not of interest to the converter class.
|
||||||
</p>
|
</p>
|
||||||
<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>
|
from the format string as in the above example<br>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Return <code>long_format</code>, <em>double_format</em>,
|
Return <code>unsigned_format</code>, <code>signed_format</code>,
|
||||||
<em>string_format</em>, or <code>enum_format</code> depending on the
|
<code>double_format</code>, <code>string_format</code>, or
|
||||||
|
<code>enum_format</code> depending on the
|
||||||
datatype associated with the conversion character.
|
datatype associated with the conversion character.
|
||||||
It is not necessary to return the same value for print and for scan
|
It is not necessary to return the same value for print and for scan
|
||||||
formats.
|
formats.
|
||||||
You can even return different values depending on the format string,
|
You can even return different values depending on the format string.
|
||||||
but I can't imagine why anyone should do that.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If the format is not a real data conversion but does other things with
|
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>
|
||||||
<p>
|
<p>
|
||||||
Return <code>false</code> if there is any parse error or if print or scan
|
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>
|
</p>
|
||||||
|
|
||||||
<a name="printing_scanning"></a>
|
<a name="printing_scanning"></a>
|
||||||
@ -191,7 +192,45 @@ That method is called whenever the conversion appears in an output or input,
|
|||||||
respectively.
|
respectively.
|
||||||
You only need to implement the flavour of print and/or scan suitable for
|
You only need to implement the flavour of print and/or scan suitable for
|
||||||
the datatype returned by <code>parse()</code>.
|
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>
|
||||||
|
</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>
|
<p>
|
||||||
Now, <code>fmt.type</code> contains the value returned by <code>parse()</code>.
|
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
|
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>
|
<p>
|
||||||
In <code>print*()</code>, append the converted value to <code>output</code>.
|
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
|
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.
|
Return <code>true</code> on success, <code>false</code> on failure.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
In <code>scan*()</code>, read the value from input and return the number of
|
In <code>scan*()</code>, read the value from input and return the number of
|
||||||
consumed bytes.
|
consumed bytes or -1 on failure.
|
||||||
In the string version, don't write more bytes than <code>maxlen</code>!
|
|
||||||
If the <code>skip_flag</code> is set, you don't need to write to
|
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.
|
<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>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p><small>Dirk Zimoch, 2007</small></p>
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Format Converters</title>
|
<title>StreamDevice: Format Converters</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -55,17 +55,19 @@ The <code>#</code> flag may alter the format, depending on the
|
|||||||
converter (see below).
|
converter (see below).
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The '<code> </code>' (space) and <code>+</code> flags print a space
|
The '<code> </code>' (space) and <code>+</code> flags usually print a
|
||||||
or a <code>+</code> sign before positive numbers, where negative
|
space or a <code>+</code> sign before positive numbers, where negative
|
||||||
numbers would have a <code>-</code>.
|
numbers would have a <code>-</code>.
|
||||||
|
Some converters may redefine the meaning of these flags (see below).
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The <code>0</code> flag says that numbers should be left padded with
|
The <code>0</code> flag usually says that numbers should be left padded
|
||||||
<code>0</code> if <em>width</em> is larger than required.
|
with <code>0</code> if <em>width</em> is larger than required.
|
||||||
</p>
|
Some converters may redefine the meaning of this flag (see below).
|
||||||
<p>
|
<p>
|
||||||
The <code>-</code> flag specifies that output is left justified if
|
The <code>-</code> flag usually specifies that output is left justified
|
||||||
<em>width</em> is larger than required.
|
if <em>width</em> is larger than required.
|
||||||
|
Some converters may redefine the meaning of this flag (see below).
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The <code>?</code> flag makes failing input conversions succeed with
|
The <code>?</code> flag makes failing input conversions succeed with
|
||||||
@ -90,31 +92,31 @@ This feature has been added by Klemen Vodopivec, SNS.
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>in "%f";</code></td>
|
<td><code>in "%f";</code></td>
|
||||||
<td>float</td>
|
<td>Read a float value</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>out "%(HOPR)7.4f";</code></td>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>out "%#010x";</code></td>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>in "%[_a-zA-Z0-9]";</code></td>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>in "%*i";</code></td>
|
<td><code>in "%*i";</code></td>
|
||||||
<td>skipped integer number</td>
|
<td>Skip over an integer number</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>in "%?d";</code></td>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>in "%=.3f";</code></td>
|
<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>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -123,9 +125,9 @@ This feature has been added by Klemen Vodopivec, SNS.
|
|||||||
<h3>Default fields</h3>
|
<h3>Default fields</h3>
|
||||||
<p>
|
<p>
|
||||||
Every conversion character corresponds to one of the data types DOUBLE,
|
Every conversion character corresponds to one of the data types DOUBLE,
|
||||||
LONG, ENUM, or STRING.
|
LONG, ULONG, ENUM, or STRING.
|
||||||
In opposite to to <em>printf()</em> and <em>scanf()</em>, it is not
|
In contrast to to the C functions <em>printf()</em> and <em>scanf()</em>,
|
||||||
required to specify a variable for the conversion.
|
it is not required to specify a variable for the conversion.
|
||||||
The variable is typically the <code>VAL</code> or <code>RVAL</code> field
|
The variable is typically the <code>VAL</code> or <code>RVAL</code> field
|
||||||
of the record, selected automatically depending on the data type.
|
of the record, selected automatically depending on the data type.
|
||||||
Not all data types make sense for all record types.
|
Not all data types make sense for all record types.
|
||||||
@ -141,23 +143,50 @@ exist in <em>StreamDevice</em> formats.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="redirection"></a>
|
<a name="redirection"></a>
|
||||||
<h3>Redirection</h3>
|
<h3>I/O Redirection to other records or fields</h3>
|
||||||
<p>
|
<p>
|
||||||
To use other fields of the record or even fields of other records on the
|
To use formats with other than the default fields of a record or even with
|
||||||
same IOC for the conversion, write the field name in parentheses directly
|
fields of other records on the same IOC, use the syntax
|
||||||
after the <code>%</code>.
|
<code>%(<var>record</var>.<var>FIEL</var>D)</code>.
|
||||||
For example <code>out "%(EGU)s";</code> outputs the <code>EGU</code>
|
If only a field name but no record is given, the active record is assumed.
|
||||||
field formatted as a string.
|
If only a record name but no field name is given, the <code>VAL</code>
|
||||||
Use <code>in "%(<i>otherrecord</i>.RVAL)f";</code> to write the floating
|
field is assumed.
|
||||||
point input value into the <code>RVAL</code> field of
|
|
||||||
<code><i>otherrecord</i></code>.
|
|
||||||
If no field is given for an other record .VAL is assumed.
|
|
||||||
When a record name conflicts with a field name use .VAL explicitly.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
This feature is very useful when one line of input contains many values that should
|
<b>Example 1:</b> <code>out "%(EGU)s";</code> outputs the
|
||||||
be distributed to many records.
|
<code>EGU</code> field of the active record.
|
||||||
If <code><i>otherrecord</i></code> is passive and the field has the PP
|
</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
|
attribute (see
|
||||||
<a href="http://www.aps.anl.gov/asd/controls/epics/EpicsDocumentation/AppDevManuals/RecordRef/Recordref-1.html"
|
<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.
|
target="ex">Record Reference Manual</a>), the record will be processed.
|
||||||
@ -166,17 +195,20 @@ compatible to the the data type of the converter.
|
|||||||
STRING formats are compatible with arrays of CHAR or UCHAR.
|
STRING formats are compatible with arrays of CHAR or UCHAR.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Note that using this syntax is by far not as efficient as using the
|
Be aware that using this syntax is by far not as efficient as using the
|
||||||
default field.
|
default field.
|
||||||
At the moment it is not possible to set <code>otherrecord</code> to an alarm
|
At the moment it is not possible to set the other record to an alarm
|
||||||
state when anything fails.
|
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>
|
</p>
|
||||||
|
|
||||||
<h3>Pseudo-converters</h3>
|
<h3>Pseudo-converters</h3>
|
||||||
<p>
|
<p>
|
||||||
Some formats are not actually converters.
|
Some formats are not actually converters.
|
||||||
They format data which is not stored in a record field, such as a
|
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
|
No data type corresponds to those <em>pseudo-converters</em> and the
|
||||||
<code>%(<em>FIELD</em>)</code> syntax cannot be used.
|
<code>%(<em>FIELD</em>)</code> syntax cannot be used.
|
||||||
</p>
|
</p>
|
||||||
@ -207,7 +239,7 @@ field witdth when the space flag is used.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="stdl"></a>
|
<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>
|
<code>%u</code>, <code>%o</code>, <code>%x</code>, <code>%X</code>)</h2>
|
||||||
<p>
|
<p>
|
||||||
<b>Output</b>: <code>%d</code> and <code>%i</code> print signed decimal,
|
<b>Output</b>: <code>%d</code> and <code>%i</code> print signed decimal,
|
||||||
@ -266,6 +298,11 @@ The empty string matches.
|
|||||||
With the <code>#</code> flag <code>%s</code> matches a sequence of not-null
|
With the <code>#</code> flag <code>%s</code> matches a sequence of not-null
|
||||||
characters instead of non-whitespace characters.
|
characters instead of non-whitespace characters.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
With the <code>0</code> flag <code>%s</code> pads with 0 bytes instead of
|
||||||
|
spaces.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<a name="cset"></a>
|
<a name="cset"></a>
|
||||||
<h2>6. Standard Charset STRING Converter (<code>%[<em>charset</em>]</code>)</h2>
|
<h2>6. Standard Charset STRING Converter (<code>%[<em>charset</em>]</code>)</h2>
|
||||||
@ -301,7 +338,8 @@ Unassigned strings increment their values by 1 as usual.
|
|||||||
<p>
|
<p>
|
||||||
If one string is the initial substing of another, the substing must come
|
If one string is the initial substing of another, the substing must come
|
||||||
later to ensure correct matching.
|
later to ensure correct matching.
|
||||||
In particular if one string is the emptry string, it must be the last one.
|
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.
|
Use <code>#</code> and <code>=</code> to renumber if necessary.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@ -318,14 +356,14 @@ a <code>\</code> must be used to escape the character.
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<b>Output:</b> 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 no value matches.
|
or the default if given and no value matches.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<b>Input:</b> 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>
|
</p>
|
||||||
|
|
||||||
<a name="bin"></a>
|
<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>
|
<p>
|
||||||
This format prints or scans an unsigned integer represented as a binary
|
This format prints or scans an unsigned integer represented as a binary
|
||||||
string (one character per bit).
|
string (one character per bit).
|
||||||
@ -355,7 +393,7 @@ one character.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="raw"></a>
|
<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>
|
<p>
|
||||||
The raw converter does not really "convert".
|
The raw converter does not really "convert".
|
||||||
A signed or unsigned integer value is written or read in the internal
|
A signed or unsigned integer value is written or read in the internal
|
||||||
@ -400,7 +438,7 @@ The <em>width</em> must be 4 (float) or 8 (double). The default is 4.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="bcd"></a>
|
<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>
|
<p>
|
||||||
Packed BCD is a format where each byte contains two binary coded
|
Packed BCD is a format where each byte contains two binary coded
|
||||||
decimal digits (<code>0</code> ... <code>9</code>).
|
decimal digits (<code>0</code> ... <code>9</code>).
|
||||||
@ -449,8 +487,17 @@ With the <code>#</code> flag, the byte order is changed to <em>little
|
|||||||
endian</em>, i.e. least significant byte first.
|
endian</em>, i.e. least significant byte first.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The <code>0</code> flag changes the checksum representation from
|
The <code>0</code> flag changes the checksum representation to
|
||||||
binary to hexadecimal ASCII (2 bytes per checksum byte).
|
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
|
In output, the case of the ASCII checksum matches the case of first
|
||||||
letter of the function name.
|
letter of the function name.
|
||||||
@ -562,10 +609,15 @@ in architecture specific RELEASE.Common.<em>arch</em> files.
|
|||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
If the regular expression is not anchored, i.e. does not start with
|
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.
|
A maximum of <em>width</em> bytes is matched, if specified.
|
||||||
If <em>precision</em> is given, it specifies the sub-expression whose match
|
If <em>precision</em> is given, it specifies the sub-expression in <code>()</code>
|
||||||
is retuned.
|
whose match is returned.
|
||||||
Otherwise the complete match is returned.
|
Otherwise the complete match is returned.
|
||||||
In any case, the complete match is consumed from the input buffer.
|
In any case, the complete match is consumed from the input buffer.
|
||||||
If the expression contains a <code>/</code> it must be escaped like <code>\/</code>.
|
If the expression contains a <code>/</code> it must be escaped like <code>\/</code>.
|
||||||
@ -586,12 +638,19 @@ as a post-processor for output.
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Matches of the <em>regex</em> are replaced by the string <em>subst</em> with all
|
Matches of the <em>regex</em> are replaced by the string <em>subst</em> with all
|
||||||
<code>&</code> or <code>\0</code> in <em>subst</em> replaced with the match itself and 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.
|
<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.
|
||||||
|
|
||||||
|
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
|
To get a literal <code>&</code> or <code>\</code> or <code>/</code> in the substitution write
|
||||||
<code>\&</code> or <code>\\</code> or <code>\/</code>.
|
<code>\&</code> or <code>\\</code> or <code>\/</code>.
|
||||||
There is no way to specify literal bytes with values less or equal to 9 in the
|
|
||||||
substitution!
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If <em>width</em> is specified, it limits the number of characters processed.
|
If <em>width</em> is specified, it limits the number of characters processed.
|
||||||
@ -714,8 +773,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
|
Thus, only the English month names can be used (week day names are
|
||||||
ignored anyway).
|
ignored anyway).
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
|
||||||
<p align="right"><a href="processing.html">Next: Record Processing</a></p>
|
<footer>
|
||||||
<p><small>Dirk Zimoch, 2015</small></p>
|
<a href="processing.html">Next: Record Processing</a>
|
||||||
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice</title>
|
<title>StreamDevice</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
<h2>What is <em>StreamDevice</em>?</h2>
|
<h2>What is <em>StreamDevice</em>?</h2>
|
||||||
<p>
|
<p>
|
||||||
<em>StreamDevice</em> is a generic
|
<em>StreamDevice</em> is a generic
|
||||||
<a href="http://www.aps.anl.gov/epics" target="ex">EPICS</a>
|
<a href="https://www.aps.anl.gov/epics" target="ex">EPICS</a>
|
||||||
device support for devices with a "byte stream" based
|
device support for devices with a "byte stream" based
|
||||||
communication interface.
|
communication interface.
|
||||||
That means devices that can be controlled by sending and
|
That means devices that can be controlled by sending and
|
||||||
@ -52,7 +52,7 @@ It does not provide loops or branches.
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<em>StreamDevice</em> comes with an interface to<a target="ex"
|
<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>
|
<em>asynDriver</em></a>
|
||||||
but can be extended to
|
but can be extended to
|
||||||
<a href="businterface.html">support other bus drivers</a>.
|
<a href="businterface.html">support other bus drivers</a>.
|
||||||
@ -82,14 +82,26 @@ primitive commands.
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
It is not a block oriented device support.
|
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.
|
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>
|
</p>
|
||||||
|
|
||||||
<h2>Recommended Readings</h2>
|
<h2>Recommended Readings</h2>
|
||||||
<p>
|
<p>
|
||||||
<a href="http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide"
|
IOC Application Developer's Guide:
|
||||||
target="ex">IOC Application Developer's Guide</a>
|
<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/5-docs/AppDevGuide/AppDevGuide.html"
|
||||||
|
target="ex">R3.15.5</a>,
|
||||||
|
<a href="https://epics.anl.gov/base/R3-16/1-docs/AppDevGuide/AppDevGuide.html"
|
||||||
|
target="ex">R3.16.1</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="https://wiki-ext.aps.anl.gov/epics/index.php/RRM_3-14"
|
<a href="https://wiki-ext.aps.anl.gov/epics/index.php/RRM_3-14"
|
||||||
@ -104,8 +116,32 @@ This marks text you typically type in configuration files etc.
|
|||||||
<pre>
|
<pre>
|
||||||
Longer code segments are often set in a box.
|
Longer code segments are often set in a box.
|
||||||
</pre>
|
</pre>
|
||||||
<hr>
|
|
||||||
<p align="right"><a href="setup.html">Next: Setup</a></p>
|
<h2>Changes in Version 2.8</h2>
|
||||||
<p><small>Dirk Zimoch, 2015</small></p>
|
<ul>
|
||||||
|
<li>Support standard EPICS module build system.
|
||||||
|
<li>Compatible with EPICS base releases up to 7.0.1.
|
||||||
|
<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>Errors are new silent by default (var streamError 0) except during init.
|
||||||
|
<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>
|
</body>
|
||||||
</html>
|
</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,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: longin Records</title>
|
<title>StreamDevice: longin Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -46,25 +46,31 @@ written or read value.
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</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="mbbiDirect.html">mbbiDirect</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: longout Records</title>
|
<title>StreamDevice: longout Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -46,25 +46,31 @@ written or read value.
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</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="mbbiDirect.html">mbbiDirect</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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>
|
@ -1,3 +1,11 @@
|
|||||||
|
#/bin/sh
|
||||||
|
if ! wkhtmltopdf -V >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "wkhtmltopdf not installed." >&2
|
||||||
|
echo "See https://wkhtmltopdf.org" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
PAGES="
|
PAGES="
|
||||||
index.html
|
index.html
|
||||||
setup.html
|
setup.html
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: mbbi Records</title>
|
<title>StreamDevice: mbbi Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -70,25 +70,31 @@ written or read value.
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: mbbiDirect Records</title>
|
<title>StreamDevice: mbbiDirect Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -56,25 +56,31 @@ written or read value.
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">calcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: mbbo Records</title>
|
<title>StreamDevice: mbbo Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -33,11 +33,11 @@ written or read value.
|
|||||||
Note that the record calculates <code>RVAL</code> by choosing one of
|
Note that the record calculates <code>RVAL</code> by choosing one of
|
||||||
<code>ZRVL</code> ... <code>FFVL</code> depending on <code>VAL</code>
|
<code>ZRVL</code> ... <code>FFVL</code> depending on <code>VAL</code>
|
||||||
and by shifting it left by <code>SHFT</code> bits.<br>
|
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
|
<code>MASK</code> is initialized to <code>NOBT</code> 1-bits shifted
|
||||||
left by <code>SHFT</code>. If <code>MASK==0</code> (because
|
left by <code>SHFT</code>. If <code>MASK==0</code> (because
|
||||||
<code>NOBT</code> was not set) it is ignored, i.e.
|
<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>
|
</dd>
|
||||||
<dt>If none of <code>ZRVL</code> ... <code>FFVL</code> is set
|
<dt>If none of <code>ZRVL</code> ... <code>FFVL</code> is set
|
||||||
(all are <code>0</code>):</dt>
|
(all are <code>0</code>):</dt>
|
||||||
@ -66,30 +66,34 @@ written or read value.
|
|||||||
<h2>Initialization</h2>
|
<h2>Initialization</h2>
|
||||||
<p>
|
<p>
|
||||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
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
|
present.
|
||||||
<code>RVAL</code> as well as to <code>RBV</code> and converted by the
|
|
||||||
record.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: mbboDirect Records</title>
|
<title>StreamDevice: mbboDirect Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -23,26 +23,23 @@ written or read value.
|
|||||||
<dd>
|
<dd>
|
||||||
Not allowed.
|
Not allowed.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>LONG format (e.g. <code>%i</code>):</dt>
|
<dt>LONG or ENUM format (e.g. <code>%i</code>):</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>If <code>MASK==0</code> (because <code>NOBT</code> is not set):</dt>
|
<dt>If <code>MASK==0</code> (because <code>NOBT</code> is not set):</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<u>Output:</u> <code><i>x</i>=VAL</code><br>
|
<u>Output:</u> <code><i>x</i>=RVAL</code><br>
|
||||||
<u>Input:</u> <code>VAL=<i>x</i></code><br>
|
<u>Input:</u> <code>RAL=<i>x</i></code>, <code>VAL=RVAL>>SHFT</code><br>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>If <code>MASK!=0</code>:</dt>
|
<dt>If <code>MASK!=0</code>:</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<u>Output:</u> <code><i>x</i>=RVAL&MASK</code><br>
|
<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>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<code>MASK</code> is initialized to <code>NOBT</code> 1-bits shifted
|
<code>MASK</code> is initialized to <code>NOBT</code> 1-bits shifted
|
||||||
left by <code>SHFT</code>.
|
left by <code>SHFT</code> (<code>((2^NOBT)-1)<<SHFT</code>).
|
||||||
</dd>
|
The record calculates <code>RVAL=VAL<<SHFT</code>.
|
||||||
<dt>ENUM format (e.g. <code>%{</code>):</dt>
|
|
||||||
<dd>
|
|
||||||
Not allowed.
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
<dt>STRING format (e.g. <code>%s</code>):</dt>
|
||||||
<dd>
|
<dd>
|
||||||
@ -53,30 +50,34 @@ written or read value.
|
|||||||
<h2>Initialization</h2>
|
<h2>Initialization</h2>
|
||||||
<p>
|
<p>
|
||||||
During <a href="processing.html#init">initialization</a>, the <code>@init</code> handler is executed, if
|
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
|
present.
|
||||||
<code>RVAL</code> as well as to <code>RBV</code> and converted by the
|
|
||||||
record if <code>MASK!=0</code>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,10 +1,10 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>Navbar</title>
|
<title>Navbar</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<meta charset="utf-8" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
<!--
|
<!--
|
||||||
body {margin:0 0 13ex 1em;
|
body {margin:0 0 13ex 1em;
|
||||||
@ -156,17 +156,21 @@ div div div a {list-style-type:circle;}
|
|||||||
<a target="_parent" href="ao.html">ao</a>
|
<a target="_parent" href="ao.html">ao</a>
|
||||||
<a target="_parent" href="bi.html">bi</a>
|
<a target="_parent" href="bi.html">bi</a>
|
||||||
<a target="_parent" href="bo.html">bo</a>
|
<a target="_parent" href="bo.html">bo</a>
|
||||||
<a target="_parent" href="mbbi.html">mbbi</a>
|
<a target="_parent" href="calcout.html">calcout</a>
|
||||||
<a target="_parent" href="mbbo.html">mbbo</a>
|
<a target="_parent" href="int64in.html">int64in</a>
|
||||||
<a target="_parent" href="mbbiDirect.html">mbbiDirect</a>
|
<a target="_parent" href="int64out.html">int64out</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="longin.html">longin</a>
|
<a target="_parent" href="longin.html">longin</a>
|
||||||
<a target="_parent" href="longout.html">longout</a>
|
<a target="_parent" href="longout.html">longout</a>
|
||||||
<a target="_parent" href="waveform.html">waveform</a>
|
<a target="_parent" href="lsi.html">lsi</a>
|
||||||
<a target="_parent" href="calcout.html">calcout</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="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>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -206,6 +210,15 @@ div div div a {list-style-type:circle;}
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a target="_parent" href="formatconverter.html">Format Converter API</a>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<a target="_parent" href="osinterface.html">Operating System API</a>
|
<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,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Record Processing</title>
|
<title>StreamDevice: Record Processing</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -54,22 +54,23 @@ its <code>SEVR</code> field set to <code>INVALID</code> and its
|
|||||||
<dl>
|
<dl>
|
||||||
<dt><code>TIMEOUT</code></dt>
|
<dt><code>TIMEOUT</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
The device could not be locked (<code>LockTimeout</code>) or the
|
The device could not be locked (<code>LockTimeout</code>) because
|
||||||
device did not reply (<code>ReplyTimeout</code>).
|
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>
|
</dd>
|
||||||
<dt><code>WRITE</code></dt>
|
<dt><code>WRITE</code></dt>
|
||||||
<dd>
|
<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>
|
</dd>
|
||||||
<dt><code>READ</code></dt>
|
<dt><code>READ</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
Input from the device started but stopped unexpectedly
|
Input from the device started but stopped unexpectedly
|
||||||
(<code>ReadTimeout</code>).
|
(<a href="protocol.html#sysvar"><code>ReadTimeout</code></a>).
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>COMM</code></dt>
|
<dt><code>COMM</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
The device driver reported some other communication error (e.g.
|
The device driver reported that the device is disconnected.
|
||||||
unplugged cable).
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>CALC</code></dt>
|
<dt><code>CALC</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
@ -95,13 +96,14 @@ will be set according to the original error.
|
|||||||
<a name="init"></a>
|
<a name="init"></a>
|
||||||
<h2>2. Initialization</h2>
|
<h2>2. Initialization</h2>
|
||||||
<p>
|
<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.
|
booting the IOC, especially output records.
|
||||||
For this purpose, initialization is formally handled as an
|
For this purpose, initialization is formally handled as an
|
||||||
<a href="protocol.html#except">exception</a>.
|
<a href="protocol.html#except">exception</a>.
|
||||||
The <code>@init</code> handler is called as part of the
|
The <code>@init</code> handler is called as part of the
|
||||||
<code>initRecord()</code> function during <code>iocInit</code>
|
<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>
|
||||||
<p>
|
<p>
|
||||||
In contrast to <a href="#proc">normal processing</a>, the protocol
|
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
|
The <code>@init</code> handler has nothing to do with the
|
||||||
<code>PINI</code> field.
|
<code>PINI</code> field.
|
||||||
The handler does <u>not</u> process the record nor does it trigger
|
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.
|
It runs <u>before</u> <code>PINI</code> is handled.
|
||||||
If the record has <code>PINI=YES</code>, the <code>PINI</code>
|
If the record has <code>PINI=YES</code>, the <code>PINI</code>
|
||||||
processing is a <a href="#proc">normal processing</a> after the
|
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
|
or restored from a bump-less reboot system
|
||||||
(e.g. <em>autosave</em> from the <em>synApps</em> package).
|
(e.g. <em>autosave</em> from the <em>synApps</em> package).
|
||||||
</p>
|
</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>
|
<a name="iointr"></a>
|
||||||
<h2>3. I/O Intr</h2>
|
<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
|
from other requests, it silently ignores every message that does not start
|
||||||
with "<code>ROI</code>", followed by two floating point numbers.
|
with "<code>ROI</code>", followed by two floating point numbers.
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
|
||||||
<p align="right"><a href="recordtypes.html">Next: Supported Record Types</a></p>
|
<footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
<a href="recordtypes.html">Next: Supported Record Types</a>
|
||||||
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Protocol Files</title>
|
<title>StreamDevice: Protocol Files</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -556,11 +556,10 @@ There is a fixed set of exception handler names starting with
|
|||||||
<dt><code>@init</code></dt>
|
<dt><code>@init</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
Not really an exception but formally specified in the same syntax.
|
Not really an exception but formally specified in the same syntax.
|
||||||
This handler is called from <code>iocInit</code> during record
|
This handler can be used to initialize an output record with a value read from
|
||||||
initialization.
|
|
||||||
It can be used to initialize an output record with a value read from
|
|
||||||
the device.
|
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>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Example:</h3>
|
<h3>Example:</h3>
|
||||||
@ -577,8 +576,10 @@ is called but the protocol terminates immediately.
|
|||||||
An exception handler uses all <a href="#sysvar">system variable</a>
|
An exception handler uses all <a href="#sysvar">system variable</a>
|
||||||
settings from the protocol in which the exception occurred.
|
settings from the protocol in which the exception occurred.
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
|
||||||
<p align="right"><a href="formats.html">Next: Format Converters</a></p>
|
<footer>
|
||||||
<p><small>Dirk Zimoch, 2011</small></p>
|
<a href="formats.html">Next: Format Converters</a>
|
||||||
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Record Types</title>
|
<title>StreamDevice: Record Types</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -18,25 +18,32 @@
|
|||||||
in EPICS base which can have device support.
|
in EPICS base which can have device support.
|
||||||
</p>
|
</p>
|
||||||
<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="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
|
||||||
<a href="scalcout.html">scalcout</a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Each page describes which record fields are used in input and output
|
Each page describes which record fields are used in input and output
|
||||||
for different <a href="formats.html#types">format data types</a>
|
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>.
|
<a href="recordinterface.html">write support for other recordtypes</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: scalcout Records</title>
|
<title>StreamDevice: scalcout Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -29,7 +29,7 @@ before the final <code>return(0)</code>:
|
|||||||
</p>
|
</p>
|
||||||
<pre class="box">
|
<pre class="box">
|
||||||
if(pscalcoutDSET->init_record ) {
|
if(pscalcoutDSET->init_record ) {
|
||||||
return (*pscalcoutDSET->init_record)(pcalc);
|
return (*pscalcoutDSET->init_record)(pcalc);
|
||||||
}
|
}
|
||||||
</pre>
|
</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.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
</p>
|
Dirk Zimoch, 2018
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Setup</title>
|
<title>StreamDevice: Setup</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -15,13 +15,17 @@
|
|||||||
<a name="pre"></a>
|
<a name="pre"></a>
|
||||||
<h2>1. Prerequisites</h2>
|
<h2>1. Prerequisites</h2>
|
||||||
<p>
|
<p>
|
||||||
<em>StreamDevice</em> requires either
|
<em>StreamDevice</em> works with
|
||||||
<a href="http://www.aps.anl.gov/epics/base/R3-14/index.php"
|
<a href="https://epics.anl.gov/base/index.php">EPICS base</a>
|
||||||
target="ex">EPICS base R3.14.6 or higher</a> or
|
versions from R3.14.6 on, tested up to 7.0.1.
|
||||||
<a href="http://www.aps.anl.gov/epics/base/R3-13.php"
|
It also works (with limitations) with older
|
||||||
target="ex">EPICS base R3.13.7 or higher</a>.
|
<a href="https://www.aps.anl.gov/epics/base/R3-13.php">R3.13</a>
|
||||||
How to use <em>StreamDevice</em> on EPICS R3.13 is described on 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>.
|
<a href="epics3_13.html">separate page</a>.
|
||||||
|
<p>
|
||||||
|
Download and build the EPICS version of your choice first before continuing.
|
||||||
|
</p>
|
||||||
</p>
|
</p>
|
||||||
<h3>Fix required for base R3.14.8.2 and earlier on Windows</h3>
|
<h3>Fix required for base R3.14.8.2 and earlier on Windows</h3>
|
||||||
<p>
|
<p>
|
||||||
@ -34,107 +38,116 @@ and rebuild base.
|
|||||||
epicsShareFunc int epicsShareAPI iocshCmd(const char *command);
|
epicsShareFunc int epicsShareAPI iocshCmd(const char *command);
|
||||||
</pre>
|
</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>
|
<h3>Configuration</h3>
|
||||||
<p>
|
<p class="new">
|
||||||
<em>StreamDevice</em> does not come with its own <kbd><top></kbd>
|
<em>StreamDevice</em> now comes with a standard
|
||||||
location and <kbd><top>/configure</kbd> directory.
|
<kbd>configure</kbd> directory.
|
||||||
It expects to be put into an already existing <kbd><top></kbd>
|
But it can still be built in an external <em><top></em>
|
||||||
directory structure.
|
directory as in previous versions.
|
||||||
You can simply create one with <code>makeBaseApp.pl</code>
|
It will automatically detect <em><top></em> locations
|
||||||
(which is part of EPICS base):
|
from the presence of <kbd>../configure</kbd> or <kbd>../config</kbd>
|
||||||
</p>
|
directories.
|
||||||
<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>
|
</p>
|
||||||
|
<p class="new">
|
||||||
|
Edit the <kbd>configure/RELEASE</kbd> file to specify the install location
|
||||||
|
of EPICS base and of additional software modules, for example:
|
||||||
|
<pre>
|
||||||
|
EPICS_BASE=/home/epics/base-3.16.1
|
||||||
|
</pre>
|
||||||
|
|
||||||
<h4>Support for <em>asynDriver</em></h4>
|
<h4>Support for <em>asynDriver</em></h4>
|
||||||
<p>
|
<p>
|
||||||
You most probably want <em>asynDriver</em> support included, because that is the
|
You most probably want to have <em>asynDriver</em> support included, because
|
||||||
standard way for <em>StreamDevice</em> to talk to hardware.
|
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/"
|
First get and install
|
||||||
target="ex"><em>asynDriver</em></a> version 4-3 or higher before you build <em>StreamDevice</em>.
|
<a href="https://www.aps.anl.gov/epics/modules/soft/asyn/"
|
||||||
I have tested <em>StreamDevice</em> with <em>asynDriver</em> versions up to 4-17.
|
><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
|
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
|
<em><top></em> directory of your <em>asyn</em> installation to the
|
||||||
<kbd>RELEASE</kbd> file:
|
<kbd>configure/RELEASE</kbd> file:
|
||||||
<pre>
|
<pre>
|
||||||
ASYN=/home/epics/asyn4-17
|
ASYN=/home/epics/asyn4-30
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h4>Support for sCalcout record</h4>
|
<h4>Support for <em>sCalcout</em> record</h4>
|
||||||
<p>
|
<p>
|
||||||
The <a target="ex"
|
The <a
|
||||||
href="http://www.aps.anl.gov/bcda/synApps/calc/R2-8/sCalcoutRecord.html"
|
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 target="ex"
|
><em>sCalcout</em></a> record is part of <a
|
||||||
href="http://www.aps.anl.gov/aod/bcda/synApps/index.php"
|
href="https://www.aps.anl.gov/BCDA/synApps"
|
||||||
><em>synApps</em></a>.
|
><em>synApps</em></a>.
|
||||||
If <em>streamDevice</em> should be built with support for this record,
|
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.
|
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:
|
Add references to the <kbd>RELEASE</kbd> file as shown here:
|
||||||
<pre>
|
<pre>
|
||||||
CALC=/home/epics/synApps/calc-2-8
|
CALC=/home/epics/synApps/calc-R3-6-1
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
Up to <em>calc</em> release R2-6 (<em>synApps</em> release R5_1),
|
Up to <em>calc</em> release R2-6 (<em>synApps</em> release R5_1),
|
||||||
the <em>sCalcout</em> record needs a fix.
|
the <em>sCalcout</em> record needs a fix.
|
||||||
(See separate <a href="scalcout.html"><em>scalcout</em> page</a>.)
|
(See separate <a href="scalcout.html"><em>scalcout</em> page</a>.)
|
||||||
And the <em>calc</em> modue had dependencies on other <em>SynApps</em>
|
And the <em>calc</em> module had dependencies on other <em>SynApps</em>
|
||||||
modules. Release R2-8 or newer is recommended.
|
modules. Release R2-8 or newer is recommended.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Support for the scalcout is optional. <em>StreamDevice</em> works
|
Support for the <em>sCalcout</em> is optional. <em>StreamDevice</em> works
|
||||||
as well without scalcout or SynApps.
|
as well without <em>sCalcout</em> or <em>SynApps</em>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h4>Support for regular expression matching</h4>
|
<h4>Support for regular expression matching</h4>
|
||||||
<p>
|
<p>
|
||||||
If you want to enable regular expression matching, you need the <em>PCRE</em> package.
|
If you want to enable regular expression matching, you need the <em>PCRE</em> package.
|
||||||
For most Linux systems, it is already installed.
|
For most Linux systems, it is already installed.
|
||||||
In that case add the locations you have to make the locations of the
|
In that case tell <em>StreamDevice</em> the locations of the
|
||||||
<em>PCRE</em> header file and library known.
|
<em>PCRE</em> header file and library.
|
||||||
However, the pre-installed package can only by used for the host architecture.
|
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>
|
Thus, add them not to <kbd>RELEASE</kbd> but to
|
||||||
(if linux-x86 is your EPICS_HOST_ARCH).
|
<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.
|
Be aware that different Linux distributions may locate the files in different
|
||||||
|
directories.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
PCRE_INCLUDE=/usr/include/pcre
|
PCRE_INCLUDE=/usr/include/pcre
|
||||||
PCRE_LIB=/usr/lib
|
PCRE_LIB=/usr/lib
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<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 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"
|
<a href="https://sourceforge.net/projects/gnuwin32/files/pcre/7.0/pcre-7.0.exe/download"
|
||||||
target="ex">sourceforge</a>
|
>sourceforge</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If you want to have <em>PCRE</em> support on platforms that don't support it natively,
|
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.
|
e.g. vxWorks, it is probably the easiest to build <em>PCRE</em> as an EPICS module.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<h4>Building the <em>PCRE</em> package as an EPICS module</h4>
|
<h4>Building the <em>PCRE</em> package as an EPICS module</h4>
|
||||||
<p>
|
<p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
Download the <em>PCRE</em> package from <a target=ex href="http://www.pcre.org">www.pcre.org</a>.
|
Download the <em>PCRE</em> package from <a href="https://www.pcre.org">www.pcre.org</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Extract the <em>PCRE</em> package in the <kbd><top></kbd> directory of
|
Extract the <em>PCRE</em> package in the <kbd><top></kbd> directory of
|
||||||
@ -142,9 +155,9 @@ Extract the <em>PCRE</em> package in the <kbd><top></kbd> directory of
|
|||||||
<code>makeBaseApp.pl</code>.
|
<code>makeBaseApp.pl</code>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Download this <a target=ex href="http://epics.web.psi.ch/software/streamdevice/pcre/Makefile"
|
Download this <a href="http://epics.web.psi.ch/software/streamdevice/pcre/Makefile"
|
||||||
>Makefile</a> and this
|
>Makefile</a> and this
|
||||||
<a target=ex href="http://epics.web.psi.ch/software/streamdevice/pcre/fixforvxworks.pl"
|
<a href="http://epics.web.psi.ch/software/streamdevice/pcre/fixforvxworks.pl"
|
||||||
>fixforvxworks.pl</a> script and save them to the extracted pcre directory.
|
>fixforvxworks.pl</a> script and save them to the extracted pcre directory.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -165,34 +178,29 @@ Regular expressions are optional. If you don't want them, you don't need this.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="lib"></a>
|
<a name="lib"></a>
|
||||||
<h2>2. Build the <em>StreamDevice</em> Library</h2>
|
<h2>2. Building <em>StreamDevice</em></h2>
|
||||||
<p>
|
<p>
|
||||||
Unpack the
|
Go to the <em>StreamDevice</em> directory
|
||||||
<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>).
|
and run <code>make</code> (or <code>gmake</code>).
|
||||||
This will create and install the <em>stream</em> library and the
|
This will create and install the <em>stream</em> library and the
|
||||||
<kbd>stream.dbd</kbd> file.
|
<kbd>stream.dbd</kbd> file and an example IOC application.
|
||||||
</p>
|
</p>
|
||||||
<a name="app"></a>
|
|
||||||
<h2>3. Build an Application</h2>
|
|
||||||
<p>
|
<p>
|
||||||
To use <em>StreamDevice</em>, your application must be built with the
|
To use <em>StreamDevice</em>, your own application must be built with the
|
||||||
<em>asyn</em> and <em>stream</em> libraries and must load
|
<em>stream</em> and <em>asyn</em> (and optionally <em>pcre</em>) libraries
|
||||||
<kbd>asyn.dbd</kbd> and <kbd>stream.dbd</kbd>.
|
and must load <kbd>asyn.dbd</kbd> and <kbd>stream.dbd</kbd>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Include the following lines in your application Makefile:
|
Include the following lines in your application <kbd>Makefile</kbd>:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
PROD_LIBS += stream
|
PROD_LIBS += stream
|
||||||
PROD_LIBS += asyn
|
PROD_LIBS += asyn
|
||||||
|
PROD_LIBS += pcre
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
Include the following lines in your xxxAppInclude.dbd file to use
|
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,
|
<em>stream</em> and <em>asyn</em> with serial lines, IP sockets,
|
||||||
and vxi11 ("GPIB over ethernet") support.
|
and vxi11 ("GPIB over ethernet") support.
|
||||||
</p>
|
</p>
|
||||||
@ -210,7 +218,7 @@ subdirectory.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="sta"></a>
|
<a name="sta"></a>
|
||||||
<h2>4. The Startup Script</h2>
|
<h2>3. The Startup Script</h2>
|
||||||
<p>
|
<p>
|
||||||
<em>StreamDevice</em> is based on <a
|
<em>StreamDevice</em> is based on <a
|
||||||
href="protocol.html"><em>protocol files</em></a>.
|
href="protocol.html"><em>protocol files</em></a>.
|
||||||
@ -231,14 +239,14 @@ connected device.
|
|||||||
</p>
|
</p>
|
||||||
<h3>Example:</h3>
|
<h3>Example:</h3>
|
||||||
<p>
|
<p>
|
||||||
A power supply with serial communication (9600 baud, 8N1) is connected to
|
A device with serial communication (9600 baud, 8N1, no flow control) is
|
||||||
<kbd>/dev/ttyS1</kbd>.
|
connected to <kbd>/dev/ttyS1</kbd>.
|
||||||
The name of the power supply is <tt>PS1</tt>.
|
The name of the device shall be <tt>PS1</tt>.
|
||||||
Protocol files are either in the current working directory or in the
|
Protocol files are either in the current working directory or in the
|
||||||
<kbd>../protocols</kbd> directory.
|
<kbd>../protocols</kbd> directory.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Then the startup script must contain lines like this:
|
Then the startup script may look like this:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||||
@ -252,9 +260,28 @@ asynSetOption ("PS1", 0, "clocal", "Y")
|
|||||||
asynSetOption ("PS1", 0, "crtscts", "N")
|
asynSetOption ("PS1", 0, "crtscts", "N")
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>If the power supply was connected via telnet-style TCP/IP
|
<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,
|
at address 192.168.164.10 on port 23,
|
||||||
the startupscript would contain:
|
the startup script would contain:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
|
||||||
@ -274,7 +301,7 @@ vxi11Configure ("PS1","192.168.164.10",1,1000,"hpib")
|
|||||||
|
|
||||||
|
|
||||||
<a name="pro"></a>
|
<a name="pro"></a>
|
||||||
<h2>5. The Protocol File</h2>
|
<h2>4. The Protocol File</h2>
|
||||||
<p>
|
<p>
|
||||||
For each different type of hardware, create a protocol file
|
For each different type of hardware, create a protocol file
|
||||||
which defines protocols for all needed functions of the device.
|
which defines protocols for all needed functions of the device.
|
||||||
@ -300,17 +327,21 @@ 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.
|
Normally, an analog output record should write its value to the device.
|
||||||
But during startup, the record should be initialized from the the device.
|
But during startup, the record should be initialized from the the device.
|
||||||
The protocol file <kbd>ExamplePS.proto</kbd> defines the protocol
|
The protocol file <kbd>ExamplePS.proto</kbd> defines the protocols
|
||||||
<code>setCurrent</code>.
|
<code>getCurrent</code> and <code>setCurrent</code>.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
Terminator = CR LF;
|
Terminator = CR LF;
|
||||||
|
|
||||||
|
getCurent {
|
||||||
|
out "CURRENT?";
|
||||||
|
in "CURRENT %f A";
|
||||||
|
}
|
||||||
|
|
||||||
setCurrent {
|
setCurrent {
|
||||||
out "CURRENT %.2f";
|
out "CURRENT %.2f";
|
||||||
@init {
|
@init {
|
||||||
out "CURRENT?";
|
getCurent;
|
||||||
in "CURRENT %f A";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -322,8 +353,13 @@ During development, the protocol files might change frequently.
|
|||||||
To prevent restarting the IOC all the time, it is possible to reload
|
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
|
the protocol file of one or all records with the shell function
|
||||||
<code>streamReload("<var>record</var>")</code>.
|
<code>streamReload("<var>record</var>")</code>.
|
||||||
If <code>"<var>record</var>"</code> is not given, all records using
|
If <code>"<var>record</var>"</code> is not given
|
||||||
|
<span class="new">or empty</span>, all records using
|
||||||
<em>StreamDevice</em> reload their protocols.
|
<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
|
Furthermore, the <code>streamReloadSub</code> function can be used
|
||||||
with a subroutine record to reload all protocols.
|
with a subroutine record to reload all protocols.
|
||||||
</p>
|
</p>
|
||||||
@ -336,21 +372,26 @@ protocol is loaded.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<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.
|
See the <a href="protocol.html">next chapter</a> for protocol files in depth.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a name="rec"></a>
|
<a name="rec"></a>
|
||||||
<h2>6. Configure the Records</h2>
|
<h2>5. Configuring the Records</h2>
|
||||||
<p>
|
<p>
|
||||||
To make a record use <em>StreamDevice</em>, set its <code>DTYP</code> field to
|
To tell a record to use <em>StreamDevice</em>, set its <code>DTYP</code> field to
|
||||||
<code>"stream"</code>.
|
<code>"stream"</code>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The <code>INP</code> or <code>OUT</code> link has the form
|
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>.
|
<code>"@<var>filename protocol</var>[(<var>arg1</var>,<var>arg2</var>,...)] </var>bus</var> [<var>address</var> [<var>parameters</var>]]"</code>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Here, <code><var>file</var></code> is the name of the protocol file and
|
(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.
|
<code><var>protocol</var></code> is the name of a protocol defined in this file.
|
||||||
(See the <a href="protocol.html">next chapter</a>.)
|
(See the <a href="protocol.html">next chapter</a>.)
|
||||||
</p>
|
</p>
|
||||||
@ -358,22 +399,38 @@ Here, <code><var>file</var></code> is the name of the protocol file and
|
|||||||
If the protocol requires <a href="protocol.html#argvar">arguments</a>,
|
If the protocol requires <a href="protocol.html#argvar">arguments</a>,
|
||||||
specify them enclosed in parentheses:
|
specify them enclosed in parentheses:
|
||||||
<code><var>protocol</var>(<var>arg1,arg2,...</var>)</code>.
|
<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>
|
||||||
<p>
|
<p>
|
||||||
The communication channel is specified with <code><var>bus</var></code>
|
The communication channel is specified with <code><var>bus</var></code>
|
||||||
(aka <em>asynDriver</em> "port") and <code><var>addr</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.
|
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.
|
Optional <code><var>parameters</var></code> are passed to the bus driver.
|
||||||
|
(At the moment, no bus driver supports parameters.)
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>Example:</h3>
|
<h3>Example:</h3>
|
||||||
<p>
|
<p>
|
||||||
Create an output record to set the current of <tt>PS1</tt>.
|
Create an input record to read and an output record to set the current of <tt>PS1</tt>.
|
||||||
Use protocol <em>setCurrent</em> from file <em>ExamplePS.proto</em>.
|
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.
|
The bus is called <em>PS1</em> like the device.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<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")
|
record (ao, "PS1:I-set")
|
||||||
{
|
{
|
||||||
field (DESC, "Set current of PS1")
|
field (DESC, "Set current of PS1")
|
||||||
@ -388,8 +445,9 @@ record (ao, "PS1:I-set")
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p align="right"><a href="protocol.html">Next: Protocol Files</a></p>
|
<a href="protocol.html">Next: Protocol Files</a>
|
||||||
<p><small>Dirk Zimoch, 2011</small></p>
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -5,10 +5,10 @@ a:hover {color: #FF0000;}
|
|||||||
body {
|
body {
|
||||||
margin-right:1em;
|
margin-right:1em;
|
||||||
margin-left:15em;
|
margin-left:15em;
|
||||||
margin-top:70px;
|
margin-top:75px;
|
||||||
padding-top:1px;
|
padding-top:1px;
|
||||||
font-family: Helvetica, Arial, sans-serif;
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
font-size:14px;
|
font-size: 100%;
|
||||||
background-color:#ffffff;
|
background-color:#ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ pre {
|
|||||||
border:1px solid #000000;
|
border:1px solid #000000;
|
||||||
white-space:pre;
|
white-space:pre;
|
||||||
margin:2ex;
|
margin:2ex;
|
||||||
|
page-break-inside:avoid;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbd {
|
kbd {
|
||||||
@ -73,11 +74,30 @@ p {
|
|||||||
margin-bottom: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 {
|
small {
|
||||||
font-size:75%;
|
font-size:75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
|
font-size: 125%;
|
||||||
color: #008000;
|
color: #008000;
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: stringin Records</title>
|
<title>StreamDevice: stringin Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -43,25 +43,31 @@ written or read value.
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringout.html">stringout</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="calcout.html">calcout</a>
|
</nav>
|
||||||
<a href="scalcout.html">scalcout</a>
|
Dirk Zimoch, 2018
|
||||||
</p>
|
</footer>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: stringout Records</title>
|
<title>StreamDevice: stringout Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -43,25 +43,31 @@ written or read value.
|
|||||||
present. All format converters work like in normal operation.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</a>
|
<a href="longout.html">longout</a>
|
||||||
<a href="stringin.html">stringin</a>
|
<a href="lsi.html">lsi</a>
|
||||||
<a href="waveform.html">waveform</a>
|
<a href="lso.html">lso</a>
|
||||||
<a href="calcout.html">calcout</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="scalcout.html">scalcout</a>
|
||||||
</p>
|
<a href="stringin.html">stringin</a>
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
<a href="stringout.html">stringout</a>
|
||||||
|
<a href="waveform.html">waveform</a>
|
||||||
|
</nav>
|
||||||
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: Tips and Tricks</title>
|
<title>StreamDevice: Tips and Tricks</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -260,7 +260,7 @@ When asked "<code>CURRENT?</code>", the device send something like
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<code>
|
<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>
|
</code>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@ -406,7 +406,9 @@ and <a href="formats.html#redirection">redirections</a>.
|
|||||||
But this only works if the order of the values is predictible.
|
But this only works if the order of the values is predictible.
|
||||||
<i>StreamDevice</i> is not an XML parser! It always reads sequentially.
|
<i>StreamDevice</i> is not an XML parser! It always reads sequentially.
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
|
||||||
<p><small>Dirk Zimoch, 2012</small></p>
|
<footer>
|
||||||
|
Dirk Zimoch, 2018
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
<!DOCTYPE HTML>
|
||||||
"http://www.w3.org/TR/html4/loose.dtd">
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>StreamDevice: waveform Records</title>
|
<title>StreamDevice: waveform Records</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="stream.css">
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<link rel="stylesheet" type="text/css" href="stream.css" />
|
||||||
<meta name="author" content="Dirk Zimoch">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="author" content="Dirk Zimoch" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="nav.html" id="navleft"></iframe>
|
<iframe src="nav.html" id="navleft"></iframe>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
<h2>Normal Operation</h2>
|
<h2>Normal Operation</h2>
|
||||||
<p>
|
<p>
|
||||||
With waveform records, the format converter is applied to
|
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>
|
or expected as specified by the <code>Separator</code>
|
||||||
<a href="protocol.html#sysvar">variable</a> in the
|
<a href="protocol.html#sysvar">variable</a> in the
|
||||||
protocol.
|
protocol.
|
||||||
@ -37,14 +37,19 @@ written.
|
|||||||
<p>
|
<p>
|
||||||
The format data type must be convertible to or from the type
|
The format data type must be convertible to or from the type
|
||||||
specified in the <code>FTVL</code> field.
|
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 variable <code><i>x[i]</i></code> stands for one element of
|
||||||
the written or read value.
|
the written or read value.
|
||||||
</p>
|
</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
<dt>DOUBLE format (e.g. <code>%f</code>):</dt>
|
||||||
<dd>
|
<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>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>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
||||||
@ -55,6 +60,7 @@ the written or read value.
|
|||||||
<dd>
|
<dd>
|
||||||
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
<u>Output:</u> <code><i>x[i]</i>=long(VAL[i])</code><br>
|
||||||
<code>FTVL</code> can be
|
<code>FTVL</code> can be
|
||||||
|
<code>"INT64"</code>, <code>"UINT64"</code>,
|
||||||
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
<code>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
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>
|
zero-extended to long before converting them.<br>
|
||||||
<u>Input:</u> <code>VAL[i]=FTVL(<i>x[i])</i></code><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>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>"LONG"</code>, <code>"ULONG"</code>, <code>"SHORT"</code>,
|
||||||
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
<code>"USHORT"</code>, <code>"CHAR"</code>, <code>"UCHAR"</code>,
|
||||||
or <code>"ENUM"</code> (which is treated as <code>"USHORT"</code>).<br>
|
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.
|
present. All format converters work like in normal operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr>
|
<footer>
|
||||||
<p>
|
<nav>
|
||||||
<a href="aai.html">aai</a>
|
<a href="aai.html">aai</a>
|
||||||
<a href="aao.html">aao</a>
|
<a href="aao.html">aao</a>
|
||||||
<a href="ai.html">ai</a>
|
<a href="ai.html">ai</a>
|
||||||
<a href="ao.html">ao</a>
|
<a href="ao.html">ao</a>
|
||||||
<a href="bi.html">bi</a>
|
<a href="bi.html">bi</a>
|
||||||
<a href="bo.html">bo</a>
|
<a href="bo.html">bo</a>
|
||||||
<a href="mbbi.html">mbbi</a>
|
<a href="calcout.html">calcout</a>
|
||||||
<a href="mbbo.html">mbbo</a>
|
<a href="int64in.html">int64in</a>
|
||||||
<a href="mbbiDirect.html">mbbiDirect</a>
|
<a href="int64out.html">int64out</a>
|
||||||
<a href="mbboDirect.html">mbboDirect</a>
|
|
||||||
<a href="longin.html">longin</a>
|
<a href="longin.html">longin</a>
|
||||||
<a href="longout.html">longout</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="stringin.html">stringin</a>
|
||||||
<a href="stringout.html">stringout</a>
|
<a href="stringout.html">stringout</a>
|
||||||
<a href="calcout.html">calcout</a>
|
<a href="waveform.html">waveform</a>
|
||||||
<a href="scalcout.html">scalcout</a>
|
</nav>
|
||||||
</p>
|
Dirk Zimoch, 2018
|
||||||
<p><small>Dirk Zimoch, 2005</small></p>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the BCD format converter of StreamDevice. *
|
* This is the BCD format converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -27,7 +27,7 @@ class BCDConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||||
int scanLong(const StreamFormat&, const char*, long&);
|
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int BCDConverter::
|
int BCDConverter::
|
||||||
@ -39,64 +39,55 @@ parse(const StreamFormat& fmt, StreamBuffer&, const char*&, bool)
|
|||||||
bool BCDConverter::
|
bool BCDConverter::
|
||||||
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||||
{
|
{
|
||||||
unsigned char bcd[6]={0,0,0,0,0,0}; // sufficient for 2^32
|
unsigned char bcd;
|
||||||
int i;
|
long i, d, s;
|
||||||
int prec = fmt.prec; // number of nibbles
|
unsigned long prec = fmt.prec < 0 ? 2 * sizeof(value) : fmt.prec; // number of nibbles
|
||||||
if (prec == -1)
|
unsigned long width = (prec + (fmt.flags & sign_flag ? 2 : 1)) / 2;
|
||||||
{
|
unsigned long val = value;
|
||||||
prec = 2 * sizeof (value);
|
|
||||||
}
|
output.append('\0', width);
|
||||||
int width = (prec + (fmt.flags & sign_flag ? 2 : 1)) / 2;
|
|
||||||
if (fmt.width > width) width = fmt.width;
|
if (fmt.width > width) width = fmt.width;
|
||||||
if (fmt.flags & sign_flag && value < 0)
|
if (fmt.flags & sign_flag && value < 0)
|
||||||
{
|
val = -value;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
if (fmt.flags & alt_flag)
|
if (fmt.flags & alt_flag)
|
||||||
{
|
{
|
||||||
// least significant byte first (little endian)
|
i = -(long)width;
|
||||||
for (i = 0; i < (prec + 1) / 2; i++)
|
d = 1;
|
||||||
{
|
s = -1;
|
||||||
output.append(bcd[i]);
|
|
||||||
}
|
|
||||||
for (; i < width; i++)
|
|
||||||
{
|
|
||||||
output.append('\0');
|
|
||||||
}
|
|
||||||
output[-1] |= bcd[5];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// most significant byte first (big endian)
|
i = -1;
|
||||||
int firstbyte = output.length();
|
d = -1;
|
||||||
for (i = 0; i < width - (prec + 1) / 2; i++)
|
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[i] = bcd;
|
||||||
{
|
i += d;
|
||||||
output.append(bcd[i]);
|
}
|
||||||
}
|
if (fmt.flags & sign_flag && value < 0) {
|
||||||
output[firstbyte] |= bcd[5];
|
output[s] |= 0xf0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BCDConverter::
|
ssize_t BCDConverter::
|
||||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||||
{
|
{
|
||||||
int length = 0;
|
ssize_t consumed = 0;
|
||||||
int val = 0;
|
long val = 0;
|
||||||
unsigned char bcd1, bcd10;
|
unsigned char bcd1, bcd10;
|
||||||
int width = fmt.width;
|
long width = fmt.width;
|
||||||
if (width == 0) width = 1;
|
if (width == 0) width = 1;
|
||||||
if (fmt.flags & alt_flag)
|
if (fmt.flags & alt_flag)
|
||||||
{
|
{
|
||||||
@ -104,7 +95,8 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
int shift = 1;
|
int shift = 1;
|
||||||
while (width--)
|
while (width--)
|
||||||
{
|
{
|
||||||
bcd1 = bcd10 = (unsigned char) input[length++];
|
bcd1 = input[consumed++];
|
||||||
|
bcd10 = bcd1>>4;
|
||||||
bcd1 &= 0x0F;
|
bcd1 &= 0x0F;
|
||||||
bcd10 >>= 4;
|
bcd10 >>= 4;
|
||||||
if (bcd1 > 9 || shift * bcd1 < bcd1) break;
|
if (bcd1 > 9 || shift * bcd1 < bcd1) break;
|
||||||
@ -127,10 +119,10 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
while (width--)
|
while (width--)
|
||||||
{
|
{
|
||||||
long temp;
|
long temp;
|
||||||
bcd1 = bcd10 = (unsigned char) input[length];
|
bcd1 = input[consumed];
|
||||||
|
bcd10 = bcd1>>4;
|
||||||
bcd1 &= 0x0F;
|
bcd1 &= 0x0F;
|
||||||
bcd10 >>= 4;
|
if (consumed == 0 && fmt.flags & sign_flag && bcd10)
|
||||||
if (length == 0 && fmt.flags & sign_flag && bcd10)
|
|
||||||
{
|
{
|
||||||
sign = -1;
|
sign = -1;
|
||||||
bcd10 = 0;
|
bcd10 = 0;
|
||||||
@ -139,17 +131,17 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
temp = val * 100 + (bcd1 + 10 * bcd10);
|
temp = val * 100 + (bcd1 + 10 * bcd10);
|
||||||
if (temp < val)
|
if (temp < val)
|
||||||
{
|
{
|
||||||
length = 0;
|
consumed = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
val = temp;
|
val = temp;
|
||||||
length++;
|
consumed++;
|
||||||
}
|
}
|
||||||
val *= sign;
|
val *= sign;
|
||||||
}
|
}
|
||||||
if (length == 0) return -1;
|
if (consumed == 0) return -1;
|
||||||
value = val;
|
value = val;
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (BCDConverter, "D");
|
RegisterConverter (BCDConverter, "D");
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the binary format converter of StreamDevice. *
|
* This is the binary format converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -29,7 +29,7 @@ class BinaryConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||||
int scanLong(const StreamFormat&, const char*, long&);
|
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int BinaryConverter::
|
int BinaryConverter::
|
||||||
@ -42,7 +42,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
info.append("01");
|
info.append("01");
|
||||||
return unsigned_format;
|
return unsigned_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
// user defined characters for %B (next 2 in source)
|
// user defined characters for %B (next 2 in source)
|
||||||
if (*source)
|
if (*source)
|
||||||
{
|
{
|
||||||
@ -70,14 +70,14 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
prec = 32;
|
prec = 32;
|
||||||
#if (LONG_BIT > 32)
|
#if (LONG_BIT > 32)
|
||||||
if (x > 0xFFFFFFFF) { prec = 64; x >>=32; }
|
if (x > 0xFFFFFFFF) { prec = 64; x >>=32; }
|
||||||
#endif
|
#endif
|
||||||
if (x <= 0x0000FFFF) { prec -= 16; x <<=16; }
|
if (x <= 0x0000FFFF) { prec -= 16; x <<=16; }
|
||||||
if (x <= 0x00FFFFFF) { prec -= 8; x <<=8; }
|
if (x <= 0x00FFFFFF) { prec -= 8; x <<=8; }
|
||||||
if (x <= 0x0FFFFFFF) { prec -= 4; x <<=4; }
|
if (x <= 0x0FFFFFFF) { prec -= 4; x <<=4; }
|
||||||
if (x <= 0x3FFFFFFF) { prec -= 2; x <<=2; }
|
if (x <= 0x3FFFFFFF) { prec -= 2; x <<=2; }
|
||||||
if (x <= 0x7FFFFFFF) { prec -= 1; }
|
if (x <= 0x7FFFFFFF) { prec -= 1; }
|
||||||
}
|
}
|
||||||
int width = prec;
|
unsigned long width = prec;
|
||||||
if (fmt.width > width) width = fmt.width;
|
if (fmt.width > width) width = fmt.width;
|
||||||
char zero = fmt.info[0];
|
char zero = fmt.info[0];
|
||||||
char one = fmt.info[1];
|
char one = fmt.info[1];
|
||||||
@ -88,7 +88,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
if (!(fmt.flags & left_flag))
|
if (!(fmt.flags & left_flag))
|
||||||
{
|
{
|
||||||
// pad left
|
// pad left
|
||||||
while (width > prec)
|
while (width > (unsigned int)prec)
|
||||||
{
|
{
|
||||||
output.append(' ');
|
output.append(' ');
|
||||||
width--;
|
width--;
|
||||||
@ -112,7 +112,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
if (!(fmt.flags & left_flag))
|
if (!(fmt.flags & left_flag))
|
||||||
{
|
{
|
||||||
// pad left
|
// pad left
|
||||||
while (width > prec)
|
while (width > (unsigned int)prec)
|
||||||
{
|
{
|
||||||
output.append(fill);
|
output.append(fill);
|
||||||
width--;
|
width--;
|
||||||
@ -132,39 +132,39 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BinaryConverter::
|
ssize_t BinaryConverter::
|
||||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||||
{
|
{
|
||||||
long val = 0;
|
long val = 0;
|
||||||
int width = fmt.width;
|
long width = fmt.width;
|
||||||
if (width == 0) width = -1;
|
if (width == 0) width = -1;
|
||||||
int length = 0;
|
size_t consumed = 0;
|
||||||
char zero = fmt.info[0];
|
char zero = fmt.info[0];
|
||||||
char one = fmt.info[1];
|
char one = fmt.info[1];
|
||||||
if (!isspace(zero) && !isspace(one))
|
if (!isspace(zero) && !isspace(one))
|
||||||
while (isspace(input[length])) length++; // skip whitespaces
|
while (isspace(input[consumed])) consumed++; // skip whitespaces
|
||||||
if (input[length] != zero && input[length] != one) return -1;
|
if (input[consumed] != zero && input[consumed] != one) return -1;
|
||||||
if (fmt.flags & alt_flag)
|
if (fmt.flags & alt_flag)
|
||||||
{
|
{
|
||||||
// little endian (least significan bit first)
|
// little endian (least significan bit first)
|
||||||
long mask = 1;
|
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;
|
mask <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// big endian (most significan bit first)
|
// big endian (most significan bit first)
|
||||||
while (width-- && (input[length] == zero || input[length] == one))
|
while (width-- && (input[consumed] == zero || input[consumed] == one))
|
||||||
{
|
{
|
||||||
val <<= 1;
|
val <<= 1;
|
||||||
if (input[length++] == one) val |= 1;
|
if (input[consumed++] == one) val |= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value = val;
|
value = val;
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (BinaryConverter, "bB");
|
RegisterConverter (BinaryConverter, "bB");
|
||||||
|
@ -1,29 +1,38 @@
|
|||||||
# Want debugging?
|
|
||||||
# HOST_OPT = NO
|
|
||||||
|
|
||||||
# You may add more record interfaces
|
# You may add more record interfaces
|
||||||
# This requires the naming conventions
|
# This requires the naming conventions
|
||||||
# dev$(RECORD)Stream.c
|
# dev$(RECORDTYPE)Stream.c
|
||||||
|
|
||||||
RECORDS += ao ai
|
RECORDTYPES += ao ai
|
||||||
RECORDS += bo bi
|
RECORDTYPES += bo bi
|
||||||
RECORDS += mbbo mbbi
|
RECORDTYPES += mbbo mbbi
|
||||||
RECORDS += mbboDirect mbbiDirect
|
RECORDTYPES += mbboDirect mbbiDirect
|
||||||
RECORDS += longout longin
|
RECORDTYPES += longout longin
|
||||||
RECORDS += stringout stringin
|
RECORDTYPES += stringout stringin
|
||||||
RECORDS += waveform
|
RECORDTYPES += waveform
|
||||||
RECORDS += calcout
|
RECORDTYPES += aai aao
|
||||||
RECORDS += 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?
|
# Do you have synApps and want support for scalcout?
|
||||||
# Then define CALC or SYNAPPS in your RELEASE file
|
# Then define CALC or SYNAPPS in your RELEASE file
|
||||||
# pointing to the 'calc' module of synApps.
|
# pointing to the 'calc' module of synApps.
|
||||||
# Due to strange cross dependencies in synApps
|
# Older 'calc' versions have a cross reference on
|
||||||
# you have to build the 'sscan' and 'genSub'
|
# 'sscan' and/or 'genSub', so you may have to build them first.
|
||||||
# modules before building 'calc'.
|
# Up to version 2-6 (synApps 5-1) the 'calc' module needs a fix.
|
||||||
# See doc/scalcout.html for a required fix in scalcout.
|
# See doc/scalcout.html for details.
|
||||||
|
ifneq ($(words $(CALC) $(SYNAPPS)), 0)
|
||||||
SYNAPPS_RECORDS += scalcout
|
RECORDTYPES += scalcout
|
||||||
|
endif
|
||||||
|
|
||||||
# You may add more bus interfaces
|
# You may add more bus interfaces
|
||||||
# This requires the naming convention
|
# This requires the naming convention
|
||||||
@ -33,6 +42,9 @@ SYNAPPS_RECORDS += scalcout
|
|||||||
|
|
||||||
BUSSES += Debug
|
BUSSES += Debug
|
||||||
BUSSES += Dummy
|
BUSSES += Dummy
|
||||||
|
ifdef ASYN
|
||||||
|
BUSSES += AsynDriver
|
||||||
|
endif
|
||||||
|
|
||||||
# You may add more format converters
|
# You may add more format converters
|
||||||
# This requires the naming convention
|
# This requires the naming convention
|
||||||
@ -63,7 +75,7 @@ ifneq ($(words $(PCRE) $(PCRE_LIB) $(PCRE_INCLUDE)),0)
|
|||||||
FORMATS += Regexp
|
FORMATS += Regexp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Want a loadable module?
|
# Want a loadable module?
|
||||||
# For Tornado 2.0.2, a fix is needed in the
|
# For Tornado 2.0.2, a fix is needed in the
|
||||||
# registerRecordDeviceDriver.pl script in base:
|
# registerRecordDeviceDriver.pl script in base:
|
||||||
# at the end replace the line "IoccrfReg iocshReg;"
|
# at the end replace the line "IoccrfReg iocshReg;"
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
* StreamDevice Support *
|
* StreamDevice Support *
|
||||||
* *
|
* *
|
||||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||||
* (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2006-2018 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the checksum pseudo-converter of StreamDevice. *
|
* This is the checksum pseudo-converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -20,12 +20,25 @@
|
|||||||
|
|
||||||
#include "StreamFormatConverter.h"
|
#include "StreamFormatConverter.h"
|
||||||
#include "StreamError.h"
|
#include "StreamError.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#if defined(__vxworks) || defined(vxWorks)
|
||||||
|
#define PRIX32 "lX"
|
||||||
|
#define PRIu32 "lu"
|
||||||
|
#define PRIX8 "X"
|
||||||
|
#define SCNx8 "hhx"
|
||||||
|
#define uint_fast8_t uint8_t
|
||||||
|
#define int_fast8_t int8_t
|
||||||
|
#else
|
||||||
|
#define __STDC_FORMAT_MACROS
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__vxworks) || defined(vxWorks) || defined(_WIN32) || defined(__rtems__)
|
#if defined(__vxworks) || defined(vxWorks) || defined(_WIN32) || defined(__rtems__)
|
||||||
// These systems have no strncasecmp
|
// These systems have no strncasecmp
|
||||||
#include <epicsVersion.h>
|
#include "epicsVersion.h"
|
||||||
#ifdef BASE_VERSION
|
#ifdef BASE_VERSION
|
||||||
// 3.13
|
// 3.13
|
||||||
#include <ctype.h>
|
|
||||||
static int strncasecmp(const char *s1, const char *s2, size_t n)
|
static int strncasecmp(const char *s1, const char *s2, size_t n)
|
||||||
{
|
{
|
||||||
int r=0;
|
int r=0;
|
||||||
@ -33,15 +46,14 @@ static int strncasecmp(const char *s1, const char *s2, size_t n)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#include <epicsString.h>
|
#include "epicsString.h"
|
||||||
#define strncasecmp epicsStrnCaseCmp
|
#define strncasecmp epicsStrnCaseCmp
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#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--)
|
while (len--)
|
||||||
{
|
{
|
||||||
@ -50,7 +62,7 @@ static unsigned int sum(const unsigned char* data, unsigned int len, unsigned in
|
|||||||
return sum;
|
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--)
|
while (len--)
|
||||||
{
|
{
|
||||||
@ -59,15 +71,15 @@ static unsigned int xor8(const unsigned char* data, unsigned int len, unsigned i
|
|||||||
return sum;
|
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;
|
return xor8(data, len, sum) & 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int crc_0x07(const unsigned char* data, unsigned int len, unsigned int crc)
|
static uint32_t crc_0x07(const uint8_t* data, size_t len, uint32_t crc)
|
||||||
{
|
{
|
||||||
// x^8 + x^2 + x^1 + x^0 (0x07)
|
// 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,
|
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
|
||||||
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
|
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
|
||||||
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
||||||
@ -105,10 +117,10 @@ static unsigned int crc_0x07(const unsigned char* data, unsigned int len, unsign
|
|||||||
return crc;
|
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)
|
// 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,
|
0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83,
|
||||||
0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41,
|
0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41,
|
||||||
0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e,
|
0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e,
|
||||||
@ -146,10 +158,10 @@ static unsigned int crc_0x31(const unsigned char* data, unsigned int len, unsign
|
|||||||
return crc;
|
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)
|
// x^16 + x^15 + x^2 + x^0 (0x8005)
|
||||||
const static unsigned short table[256] = {
|
const uint16_t table[256] = {
|
||||||
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
|
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
|
||||||
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
|
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
|
||||||
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
|
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
|
||||||
@ -187,11 +199,11 @@ static unsigned int crc_0x8005(const unsigned char* data, unsigned int len, unsi
|
|||||||
return crc;
|
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)
|
// x^16 + x^15 + x^2 + x^0 (0x8005)
|
||||||
// reflected
|
// reflected
|
||||||
const static unsigned short table[256] = {
|
const uint16_t table[256] = {
|
||||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||||
@ -229,10 +241,10 @@ static unsigned int crc_0x8005_r(const unsigned char* data, unsigned int len, un
|
|||||||
return crc;
|
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)
|
// 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,
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||||
@ -270,11 +282,11 @@ static unsigned int crc_0x1021(const unsigned char* data, unsigned int len, unsi
|
|||||||
return crc;
|
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^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)
|
// 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,
|
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||||
@ -344,12 +356,12 @@ static unsigned int crc_0x04C11DB7(const unsigned char* data, unsigned int len,
|
|||||||
return crc;
|
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^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)
|
// x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + x^0 (0x04C11DB7)
|
||||||
// reflected
|
// reflected
|
||||||
const static unsigned int table[] = {
|
const uint32_t table[] = {
|
||||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||||
@ -419,13 +431,13 @@ static unsigned int crc_0x04C11DB7_r(const unsigned char* data, unsigned int len
|
|||||||
return crc;
|
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;
|
uint32_t a = init & 0xFFFF;
|
||||||
unsigned int b = (init >> 16) & 0xFFFF;
|
uint32_t b = (init >> 16) & 0xFFFF;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned int tlen = len > 5550 ? 5550 : len;
|
size_t tlen = len > 5550 ? 5550 : len;
|
||||||
len -= tlen;
|
len -= tlen;
|
||||||
do {
|
do {
|
||||||
a += *data++;
|
a += *data++;
|
||||||
@ -433,17 +445,17 @@ static unsigned int adler32(const unsigned char* data, unsigned int len, unsigne
|
|||||||
} while (--tlen);
|
} while (--tlen);
|
||||||
a = (a & 0xFFFF) + (a >> 16) * 15;
|
a = (a & 0xFFFF) + (a >> 16) * 15;
|
||||||
b = (b & 0xFFFF) + (b >> 16) * 15;
|
b = (b & 0xFFFF) + (b >> 16) * 15;
|
||||||
}
|
}
|
||||||
if (a >= 65521) a -= 65521;
|
if (a >= 65521) a -= 65521;
|
||||||
b = (b & 0xFFFF) + (b >> 16) * 15;
|
b = (b & 0xFFFF) + (b >> 16) * 15;
|
||||||
if (b >= 65521) b -= 65521;
|
if (b >= 65521) b -= 65521;
|
||||||
return b << 16 | a;
|
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.
|
// Add all hex digits, ignore all other bytes.
|
||||||
unsigned int d;
|
uint32_t d;
|
||||||
while (len--)
|
while (len--)
|
||||||
{
|
{
|
||||||
d = toupper(*data++);
|
d = toupper(*data++);
|
||||||
@ -457,13 +469,42 @@ static unsigned int hexsum(const unsigned char* data, unsigned int len, unsigned
|
|||||||
return sum;
|
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;
|
||||||
|
if (sum < 32) sum+=32;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
struct checksum
|
struct checksum
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
checksumFunc func;
|
checksumFunc func;
|
||||||
unsigned int init;
|
uint32_t init;
|
||||||
unsigned int xorout;
|
uint32_t xorout;
|
||||||
signed char bytes;
|
uint8_t bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
static checksum checksumMap[] =
|
static checksum checksumMap[] =
|
||||||
@ -491,16 +532,18 @@ static checksum checksumMap[] =
|
|||||||
{"crc32r", crc_0x04C11DB7_r, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xCBF43926
|
{"crc32r", crc_0x04C11DB7_r, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xCBF43926
|
||||||
{"jamcrc", crc_0x04C11DB7_r, 0xFFFFFFFF, 0x00000000, 4}, // 0x340BC6D9
|
{"jamcrc", crc_0x04C11DB7_r, 0xFFFFFFFF, 0x00000000, 4}, // 0x340BC6D9
|
||||||
{"adler32", adler32, 0x00000001, 0x00000000, 4}, // 0x091E01DE
|
{"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
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int mask[5] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF};
|
static uint32_t mask[5] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF};
|
||||||
|
|
||||||
class ChecksumConverter : public StreamFormatConverter
|
class ChecksumConverter : public StreamFormatConverter
|
||||||
{
|
{
|
||||||
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printPseudo(const StreamFormat&, StreamBuffer&);
|
bool printPseudo(const StreamFormat&, StreamBuffer&);
|
||||||
int scanPseudo(const StreamFormat&, StreamBuffer&, long& cursor);
|
ssize_t scanPseudo(const StreamFormat&, StreamBuffer&, size_t& cursor);
|
||||||
};
|
};
|
||||||
|
|
||||||
int ChecksumConverter::
|
int ChecksumConverter::
|
||||||
@ -535,9 +578,9 @@ parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
|
|||||||
source+=3;
|
source+=3;
|
||||||
notflag = true;
|
notflag = true;
|
||||||
}
|
}
|
||||||
unsigned fnum;
|
uint8_t fnum;
|
||||||
int len = p-source;
|
size_t len = p-source;
|
||||||
unsigned int init, xorout;
|
uint32_t init, xorout;
|
||||||
for (fnum = 0; fnum < sizeof(checksumMap)/sizeof(checksum); fnum++)
|
for (fnum = 0; fnum < sizeof(checksumMap)/sizeof(checksum); fnum++)
|
||||||
{
|
{
|
||||||
if ((strncasecmp(source, checksumMap[fnum].name, len) == 0) ||
|
if ((strncasecmp(source, checksumMap[fnum].name, len) == 0) ||
|
||||||
@ -562,54 +605,54 @@ parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error ("Unknown checksum algorithm \"%.*s\"\n", len, source);
|
error ("Unknown checksum algorithm \"%.*s\"\n", (int)len, source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChecksumConverter::
|
bool ChecksumConverter::
|
||||||
printPseudo(const StreamFormat& format, StreamBuffer& output)
|
printPseudo(const StreamFormat& format, StreamBuffer& output)
|
||||||
{
|
{
|
||||||
unsigned int sum;
|
uint32_t sum;
|
||||||
const char* info = format.info;
|
const char* info = format.info;
|
||||||
unsigned int init = extract<unsigned int>(info);
|
uint32_t init = extract<uint32_t>(info);
|
||||||
unsigned int xorout = extract<unsigned int>(info);
|
uint32_t xorout = extract<uint32_t>(info);
|
||||||
int fnum = extract<char>(info);
|
uint_fast8_t fnum = extract<uint8_t>(info);
|
||||||
|
|
||||||
int start = format.width;
|
size_t start = format.width;
|
||||||
int length = output.length()-format.width;
|
size_t length = output.length()-format.width;
|
||||||
if (format.prec > 0) length -= format.prec;
|
if (format.prec > 0) length -= format.prec;
|
||||||
|
|
||||||
debug("ChecksumConverter %s: output to check: \"%s\"\n",
|
debug("ChecksumConverter %s: output to check: \"%s\"\n",
|
||||||
checksumMap[fnum].name, output.expand(start,length)());
|
checksumMap[fnum].name, output.expand(start,length)());
|
||||||
|
|
||||||
sum = (xorout ^ checksumMap[fnum].func(
|
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];
|
& 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);
|
checksumMap[fnum].name, sum);
|
||||||
|
|
||||||
int i;
|
uint_fast8_t i;
|
||||||
unsigned outchar;
|
uint_fast8_t outchar;
|
||||||
|
|
||||||
if (format.flags & sign_flag) // decimal
|
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;
|
i = (checksumMap[fnum].bytes+1)*25/10-2;
|
||||||
output.print("%0*d", i, sum);
|
output.print("%0*" PRIu32, i, sum);
|
||||||
debug("ChecksumConverter %s: decimal appending %0*d\n",
|
debug("ChecksumConverter %s: decimal appending %0*" PRIu32 "\n",
|
||||||
checksumMap[fnum].name, i, sum);
|
checksumMap[fnum].name, i, sum);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (format.flags & alt_flag) // lsb first (little endian)
|
if (format.flags & alt_flag) // lsb first (little endian)
|
||||||
{
|
{
|
||||||
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
||||||
{
|
{
|
||||||
outchar = sum & 0xff;
|
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);
|
checksumMap[fnum].name, outchar);
|
||||||
if (format.flags & zero_flag) // ASCII
|
if (format.flags & zero_flag) // ASCII
|
||||||
output.print("%02X", outchar);
|
output.print("%02" PRIX8, outchar);
|
||||||
else
|
else
|
||||||
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
||||||
output.print("%c%c",
|
output.print("%c%c",
|
||||||
@ -625,10 +668,10 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
|
|||||||
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
||||||
{
|
{
|
||||||
outchar = (sum >> 24) & 0xff;
|
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);
|
checksumMap[fnum].name, outchar);
|
||||||
if (format.flags & zero_flag) // ASCII
|
if (format.flags & zero_flag) // ASCII
|
||||||
output.print("%02X", outchar);
|
output.print("%02" PRIX8, outchar);
|
||||||
else
|
else
|
||||||
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
||||||
output.print("%c%c",
|
output.print("%c%c",
|
||||||
@ -641,28 +684,28 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ChecksumConverter::
|
ssize_t ChecksumConverter::
|
||||||
scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
|
||||||
{
|
{
|
||||||
unsigned int sum;
|
uint32_t sum;
|
||||||
const char* info = format.info;
|
const char* info = format.info;
|
||||||
unsigned int init = extract<unsigned int>(info);
|
uint32_t init = extract<uint32_t>(info);
|
||||||
unsigned int xorout = extract<unsigned int>(info);
|
uint32_t xorout = extract<uint32_t>(info);
|
||||||
int start = format.width;
|
size_t start = format.width;
|
||||||
int fnum = extract<char>(info);
|
uint_fast8_t fnum = extract<uint8_t>(info);
|
||||||
int length = cursor-format.width;
|
size_t length = cursor-format.width;
|
||||||
|
|
||||||
if (format.prec > 0) length -= format.prec;
|
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)());
|
checksumMap[fnum].name, input.expand(start,length)());
|
||||||
|
|
||||||
int expectedLength =
|
uint_fast8_t expectedLength =
|
||||||
// get number of decimal digits from number of bytes: ceil(bytes*2.5)
|
// 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 & sign_flag ? (checksumMap[fnum].bytes + 1) * 25 / 10 - 2 :
|
||||||
format.flags & (zero_flag|left_flag) ? 2 * checksumMap[fnum].bytes :
|
format.flags & (zero_flag|left_flag) ? 2 * checksumMap[fnum].bytes :
|
||||||
checksumMap[fnum].bytes;
|
checksumMap[fnum].bytes;
|
||||||
|
|
||||||
if (input.length() - cursor < expectedLength)
|
if (input.length() - cursor < expectedLength)
|
||||||
{
|
{
|
||||||
debug("ChecksumConverter %s: Input '%s' too short for checksum\n",
|
debug("ChecksumConverter %s: Input '%s' too short for checksum\n",
|
||||||
@ -671,18 +714,18 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sum = (xorout ^ checksumMap[fnum].func(
|
sum = (xorout ^ checksumMap[fnum].func(
|
||||||
reinterpret_cast<unsigned char*>(input(start)), length, init))
|
(uint8_t*)input(start), length, init))
|
||||||
& mask[checksumMap[fnum].bytes];
|
& 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);
|
checksumMap[fnum].name, 2*checksumMap[fnum].bytes, sum);
|
||||||
|
|
||||||
int i, j;
|
uint_fast8_t inchar;
|
||||||
unsigned inchar;
|
|
||||||
|
|
||||||
if (format.flags & sign_flag) // decimal
|
if (format.flags & sign_flag) // decimal
|
||||||
{
|
{
|
||||||
unsigned int sumin = 0;
|
uint32_t sumin = 0;
|
||||||
|
size_t i;
|
||||||
for (i = 0; i < expectedLength; i++)
|
for (i = 0; i < expectedLength; i++)
|
||||||
{
|
{
|
||||||
inchar = input[cursor+i];
|
inchar = input[cursor+i];
|
||||||
@ -691,21 +734,22 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
|||||||
}
|
}
|
||||||
if (sumin != sum)
|
if (sumin != sum)
|
||||||
{
|
{
|
||||||
debug("ChecksumConverter %s: Input %0*u does not match checksum %0*u\n",
|
debug("ChecksumConverter %s: Input %0*" PRIu32 " does not match checksum %0*" PRIu32 "\n",
|
||||||
checksumMap[fnum].name, i, sumin, expectedLength, sum);
|
checksumMap[fnum].name, (int)i, sumin, (int)expectedLength, sum);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (format.flags & alt_flag) // lsb first (little endian)
|
if (format.flags & alt_flag) // lsb first (little endian)
|
||||||
{
|
{
|
||||||
|
uint_fast8_t i;
|
||||||
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
for (i = 0; i < checksumMap[fnum].bytes; i++)
|
||||||
{
|
{
|
||||||
if (format.flags & zero_flag) // ASCII
|
if (format.flags & zero_flag) // ASCII
|
||||||
{
|
{
|
||||||
if (sscanf(input(cursor+2*i), "%2X", &inchar) != 1)
|
if (sscanf(input(cursor+2*i), "%2" SCNx8, &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)());
|
checksumMap[fnum].name, input.expand(cursor+2*i,2)());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -715,13 +759,13 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
|||||||
{
|
{
|
||||||
if ((input[cursor+2*i] & 0xf0) != 0x30)
|
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]);
|
checksumMap[fnum].name, input[cursor+2*i]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((input[cursor+2*i+1] & 0xf0) != 0x30)
|
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]);
|
checksumMap[fnum].name, input[cursor+2*i+1]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -733,7 +777,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
|||||||
}
|
}
|
||||||
if (inchar != ((sum >> 8*i) & 0xff))
|
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);
|
checksumMap[fnum].name, inchar, 2*checksumMap[fnum].bytes, sum);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -741,24 +785,26 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
|||||||
}
|
}
|
||||||
else // msb first (big endian)
|
else // msb first (big endian)
|
||||||
{
|
{
|
||||||
|
int_fast8_t i;
|
||||||
|
uint_fast8_t j;
|
||||||
for (i = checksumMap[fnum].bytes-1, j = 0; i >= 0; i--, j++)
|
for (i = checksumMap[fnum].bytes-1, j = 0; i >= 0; i--, j++)
|
||||||
{
|
{
|
||||||
if (format.flags & zero_flag) // ASCII
|
if (format.flags & zero_flag) // ASCII
|
||||||
{
|
{
|
||||||
sscanf(input(cursor+2*i), "%2x", &inchar);
|
sscanf(input(cursor+2*i), "%2" SCNx8, &inchar);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
if (format.flags & left_flag) // poor man's hex: 0x30 - 0x3F
|
||||||
{
|
{
|
||||||
if ((input[cursor+2*i] & 0xf0) != 0x30)
|
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]);
|
checksumMap[fnum].name, input[cursor+2*i]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((input[cursor+2*i+1] & 0xf0) != 0x30)
|
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]);
|
checksumMap[fnum].name, input[cursor+2*i+1]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -770,7 +816,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
|
|||||||
}
|
}
|
||||||
if (inchar != ((sum >> 8*j) & 0xff))
|
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);
|
checksumMap[fnum].name, inchar, 2*checksumMap[fnum].bytes, sum);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include "StreamError.h"
|
#include "StreamError.h"
|
||||||
#include "StreamBuffer.h"
|
#include "StreamBuffer.h"
|
||||||
|
|
||||||
|
#define Z PRINTF_SIZE_T_PREFIX
|
||||||
|
|
||||||
// This is a non-blocking bus interface for debugging purpose.
|
// This is a non-blocking bus interface for debugging purpose.
|
||||||
// Normally, a bus interface will use blocking I/O and thus require
|
// Normally, a bus interface will use blocking I/O and thus require
|
||||||
// a separate thread.
|
// a separate thread.
|
||||||
@ -35,7 +37,7 @@ class DebugInterface : StreamBusInterface
|
|||||||
bool writeRequest(const void* output, size_t size,
|
bool writeRequest(const void* output, size_t size,
|
||||||
unsigned long writeTimeout_ms);
|
unsigned long writeTimeout_ms);
|
||||||
bool readRequest(unsigned long replyTimeout_ms,
|
bool readRequest(unsigned long replyTimeout_ms,
|
||||||
unsigned long readTimeout_ms, long expectedLength, bool async);
|
unsigned long readTimeout_ms, size_t expectedLength, bool async);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~DebugInterface();
|
~DebugInterface();
|
||||||
@ -167,9 +169,9 @@ writeRequest(const void* output, size_t size, unsigned long writeTimeout_ms)
|
|||||||
// Return false if the read request cannot be accepted.
|
// Return false if the read request cannot be accepted.
|
||||||
bool DebugInterface::
|
bool DebugInterface::
|
||||||
readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
readRequest(unsigned long replyTimeout_ms, unsigned long readTimeout_ms,
|
||||||
long expectedLength, bool async)
|
size_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 "u bytes, asyn=%s)\n",
|
||||||
clientName(), replyTimeout_ms, readTimeout_ms, expectedLength, async?"yes":"no");
|
clientName(), replyTimeout_ms, readTimeout_ms, expectedLength, async?"yes":"no");
|
||||||
|
|
||||||
// Debug interface does not support async mode.
|
// Debug interface does not support async mode.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the enum format converter of StreamDevice. *
|
* This is the enum format converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -29,7 +29,7 @@ class EnumConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
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...
|
// info format: <numEnums><index><string>0<index><string>0...
|
||||||
@ -45,10 +45,10 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
long numEnums = 0;
|
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));
|
info.append(&numEnums, sizeof(numEnums));
|
||||||
long index = 0;
|
long index = 0;
|
||||||
int i = 0;
|
size_t i = 0;
|
||||||
i = info.length(); // put index here later
|
i = info.length(); // put index here later
|
||||||
info.append(&index, sizeof(index));
|
info.append(&index, sizeof(index));
|
||||||
while (*source)
|
while (*source)
|
||||||
@ -56,7 +56,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
if (*source == '=' && (fmt.flags & alt_flag))
|
if (*source == '=' && (fmt.flags & alt_flag))
|
||||||
{
|
{
|
||||||
char* p;
|
char* p;
|
||||||
|
|
||||||
if (*++source == '?')
|
if (*++source == '?')
|
||||||
{
|
{
|
||||||
// default choice
|
// default choice
|
||||||
@ -78,7 +78,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
-numEnums, info.expand()());
|
-numEnums, info.expand()());
|
||||||
return enum_format;
|
return enum_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = strtol(source, &p, 0);
|
index = strtol(source, &p, 0);
|
||||||
if (p == source || (*p != '|' && *p != '}'))
|
if (p == source || (*p != '|' && *p != '}'))
|
||||||
{
|
{
|
||||||
@ -93,7 +93,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
{
|
{
|
||||||
numEnums++;
|
numEnums++;
|
||||||
info.append('\0');
|
info.append('\0');
|
||||||
|
|
||||||
if (*source++ == '}')
|
if (*source++ == '}')
|
||||||
{
|
{
|
||||||
memcpy(info(n), &numEnums, sizeof(numEnums));
|
memcpy(info(n), &numEnums, sizeof(numEnums));
|
||||||
@ -101,7 +101,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
numEnums, info.expand()());
|
numEnums, info.expand()());
|
||||||
return enum_format;
|
return enum_format;
|
||||||
}
|
}
|
||||||
index ++;
|
index++;
|
||||||
i = info.length();
|
i = info.length();
|
||||||
info.append(&index, sizeof(index));
|
info.append(&index, sizeof(index));
|
||||||
}
|
}
|
||||||
@ -123,8 +123,8 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
long numEnums = extract<long>(s);
|
long numEnums = extract<long>(s);
|
||||||
long index = extract<long>(s);
|
long index = extract<long>(s);
|
||||||
bool noDefault = numEnums >= 0;
|
bool noDefault = numEnums >= 0;
|
||||||
|
|
||||||
if (numEnums < 0) numEnums=-numEnums-1;
|
if (numEnums < 0) numEnums=-numEnums-1;
|
||||||
while (numEnums-- && (value != index))
|
while (numEnums-- && (value != index))
|
||||||
{
|
{
|
||||||
while(*s)
|
while(*s)
|
||||||
@ -148,7 +148,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EnumConverter::
|
ssize_t EnumConverter::
|
||||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||||
{
|
{
|
||||||
debug("EnumConverter::scanLong(%%%c, \"%s\")\n",
|
debug("EnumConverter::scanLong(%%%c, \"%s\")\n",
|
||||||
@ -156,31 +156,31 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
const char* s = fmt.info;
|
const char* s = fmt.info;
|
||||||
long numEnums = extract<long>(s);
|
long numEnums = extract<long>(s);
|
||||||
long index;
|
long index;
|
||||||
int length;
|
ssize_t consumed;
|
||||||
|
|
||||||
bool match;
|
bool match;
|
||||||
|
|
||||||
while (numEnums--)
|
while (numEnums--)
|
||||||
{
|
{
|
||||||
index = extract<long>(s);
|
index = extract<long>(s);
|
||||||
debug("EnumConverter::scanLong: check #%ld \"%s\"\n", index, s);
|
debug("EnumConverter::scanLong: check #%ld \"%s\"\n", index, s);
|
||||||
length = 0;
|
consumed = 0;
|
||||||
match = true;
|
match = true;
|
||||||
while(*s)
|
while(*s)
|
||||||
{
|
{
|
||||||
if (*s == StreamProtocolParser::skip)
|
if (*s == StreamProtocolParser::skip)
|
||||||
{
|
{
|
||||||
s++;
|
s++;
|
||||||
length++;
|
consumed++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*s == esc) s++;
|
if (*s == esc) s++;
|
||||||
if (*s++ != input[length++]) match = false;
|
if (*s++ != input[consumed++]) match = false;
|
||||||
}
|
}
|
||||||
if (match)
|
if (match)
|
||||||
{
|
{
|
||||||
debug("EnumConverter::scanLong: value %ld matches\n", index);
|
debug("EnumConverter::scanLong: value %ld matches\n", index);
|
||||||
value = index;
|
value = index;
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
72
src/MacroMagic.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
#define _fe_0(_call, ...)
|
||||||
|
#define _fe_1(_call, x) _call(x)
|
||||||
|
#define _fe_2(_call, x, ...) _call(x) _fe_1(_call, __VA_ARGS__)
|
||||||
|
#define _fe_3(_call, x, ...) _call(x) _fe_2(_call, __VA_ARGS__)
|
||||||
|
#define _fe_4(_call, x, ...) _call(x) _fe_3(_call, __VA_ARGS__)
|
||||||
|
#define _fe_5(_call, x, ...) _call(x) _fe_4(_call, __VA_ARGS__)
|
||||||
|
#define _fe_6(_call, x, ...) _call(x) _fe_5(_call, __VA_ARGS__)
|
||||||
|
#define _fe_7(_call, x, ...) _call(x) _fe_6(_call, __VA_ARGS__)
|
||||||
|
#define _fe_8(_call, x, ...) _call(x) _fe_7(_call, __VA_ARGS__)
|
||||||
|
#define _fe_9(_call, x, ...) _call(x) _fe_8(_call, __VA_ARGS__)
|
||||||
|
#define _fe_10(_call, x, ...) _call(x) _fe_9(_call, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MACRO_FOR_EACH(x, ...) \
|
||||||
|
_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){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
|
50
src/Makefile
@ -18,18 +18,16 @@
|
|||||||
# #
|
# #
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
TOP=../..
|
TOP = ../..
|
||||||
|
ifneq ($(wildcard ../../configure),)
|
||||||
# Look if we have EPICS R3.13 or R3.14
|
include $(TOP)/configure/CONFIG
|
||||||
ifeq ($(wildcard $(TOP)/configure),)
|
else ifneq ($(wildcard ../../config),)
|
||||||
# EPICS R3.13
|
include $(TOP)/config/CONFIG_APP
|
||||||
include $(TOP)/config/CONFIG_APP
|
include $(TOP)/config/RULES_ARCHS
|
||||||
# The real work is in Makefile.Vx
|
|
||||||
include $(TOP)/config/RULES_ARCHS
|
|
||||||
else
|
else
|
||||||
|
TOP= ..
|
||||||
# EPICS R3.14
|
include $(TOP)/configure/CONFIG
|
||||||
include $(TOP)/configure/CONFIG
|
endif
|
||||||
|
|
||||||
-include CONFIG_STREAM
|
-include CONFIG_STREAM
|
||||||
-include ../CONFIG_STREAM
|
-include ../CONFIG_STREAM
|
||||||
@ -40,13 +38,8 @@ DBD += $(LIBRARY_DEFAULT).dbd
|
|||||||
|
|
||||||
ifdef ASYN
|
ifdef ASYN
|
||||||
LIB_LIBS += asyn
|
LIB_LIBS += asyn
|
||||||
BUSSES += AsynDriver
|
else
|
||||||
endif
|
$(warning Asyn not included! Didn't you set ASYN in your RELEASE file?)
|
||||||
|
|
||||||
ifdef T_A
|
|
||||||
ifndef BUSSES
|
|
||||||
$(error No bus interface defined! Didn't you set ASYN in your RELEASE file?)
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(LOADABLE_MODULE),YES)
|
ifeq ($(LOADABLE_MODULE),YES)
|
||||||
@ -54,7 +47,7 @@ SRCS += $(LIBRARY_DEFAULT)_registerRecordDeviceDriver.cpp
|
|||||||
endif
|
endif
|
||||||
SRCS += $(BUSSES:%=%Interface.cc)
|
SRCS += $(BUSSES:%=%Interface.cc)
|
||||||
SRCS += $(FORMATS:%=%Converter.cc)
|
SRCS += $(FORMATS:%=%Converter.cc)
|
||||||
SRCS += $(RECORDS:%=dev%Stream.c)
|
SRCS += $(RECORDTYPES:%=dev%Stream.c)
|
||||||
SRCS += $(STREAM_SRCS)
|
SRCS += $(STREAM_SRCS)
|
||||||
|
|
||||||
# find system wide or local PCRE header and library
|
# find system wide or local PCRE header and library
|
||||||
@ -75,11 +68,13 @@ LIB_LIBS += $(EPICS_BASE_IOC_LIBS)
|
|||||||
|
|
||||||
INC += devStream.h
|
INC += devStream.h
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
# switch off annoying rset warnings in 3.16+
|
||||||
|
CPPFLAGS += -DUSE_TYPED_RSET
|
||||||
|
|
||||||
# Update version string (contains __DATE__ and __TIME__)
|
-include $(TOP)/configure/RULES
|
||||||
# each time make runs.
|
|
||||||
StreamVersion$(OBJ): ../*.c ../*.h ../*.cc ../CONFIG_STREAM ../Makefile
|
# Update version string whenever something changes
|
||||||
|
StreamVersion$(OBJ): ../*.c ../*.h ../*.cc ../CONFIG_STREAM
|
||||||
|
|
||||||
# Add references to all registrars to main file to avoid
|
# Add references to all registrars to main file to avoid
|
||||||
# missing initialization.
|
# missing initialization.
|
||||||
@ -89,11 +84,12 @@ streamReferences: ../CONFIG_STREAM
|
|||||||
$(PERL) ../makeref.pl Interface $(BUSSES) > $@
|
$(PERL) ../makeref.pl Interface $(BUSSES) > $@
|
||||||
$(PERL) ../makeref.pl Converter $(FORMATS) >> $@
|
$(PERL) ../makeref.pl Converter $(FORMATS) >> $@
|
||||||
|
|
||||||
# create stream.dbd from all RECORDS
|
# create stream.dbd from all RECORDTYPES
|
||||||
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM
|
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM
|
||||||
$(PERL) ../makedbd.pl $(RECORDS) > $@
|
$(PERL) ../makedbd.pl $(RECORDTYPES) > $@
|
||||||
|
ifdef ASYN
|
||||||
|
echo "registrar(AsynDriverInterfaceRegistrar)" >> $@
|
||||||
|
endif
|
||||||
|
|
||||||
$(LIBRARY_DEFAULT).dbd$(DEP): ../CONFIG_STREAM
|
$(LIBRARY_DEFAULT).dbd$(DEP): ../CONFIG_STREAM
|
||||||
echo $(LIBRARY_DEFAULT).dbd: $< > $@
|
echo $(LIBRARY_DEFAULT).dbd: $< > $@
|
||||||
|
|
||||||
endif
|
|
||||||
|
@ -18,25 +18,19 @@
|
|||||||
# #
|
# #
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
|
TOP = ../..
|
||||||
|
ifneq ($(wildcard ../../../config),)
|
||||||
TOP = ../../..
|
TOP = ../../..
|
||||||
|
endif
|
||||||
|
|
||||||
include $(TOP)/config/CONFIG_APP
|
include $(TOP)/config/CONFIG_APP
|
||||||
include ../CONFIG_STREAM
|
include ../CONFIG_STREAM
|
||||||
|
|
||||||
# In 3.13, calcout has no device support
|
|
||||||
RECORDS_3_13 = $(filter-out calcout,$(RECORDS))
|
|
||||||
|
|
||||||
DBDNAME = stream.dbd
|
DBDNAME = stream.dbd
|
||||||
|
|
||||||
INC += devStream.h
|
INC += devStream.h
|
||||||
|
|
||||||
# This is the munch.pl taken from EPICS 3.14.8.2
|
include $(EPICS_BASE)/config/RULES.Host
|
||||||
# Install script and rule.
|
|
||||||
CONFIGS = RULES.munch
|
|
||||||
SCRIPTS = munch.pl
|
|
||||||
|
|
||||||
include $(TOP)/config/RULES.Host
|
# create stream.dbd from all RECORDTYPES
|
||||||
|
|
||||||
# create stream.dbd from all RECORDS
|
|
||||||
stream.dbd: ../CONFIG_STREAM
|
stream.dbd: ../CONFIG_STREAM
|
||||||
$(PERL) ../makedbd.pl -3.13 $(RECORDS_3_13) > $@
|
$(PERL) ../makedbd.pl -3.13 $(RECORDTYPES) > $@
|
||||||
|
@ -18,39 +18,33 @@
|
|||||||
# #
|
# #
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
|
TOP = ../..
|
||||||
|
ifneq ($(wildcard ../../../config),)
|
||||||
TOP = ../../..
|
TOP = ../../..
|
||||||
|
endif
|
||||||
|
|
||||||
include $(TOP)/config/CONFIG_APP
|
include $(TOP)/config/CONFIG_APP
|
||||||
include ../CONFIG_STREAM
|
include ../CONFIG_STREAM
|
||||||
|
|
||||||
LIBNAME = streamLib
|
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 += $(BUSSES:%=../%Interface.cc)
|
||||||
SRCS.cc += $(FORMATS:%=../%Converter.cc)
|
SRCS.cc += $(FORMATS:%=../%Converter.cc)
|
||||||
SRCS.c += $(patsubst %,../%,$(filter %.c,$(STREAM_SRCS)))
|
SRCS.cc += $(filter %.cc,$(STREAM_SRCS:%=%../%))
|
||||||
SRCS.c += $(RECORDS_3_13:%=../dev%Stream.c)
|
SRCS.c += $(RECORDTYPES:%=../dev%Stream.c)
|
||||||
|
SRCS.c += $(filter %.c,$(STREAM_SRCS:%=%../%))
|
||||||
|
|
||||||
LIBOBJS = $(patsubst ../%,%.o,$(basename $(SRCS.cc) $(SRCS.c)))
|
LIBOBJS = $(patsubst ../%,%.o,$(basename $(SRCS.cc) $(SRCS.c)))
|
||||||
|
|
||||||
include $(TOP)/config/RULES.Vx
|
include $(EPICS_BASE)/config/RULES.Vx
|
||||||
include $(TOP)/config/RULES.munch
|
include ../../config/RULES.munch
|
||||||
|
|
||||||
build:: depends
|
|
||||||
|
|
||||||
|
DEPENDS: depends
|
||||||
-include DEPENDS
|
-include DEPENDS
|
||||||
|
|
||||||
# Update version string (contains __DATE__ and __TIME__)
|
# Update version string whenever something changes
|
||||||
# each time make runs.
|
StreamVersion.o: ../*.c ../*.h ../*.cc ../CONFIG_STREAM
|
||||||
StreamVersion.o: FORCE
|
$(LIBNAME): StreamVersion.o
|
||||||
FORCE:
|
|
||||||
|
|
||||||
StreamCore.o: streamReferences
|
StreamCore.o: streamReferences
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
* *
|
* *
|
||||||
* (C) 2008 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2008 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is a custom exponential format converter for *
|
* This is a custom exponential format converter for *
|
||||||
* StreamDevice. *
|
* StreamDevice. *
|
||||||
* The number is represented as two signed integers, mantissa *
|
* The number is represented as two signed integers, mantissa *
|
||||||
* and exponent, like in +00011-01 *
|
* and exponent, like in +00011-01 *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -39,7 +39,7 @@
|
|||||||
class MantissaExponentConverter : public StreamFormatConverter
|
class MantissaExponentConverter : public StreamFormatConverter
|
||||||
{
|
{
|
||||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
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);
|
virtual bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,13 +50,13 @@ parse(const StreamFormat&, StreamBuffer&,
|
|||||||
return double_format;
|
return double_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MantissaExponentConverter::
|
ssize_t MantissaExponentConverter::
|
||||||
scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
||||||
{
|
{
|
||||||
int mantissa;
|
int mantissa;
|
||||||
int exponent;
|
int exponent;
|
||||||
int length = -1;
|
int length = -1;
|
||||||
|
|
||||||
sscanf(input, "%d%d%n", &mantissa, &exponent, &length);
|
sscanf(input, "%d%d%n", &mantissa, &exponent, &length);
|
||||||
if (fmt.flags & skip_flag) return length;
|
if (fmt.flags & skip_flag) return length;
|
||||||
if (length == -1) return -1;
|
if (length == -1) return -1;
|
||||||
@ -70,15 +70,15 @@ printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
|
|||||||
// Have to divide value into mantissa and exponent
|
// Have to divide value into mantissa and exponent
|
||||||
// precision field is number of characters in mantissa
|
// precision field is number of characters in mantissa
|
||||||
// number of characters in exponent is at least 2
|
// number of characters in exponent is at least 2
|
||||||
int spaces;
|
ssize_t spaces;
|
||||||
StreamBuffer buf;
|
StreamBuffer buf;
|
||||||
int prec = fmt.prec;
|
int prec = fmt.prec;
|
||||||
|
|
||||||
if (prec < 1) prec = 6;
|
if (prec < 1) prec = 6;
|
||||||
buf.print("%.*e", prec-1, fabs(value)/pow(10.0, prec-1));
|
buf.print("%.*e", prec-1, fabs(value)/pow(10.0, prec-1));
|
||||||
buf.remove(1,1);
|
buf.remove(1,1);
|
||||||
buf.remove(buf.find('e'),1);
|
buf.remove(buf.find('e'),1);
|
||||||
|
|
||||||
spaces = fmt.width-buf.length();
|
spaces = fmt.width-buf.length();
|
||||||
if (fmt.flags & (space_flag|sign_flag) || value < 0.0) spaces--;
|
if (fmt.flags & (space_flag|sign_flag) || value < 0.0) spaces--;
|
||||||
if (spaces < 0) spaces = 0;
|
if (spaces < 0) spaces = 0;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the raw format converter of StreamDevice. *
|
* This is the raw format converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -27,25 +27,24 @@ class RawConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||||
int scanLong(const StreamFormat&, const char*, long&);
|
ssize_t scanLong(const StreamFormat&, const char*, long&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int RawConverter::
|
int RawConverter::
|
||||||
parse(const StreamFormat& fmt, StreamBuffer&,
|
parse(const StreamFormat& fmt, StreamBuffer&,
|
||||||
const char*&, bool)
|
const char*&, bool)
|
||||||
{
|
{
|
||||||
return (fmt.flags & (sign_flag|zero_flag)) ? signed_format : unsigned_format;
|
return (fmt.flags & zero_flag) ? unsigned_format : signed_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RawConverter::
|
bool RawConverter::
|
||||||
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||||
{
|
{
|
||||||
int prec = fmt.prec; // number of bytes from value
|
unsigned int prec = fmt.prec < 0 ? 1 : fmt.prec; // number of bytes from value, default 1
|
||||||
if (prec == -1) prec = 1; // default: 1 byte
|
unsigned long width = prec; // number of bytes in output
|
||||||
int width = prec; // number of bytes in output
|
if (prec > sizeof(long)) prec=sizeof(long);
|
||||||
if (prec > (int)sizeof(long)) prec=sizeof(long);
|
|
||||||
if (fmt.width > width) width = fmt.width;
|
if (fmt.width > width) width = fmt.width;
|
||||||
|
|
||||||
char byte = 0;
|
char byte = 0;
|
||||||
if (fmt.flags & alt_flag) // little endian (lsb first)
|
if (fmt.flags & alt_flag) // little endian (lsb first)
|
||||||
{
|
{
|
||||||
@ -96,12 +95,12 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawConverter::
|
ssize_t RawConverter::
|
||||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||||
{
|
{
|
||||||
long length = 0;
|
ssize_t consumed = 0;
|
||||||
long val = 0;
|
long val = 0;
|
||||||
int width = fmt.width;
|
unsigned long width = fmt.width;
|
||||||
if (width == 0) width = 1; // default: 1 byte
|
if (width == 0) width = 1; // default: 1 byte
|
||||||
if (fmt.flags & skip_flag)
|
if (fmt.flags & skip_flag)
|
||||||
{
|
{
|
||||||
@ -113,7 +112,7 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
unsigned int shift = 0;
|
unsigned int shift = 0;
|
||||||
while (--width && shift < sizeof(long)*8)
|
while (--width && shift < sizeof(long)*8)
|
||||||
{
|
{
|
||||||
val |= ((unsigned char) input[length++]) << shift;
|
val |= (unsigned long)((unsigned char)input[consumed++]) << shift;
|
||||||
shift += 8;
|
shift += 8;
|
||||||
}
|
}
|
||||||
if (width == 0)
|
if (width == 0)
|
||||||
@ -121,15 +120,15 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
if (fmt.flags & zero_flag)
|
if (fmt.flags & zero_flag)
|
||||||
{
|
{
|
||||||
// fill with zero
|
// fill with zero
|
||||||
val |= ((unsigned char) input[length++]) << shift;
|
val |= (unsigned long)((unsigned char)input[consumed++]) << shift;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// fill with sign
|
// 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
|
else
|
||||||
{
|
{
|
||||||
@ -137,21 +136,21 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
if (fmt.flags & zero_flag)
|
if (fmt.flags & zero_flag)
|
||||||
{
|
{
|
||||||
// fill with zero
|
// fill with zero
|
||||||
val = (unsigned char) input[length++];
|
val = (unsigned char)input[consumed++];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// fill with sign
|
// fill with sign
|
||||||
val = (signed char) input[length++];
|
val = (signed char)input[consumed++];
|
||||||
}
|
}
|
||||||
while (--width)
|
while (--width)
|
||||||
{
|
{
|
||||||
val <<= 8;
|
val <<= 8;
|
||||||
val |= (unsigned char) input[length++];
|
val |= (unsigned char)input[consumed++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value = val;
|
value = val;
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (RawConverter, "r");
|
RegisterConverter (RawConverter, "r");
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the raw format converter of StreamDevice. *
|
* This is the raw format converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -29,7 +29,7 @@ class RawFloatConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||||
int scanDouble(const StreamFormat&, const char*, double&);
|
ssize_t scanDouble(const StreamFormat&, const char*, double&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int RawFloatConverter::
|
int RawFloatConverter::
|
||||||
@ -90,7 +90,7 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawFloatConverter::
|
ssize_t RawFloatConverter::
|
||||||
scanDouble(const StreamFormat& format, const char* input, double& value)
|
scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||||
{
|
{
|
||||||
int nbOfBytes;
|
int nbOfBytes;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2007 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2007 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the regexp format converter of StreamDevice. *
|
* This is the regexp format converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -22,6 +22,9 @@
|
|||||||
#include "StreamError.h"
|
#include "StreamError.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "pcre.h"
|
#include "pcre.h"
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#define Z PRINTF_SIZE_T_PREFIX
|
||||||
|
|
||||||
// Perl regular expressions (PCRE) %/regexp/ and %#/regexp/subst/
|
// Perl regular expressions (PCRE) %/regexp/ and %#/regexp/subst/
|
||||||
|
|
||||||
@ -32,14 +35,13 @@
|
|||||||
run-time leak.
|
run-time leak.
|
||||||
- A maximum of 9 subexpressions is supported. Only one of them can
|
- A maximum of 9 subexpressions is supported. Only one of them can
|
||||||
be the result of the match.
|
be the result of the match.
|
||||||
- vxWorks and maybe other OS don't have a PCRE library. Provide one?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class RegexpConverter : public StreamFormatConverter
|
class RegexpConverter : public StreamFormatConverter
|
||||||
{
|
{
|
||||||
int parse (const StreamFormat& fmt, StreamBuffer&, const char*&, bool);
|
int parse (const StreamFormat& fmt, StreamBuffer&, const char*&, bool);
|
||||||
int scanString(const StreamFormat& fmt, const char*, char*, size_t);
|
ssize_t scanString(const StreamFormat& fmt, const char*, char*, size_t&);
|
||||||
int scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor);
|
ssize_t scanPseudo(const StreamFormat& fmt, StreamBuffer& input, size_t& cursor);
|
||||||
bool printPseudo(const StreamFormat& fmt, StreamBuffer& output);
|
bool printPseudo(const StreamFormat& fmt, StreamBuffer& output);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,9 +56,9 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
}
|
}
|
||||||
if (fmt.prec > 9)
|
if (fmt.prec > 9)
|
||||||
{
|
{
|
||||||
error("Subexpression index %d too big (>9)\n", fmt.prec);
|
error("Sub-expression index %ld too big (>9)\n", fmt.prec);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamBuffer pattern;
|
StreamBuffer pattern;
|
||||||
while (*source != '/')
|
while (*source != '/')
|
||||||
@ -81,22 +83,30 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
}
|
}
|
||||||
source++;
|
source++;
|
||||||
debug("regexp = \"%s\"\n", pattern.expand()());
|
debug("regexp = \"%s\"\n", pattern.expand()());
|
||||||
|
|
||||||
const char* errormsg;
|
const char* errormsg;
|
||||||
int eoffset;
|
int eoffset;
|
||||||
pcre* code = pcre_compile(pattern(), 0,
|
int nsubexpr;
|
||||||
&errormsg, &eoffset, NULL);
|
|
||||||
|
pcre* code = pcre_compile(pattern(), 0, &errormsg, &eoffset, NULL);
|
||||||
if (!code)
|
if (!code)
|
||||||
{
|
{
|
||||||
error("%s after \"%s\"\n", errormsg, pattern.expand(0, eoffset)());
|
error("%s after \"%s\"\n", errormsg, pattern.expand(0, eoffset)());
|
||||||
return false;
|
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));
|
info.append(&code, sizeof(code));
|
||||||
|
|
||||||
if (fmt.flags & alt_flag)
|
if (fmt.flags & alt_flag)
|
||||||
{
|
{
|
||||||
StreamBuffer subst;
|
StreamBuffer subst;
|
||||||
debug("check for subst in \"%s\"\n", StreamBuffer(source).expand()());
|
|
||||||
|
debug("check for subst in \"%s\"\n", StreamBuffer(source).expand()());
|
||||||
while (*source != '/')
|
while (*source != '/')
|
||||||
{
|
{
|
||||||
if (!*source) {
|
if (!*source) {
|
||||||
@ -115,24 +125,25 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
return string_format;
|
return string_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegexpConverter::
|
ssize_t RegexpConverter::
|
||||||
scanString(const StreamFormat& fmt, const char* input,
|
scanString(const StreamFormat& fmt, const char* input,
|
||||||
char* value, size_t maxlen)
|
char* value, size_t& size)
|
||||||
{
|
{
|
||||||
int ovector[30];
|
int ovector[30];
|
||||||
int rc;
|
int rc;
|
||||||
unsigned int l;
|
size_t l;
|
||||||
|
|
||||||
const char* info = fmt.info;
|
const char* info = fmt.info;
|
||||||
pcre* code = extract<pcre*>(info);
|
pcre* code = extract<pcre*>(info);
|
||||||
int length = fmt.width > 0 ? fmt.width : strlen(input);
|
size_t length = fmt.width > 0 ? fmt.width : strlen(input);
|
||||||
int subexpr = fmt.prec > 0 ? fmt.prec : 0;
|
int subexpr = fmt.prec > 0 ? fmt.prec : 0;
|
||||||
|
|
||||||
|
if (length > INT_MAX)
|
||||||
|
length = INT_MAX;
|
||||||
debug("input = \"%s\"\n", input);
|
debug("input = \"%s\"\n", input);
|
||||||
debug("length=%d\n", length);
|
debug("length=%" Z "u\n", length);
|
||||||
|
|
||||||
rc = pcre_exec(code, NULL, input, length, 0, 0, ovector, 30);
|
rc = pcre_exec(code, NULL, input, (int)length, 0, 0, ovector, 30);
|
||||||
debug("pcre_exec match \"%.*s\" result = %d\n", length, input, rc);
|
debug("pcre_exec match \"%.*s\" result = %d\n", (int)length, input, rc);
|
||||||
if ((subexpr && rc <= subexpr) || rc < 0)
|
if ((subexpr && rc <= subexpr) || rc < 0)
|
||||||
{
|
{
|
||||||
// error or no match or not enough sub-expressions
|
// error or no match or not enough sub-expressions
|
||||||
@ -141,96 +152,110 @@ scanString(const StreamFormat& fmt, const char* input,
|
|||||||
if (fmt.flags & skip_flag) return ovector[subexpr*2+1];
|
if (fmt.flags & skip_flag) return ovector[subexpr*2+1];
|
||||||
|
|
||||||
l = ovector[subexpr*2+1] - ovector[subexpr*2];
|
l = ovector[subexpr*2+1] - ovector[subexpr*2];
|
||||||
if (l >= maxlen) {
|
if (l >= size) {
|
||||||
if (!(fmt.flags & sign_flag)) {
|
if (!(fmt.flags & sign_flag)) {
|
||||||
error("Regexp: Matching string \"%s\" too long (%d>%ld bytes). You may want to try the + flag: \"%%+/.../\"\n",
|
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()(),
|
StreamBuffer(input + ovector[subexpr*2],l).expand()(),
|
||||||
l, (long)maxlen-1);
|
l, size-1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
l = maxlen-1;
|
l = size-1;
|
||||||
}
|
}
|
||||||
memcpy(value, input + ovector[subexpr*2], l);
|
memcpy(value, input + ovector[subexpr*2], l);
|
||||||
value[l] = '\0';
|
value[l] = '\0';
|
||||||
return ovector[1]; // consume input until end of match
|
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, long start)
|
static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, size_t start)
|
||||||
{
|
{
|
||||||
const char* subst = fmt.info;
|
const char* subst = fmt.info;
|
||||||
pcre* code = extract<pcre*>(subst);
|
pcre* code = extract<pcre*>(subst);
|
||||||
long length;
|
size_t length, c;
|
||||||
int rc, l, c, r, rl, n;
|
int rc, l, r, rl, n;
|
||||||
int ovector[30];
|
int ovector[30];
|
||||||
StreamBuffer s;
|
StreamBuffer s;
|
||||||
|
|
||||||
length = buffer.length() - start;
|
length = buffer.length() - start;
|
||||||
if (fmt.width && fmt.width < length)
|
if (fmt.width && fmt.width < length)
|
||||||
length = fmt.width;
|
length = fmt.width;
|
||||||
if (fmt.flags & sign_flag)
|
if (length > INT_MAX)
|
||||||
|
length = INT_MAX;
|
||||||
|
if (fmt.flags & left_flag)
|
||||||
start = buffer.length() - length;
|
start = buffer.length() - length;
|
||||||
|
|
||||||
debug("regsubst buffer=\"%s\", start=%ld, length=%ld, subst = \"%s\"\n",
|
debug("regsubst buffer=\"%s\", start=%" Z "u, length=%" Z "u, subst = \"%s\"\n",
|
||||||
buffer.expand()(), start, length, subst);
|
buffer.expand()(), start, length, StreamBuffer(subst).expand()());
|
||||||
|
|
||||||
for (c = 0, n = 1; c < length; n++)
|
for (c = 0, n = 1; c < length; n++)
|
||||||
{
|
{
|
||||||
rc = pcre_exec(code, NULL, buffer(start+c), length-c, 0, 0, ovector, 30);
|
rc = pcre_exec(code, NULL, buffer(start+c), (int)(length-c), 0, 0, ovector, 30);
|
||||||
debug("pcre_exec match \"%.*s\" result = %d\n", (int)length-c, buffer(start+c), rc);
|
debug("pcre_exec match \"%s\" result = %d\n", buffer.expand(start+c, length-c)(), rc);
|
||||||
if (rc < 0) // no match
|
|
||||||
return;
|
if (rc < 0) // no match
|
||||||
|
{
|
||||||
|
debug("pcre_exec: no match\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!(fmt.flags & sign_flag) && n < fmt.prec) // without + flag
|
if (!(fmt.flags & sign_flag) && n < fmt.prec) // without + flag
|
||||||
{
|
{
|
||||||
// do not yet replace this match
|
// do not yet replace this match
|
||||||
c += ovector[1];
|
c += ovector[1];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// replace & by match in subst
|
// replace subexpressions
|
||||||
l = ovector[1] - ovector[0];
|
l = ovector[1] - ovector[0];
|
||||||
debug("start = \"%s\"\n", buffer(start+c));
|
debug("before [%d]= \"%s\"\n", ovector[0], buffer.expand(start+c,ovector[0])());
|
||||||
debug("match = \"%.*s\"\n", l, buffer(start+c+ovector[0]));
|
debug("match [%d]= \"%s\"\n", l, buffer.expand(start+c+ovector[0],l)());
|
||||||
for (r = 1; r < rc; r++)
|
for (r = 1; r < rc; r++)
|
||||||
debug("sub%d = \"%.*s\"\n", r, ovector[r*2+1]-ovector[r*2], buffer(start+c+ovector[r*2]));
|
debug("sub%d = \"%s\"\n", r, buffer.expand(start+c+ovector[r*2], ovector[r*2+1]-ovector[r*2])());
|
||||||
debug("rest = \"%s\"\n", buffer(start+c+ovector[1]));
|
debug("after = \"%s\"\n", buffer.expand(start+c+ovector[1])());
|
||||||
s = subst;
|
s = subst;
|
||||||
debug("subs = \"%s\"\n", s.expand()());
|
debug("subs = \"%s\"\n", s.expand()());
|
||||||
for (r = 0; r < s.length(); r++)
|
for (r = 0; r < (int)s.length(); r++)
|
||||||
{
|
{
|
||||||
debug("check \"%s\"\n", s.expand(r)());
|
debug("check \"%s\"\n", s.expand(r)());
|
||||||
if (s[r] == esc)
|
if (s[r] == esc)
|
||||||
{
|
{
|
||||||
unsigned char ch = s[r+1];
|
unsigned char ch = s[r+1];
|
||||||
if (ch < 9) // escaped 0 - 9 : replace with subexpr
|
debug("found escaped \\%u, in range 1-%d?\n", ch, rc-1);
|
||||||
|
if (ch != 0 && ch < rc) // escaped 1 - 9 : replace with subexpr
|
||||||
{
|
{
|
||||||
ch *= 2;
|
ch *= 2;
|
||||||
rl = ovector[ch+1] - ovector[ch];
|
rl = ovector[ch+1] - ovector[ch];
|
||||||
debug("replace \\%d: \"%.*s\"\n", ch/2, rl, buffer(start+c+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);
|
s.replace(r, 2, buffer(start+c+ovector[ch]), rl);
|
||||||
r += rl - 1;
|
r += rl - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
debug("no, use literal \\%u\n", ch);
|
||||||
s.remove(r, 1); // just remove escape
|
s.remove(r, 1); // just remove escape
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (s[r] == '&') // unescaped & : replace with match
|
else if (s[r] == '&') // unescaped & : replace with match
|
||||||
{
|
{
|
||||||
debug("replace &: \"%.*s\"\n", l, buffer(start+c+ovector[0]));
|
debug("replace &: \"%s\"\n", buffer.expand(start+c+ovector[0], l)());
|
||||||
s.replace(r, 1, buffer(start+c+ovector[0]), l);
|
s.replace(r, 1, buffer(start+c+ovector[0]), l);
|
||||||
r += l - 1;
|
r += l - 1;
|
||||||
}
|
}
|
||||||
else continue;
|
else continue;
|
||||||
debug("subs = \"%s\"\n", s());
|
debug("subs = \"%s\"\n", s.expand()());
|
||||||
}
|
}
|
||||||
buffer.replace(start+c+ovector[0], l, s);
|
buffer.replace(start+c+ovector[0], l, s);
|
||||||
length += s.length() - l;
|
length += s.length() - l;
|
||||||
c += s.length();
|
c += ovector[0] + s.length();
|
||||||
if (n == fmt.prec) // max match reached
|
if (n == fmt.prec) // max match reached
|
||||||
return;
|
{
|
||||||
|
debug("pcre_exec: max match %d reached\n", n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
debug("pcre_exec converted string: %s\n", buffer.expand()());
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegexpConverter::
|
ssize_t RegexpConverter::
|
||||||
scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor)
|
scanPseudo(const StreamFormat& fmt, StreamBuffer& input, size_t& cursor)
|
||||||
{
|
{
|
||||||
/* re-write input buffer */
|
/* re-write input buffer */
|
||||||
regsubst(fmt, input, cursor);
|
regsubst(fmt, input, cursor);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is a buffer class used in StreamDevice for I/O. *
|
* This is a buffer class used in StreamDevice for I/O. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -26,8 +26,7 @@
|
|||||||
|
|
||||||
#if defined(__vxworks) || defined(vxWorks) || defined(_WIN32) || defined(__rtems__)
|
#if defined(__vxworks) || defined(vxWorks) || defined(_WIN32) || defined(__rtems__)
|
||||||
// These systems have no vsnprintf
|
// These systems have no vsnprintf
|
||||||
#include <epicsStdio.h>
|
#define vsnprintf(p,l,f,v) vsprintf(p,f,v)
|
||||||
#define vsnprintf epicsVsnprintf
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define P PRINTF_SIZE_T_PREFIX
|
#define P PRINTF_SIZE_T_PREFIX
|
||||||
@ -288,7 +287,7 @@ StreamBuffer StreamBuffer::expand(ssize_t start, ssize_t length) const
|
|||||||
}
|
}
|
||||||
end = start+length;
|
end = start+length;
|
||||||
if (end > len) end = len;
|
if (end > len) end = len;
|
||||||
StreamBuffer result((end-start)*2);
|
StreamBuffer result;
|
||||||
start += offs;
|
start += offs;
|
||||||
end += offs;
|
end += offs;
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -296,14 +295,10 @@ StreamBuffer StreamBuffer::expand(ssize_t start, ssize_t length) const
|
|||||||
for (i = start; i < end; i++)
|
for (i = start; i < end; i++)
|
||||||
{
|
{
|
||||||
c = buffer[i];
|
c = buffer[i];
|
||||||
if ((c & 0x7f) < 0x20 || (c & 0x7f) == 0x7f)
|
if (c < 0x20 || c >= 0x7f)
|
||||||
{
|
result.print("\033[1m<%02x>\033[22m", c & 0xff);
|
||||||
result.print("<%02x>", c & 0xff);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
result.append(c);
|
result.append(c);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -311,27 +306,20 @@ StreamBuffer StreamBuffer::expand(ssize_t start, ssize_t length) const
|
|||||||
StreamBuffer StreamBuffer::
|
StreamBuffer StreamBuffer::
|
||||||
dump() const
|
dump() const
|
||||||
{
|
{
|
||||||
StreamBuffer result(256+cap*5);
|
StreamBuffer result;
|
||||||
result.append("\033[0m");
|
|
||||||
size_t i;
|
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("\033[47m");
|
||||||
|
char c;
|
||||||
for (i = 0; i < cap; i++)
|
for (i = 0; i < cap; i++)
|
||||||
{
|
{
|
||||||
if (i == offs) result.append("\033[34m[\033[0m");
|
c = buffer[i];
|
||||||
if ((buffer[i] & 0x7f) < 0x20 || (buffer[i] & 0x7f) == 0x7f)
|
if (offs && i == offs) result.append("\033[0m");
|
||||||
{
|
if (c < 0x20 || c >= 0x7f)
|
||||||
if (i < offs || i >= offs+len)
|
result.print("\033[1m<%02x>\033[22m", c & 0xff);
|
||||||
result.print(
|
|
||||||
"<%02x>", buffer[i] & 0xff);
|
|
||||||
else
|
|
||||||
result.print(
|
|
||||||
"\033[34m<%02x>\033[37m", buffer[i] & 0xff);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
result.append(c);
|
||||||
result.append(buffer[i]);
|
if (i == offs+len-1) result.append("\033[47m");
|
||||||
}
|
|
||||||
if (i == offs+len-1) result.append("\033[34m]\033[37m");
|
|
||||||
}
|
}
|
||||||
result.append("\033[0m");
|
result.append("\033[0m");
|
||||||
return result;
|
return result;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is a buffer class used in StreamDevice for I/O. *
|
* This is a buffer class used in StreamDevice for I/O. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -22,13 +22,14 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
#define __attribute__(x)
|
#define __attribute__(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
#define ssize_t ptrdiff_t
|
typedef ptrdiff_t ssize_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class StreamBuffer
|
class StreamBuffer
|
||||||
@ -93,11 +94,11 @@ public:
|
|||||||
{return len>0;}
|
{return len>0;}
|
||||||
|
|
||||||
// length: get current data length
|
// length: get current data length
|
||||||
ssize_t length() const
|
size_t length() const
|
||||||
{return len;}
|
{return len;}
|
||||||
|
|
||||||
// capacity: get current max data length (spare one byte for end)
|
// capacity: get current max data length (spare one byte for end)
|
||||||
ssize_t capacity() const
|
size_t capacity() const
|
||||||
{return cap-1;}
|
{return cap-1;}
|
||||||
|
|
||||||
// end: get pointer to byte after last data byte
|
// end: get pointer to byte after last data byte
|
||||||
@ -129,7 +130,7 @@ public:
|
|||||||
|
|
||||||
StreamBuffer& append(const StreamBuffer& s)
|
StreamBuffer& append(const StreamBuffer& s)
|
||||||
{return append(s.buffer+s.offs, s.len);}
|
{return append(s.buffer+s.offs, s.len);}
|
||||||
|
|
||||||
// operator += alias for append
|
// operator += alias for append
|
||||||
StreamBuffer& operator+=(char c)
|
StreamBuffer& operator+=(char c)
|
||||||
{return append(c);}
|
{return append(c);}
|
||||||
@ -194,7 +195,7 @@ public:
|
|||||||
{return replace(pos, 0, &c, 1);}
|
{return replace(pos, 0, &c, 1);}
|
||||||
|
|
||||||
StreamBuffer& print(const char* fmt, ...)
|
StreamBuffer& print(const char* fmt, ...)
|
||||||
__attribute__ ((format(printf,2,3)));
|
__attribute__((__format__(__printf__,2,3)));
|
||||||
|
|
||||||
// find: get index of data in buffer or -1
|
// find: get index of data in buffer or -1
|
||||||
ssize_t find(char c, ssize_t start=0) const
|
ssize_t find(char c, ssize_t start=0) const
|
||||||
@ -223,7 +224,7 @@ public:
|
|||||||
// expand: create copy of StreamBuffer where all nonprintable characters
|
// expand: create copy of StreamBuffer where all nonprintable characters
|
||||||
// are replaced by <xx> with xx being the hex code of the 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, ssize_t length) const;
|
||||||
|
|
||||||
StreamBuffer expand(ssize_t start=0) const
|
StreamBuffer expand(ssize_t start=0) const
|
||||||
{return expand(start, len);}
|
{return expand(start, len);}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the interface to bus drivers for StreamDevice. *
|
* This is the interface to bus drivers for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -17,11 +17,10 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include "StreamBusInterface.h"
|
#include "StreamBusInterface.h"
|
||||||
#include "StreamError.h"
|
#include "StreamError.h"
|
||||||
|
|
||||||
StreamIoStatusStrClass StreamIoStatusStr;
|
|
||||||
|
|
||||||
StreamBusInterfaceRegistrarBase* StreamBusInterfaceRegistrarBase::first;
|
StreamBusInterfaceRegistrarBase* StreamBusInterfaceRegistrarBase::first;
|
||||||
|
|
||||||
StreamBusInterfaceRegistrarBase::
|
StreamBusInterfaceRegistrarBase::
|
||||||
@ -70,7 +69,20 @@ find(Client* client, const char* busname, int addr, const char* param)
|
|||||||
bus = r->find(client, busname, addr, param);
|
bus = r->find(client, busname, addr, param);
|
||||||
debug("StreamBusInterface::find %s %s\n",
|
debug("StreamBusInterface::find %s %s\n",
|
||||||
r->name, bus ? "matches" : "does not match");
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -106,7 +118,7 @@ writeRequest(const void*, size_t, unsigned long)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StreamBusInterface::
|
bool StreamBusInterface::
|
||||||
readRequest(unsigned long, unsigned long, long, bool)
|
readRequest(unsigned long, unsigned long, size_t, bool)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -126,8 +138,8 @@ writeCallback(StreamIoStatus)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
long StreamBusInterface::Client::
|
ssize_t StreamBusInterface::Client::
|
||||||
readCallback(StreamIoStatus, const void*, long)
|
readCallback(StreamIoStatus, const void*, size_t)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the interface to bus drivers for StreamDevice. *
|
* This is the interface to bus drivers for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -21,26 +21,12 @@
|
|||||||
#define StreamBusInterface_h
|
#define StreamBusInterface_h
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <StreamBuffer.h>
|
#include "StreamBuffer.h"
|
||||||
|
#include "MacroMagic.h"
|
||||||
|
|
||||||
enum StreamIoStatus {
|
ENUM (StreamIoStatus,
|
||||||
StreamIoSuccess, StreamIoTimeout, StreamIoNoReply,
|
StreamIoSuccess, StreamIoTimeout, StreamIoNoReply,
|
||||||
StreamIoEnd, StreamIoFault
|
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;
|
|
||||||
|
|
||||||
class StreamBusInterface
|
class StreamBusInterface
|
||||||
{
|
{
|
||||||
@ -48,11 +34,13 @@ public:
|
|||||||
|
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
friend class StreamBusInterface;
|
friend class StreamBusInterface;
|
||||||
|
|
||||||
virtual void lockCallback(StreamIoStatus status) = 0;
|
virtual void lockCallback(StreamIoStatus status) = 0;
|
||||||
virtual void writeCallback(StreamIoStatus status);
|
virtual void writeCallback(StreamIoStatus status);
|
||||||
virtual long readCallback(StreamIoStatus status,
|
virtual ssize_t readCallback(StreamIoStatus status,
|
||||||
const void* input, long size);
|
const void* input, size_t size);
|
||||||
virtual void eventCallback(StreamIoStatus status);
|
virtual void eventCallback(StreamIoStatus status);
|
||||||
virtual void connectCallback(StreamIoStatus status);
|
virtual void connectCallback(StreamIoStatus status);
|
||||||
virtual void disconnectCallback(StreamIoStatus status);
|
virtual void disconnectCallback(StreamIoStatus status);
|
||||||
@ -88,7 +76,7 @@ public:
|
|||||||
return businterface && businterface->writeRequest(output, size, timeout_ms);
|
return businterface && businterface->writeRequest(output, size, timeout_ms);
|
||||||
}
|
}
|
||||||
bool busReadRequest(unsigned long replytimeout_ms,
|
bool busReadRequest(unsigned long replytimeout_ms,
|
||||||
unsigned long readtimeout_ms, long expectedLength,
|
unsigned long readtimeout_ms, size_t expectedLength,
|
||||||
bool async) {
|
bool async) {
|
||||||
return businterface && businterface->readRequest(replytimeout_ms,
|
return businterface && businterface->readRequest(replytimeout_ms,
|
||||||
readtimeout_ms, expectedLength, async);
|
readtimeout_ms, expectedLength, async);
|
||||||
@ -110,27 +98,29 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class StreamBusInterfaceClass; // the iterator
|
friend class StreamBusInterfaceClass; // the iterator
|
||||||
friend class Client;
|
friend class Client;
|
||||||
|
char* _name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Client* client;
|
Client* client;
|
||||||
virtual ~StreamBusInterface() {};
|
virtual ~StreamBusInterface() {};
|
||||||
|
const char* name() { return _name; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StreamBusInterface(Client* client);
|
StreamBusInterface(Client* client);
|
||||||
|
|
||||||
// map client functions into StreamBusInterface namespace
|
// map client functions into StreamBusInterface namespace
|
||||||
void lockCallback(StreamIoStatus status)
|
void lockCallback(StreamIoStatus status = StreamIoSuccess)
|
||||||
{ client->lockCallback(status); }
|
{ client->lockCallback(status); }
|
||||||
void writeCallback(StreamIoStatus status)
|
void writeCallback(StreamIoStatus status = StreamIoSuccess)
|
||||||
{ client->writeCallback(status); }
|
{ client->writeCallback(status); }
|
||||||
long readCallback(StreamIoStatus status,
|
ssize_t readCallback(StreamIoStatus status,
|
||||||
const void* input = NULL, long size = 0)
|
const void* input = NULL, size_t size = 0)
|
||||||
{ return client->readCallback(status, input, size); }
|
{ return client->readCallback(status, input, size); }
|
||||||
void eventCallback(StreamIoStatus status)
|
void eventCallback(StreamIoStatus status = StreamIoSuccess)
|
||||||
{ client->eventCallback(status); }
|
{ client->eventCallback(status); }
|
||||||
void connectCallback(StreamIoStatus status)
|
void connectCallback(StreamIoStatus status = StreamIoSuccess)
|
||||||
{ client->connectCallback(status); }
|
{ client->connectCallback(status); }
|
||||||
void disconnectCallback(StreamIoStatus status)
|
void disconnectCallback(StreamIoStatus status = StreamIoSuccess)
|
||||||
{ client->disconnectCallback(status); }
|
{ client->disconnectCallback(status); }
|
||||||
const char* getInTerminator(size_t& length)
|
const char* getInTerminator(size_t& length)
|
||||||
{ return client->getInTerminator(length); }
|
{ return client->getInTerminator(length); }
|
||||||
@ -143,7 +133,7 @@ protected:
|
|||||||
virtual bool writeRequest(const void* output, size_t size,
|
virtual bool writeRequest(const void* output, size_t size,
|
||||||
unsigned long timeout_ms);
|
unsigned long timeout_ms);
|
||||||
virtual bool readRequest(unsigned long replytimeout_ms,
|
virtual bool readRequest(unsigned long replytimeout_ms,
|
||||||
unsigned long readtimeout_ms, long expectedLength,
|
unsigned long readtimeout_ms, size_t expectedLength,
|
||||||
bool async);
|
bool async);
|
||||||
virtual bool supportsEvent(); // defaults to false
|
virtual bool supportsEvent(); // defaults to false
|
||||||
virtual bool supportsAsyncRead(); // defaults to false
|
virtual bool supportsAsyncRead(); // defaults to false
|
||||||
@ -178,7 +168,7 @@ protected:
|
|||||||
StreamBusInterfaceRegistrarBase(const char* name);
|
StreamBusInterfaceRegistrarBase(const char* name);
|
||||||
virtual ~StreamBusInterfaceRegistrarBase();
|
virtual ~StreamBusInterfaceRegistrarBase();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class C>
|
template <class C>
|
||||||
class StreamBusInterfaceRegistrar : protected StreamBusInterfaceRegistrarBase
|
class StreamBusInterfaceRegistrar : protected StreamBusInterfaceRegistrarBase
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the kernel of StreamDevice. *
|
* This is the kernel of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -70,25 +70,28 @@ void acceptEvent(unsigned short mask, unsigned short timeout)
|
|||||||
|
|
||||||
***************************************/
|
***************************************/
|
||||||
|
|
||||||
enum Flags {
|
#include "MacroMagic.h"
|
||||||
// 0x00FFFFFF reserved for StreamCore
|
|
||||||
None = 0x0000,
|
|
||||||
IgnoreExtraInput = 0x0001,
|
// Flags: 0x00FFFFFF reserved for StreamCore
|
||||||
InitRun = 0x0002,
|
const unsigned long None = 0x0000;
|
||||||
AsyncMode = 0x0004,
|
const unsigned long IgnoreExtraInput = 0x0001;
|
||||||
GotValue = 0x0008,
|
const unsigned long InitRun = 0x0002;
|
||||||
BusOwner = 0x0010,
|
const unsigned long AsyncMode = 0x0004;
|
||||||
Separator = 0x0020,
|
const unsigned long GotValue = 0x0008;
|
||||||
ScanTried = 0x0040,
|
const unsigned long BusOwner = 0x0010;
|
||||||
AcceptInput = 0x0100,
|
const unsigned long Separator = 0x0020;
|
||||||
AcceptEvent = 0x0200,
|
const unsigned long ScanTried = 0x0040;
|
||||||
LockPending = 0x0400,
|
const unsigned long AcceptInput = 0x0100;
|
||||||
WritePending = 0x0800,
|
const unsigned long AcceptEvent = 0x0200;
|
||||||
WaitPending = 0x1000,
|
const unsigned long LockPending = 0x0400;
|
||||||
BusPending = LockPending|WritePending|WaitPending,
|
const unsigned long WritePending = 0x0800;
|
||||||
ClearOnStart = InitRun|AsyncMode|GotValue|BusOwner|Separator|ScanTried|
|
const unsigned long WaitPending = 0x1000;
|
||||||
AcceptInput|AcceptEvent|BusPending
|
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;
|
||||||
|
|
||||||
struct StreamFormat;
|
struct StreamFormat;
|
||||||
|
|
||||||
@ -97,14 +100,12 @@ class StreamCore :
|
|||||||
StreamBusInterface::Client
|
StreamBusInterface::Client
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
enum ProtocolResult {
|
|
||||||
Success, LockTimeout, WriteTimeout, ReplyTimeout, ReadTimeout,
|
|
||||||
ScanError, FormatError, Abort, Fault
|
|
||||||
};
|
|
||||||
|
|
||||||
enum StartMode {
|
ENUM(ProtocolResult,
|
||||||
StartNormal, StartInit, StartAsync
|
Success, LockTimeout, WriteTimeout, ReplyTimeout, ReadTimeout, ScanError, FormatError, Abort, Fault, Offline);
|
||||||
};
|
|
||||||
|
ENUM(StartMode,
|
||||||
|
StartNormal, StartInit, StartAsync);
|
||||||
|
|
||||||
class MutexLock
|
class MutexLock
|
||||||
{
|
{
|
||||||
@ -135,10 +136,10 @@ protected:
|
|||||||
bool printValue(const StreamFormat& format, long value);
|
bool printValue(const StreamFormat& format, long value);
|
||||||
bool printValue(const StreamFormat& format, double value);
|
bool printValue(const StreamFormat& format, double value);
|
||||||
bool printValue(const StreamFormat& format, char* value);
|
bool printValue(const StreamFormat& format, char* value);
|
||||||
long scanValue(const StreamFormat& format, long& value);
|
ssize_t scanValue(const StreamFormat& format, long& value);
|
||||||
long scanValue(const StreamFormat& format, double& value);
|
ssize_t scanValue(const StreamFormat& format, double& value);
|
||||||
long scanValue(const StreamFormat& format, char* value, long maxlen);
|
ssize_t scanValue(const StreamFormat& format, char* value, size_t& size);
|
||||||
long scanValue(const StreamFormat& format);
|
ssize_t scanValue(const StreamFormat& format);
|
||||||
|
|
||||||
StreamBuffer protocolname;
|
StreamBuffer protocolname;
|
||||||
unsigned long lockTimeout;
|
unsigned long lockTimeout;
|
||||||
@ -159,11 +160,11 @@ protected:
|
|||||||
StreamBuffer onReadTimeout; // error handler (optional)
|
StreamBuffer onReadTimeout; // error handler (optional)
|
||||||
StreamBuffer onMismatch; // error handler (optional)
|
StreamBuffer onMismatch; // error handler (optional)
|
||||||
const char* commandIndex; // current position
|
const char* commandIndex; // current position
|
||||||
const char* activeCommand; // start of current command
|
char activeCommand; // current command
|
||||||
StreamBuffer outputLine;
|
StreamBuffer outputLine;
|
||||||
StreamBuffer inputBuffer;
|
StreamBuffer inputBuffer;
|
||||||
StreamBuffer inputLine;
|
StreamBuffer inputLine;
|
||||||
long consumedInput;
|
size_t consumedInput;
|
||||||
ProtocolResult runningHandler;
|
ProtocolResult runningHandler;
|
||||||
StreamBuffer fieldAddress;
|
StreamBuffer fieldAddress;
|
||||||
|
|
||||||
@ -194,8 +195,8 @@ protected:
|
|||||||
// StreamBusInterface::Client methods
|
// StreamBusInterface::Client methods
|
||||||
void lockCallback(StreamIoStatus status);
|
void lockCallback(StreamIoStatus status);
|
||||||
void writeCallback(StreamIoStatus status);
|
void writeCallback(StreamIoStatus status);
|
||||||
long readCallback(StreamIoStatus status,
|
ssize_t readCallback(StreamIoStatus status,
|
||||||
const void* input, long size);
|
const void* input, size_t size);
|
||||||
void eventCallback(StreamIoStatus status);
|
void eventCallback(StreamIoStatus status);
|
||||||
void execCallback(StreamIoStatus status);
|
void execCallback(StreamIoStatus status);
|
||||||
void connectCallback(StreamIoStatus status);
|
void connectCallback(StreamIoStatus status);
|
||||||
@ -217,7 +218,7 @@ public:
|
|||||||
StreamCore();
|
StreamCore();
|
||||||
virtual ~StreamCore();
|
virtual ~StreamCore();
|
||||||
bool parse(const char* filename, const char* protocolname);
|
bool parse(const char* filename, const char* protocolname);
|
||||||
void printProtocol();
|
void printProtocol(FILE* = stdout);
|
||||||
const char* name() { return streamname; }
|
const char* name() { return streamname; }
|
||||||
void printStatus(StreamBuffer& buffer);
|
void printStatus(StreamBuffer& buffer);
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is error and debug message handling of StreamDevice. *
|
* This is error and debug message handling of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -37,24 +37,24 @@ FILE *StreamDebugFile = NULL;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define localtime_r(timet,tm) localtime_s(tm,timet)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* You can globally change the printTimestamp function
|
/* You can globally change the printTimestamp function
|
||||||
by setting the StreamPrintTimestampFunction variable
|
by setting the StreamPrintTimestampFunction variable
|
||||||
to your own function.
|
to your own function.
|
||||||
*/
|
*/
|
||||||
static void printTimestamp(char* buffer, int size)
|
static void printTimestamp(char* buffer, size_t size)
|
||||||
{
|
{
|
||||||
time_t t;
|
time_t t;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
time(&t);
|
time(&t);
|
||||||
#ifdef _WIN32
|
|
||||||
tm = *localtime(&t);
|
|
||||||
#else
|
|
||||||
localtime_r(&t, &tm);
|
localtime_r(&t, &tm);
|
||||||
#endif
|
|
||||||
strftime(buffer, size, "%Y/%m/%d %H:%M:%S", &tm);
|
strftime(buffer, size, "%Y/%m/%d %H:%M:%S", &tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*StreamPrintTimestampFunction)(char* buffer, int size) = printTimestamp;
|
void (*StreamPrintTimestampFunction)(char* buffer, size_t size) = printTimestamp;
|
||||||
|
|
||||||
void StreamError(const char* fmt, ...)
|
void StreamError(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is error and debug message handling of StreamDevice. *
|
* This is error and debug message handling of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -29,20 +29,20 @@
|
|||||||
|
|
||||||
extern int streamDebug;
|
extern int streamDebug;
|
||||||
extern int streamError;
|
extern int streamError;
|
||||||
extern void (*StreamPrintTimestampFunction)(char* buffer, int size);
|
extern void (*StreamPrintTimestampFunction)(char* buffer, size_t size);
|
||||||
|
|
||||||
void StreamError(int line, const char* file, const char* fmt, ...)
|
void StreamError(int line, const char* file, const char* fmt, ...)
|
||||||
__attribute__ ((format(printf,3,4)));
|
__attribute__((__format__(__printf__,3,4)));
|
||||||
|
|
||||||
void StreamVError(int line, const char* file, const char* fmt, va_list args)
|
void StreamVError(int line, const char* file, const char* fmt, va_list args)
|
||||||
__attribute__ ((format(printf,3,0)));
|
__attribute__((__format__(__printf__,3,0)));
|
||||||
|
|
||||||
void StreamError(const char* fmt, ...)
|
void StreamError(const char* fmt, ...)
|
||||||
__attribute__ ((format(printf,1,2)));
|
__attribute__((__format__(__printf__,1,2)));
|
||||||
|
|
||||||
inline void StreamVError(const char* fmt, va_list args)
|
inline void StreamVError(const char* fmt, va_list args)
|
||||||
{
|
{
|
||||||
StreamVError(0, NULL, fmt, args);
|
StreamVError(0, NULL, fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
class StreamDebugClass
|
class StreamDebugClass
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
StreamDebugClass(const char* file, int line) :
|
StreamDebugClass(const char* file, int line) :
|
||||||
file(file), line(line) {}
|
file(file), line(line) {}
|
||||||
int print(const char* fmt, ...)
|
int print(const char* fmt, ...)
|
||||||
__attribute__ ((format(printf,2,3)));
|
__attribute__((__format__(__printf__,2,3)));
|
||||||
};
|
};
|
||||||
|
|
||||||
inline StreamDebugClass
|
inline StreamDebugClass
|
||||||
@ -63,9 +63,4 @@ StreamDebugObject(const char* file, int line)
|
|||||||
#define error StreamError
|
#define error StreamError
|
||||||
#define debug (!streamDebug)?0:StreamDebugObject(__FILE__,__LINE__).print
|
#define debug (!streamDebug)?0:StreamDebugObject(__FILE__,__LINE__).print
|
||||||
|
|
||||||
#if (__GNUC__ == 2 && __GNUC_MINOR__ == 7)
|
|
||||||
/* Bug in cygnus-2.7.2 compiler: temporary objects crash the compiler */
|
|
||||||
#define NO_TEMPORARY
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* *
|
* *
|
||||||
* This header defines the format stucture used to interface *
|
* This header defines the format stucture used to interface *
|
||||||
* format converters and record interfaces to StreamDevice *
|
* format converters and record interfaces to StreamDevice *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -31,7 +31,7 @@ typedef enum {
|
|||||||
skip_flag = 0x20,
|
skip_flag = 0x20,
|
||||||
default_flag = 0x40,
|
default_flag = 0x40,
|
||||||
compare_flag = 0x80,
|
compare_flag = 0x80,
|
||||||
fix_width_flag = 0x100,
|
fix_width_flag = 0x100
|
||||||
} StreamFormatFlag;
|
} StreamFormatFlag;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -50,9 +50,9 @@ typedef struct StreamFormat
|
|||||||
char conv;
|
char conv;
|
||||||
StreamFormatType type;
|
StreamFormatType type;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
short prec;
|
long prec;
|
||||||
unsigned short width;
|
unsigned long width;
|
||||||
unsigned short infolen;
|
unsigned long infolen;
|
||||||
const char* info;
|
const char* info;
|
||||||
} StreamFormat;
|
} StreamFormat;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* *
|
* *
|
||||||
* This is the format converter base and includes the standard *
|
* This is the format converter base and includes the standard *
|
||||||
* format converters for StreamDevice. *
|
* format converters for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -113,12 +113,12 @@ parseFormat(const char*& source, FormatType formatType, StreamFormat& streamForm
|
|||||||
char* p;
|
char* p;
|
||||||
val = strtoul (source, &p, 10);
|
val = strtoul (source, &p, 10);
|
||||||
source = p;
|
source = p;
|
||||||
if (val > 0xFFFF)
|
if (val > LONG_MAX)
|
||||||
{
|
{
|
||||||
error("Field width %ld out of range\n", val);
|
error("Field width %ld out of range\n", val);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
streamFormat.width = (unsigned short)val;
|
streamFormat.width = val;
|
||||||
// look for prec
|
// look for prec
|
||||||
streamFormat.prec = -1;
|
streamFormat.prec = -1;
|
||||||
if (*source == '.')
|
if (*source == '.')
|
||||||
@ -132,7 +132,7 @@ parseFormat(const char*& source, FormatType formatType, StreamFormat& streamForm
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
source = p;
|
source = p;
|
||||||
if (val > 0x7FFF)
|
if (val > SHRT_MAX)
|
||||||
{
|
{
|
||||||
error("Precision %ld out of range\n", val);
|
error("Precision %ld out of range\n", val);
|
||||||
return false;
|
return false;
|
||||||
@ -205,7 +205,7 @@ printPseudo(const StreamFormat& fmt, StreamBuffer&)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamFormatConverter::
|
ssize_t StreamFormatConverter::
|
||||||
scanLong(const StreamFormat& fmt, const char*, long&)
|
scanLong(const StreamFormat& fmt, const char*, long&)
|
||||||
{
|
{
|
||||||
error("Unimplemented scanLong method for %%%c format\n",
|
error("Unimplemented scanLong method for %%%c format\n",
|
||||||
@ -213,7 +213,7 @@ scanLong(const StreamFormat& fmt, const char*, long&)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamFormatConverter::
|
ssize_t StreamFormatConverter::
|
||||||
scanDouble(const StreamFormat& fmt, const char*, double&)
|
scanDouble(const StreamFormat& fmt, const char*, double&)
|
||||||
{
|
{
|
||||||
error("Unimplemented scanDouble method for %%%c format\n",
|
error("Unimplemented scanDouble method for %%%c format\n",
|
||||||
@ -221,16 +221,16 @@ scanDouble(const StreamFormat& fmt, const char*, double&)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamFormatConverter::
|
ssize_t StreamFormatConverter::
|
||||||
scanString(const StreamFormat& fmt, const char*, char*, size_t)
|
scanString(const StreamFormat& fmt, const char*, char*, size_t&)
|
||||||
{
|
{
|
||||||
error("Unimplemented scanString method for %%%c format\n",
|
error("Unimplemented scanString method for %%%c format\n",
|
||||||
fmt.conv);
|
fmt.conv);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamFormatConverter::
|
ssize_t StreamFormatConverter::
|
||||||
scanPseudo(const StreamFormat& fmt, StreamBuffer&, long&)
|
scanPseudo(const StreamFormat& fmt, StreamBuffer&, size_t&)
|
||||||
{
|
{
|
||||||
error("Unimplemented scanPseudo method for %%%c format\n",
|
error("Unimplemented scanPseudo method for %%%c format\n",
|
||||||
fmt.conv);
|
fmt.conv);
|
||||||
@ -255,20 +255,20 @@ static void copyFormatString(StreamBuffer& info, const char* source)
|
|||||||
|
|
||||||
// Standard Long Converter for 'diouxX'
|
// Standard Long Converter for 'diouxX'
|
||||||
|
|
||||||
static int prepareval(const StreamFormat& fmt, const char*& input, bool& neg)
|
static ssize_t prepareval(const StreamFormat& fmt, const char*& input, bool& neg)
|
||||||
{
|
{
|
||||||
int length = 0;
|
size_t consumed = 0;
|
||||||
neg = false;
|
neg = false;
|
||||||
while (isspace(*input)) { input++; length++; }
|
while (isspace(*input)) { input++; consumed++; }
|
||||||
if (fmt.width)
|
if (fmt.width)
|
||||||
{
|
{
|
||||||
// take local copy because strto* don't have width parameter
|
// take local copy because strto* don't have width parameter
|
||||||
int width = fmt.width;
|
size_t width = fmt.width;
|
||||||
if (fmt.flags & space_flag)
|
if (fmt.flags & space_flag)
|
||||||
{
|
{
|
||||||
// normally whitespace does not count to width
|
// normally whitespace does not count to width
|
||||||
// but do so if space flag is present
|
// but do so if space flag is present
|
||||||
width -= length;
|
width -= consumed;
|
||||||
}
|
}
|
||||||
strncpy((char*)fmt.info, input, width);
|
strncpy((char*)fmt.info, input, width);
|
||||||
((char*)fmt.info)[width] = 0;
|
((char*)fmt.info)[width] = 0;
|
||||||
@ -283,21 +283,21 @@ static int prepareval(const StreamFormat& fmt, const char*& input, bool& neg)
|
|||||||
neg = true;
|
neg = true;
|
||||||
skipsign:
|
skipsign:
|
||||||
input++;
|
input++;
|
||||||
length++;
|
consumed++;
|
||||||
}
|
}
|
||||||
if (isspace(*input))
|
if (isspace(*input))
|
||||||
{
|
{
|
||||||
// allow space after sign only if # flag is set
|
// allow space after sign only if # flag is set
|
||||||
if (!(fmt.flags & alt_flag)) return -1;
|
if (!(fmt.flags & alt_flag)) return -1;
|
||||||
}
|
}
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
class StdLongConverter : public StreamFormatConverter
|
class StdLongConverter : public StreamFormatConverter
|
||||||
{
|
{
|
||||||
int parse(const StreamFormat& fmt, StreamBuffer& output, const char*& value, bool scanFormat);
|
int parse(const StreamFormat& fmt, StreamBuffer& output, const char*& value, bool scanFormat);
|
||||||
bool printLong(const StreamFormat& fmt, StreamBuffer& output, long value);
|
bool printLong(const StreamFormat& fmt, StreamBuffer& output, long value);
|
||||||
int scanLong(const StreamFormat& fmt, const char* input, long& value);
|
ssize_t scanLong(const StreamFormat& fmt, const char* input, long& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
int StdLongConverter::
|
int StdLongConverter::
|
||||||
@ -306,7 +306,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
{
|
{
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
{
|
{
|
||||||
error("Use of precision field '.%d' not allowed with %%%c input conversion\n",
|
error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
|
||||||
fmt.prec, fmt.conv);
|
fmt.prec, fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -320,7 +320,9 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
info.append('l');
|
info.append('l');
|
||||||
info.append(fmt.conv);
|
info.append(fmt.conv);
|
||||||
}
|
}
|
||||||
if (fmt.conv == 'd' || fmt.conv == 'i') return signed_format;
|
if (fmt.conv == 'd' || fmt.conv == 'i'
|
||||||
|
|| ((fmt.conv == 'x' || fmt.conv == 'o') && fmt.flags & (left_flag | sign_flag)))
|
||||||
|
return signed_format;
|
||||||
return unsigned_format;
|
return unsigned_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,17 +336,17 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StdLongConverter::
|
ssize_t StdLongConverter::
|
||||||
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||||
{
|
{
|
||||||
char* end;
|
char* end;
|
||||||
int length;
|
ssize_t consumed;
|
||||||
bool neg;
|
bool neg;
|
||||||
int base;
|
int base;
|
||||||
long v;
|
long v;
|
||||||
|
|
||||||
length = prepareval(fmt, input, neg);
|
consumed = prepareval(fmt, input, neg);
|
||||||
if (length < 0) return -1;
|
if (consumed < 0) return -1;
|
||||||
switch (fmt.conv)
|
switch (fmt.conv)
|
||||||
{
|
{
|
||||||
case 'd':
|
case 'd':
|
||||||
@ -366,9 +368,9 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
|||||||
}
|
}
|
||||||
v = strtoul(input, &end, base);
|
v = strtoul(input, &end, base);
|
||||||
if (end == input) return -1;
|
if (end == input) return -1;
|
||||||
length += end-input;
|
consumed += end-input;
|
||||||
value = neg ? -v : v;
|
value = neg ? -v : v;
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (StdLongConverter, "diouxX");
|
RegisterConverter (StdLongConverter, "diouxX");
|
||||||
@ -379,7 +381,7 @@ class StdDoubleConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
virtual bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
virtual bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||||
virtual int scanDouble(const StreamFormat&, const char*, double&);
|
virtual ssize_t scanDouble(const StreamFormat&, const char*, double&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int StdDoubleConverter::
|
int StdDoubleConverter::
|
||||||
@ -388,7 +390,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
{
|
{
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
{
|
{
|
||||||
error("Use of precision field '.%d' not allowed with %%%c input conversion\n",
|
error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
|
||||||
fmt.prec, fmt.conv);
|
fmt.prec, fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -411,20 +413,20 @@ printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StdDoubleConverter::
|
ssize_t StdDoubleConverter::
|
||||||
scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
||||||
{
|
{
|
||||||
char* end;
|
char* end;
|
||||||
int length;
|
ssize_t consumed;
|
||||||
bool neg;
|
bool neg;
|
||||||
|
|
||||||
length = prepareval(fmt, input, neg);
|
consumed = prepareval(fmt, input, neg);
|
||||||
if (length < 0) return -1;
|
if (consumed < 0) return -1;
|
||||||
value = strtod(input, &end);
|
value = strtod(input, &end);
|
||||||
if (neg) value = -value;
|
if (neg) value = -value;
|
||||||
if (end == input) return -1;
|
if (end == input) return -1;
|
||||||
length += end-input;
|
consumed += end-input;
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (StdDoubleConverter, "feEgG");
|
RegisterConverter (StdDoubleConverter, "feEgG");
|
||||||
@ -435,22 +437,23 @@ class StdStringConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
virtual bool printString(const StreamFormat&, StreamBuffer&, const char*);
|
virtual bool printString(const StreamFormat&, StreamBuffer&, const char*);
|
||||||
virtual int scanString(const StreamFormat&, const char*, char*, size_t);
|
virtual ssize_t scanString(const StreamFormat&, const char*, char*, size_t&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int StdStringConverter::
|
int StdStringConverter::
|
||||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||||
const char*& source, bool scanFormat)
|
const char*& source, bool scanFormat)
|
||||||
{
|
{
|
||||||
if (fmt.flags & (sign_flag|zero_flag))
|
if (fmt.flags & sign_flag)
|
||||||
{
|
{
|
||||||
error("Use of modifiers '+', '0'"
|
error("Use of modifier '+'"
|
||||||
"not allowed with %%s conversion\n");
|
"not allowed with %%%c conversion\n",
|
||||||
|
fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
{
|
{
|
||||||
error("Use of precision field '.%d' not allowed with %%%c input conversion\n",
|
error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
|
||||||
fmt.prec, fmt.conv);
|
fmt.prec, fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -463,21 +466,36 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
bool StdStringConverter::
|
bool StdStringConverter::
|
||||||
printString(const StreamFormat& fmt, StreamBuffer& output, const char* value)
|
printString(const StreamFormat& fmt, StreamBuffer& output, const char* value)
|
||||||
{
|
{
|
||||||
output.print(fmt.info, value);
|
if (fmt.flags & zero_flag && fmt.width)
|
||||||
|
{
|
||||||
|
size_t l;
|
||||||
|
if (fmt.prec > -1)
|
||||||
|
{
|
||||||
|
char* p = (char*)memchr(value, 0, fmt.prec);
|
||||||
|
if (p) l = p - value;
|
||||||
|
else l = fmt.prec;
|
||||||
|
}
|
||||||
|
else l = strlen(value);
|
||||||
|
if (!(fmt.flags & left_flag)) output.append('\0', fmt.width-l);
|
||||||
|
output.append(value, l);
|
||||||
|
if (fmt.flags & left_flag) output.append('\0', fmt.width-l);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
output.print(fmt.info, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StdStringConverter::
|
ssize_t StdStringConverter::
|
||||||
scanString(const StreamFormat& fmt, const char* input,
|
scanString(const StreamFormat& fmt, const char* input,
|
||||||
char* value, size_t maxlen)
|
char* value, size_t& size)
|
||||||
{
|
{
|
||||||
int length = 0;
|
ssize_t consumed = 0;
|
||||||
|
size_t space_left = size;
|
||||||
|
ssize_t width = fmt.width;
|
||||||
|
|
||||||
int width = fmt.width;
|
if ((fmt.flags & skip_flag) || value == NULL) space_left = 0;
|
||||||
|
|
||||||
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
// if user does not specify width assume "infinity" (-1)
|
||||||
|
|
||||||
// if user does not specify width assume "ininity" (-1)
|
|
||||||
if (width == 0)
|
if (width == 0)
|
||||||
{
|
{
|
||||||
if (fmt.conv == 'c') width = 1;
|
if (fmt.conv == 'c') width = 1;
|
||||||
@ -490,14 +508,14 @@ scanString(const StreamFormat& fmt, const char* input,
|
|||||||
// but do so if space flag is present
|
// but do so if space flag is present
|
||||||
if (fmt.flags & space_flag)
|
if (fmt.flags & space_flag)
|
||||||
{
|
{
|
||||||
if (maxlen > 1)
|
if (space_left > 1) // keep space for terminal null byte
|
||||||
{
|
{
|
||||||
*value++ = *input;
|
*value++ = *input;
|
||||||
maxlen--;
|
space_left--;
|
||||||
}
|
}
|
||||||
width--;
|
width--;
|
||||||
}
|
}
|
||||||
length++;
|
consumed++;
|
||||||
input++;
|
input++;
|
||||||
}
|
}
|
||||||
while (*input && width)
|
while (*input && width)
|
||||||
@ -505,20 +523,22 @@ scanString(const StreamFormat& fmt, const char* input,
|
|||||||
// normally whitespace ends string
|
// normally whitespace ends string
|
||||||
// but don't end if # flag is present
|
// but don't end if # flag is present
|
||||||
if (!(fmt.flags & alt_flag) && isspace(*input)) break;
|
if (!(fmt.flags & alt_flag) && isspace(*input)) break;
|
||||||
if (maxlen > 1)
|
if (space_left > 1)
|
||||||
{
|
{
|
||||||
*value++ = *input;
|
*value++ = *input;
|
||||||
maxlen--;
|
space_left--;
|
||||||
}
|
}
|
||||||
length++;
|
consumed++;
|
||||||
width--;
|
width--;
|
||||||
input++;
|
input++;
|
||||||
}
|
}
|
||||||
if (maxlen > 0)
|
if (space_left)
|
||||||
{
|
{
|
||||||
*value = '\0';
|
*value = '\0';
|
||||||
|
space_left--;
|
||||||
|
size -= space_left; // update number of bytes copied to value
|
||||||
}
|
}
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (StdStringConverter, "s");
|
RegisterConverter (StdStringConverter, "s");
|
||||||
@ -529,7 +549,7 @@ class StdCharsConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
virtual bool printLong(const StreamFormat&, StreamBuffer&, long);
|
virtual bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||||
virtual int scanString(const StreamFormat&, const char*, char*, size_t);
|
virtual ssize_t scanString(const StreamFormat&, const char*, char*, size_t&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int StdCharsConverter::
|
int StdCharsConverter::
|
||||||
@ -544,7 +564,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
}
|
}
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
{
|
{
|
||||||
error("Use of precision field '.%d' not allowed with %%%c input conversion\n",
|
error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
|
||||||
fmt.prec, fmt.conv);
|
fmt.prec, fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -565,35 +585,37 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StdCharsConverter::
|
ssize_t StdCharsConverter::
|
||||||
scanString(const StreamFormat& fmt, const char* input,
|
scanString(const StreamFormat& fmt, const char* input,
|
||||||
char* value, size_t maxlen)
|
char* value, size_t& size)
|
||||||
{
|
{
|
||||||
int length = 0;
|
size_t consumed = 0;
|
||||||
|
size_t width = fmt.width;
|
||||||
|
size_t space_left = size;
|
||||||
|
|
||||||
int width = fmt.width;
|
if ((fmt.flags & skip_flag) || value == NULL) space_left = 0;
|
||||||
|
|
||||||
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
|
||||||
|
|
||||||
// if user does not specify width assume 1
|
// if user does not specify width assume 1
|
||||||
if (width == 0) width = 1;
|
if (width == 0) width = 1;
|
||||||
|
|
||||||
while (*input && width)
|
while (*input && width)
|
||||||
{
|
{
|
||||||
if (maxlen > 1)
|
if (space_left > 1) // keep space for terminal null byte
|
||||||
{
|
{
|
||||||
*value++ = *input;
|
*value++ = *input;
|
||||||
maxlen--;
|
space_left--;
|
||||||
}
|
}
|
||||||
length++;
|
consumed++;
|
||||||
width--;
|
width--;
|
||||||
input++;
|
input++;
|
||||||
}
|
}
|
||||||
if (maxlen > 0)
|
if (space_left)
|
||||||
{
|
{
|
||||||
*value = '\0';
|
*value = '\0';
|
||||||
|
space_left--;
|
||||||
|
size -= space_left; // update number of bytes written to value
|
||||||
}
|
}
|
||||||
return length;
|
return consumed; // return number of bytes consumed from input
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (StdCharsConverter, "c");
|
RegisterConverter (StdCharsConverter, "c");
|
||||||
@ -603,7 +625,7 @@ RegisterConverter (StdCharsConverter, "c");
|
|||||||
class StdCharsetConverter : public StreamFormatConverter
|
class StdCharsetConverter : public StreamFormatConverter
|
||||||
{
|
{
|
||||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
virtual int scanString(const StreamFormat&, const char*, char*, size_t);
|
virtual ssize_t scanString(const StreamFormat&, const char*, char*, size_t&);
|
||||||
// no print method, %[ is readonly
|
// no print method, %[ is readonly
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -635,7 +657,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
}
|
}
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
{
|
{
|
||||||
error("Use of precision field '.%d' not allowed with %%%c input conversion\n",
|
error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
|
||||||
fmt.prec, fmt.conv);
|
fmt.prec, fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -682,35 +704,38 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
return string_format;
|
return string_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StdCharsetConverter::
|
ssize_t StdCharsetConverter::
|
||||||
scanString(const StreamFormat& fmt, const char* input,
|
scanString(const StreamFormat& fmt, const char* input,
|
||||||
char* value, size_t maxlen)
|
char* value, size_t& size)
|
||||||
{
|
{
|
||||||
int length = 0;
|
ssize_t consumed = 0;
|
||||||
int width = fmt.width;
|
ssize_t width = fmt.width;
|
||||||
|
size_t space_left = size;
|
||||||
|
|
||||||
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
if ((fmt.flags & skip_flag) || value == NULL) space_left = 0;
|
||||||
|
|
||||||
// if user does not specify width assume "ininity" (-1)
|
// if user does not specify width assume "infinity" (-1)
|
||||||
if (width == 0) width = -1;
|
if (width == 0) width = -1;
|
||||||
|
|
||||||
while (*input && width)
|
while (*input && width)
|
||||||
{
|
{
|
||||||
if (fmt.info[*input>>3] & 1<<(*input&7)) break;
|
if (fmt.info[*input>>3] & 1<<(*input&7)) break;
|
||||||
if (maxlen > 1)
|
if (space_left > 1) // keep space for terminal null byte
|
||||||
{
|
{
|
||||||
*value++ = *input;
|
*value++ = *input;
|
||||||
maxlen--;
|
space_left--;
|
||||||
}
|
}
|
||||||
length++;
|
consumed++;
|
||||||
width--;
|
width--;
|
||||||
input++;
|
input++;
|
||||||
}
|
}
|
||||||
if (maxlen > 0)
|
if (space_left)
|
||||||
{
|
{
|
||||||
*value = '\0';
|
*value = '\0';
|
||||||
|
space_left--;
|
||||||
|
size -= space_left; // update number of bytes written to value
|
||||||
}
|
}
|
||||||
return length;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterConverter (StdCharsetConverter, "[");
|
RegisterConverter (StdCharsetConverter, "[");
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the format converter header of StreamDevice. *
|
* This is the format converter header of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -56,14 +56,14 @@ public:
|
|||||||
StreamBuffer& output, const char* value);
|
StreamBuffer& output, const char* value);
|
||||||
virtual bool printPseudo(const StreamFormat& fmt,
|
virtual bool printPseudo(const StreamFormat& fmt,
|
||||||
StreamBuffer& output);
|
StreamBuffer& output);
|
||||||
virtual int scanLong(const StreamFormat& fmt,
|
virtual ssize_t scanLong(const StreamFormat& fmt,
|
||||||
const char* input, long& value);
|
const char* input, long& value);
|
||||||
virtual int scanDouble(const StreamFormat& fmt,
|
virtual ssize_t scanDouble(const StreamFormat& fmt,
|
||||||
const char* input, double& value);
|
const char* input, double& value);
|
||||||
virtual int scanString(const StreamFormat& fmt,
|
virtual ssize_t scanString(const StreamFormat& fmt,
|
||||||
const char* input, char* value, size_t maxlen);
|
const char* input, char* value, size_t& size);
|
||||||
virtual int scanPseudo(const StreamFormat& fmt,
|
virtual ssize_t scanPseudo(const StreamFormat& fmt,
|
||||||
StreamBuffer& inputLine, long& cursor);
|
StreamBuffer& inputLine, size_t& cursor);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline StreamFormatConverter* StreamFormatConverter::
|
inline StreamFormatConverter* StreamFormatConverter::
|
||||||
@ -130,8 +130,8 @@ void* ref_##converter = ®istrar_##converter\
|
|||||||
* You only need to implement the flavour of print and/or scan suitable for
|
* You only need to implement the flavour of print and/or scan suitable for
|
||||||
* the datatype returned by parse().
|
* the datatype returned by parse().
|
||||||
*
|
*
|
||||||
* Now, fmt.type contains the value returned by parse(). With fmt.info()
|
* Now, fmt.type contains the value returned by parse(). With fmt.info() you
|
||||||
* you will get the string you have written to info in parse() (null terminated).
|
* will get the string you have written to info in parse() (null terminated).
|
||||||
* The length of the info string can be found in fmt.infolen.
|
* The length of the info string can be found in fmt.infolen.
|
||||||
*
|
*
|
||||||
* In print*(), append the converted value to output. Do not modify what is
|
* In print*(), append the converted value to output. Do not modify what is
|
||||||
@ -139,9 +139,14 @@ void* ref_##converter = ®istrar_##converter\
|
|||||||
* Return true on success, false on failure.
|
* Return true on success, false on failure.
|
||||||
*
|
*
|
||||||
* In scan*(), read the value from input and return the number of consumed
|
* In scan*(), read the value from input and return the number of consumed
|
||||||
* bytes. In the string version, don't write more bytes than maxlen! If the
|
* bytes.
|
||||||
* skip_flag is set, you don't need to write to value, since the value will be
|
* In the string version, don't write more bytes than size including a
|
||||||
* discarded anyway. Return -1 on failure.
|
* mandatory terminating null byte. Update size with the number of bytes
|
||||||
|
* written into the value, wich may differ from the number of bytes consumed
|
||||||
|
* from the input (e.g. due to leading space). If the skip_flag is set, the
|
||||||
|
* input will be discarded. Thus, don't write to value. You also don't need
|
||||||
|
* to update size.
|
||||||
|
* Return -1 on failure.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Register your class
|
* Register your class
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the protocol parser of StreamDevice. *
|
* This is the protocol parser of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -281,20 +281,27 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
|||||||
// end of protocol or handler definition
|
// end of protocol or handler definition
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
error(line, filename(), "Stray '}' in global context\n");
|
error(line, filename(), "Unexpected '}' (no matching '{') in global context\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (strchr("{=", token[0]))
|
if (token[0] == '{')
|
||||||
{
|
{
|
||||||
error(line, filename(), "Expect name before '%c'\n", token[0]);
|
error(line, filename(), "Expect %s name before '%c'\n",
|
||||||
|
isGlobalContext(commands) ? "protocol" : "handler",
|
||||||
|
token[0]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (token[0] == '=')
|
||||||
|
{
|
||||||
|
error(line, filename(), "Expect variable name before '%c'\n", token[0]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (token[0] != '@' && !isalpha(token[0]))
|
||||||
|
{
|
||||||
|
error(line, filename(), "Unexpected '%s'\n", token());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
do op = readChar(); while (op == ' '); // what comes after token?
|
do op = readChar(); while (op == ' '); // what comes after token?
|
||||||
if (op == EOF)
|
|
||||||
{
|
|
||||||
error(line, filename(), "Unexpected end of file after: %s\n", token());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (op == '=')
|
if (op == '=')
|
||||||
{
|
{
|
||||||
// variable assignment
|
// variable assignment
|
||||||
@ -367,16 +374,20 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
|||||||
*ppP = pP;
|
*ppP = pP;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (token[0] == '@')
|
||||||
|
{
|
||||||
|
error(line, filename(), "Expect '{' after handler '%s'\n", token());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Must be a command or a protocol reference.
|
// Must be a command or a protocol reference.
|
||||||
if (isGlobalContext(commands))
|
if (isGlobalContext(commands))
|
||||||
{
|
{
|
||||||
error(line, filename(), "Expect '=' or '{' instead of '%c' after '%s'\n",
|
error(line, filename(), "Expect '=' or '{' instead after '%s'\n",
|
||||||
op, token());
|
token());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (op == ';' || op == '}') // no arguments
|
if (op == ';' || op == '}') // no arguments
|
||||||
{
|
{
|
||||||
if (op == '}') ungetc(op, file);
|
|
||||||
// Check for protocol reference
|
// Check for protocol reference
|
||||||
Protocol* p;
|
Protocol* p;
|
||||||
for (p = protocols; p; p = p->next)
|
for (p = protocols; p; p = p->next)
|
||||||
@ -384,14 +395,16 @@ parseProtocol(Protocol& protocol, StreamBuffer* commands)
|
|||||||
if (p->protocolname.startswith(token()))
|
if (p->protocolname.startswith(token()))
|
||||||
{
|
{
|
||||||
commands->append(*p->commands);
|
commands->append(*p->commands);
|
||||||
|
if (op == '}') ungetc(op, file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p) continue;
|
if (p) continue;
|
||||||
|
// Fall through for commands without arguments
|
||||||
}
|
}
|
||||||
// must be a command (validity will be checked later)
|
// must be a command (validity will be checked later)
|
||||||
commands->append(token); // is null separated
|
commands->append(token); // is null separated
|
||||||
ungetc(op, file); // put back first char of value
|
ungetc(op, file); // put back first char after command
|
||||||
if (parseValue(*commands, true) == false)
|
if (parseValue(*commands, true) == false)
|
||||||
{
|
{
|
||||||
line = startline;
|
line = startline;
|
||||||
@ -446,7 +459,7 @@ terminated and the line number is stored for later use.
|
|||||||
Each time newline is read, line is incremented.
|
Each time newline is read, line is incremented.
|
||||||
*/
|
*/
|
||||||
if (!specialchars) specialchars = specialChars;
|
if (!specialchars) specialchars = specialChars;
|
||||||
long token = buffer.length();
|
size_t token = buffer.length();
|
||||||
int l = line;
|
int l = line;
|
||||||
|
|
||||||
int c = readChar();
|
int c = readChar();
|
||||||
@ -484,7 +497,7 @@ Each time newline is read, line is incremented.
|
|||||||
}
|
}
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
{
|
{
|
||||||
error(line, filename(), "Unexpected end of file after '$'\n");
|
error(line, filename(), "Unexpected end of file after '$' (looking for '}')\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (strchr (specialchars, c))
|
if (strchr (specialchars, c))
|
||||||
@ -512,20 +525,31 @@ Each time newline is read, line is incremented.
|
|||||||
buffer(token));
|
buffer(token));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (c == '$' && buffer[-1] == '\\')
|
|
||||||
{
|
|
||||||
// quoted variable reference
|
|
||||||
// terminate string here and do variable in next pass
|
|
||||||
buffer[-1] = quote;
|
|
||||||
ungetc(c, file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buffer.append(c);
|
buffer.append(c);
|
||||||
if (c == quote && buffer[-2] != '\\')
|
if (c == quote)
|
||||||
{
|
{
|
||||||
quote = false;
|
quote = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
c = getc(file);
|
||||||
|
if (c == '$')
|
||||||
|
{
|
||||||
|
// quoted variable reference
|
||||||
|
// terminate string here and do variable in next pass
|
||||||
|
buffer[-1] = quote;
|
||||||
|
ungetc(c, file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == EOF || c == '\n')
|
||||||
|
{
|
||||||
|
error(line, filename(), "Backslash at end of line: %s\n",
|
||||||
|
buffer(token));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
buffer.append(c);
|
||||||
|
}
|
||||||
c = getc(file);
|
c = getc(file);
|
||||||
}
|
}
|
||||||
buffer.append('\0').append(&l, sizeof(l)); // append line number
|
buffer.append('\0').append(&l, sizeof(l)); // append line number
|
||||||
@ -536,7 +560,7 @@ Each time newline is read, line is incremented.
|
|||||||
// end of file
|
// end of file
|
||||||
if (!eofAllowed)
|
if (!eofAllowed)
|
||||||
{
|
{
|
||||||
error(line, filename(), "Unexpected end of file\n");
|
error(line, filename(), "Unexpected end of file (looking for '}')\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
buffer.append('\0');
|
buffer.append('\0');
|
||||||
@ -580,7 +604,7 @@ parseAssignment(const char* name, Protocol& protocol)
|
|||||||
bool StreamProtocolParser::
|
bool StreamProtocolParser::
|
||||||
parseValue(StreamBuffer& buffer, bool lazy)
|
parseValue(StreamBuffer& buffer, bool lazy)
|
||||||
{
|
{
|
||||||
long token;
|
size_t token;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
do c = readChar(); while (c == ' '); // skip leading spaces
|
do c = readChar(); while (c == ' '); // skip leading spaces
|
||||||
@ -594,7 +618,7 @@ parseValue(StreamBuffer& buffer, bool lazy)
|
|||||||
c = buffer[token];
|
c = buffer[token];
|
||||||
if (c == '$') // a variable
|
if (c == '$') // a variable
|
||||||
{
|
{
|
||||||
long varname = token+1;
|
size_t varname = token+1;
|
||||||
if (buffer[varname] == '"') varname++; // quoted variable
|
if (buffer[varname] == '"') varname++; // quoted variable
|
||||||
if (lazy || (buffer[varname] >= '0' && buffer[varname] <= '9'))
|
if (lazy || (buffer[varname] >= '0' && buffer[varname] <= '9'))
|
||||||
{
|
{
|
||||||
@ -656,11 +680,15 @@ printString(StreamBuffer& buffer, const char* s)
|
|||||||
buffer.append("\\\\");
|
buffer.append("\\\\");
|
||||||
break;
|
break;
|
||||||
case format_field:
|
case format_field:
|
||||||
|
// <format_field> field <eos> addrLength AddressStructure formatstr <eos> StreamFormat [info <eos>]
|
||||||
|
unsigned short fieldSize;
|
||||||
buffer.print("%%(%s)", ++s);
|
buffer.print("%%(%s)", ++s);
|
||||||
while (*s++);
|
while (*s++);
|
||||||
s += extract<unsigned short>(s); // skip fieldaddress
|
fieldSize = extract<unsigned short>(s);
|
||||||
|
s += fieldSize; // skip fieldAddress
|
||||||
goto format;
|
goto format;
|
||||||
case format:
|
case format:
|
||||||
|
// <format> formatstr <eos> StreamFormat [info <eos>]
|
||||||
buffer.append('%');
|
buffer.append('%');
|
||||||
s++;
|
s++;
|
||||||
format: {
|
format: {
|
||||||
@ -866,12 +894,12 @@ getEnumVariable(const char* varname, unsigned short& value, const char** enumstr
|
|||||||
bool StreamProtocolParser::Protocol::
|
bool StreamProtocolParser::Protocol::
|
||||||
getStringVariable(const char* varname, StreamBuffer& value, bool* defined)
|
getStringVariable(const char* varname, StreamBuffer& value, bool* defined)
|
||||||
{
|
{
|
||||||
|
value.clear();
|
||||||
const Variable* pvar = getVariable(varname);
|
const Variable* pvar = getVariable(varname);
|
||||||
if (!pvar) return true;
|
if (!pvar) return true;
|
||||||
if (defined) *defined = true;
|
if (defined) *defined = true;
|
||||||
const StreamBuffer* pvalue = &pvar->value;
|
const StreamBuffer* pvalue = &pvar->value;
|
||||||
const char* source = (*pvalue)();
|
const char* source = (*pvalue)();
|
||||||
value.clear();
|
|
||||||
if (!compileString(value, source))
|
if (!compileString(value, source))
|
||||||
{
|
{
|
||||||
error("in string variable '%s' in protocol file '%s' line %d\n",
|
error("in string variable '%s' in protocol file '%s' line %d\n",
|
||||||
@ -891,12 +919,12 @@ getStringVariable(const char* varname, StreamBuffer& value, bool* defined)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StreamProtocolParser::Protocol::
|
bool StreamProtocolParser::Protocol::
|
||||||
getCommands(const char* handlername,StreamBuffer& code, Client* client)
|
getCommands(const char* handlername, StreamBuffer& code, Client* client)
|
||||||
{
|
{
|
||||||
|
code.clear();
|
||||||
const Variable* pvar = getVariable(handlername);
|
const Variable* pvar = getVariable(handlername);
|
||||||
if (!pvar) return true;
|
if (!pvar) return true;
|
||||||
if (!pvar->value) return true;
|
if (!pvar->value) return true;
|
||||||
code.clear();
|
|
||||||
const char* source = pvar->value();
|
const char* source = pvar->value();
|
||||||
debug("StreamProtocolParser::Protocol::getCommands"
|
debug("StreamProtocolParser::Protocol::getCommands"
|
||||||
"(handlername=\"%s\", client=\"%s\"): source=%s\n",
|
"(handlername=\"%s\", client=\"%s\"): source=%s\n",
|
||||||
@ -974,7 +1002,7 @@ replaceVariable(StreamBuffer& buffer, const char* varname)
|
|||||||
}
|
}
|
||||||
// quoted
|
// quoted
|
||||||
buffer.append('"');
|
buffer.append('"');
|
||||||
long i;
|
size_t i;
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
for (i = 0; i < v->value.length(); i++)
|
for (i = 0; i < v->value.length(); i++)
|
||||||
{
|
{
|
||||||
@ -1019,7 +1047,7 @@ compileNumber(unsigned long& number, const char*& source, unsigned long max)
|
|||||||
{
|
{
|
||||||
buffer.append(source);
|
buffer.append(source);
|
||||||
}
|
}
|
||||||
source += strlen(source)+1+sizeof(int); // skip eos + line
|
source += strlen(source) + 1 + sizeof(int); // skip eos + line
|
||||||
};
|
};
|
||||||
n = strtoul(buffer(), &end, 0);
|
n = strtoul(buffer(), &end, 0);
|
||||||
if (end == buffer())
|
if (end == buffer())
|
||||||
@ -1057,17 +1085,17 @@ compileNumber(unsigned long& number, const char*& source, unsigned long max)
|
|||||||
|
|
||||||
bool StreamProtocolParser::Protocol::
|
bool StreamProtocolParser::Protocol::
|
||||||
compileString(StreamBuffer& buffer, const char*& source,
|
compileString(StreamBuffer& buffer, const char*& source,
|
||||||
FormatType formatType, Client* client, int quoted)
|
FormatType formatType, Client* client, int quoted, int recursionDepth)
|
||||||
{
|
{
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
int newline = 0;
|
int newline = 0;
|
||||||
StreamBuffer formatbuffer;
|
StreamBuffer formatbuffer;
|
||||||
int formatpos = buffer.length();
|
size_t formatpos = buffer.length();
|
||||||
line = getLineNumber(source);
|
line = getLineNumber(source);
|
||||||
|
|
||||||
debug("StreamProtocolParser::Protocol::compileString "
|
debug("StreamProtocolParser::Protocol::compileString "
|
||||||
"line %d source=\"%s\"\n",
|
"line %d source=\"%s\" formatType=%s quoted=%i recursionDepth=%d\n",
|
||||||
line, source);
|
line, source, ::toStr(formatType), quoted, recursionDepth);
|
||||||
|
|
||||||
// coding is done in two steps:
|
// coding is done in two steps:
|
||||||
// 1) read a line from protocol source and code quoted strings,
|
// 1) read a line from protocol source and code quoted strings,
|
||||||
@ -1077,19 +1105,18 @@ compileString(StreamBuffer& buffer, const char*& source,
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
debug("StreamProtocolParser::Protocol::compileString "
|
|
||||||
"buffer so far: %s\n", buffer.expand()());
|
|
||||||
// this is step 2: replacing the formats
|
// this is step 2: replacing the formats
|
||||||
if (!*source || (newline = getLineNumber(source)) != line)
|
if (!*source || (newline = getLineNumber(source)) != line)
|
||||||
{
|
{
|
||||||
|
debug("StreamProtocolParser::Protocol::compileString line %i: %s\n", line, buffer.expand()());
|
||||||
// compile all formats in this line
|
// compile all formats in this line
|
||||||
// We do this here after all variables in this line
|
// We do this here after all variables in this line
|
||||||
// have been replaced and after string has been coded.
|
// have been replaced and after string has been coded.
|
||||||
if (formatType != NoFormat)
|
if (recursionDepth == 0 && formatType != NoFormat)
|
||||||
{
|
{
|
||||||
int nformats=0;
|
int nformats=0;
|
||||||
char c;
|
char c;
|
||||||
while ((c = buffer[formatpos]) != '\0')
|
while (formatpos < buffer.length() && (c = buffer[formatpos]) != '\0')
|
||||||
{
|
{
|
||||||
if (c == esc) {
|
if (c == esc) {
|
||||||
// ignore escaped %
|
// ignore escaped %
|
||||||
@ -1112,7 +1139,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
|||||||
formatbuffer());
|
formatbuffer());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int formatlen = p - buffer(formatpos);
|
size_t formatlen = p - buffer(formatpos);
|
||||||
buffer.replace(formatpos, formatlen, formatbuffer);
|
buffer.replace(formatpos, formatlen, formatbuffer);
|
||||||
debug("StreamProtocolParser::Protocol::compileString "
|
debug("StreamProtocolParser::Protocol::compileString "
|
||||||
"replaced by: \"%s\"\n", buffer.expand(formatpos)());
|
"replaced by: \"%s\"\n", buffer.expand(formatpos)());
|
||||||
@ -1247,10 +1274,10 @@ compileString(StreamBuffer& buffer, const char*& source,
|
|||||||
{
|
{
|
||||||
StreamBuffer value;
|
StreamBuffer value;
|
||||||
if (!replaceVariable(value, source)) return false;
|
if (!replaceVariable(value, source)) return false;
|
||||||
source += strlen(source)+1+sizeof(int);
|
source += strlen(source) + 1 + sizeof(int);
|
||||||
p = value();
|
p = value();
|
||||||
int saveline = line;
|
int saveline = line;
|
||||||
if (!compileString(buffer, p, formatType, client))
|
if (!compileString(buffer, p, formatType, client, false, recursionDepth + 1))
|
||||||
return false;
|
return false;
|
||||||
line = saveline;
|
line = saveline;
|
||||||
continue;
|
continue;
|
||||||
@ -1332,7 +1359,7 @@ compileString(StreamBuffer& buffer, const char*& source,
|
|||||||
{"gs", 0x1D},
|
{"gs", 0x1D},
|
||||||
{"rs", 0x1E},
|
{"rs", 0x1E},
|
||||||
{"us", 0x1F},
|
{"us", 0x1F},
|
||||||
{"del", 0x7f}
|
{"del", 0x7F}
|
||||||
};
|
};
|
||||||
size_t i;
|
size_t i;
|
||||||
c=-1;
|
c=-1;
|
||||||
@ -1348,19 +1375,20 @@ compileString(StreamBuffer& buffer, const char*& source,
|
|||||||
source);
|
source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (formatType != NoFormat)
|
if (formatType != NoFormat &&
|
||||||
|
i > 2 /* do not escape skip */)
|
||||||
{
|
{
|
||||||
buffer.append(esc);
|
buffer.append(esc);
|
||||||
}
|
}
|
||||||
buffer.append(c);
|
buffer.append(c);
|
||||||
source += strlen(source)+1+sizeof(int);
|
source += strlen(source) + 1 + sizeof(int);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c >= 0) continue;
|
if (c >= 0) continue;
|
||||||
// source may contain a function name
|
// source may contain a function name
|
||||||
error(line, filename(),
|
error(line, filename(),
|
||||||
"Unexpected word: \"%s\"\n", source);
|
"Unexpected '%s' in string\n", source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
debug("StreamProtocolParser::Protocol::compileString buffer=%s\n", buffer.expand()());
|
debug("StreamProtocolParser::Protocol::compileString buffer=%s\n", buffer.expand()());
|
||||||
@ -1388,7 +1416,7 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
|||||||
*/
|
*/
|
||||||
const char* source = formatstr;
|
const char* source = formatstr;
|
||||||
StreamFormat streamFormat;
|
StreamFormat streamFormat;
|
||||||
int fieldname = 0;
|
size_t fieldname = 0;
|
||||||
// look for fieldname
|
// look for fieldname
|
||||||
if (source[1] == '(')
|
if (source[1] == '(')
|
||||||
{
|
{
|
||||||
@ -1428,12 +1456,12 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
|||||||
buffer.append(format);
|
buffer.append(format);
|
||||||
}
|
}
|
||||||
const char* formatstart = source + 1;
|
const char* formatstart = source + 1;
|
||||||
|
|
||||||
// parse format and get info string
|
// parse format and get info string
|
||||||
StreamBuffer infoString;
|
StreamBuffer infoString;
|
||||||
int type = StreamFormatConverter::parseFormat(source,
|
int type = StreamFormatConverter::parseFormat(source,
|
||||||
formatType, streamFormat, infoString);
|
formatType, streamFormat, infoString);
|
||||||
|
|
||||||
if (!type)
|
if (!type)
|
||||||
{
|
{
|
||||||
// parsing failed
|
// parsing failed
|
||||||
@ -1470,17 +1498,15 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
|||||||
// add formatstr for debug purpose
|
// add formatstr for debug purpose
|
||||||
buffer.append(formatstart, source-formatstart).append(eos);
|
buffer.append(formatstart, source-formatstart).append(eos);
|
||||||
|
|
||||||
#ifndef NO_TEMPORARY
|
|
||||||
debug("StreamProtocolParser::Protocol::compileFormat: formatstring=\"%s\"\n",
|
debug("StreamProtocolParser::Protocol::compileFormat: formatstring=\"%s\"\n",
|
||||||
StreamBuffer(formatstart, source-formatstart).expand()());
|
StreamBuffer(formatstart, source-formatstart).expand()());
|
||||||
#endif
|
|
||||||
|
|
||||||
// add streamFormat structure and info
|
// add streamFormat structure and info
|
||||||
buffer.append(&streamFormat, sizeof(streamFormat));
|
buffer.append(&streamFormat, sizeof(streamFormat));
|
||||||
buffer.append(infoString);
|
buffer.append(infoString);
|
||||||
|
|
||||||
debug("StreamProtocolParser::Protocol::compileFormat: format.type=%s, "
|
debug("StreamProtocolParser::Protocol::compileFormat: format.type=%s, "
|
||||||
"infolen=%d infostring=\"%s\"\n",
|
"infolen=%ld infostring=\"%s\"\n",
|
||||||
StreamFormatTypeStr[streamFormat.type],
|
StreamFormatTypeStr[streamFormat.type],
|
||||||
streamFormat.infolen, infoString.expand()());
|
streamFormat.infolen, infoString.expand()());
|
||||||
formatstr = source; // move pointer after parsed format
|
formatstr = source; // move pointer after parsed format
|
||||||
@ -1496,7 +1522,7 @@ compileCommands(StreamBuffer& buffer, const char*& source, Client* client)
|
|||||||
while (*source)
|
while (*source)
|
||||||
{
|
{
|
||||||
command = source;
|
command = source;
|
||||||
args = source + strlen(source)+1+sizeof(int);
|
args = source + strlen(source) + 1 + sizeof(int);
|
||||||
if (!client->compileCommand(this, buffer, command, args))
|
if (!client->compileCommand(this, buffer, command, args))
|
||||||
{
|
{
|
||||||
error(getLineNumber(source), filename(),
|
error(getLineNumber(source), filename(),
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the protocol parser of StreamDevice. *
|
* This is the protocol parser of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -21,19 +21,19 @@
|
|||||||
#ifndef StreamProtocol_h
|
#ifndef StreamProtocol_h
|
||||||
#define StreamProtocol_h
|
#define StreamProtocol_h
|
||||||
|
|
||||||
#include "StreamBuffer.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "StreamBuffer.h"
|
||||||
|
#include "MacroMagic.h"
|
||||||
|
|
||||||
enum FormatType {NoFormat, ScanFormat, PrintFormat};
|
ENUM (FormatType,
|
||||||
|
NoFormat, ScanFormat, PrintFormat);
|
||||||
|
|
||||||
class StreamProtocolParser
|
class StreamProtocolParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Codes
|
ENUM (Codes,
|
||||||
{
|
eos, skip, whitespace, format, format_field, last_function_code);
|
||||||
eos = 0, skip, whitespace, format, format_field, last_function_code
|
|
||||||
};
|
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
@ -59,6 +59,8 @@ public:
|
|||||||
bool compileCommands(StreamBuffer&, const char*& source, Client*);
|
bool compileCommands(StreamBuffer&, const char*& source, Client*);
|
||||||
bool replaceVariable(StreamBuffer&, const char* varname);
|
bool replaceVariable(StreamBuffer&, const char* varname);
|
||||||
const Variable* getVariable(const char* name);
|
const Variable* getVariable(const char* name);
|
||||||
|
bool compileString(StreamBuffer& buffer, const char*& source,
|
||||||
|
FormatType formatType, Client*, int quoted, int recursionDepth);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -73,7 +75,9 @@ public:
|
|||||||
bool compileNumber(unsigned long& number, const char*& source,
|
bool compileNumber(unsigned long& number, const char*& source,
|
||||||
unsigned long max = 0xFFFFFFFF);
|
unsigned long max = 0xFFFFFFFF);
|
||||||
bool compileString(StreamBuffer& buffer, const char*& source,
|
bool compileString(StreamBuffer& buffer, const char*& source,
|
||||||
FormatType formatType = NoFormat, Client* = NULL, int quoted = false);
|
FormatType formatType = NoFormat, Client* client = NULL, int quoted = false) {
|
||||||
|
return compileString(buffer, source, formatType, client, quoted, 0);
|
||||||
|
}
|
||||||
bool checkUnused();
|
bool checkUnused();
|
||||||
~Protocol();
|
~Protocol();
|
||||||
void report();
|
void report();
|
||||||
@ -114,7 +118,7 @@ private:
|
|||||||
bool parseAssignment(const char* variable, Protocol&);
|
bool parseAssignment(const char* variable, Protocol&);
|
||||||
bool parseValue(StreamBuffer& buffer, bool lazy = false);
|
bool parseValue(StreamBuffer& buffer, bool lazy = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~StreamProtocolParser(); // get rid of cygnus-2.7.2 compiler warning
|
~StreamProtocolParser(); // get rid of cygnus-2.7.2 compiler warning
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This provides a version string for StreamDevice. *
|
* This provides a version string for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2010 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2010 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the time stamp converter of StreamDevice. *
|
* This is the time stamp converter of StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -29,10 +29,10 @@
|
|||||||
/* timezone in UNIX contains the seconds between UTC and local time,
|
/* timezone in UNIX contains the seconds between UTC and local time,
|
||||||
but not in Free-BSD! Here timezone() is a function delivering
|
but not in Free-BSD! Here timezone() is a function delivering
|
||||||
the time zone abbreviation (e.g. CET). Alternatively, the timezone
|
the time zone abbreviation (e.g. CET). Alternatively, the timezone
|
||||||
value can also be gained from tm_gmtoff of the tm-structure.
|
value can also be gained from tm_gmtoff of the tm-structure.
|
||||||
HJK, 4.4.14 */
|
HJK, 4.4.14 */
|
||||||
/* The same seems to be true for other BSDs. DZ. */
|
/* The same seems to be true for other BSDs. DZ. */
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || \
|
#if defined(__FreeBSD__) || \
|
||||||
defined(__NetBSD__) || \
|
defined(__NetBSD__) || \
|
||||||
defined(__OpenBSD__) || \
|
defined(__OpenBSD__) || \
|
||||||
@ -47,7 +47,7 @@ static int timezone_bsd=0;
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define tzset() _tzset()
|
#define tzset() _tzset()
|
||||||
#define timezone _timezone
|
#define timezone _timezone
|
||||||
#define localtime_r(timet,tm) localtime_s(tm,timet) /* Windows sucks */
|
#define localtime_r(timet,tm) localtime_s(tm,timet)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __rtems__
|
#ifdef __rtems__
|
||||||
@ -75,7 +75,7 @@ class TimestampConverter : public StreamFormatConverter
|
|||||||
{
|
{
|
||||||
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||||
int scanDouble(const StreamFormat&, const char*, double&);
|
ssize_t scanDouble(const StreamFormat&, const char*, double&);
|
||||||
};
|
};
|
||||||
|
|
||||||
int TimestampConverter::
|
int TimestampConverter::
|
||||||
@ -151,10 +151,11 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
|||||||
struct tm brokenDownTime;
|
struct tm brokenDownTime;
|
||||||
char buffer [40];
|
char buffer [40];
|
||||||
char fracbuffer [15];
|
char fracbuffer [15];
|
||||||
int length;
|
size_t length;
|
||||||
time_t sec;
|
time_t sec;
|
||||||
double frac;
|
double frac;
|
||||||
int i, n;
|
ssize_t i;
|
||||||
|
size_t n;
|
||||||
char* c;
|
char* c;
|
||||||
char* p;
|
char* p;
|
||||||
|
|
||||||
@ -172,7 +173,7 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
|||||||
n = strtol(output(i+1), &c, 10);
|
n = strtol(output(i+1), &c, 10);
|
||||||
if (*c++ != 'f') return false;
|
if (*c++ != 'f') return false;
|
||||||
/* print fractional part */
|
/* print fractional part */
|
||||||
sprintf(fracbuffer, "%.*f", n, frac);
|
sprintf(fracbuffer, "%.*f", (int)n, frac);
|
||||||
p = strchr(fracbuffer, '.')+1;
|
p = strchr(fracbuffer, '.')+1;
|
||||||
output.replace(i, c-output(i), p);
|
output.replace(i, c-output(i), p);
|
||||||
}
|
}
|
||||||
@ -183,10 +184,10 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
|||||||
all fields, e.g. %z.
|
all fields, e.g. %z.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int strmatch(const char*& input, const char** strings, int minlen)
|
static int strmatch(const char*& input, const char** strings, size_t minlen)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int c;
|
size_t c;
|
||||||
|
|
||||||
for (i=0; strings[i]; i++) {
|
for (i=0; strings[i]; i++) {
|
||||||
for (c=0; ; c++)
|
for (c=0; ; c++)
|
||||||
@ -516,9 +517,7 @@ startover:
|
|||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t TimestampConverter::
|
||||||
|
|
||||||
int TimestampConverter::
|
|
||||||
scanDouble(const StreamFormat& format, const char* input, double& value)
|
scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||||
{
|
{
|
||||||
struct tm brokenDownTime;
|
struct tm brokenDownTime;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is the header for the EPICS interface to StreamDevice. *
|
* This is the header for the EPICS interface to StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -21,14 +21,19 @@
|
|||||||
#ifndef devStream_h
|
#ifndef devStream_h
|
||||||
#define devStream_h
|
#define devStream_h
|
||||||
|
|
||||||
#define STREAM_MAJOR 2
|
#include <stdio.h>
|
||||||
#define STREAM_MINOR 7
|
#include <stdlib.h>
|
||||||
#define STREAM_PATCHLEVEL 8
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#if defined(__vxworks) || defined(vxWorks)
|
#if defined(__cplusplus)
|
||||||
#include <vxWorks.h>
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define STREAM_MAJOR 2
|
||||||
|
#define STREAM_MINOR 8
|
||||||
|
#define STREAM_PATCHLEVEL 0
|
||||||
|
|
||||||
#ifndef OK
|
#ifndef OK
|
||||||
#define OK 0
|
#define OK 0
|
||||||
#endif
|
#endif
|
||||||
@ -40,83 +45,69 @@
|
|||||||
#define DO_NOT_CONVERT 2
|
#define DO_NOT_CONVERT 2
|
||||||
#define INIT_RUN (!interruptAccept)
|
#define INIT_RUN (!interruptAccept)
|
||||||
|
|
||||||
#include <epicsVersion.h>
|
#include "epicsVersion.h"
|
||||||
#ifdef BASE_VERSION
|
#ifdef BASE_VERSION
|
||||||
#define EPICS_3_13
|
#define EPICS_3_13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__cplusplus) && defined(EPICS_3_13)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef epicsExportSharedSymbols
|
#ifdef epicsExportSharedSymbols
|
||||||
# define devStream_epicsExportSharedSymbols
|
# define devStream_epicsExportSharedSymbols
|
||||||
# undef epicsExportSharedSymbols
|
# undef epicsExportSharedSymbols
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "dbCommon.h"
|
||||||
#include <dbCommon.h>
|
#include "dbScan.h"
|
||||||
#include <dbScan.h>
|
#include "devSup.h"
|
||||||
#include <devSup.h>
|
#include "dbAccess.h"
|
||||||
/* #include <dbFldTypes.h> */
|
#include "errlog.h"
|
||||||
#include <dbAccess.h>
|
#include "alarm.h"
|
||||||
|
#include "recGbl.h"
|
||||||
|
#include "dbEvent.h"
|
||||||
|
#include "epicsMath.h"
|
||||||
|
|
||||||
#ifdef devStream_epicsExportSharedSymbols
|
#ifdef devStream_epicsExportSharedSymbols
|
||||||
# define epicsExportSharedSymbols
|
# define epicsExportSharedSymbols
|
||||||
# include "shareLib.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__cplusplus) && defined(EPICS_3_13)
|
#if defined(_WIN32)
|
||||||
}
|
typedef ptrdiff_t ssize_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef const struct format_s {
|
typedef const struct format_s {
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
const struct StreamFormat* priv;
|
const struct StreamFormat* priv;
|
||||||
} format_t;
|
} format_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
epicsShareExtern FILE* StreamDebugFile;
|
epicsShareExtern FILE* StreamDebugFile;
|
||||||
|
|
||||||
extern const char StreamVersion [];
|
extern const char StreamVersion [];
|
||||||
|
|
||||||
typedef long (*streamIoFunction) (dbCommon*, format_t*);
|
typedef long (*streamIoFunction) (dbCommon*, format_t*);
|
||||||
|
|
||||||
epicsShareFunc long streamInit(int after);
|
long streamInit(int after);
|
||||||
epicsShareFunc long streamInitRecord(dbCommon *record,
|
long streamInitRecord(dbCommon *record,
|
||||||
const struct link *ioLink,
|
const struct link *ioLink,
|
||||||
streamIoFunction readData, streamIoFunction writeData);
|
streamIoFunction readData, streamIoFunction writeData);
|
||||||
epicsShareFunc long streamReport(int interest);
|
long streamReport(int interest);
|
||||||
epicsShareFunc long streamReadWrite(dbCommon *record);
|
long streamReadWrite(dbCommon *record);
|
||||||
epicsShareFunc long streamGetIointInfo(int cmd,
|
long streamGetIointInfo(int cmd,
|
||||||
dbCommon *record, IOSCANPVT *ppvt);
|
dbCommon *record, IOSCANPVT *ppvt);
|
||||||
epicsShareFunc long streamPrintf(dbCommon *record, format_t *format, ...);
|
long streamPrintf(dbCommon *record, format_t *format, ...);
|
||||||
epicsShareFunc long streamScanfN(dbCommon *record, format_t *format,
|
ssize_t streamScanfN(dbCommon *record, format_t *format,
|
||||||
void*, size_t maxStringSize);
|
void*, size_t maxStringSize);
|
||||||
|
|
||||||
/* backward compatibility stuff */
|
/* backward compatibility stuff */
|
||||||
#define devStreamIoFunction streamIoFunction
|
|
||||||
#define devStreamInit streamInit
|
|
||||||
#define devStreamInitRecord streamInitRecord
|
|
||||||
#define devStreamReport streamReport
|
|
||||||
#define devStreamRead streamReadWrite
|
|
||||||
#define devStreamWrite streamReadWrite
|
|
||||||
#define devStreamGetIointInfo streamGetIointInfo
|
|
||||||
#define devStreamPrintf streamPrintf
|
|
||||||
#define devStreamPrintSep(record) (0)
|
|
||||||
#define devStreamScanSep (0)
|
|
||||||
#define devStreamScanf(record, format, value) \
|
|
||||||
streamScanfN(record, format, value, MAX_STRING_SIZE)
|
|
||||||
#define streamScanf(record, format, value) \
|
#define streamScanf(record, format, value) \
|
||||||
streamScanfN(record, format, value, MAX_STRING_SIZE)
|
streamScanfN(record, format, value, MAX_STRING_SIZE)
|
||||||
#define streamRead streamReadWrite
|
#define streamRead streamReadWrite
|
||||||
#define streamWrite streamReadWrite
|
#define streamWrite streamReadWrite
|
||||||
#define streamReport NULL
|
#define streamReport NULL
|
||||||
|
|
||||||
|
#ifdef EPICS_3_13
|
||||||
|
#define epicsExportAddress(a,b) extern int dummy
|
||||||
|
#else
|
||||||
|
#include "epicsExport.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is an EPICS record Interface for StreamDevice. *
|
* This is an EPICS record Interface for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -18,16 +18,12 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
#include <string.h>
|
#include "aaiRecord.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errlog.h>
|
|
||||||
#include <aaiRecord.h>
|
|
||||||
#include "devStream.h"
|
#include "devStream.h"
|
||||||
#include <epicsExport.h>
|
|
||||||
|
|
||||||
static long readData (dbCommon *record, format_t *format)
|
static long readData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
aaiRecord *aai = (aaiRecord *) record;
|
aaiRecord *aai = (aaiRecord *)record;
|
||||||
double dval;
|
double dval;
|
||||||
long lval;
|
long lval;
|
||||||
|
|
||||||
@ -37,7 +33,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
{
|
{
|
||||||
if (streamScanf (record, format, &dval) != OK)
|
if (streamScanf(record, format, &dval) == ERROR)
|
||||||
{
|
{
|
||||||
return aai->nord ? OK : ERROR;
|
return aai->nord ? OK : ERROR;
|
||||||
}
|
}
|
||||||
@ -50,7 +46,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
((epicsFloat32 *)aai->bptr)[aai->nord] = (epicsFloat32)dval;
|
((epicsFloat32 *)aai->bptr)[aai->nord] = (epicsFloat32)dval;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"readData %s: can't convert from double to %s\n",
|
"readData %s: can't convert from double to %s\n",
|
||||||
record->name, pamapdbfType[aai->ftvl].strvalue);
|
record->name, pamapdbfType[aai->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -61,7 +57,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
case DBF_ENUM:
|
case DBF_ENUM:
|
||||||
{
|
{
|
||||||
if (streamScanf (record, format, &lval) != OK)
|
if (streamScanf(record, format, &lval) == ERROR)
|
||||||
{
|
{
|
||||||
return aai->nord ? OK : ERROR;
|
return aai->nord ? OK : ERROR;
|
||||||
}
|
}
|
||||||
@ -73,6 +69,12 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
((epicsFloat32 *)aai->bptr)[aai->nord] = (epicsFloat32)lval;
|
((epicsFloat32 *)aai->bptr)[aai->nord] = (epicsFloat32)lval;
|
||||||
break;
|
break;
|
||||||
|
#ifdef DBF_INT64
|
||||||
|
case DBF_INT64:
|
||||||
|
case DBF_UINT64:
|
||||||
|
((epicsInt64 *)aai->bptr)[aai->nord] = (epicsInt64)lval;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
((epicsInt32 *)aai->bptr)[aai->nord] = (epicsInt32)lval;
|
((epicsInt32 *)aai->bptr)[aai->nord] = (epicsInt32)lval;
|
||||||
@ -87,7 +89,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
((epicsInt8 *)aai->bptr)[aai->nord] = (epicsInt8)lval;
|
((epicsInt8 *)aai->bptr)[aai->nord] = (epicsInt8)lval;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"readData %s: can't convert from long to %s\n",
|
"readData %s: can't convert from long to %s\n",
|
||||||
record->name, pamapdbfType[aai->ftvl].strvalue);
|
record->name, pamapdbfType[aai->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -99,30 +101,32 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
switch (aai->ftvl)
|
switch (aai->ftvl)
|
||||||
{
|
{
|
||||||
case DBF_STRING:
|
case DBF_STRING:
|
||||||
if (streamScanfN (record, format,
|
if (streamScanfN(record, format,
|
||||||
(char *)aai->bptr + aai->nord * MAX_STRING_SIZE,
|
(char *)aai->bptr + aai->nord * MAX_STRING_SIZE,
|
||||||
MAX_STRING_SIZE) != OK)
|
MAX_STRING_SIZE) == ERROR)
|
||||||
{
|
{
|
||||||
return aai->nord ? OK : ERROR;
|
return aai->nord ? OK : ERROR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DBF_CHAR:
|
case DBF_CHAR:
|
||||||
case DBF_UCHAR:
|
case DBF_UCHAR:
|
||||||
memset (aai->bptr, 0, aai->nelm);
|
{
|
||||||
|
ssize_t length;
|
||||||
aai->nord = 0;
|
aai->nord = 0;
|
||||||
if (streamScanfN (record, format,
|
if ((length = streamScanfN(record, format,
|
||||||
(char *)aai->bptr, aai->nelm) != OK)
|
(char *)aai->bptr, aai->nelm)) == ERROR)
|
||||||
{
|
{
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
((char*)aai->bptr)[aai->nelm] = 0;
|
if (length < (ssize_t)aai->nelm)
|
||||||
for (lval = aai->nelm;
|
{
|
||||||
lval >= 0 && ((char*)aai->bptr)[lval] == 0;
|
((char*)aai->bptr)[length] = 0;
|
||||||
lval--);
|
}
|
||||||
aai->nord = lval+1;
|
aai->nord = (long)length;
|
||||||
return OK;
|
return OK;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"readData %s: can't convert from string to %s\n",
|
"readData %s: can't convert from string to %s\n",
|
||||||
record->name, pamapdbfType[aai->ftvl].strvalue);
|
record->name, pamapdbfType[aai->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -131,7 +135,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
errlogSevPrintf (errlogMajor,
|
errlogSevPrintf(errlogMajor,
|
||||||
"readData %s: can't convert from %s to %s\n",
|
"readData %s: can't convert from %s to %s\n",
|
||||||
record->name, pamapdbfType[format->type].strvalue,
|
record->name, pamapdbfType[format->type].strvalue,
|
||||||
pamapdbfType[aai->ftvl].strvalue);
|
pamapdbfType[aai->ftvl].strvalue);
|
||||||
@ -142,9 +146,9 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long writeData (dbCommon *record, format_t *format)
|
static long writeData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
aaiRecord *aai = (aaiRecord *) record;
|
aaiRecord *aai = (aaiRecord *)record;
|
||||||
double dval;
|
double dval;
|
||||||
long lval;
|
long lval;
|
||||||
unsigned long nowd;
|
unsigned long nowd;
|
||||||
@ -163,6 +167,14 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
dval = ((epicsFloat32 *)aai->bptr)[nowd];
|
dval = ((epicsFloat32 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
|
#ifdef DBF_INT64
|
||||||
|
case DBF_INT64:
|
||||||
|
dval = ((epicsInt64 *)aai->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
case DBF_UINT64:
|
||||||
|
dval = ((epicsUInt64 *)aai->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
dval = ((epicsInt32 *)aai->bptr)[nowd];
|
dval = ((epicsInt32 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
@ -170,10 +182,10 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
dval = ((epicsUInt32 *)aai->bptr)[nowd];
|
dval = ((epicsUInt32 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_SHORT:
|
case DBF_SHORT:
|
||||||
|
case DBF_ENUM:
|
||||||
dval = ((epicsInt16 *)aai->bptr)[nowd];
|
dval = ((epicsInt16 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_USHORT:
|
case DBF_USHORT:
|
||||||
case DBF_ENUM:
|
|
||||||
dval = ((epicsUInt16 *)aai->bptr)[nowd];
|
dval = ((epicsUInt16 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_CHAR:
|
case DBF_CHAR:
|
||||||
@ -183,12 +195,12 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
dval = ((epicsUInt8 *)aai->bptr)[nowd];
|
dval = ((epicsUInt8 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to double\n",
|
"writeData %s: can't convert from %s to double\n",
|
||||||
record->name, pamapdbfType[aai->ftvl].strvalue);
|
record->name, pamapdbfType[aai->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (streamPrintf (record, format, dval))
|
if (streamPrintf(record, format, dval))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -198,6 +210,14 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
switch (aai->ftvl)
|
switch (aai->ftvl)
|
||||||
{
|
{
|
||||||
|
#ifdef DBF_INT64
|
||||||
|
case DBF_INT64:
|
||||||
|
lval = ((epicsInt64 *)aao->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
case DBF_UINT64:
|
||||||
|
lval = ((epicsUInt64 *)aao->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
lval = ((epicsInt32 *)aai->bptr)[nowd];
|
lval = ((epicsInt32 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
@ -205,10 +225,10 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
lval = ((epicsUInt32 *)aai->bptr)[nowd];
|
lval = ((epicsUInt32 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_SHORT:
|
case DBF_SHORT:
|
||||||
|
case DBF_ENUM:
|
||||||
lval = ((epicsInt16 *)aai->bptr)[nowd];
|
lval = ((epicsInt16 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_USHORT:
|
case DBF_USHORT:
|
||||||
case DBF_ENUM:
|
|
||||||
lval = ((epicsUInt16 *)aai->bptr)[nowd];
|
lval = ((epicsUInt16 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_CHAR:
|
case DBF_CHAR:
|
||||||
@ -218,12 +238,12 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
lval = ((epicsUInt8 *)aai->bptr)[nowd];
|
lval = ((epicsUInt8 *)aai->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to long\n",
|
"writeData %s: can't convert from %s to long\n",
|
||||||
record->name, pamapdbfType[aai->ftvl].strvalue);
|
record->name, pamapdbfType[aai->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (streamPrintf (record, format, lval))
|
if (streamPrintf(record, format, lval))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -232,7 +252,7 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
switch (aai->ftvl)
|
switch (aai->ftvl)
|
||||||
{
|
{
|
||||||
case DBF_STRING:
|
case DBF_STRING:
|
||||||
if (streamPrintf (record, format,
|
if (streamPrintf(record, format,
|
||||||
((char *)aai->bptr) + nowd * MAX_STRING_SIZE))
|
((char *)aai->bptr) + nowd * MAX_STRING_SIZE))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
break;
|
break;
|
||||||
@ -247,12 +267,12 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
((char *)aai->bptr)[aai->nelm-1] = 0;
|
((char *)aai->bptr)[aai->nelm-1] = 0;
|
||||||
}
|
}
|
||||||
if (streamPrintf (record, format,
|
if (streamPrintf(record, format,
|
||||||
((char *)aai->bptr)))
|
((char *)aai->bptr)))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
return OK;
|
return OK;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to string\n",
|
"writeData %s: can't convert from %s to string\n",
|
||||||
record->name, pamapdbfType[aai->ftvl].strvalue);
|
record->name, pamapdbfType[aai->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -261,7 +281,7 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to %s\n",
|
"writeData %s: can't convert from %s to %s\n",
|
||||||
record->name, pamapdbfType[aai->ftvl].strvalue,
|
record->name, pamapdbfType[aai->ftvl].strvalue,
|
||||||
pamapdbfType[format->type].strvalue);
|
pamapdbfType[format->type].strvalue);
|
||||||
@ -272,20 +292,19 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long initRecord (dbCommon *record)
|
static long initRecord(dbCommon *record)
|
||||||
{
|
{
|
||||||
static const int typesize[] = {MAX_STRING_SIZE,1,1,2,2,4,4,4,8,2};
|
aaiRecord *aai = (aaiRecord *)record;
|
||||||
aaiRecord *aai = (aaiRecord *) record;
|
|
||||||
|
|
||||||
aai->bptr = calloc(aai->nelm, typesize[aai->ftvl]);
|
aai->bptr = calloc(aai->nelm, dbValueSize(aai->ftvl));
|
||||||
if (aai->bptr == NULL)
|
if (aai->bptr == NULL)
|
||||||
{
|
{
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"initRecord %s: can't allocate memory for data array\n",
|
"initRecord %s: can't allocate memory for data array\n",
|
||||||
record->name);
|
record->name);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
return streamInitRecord (record, &aai->inp, readData, writeData) == ERROR ?
|
return streamInitRecord(record, &aai->inp, readData, writeData) == ERROR ?
|
||||||
ERROR : OK;
|
ERROR : OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2006 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is an EPICS record Interface for StreamDevice. *
|
* This is an EPICS record Interface for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -18,18 +18,17 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include "epicsString.h"
|
||||||
#include <errlog.h>
|
#include "aaoRecord.h"
|
||||||
#include <aaoRecord.h>
|
|
||||||
#include "devStream.h"
|
#include "devStream.h"
|
||||||
#include <epicsExport.h>
|
|
||||||
|
|
||||||
static long readData (dbCommon *record, format_t *format)
|
static long readData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
aaoRecord *aao = (aaoRecord *) record;
|
aaoRecord *aao = (aaoRecord *)record;
|
||||||
double dval;
|
double dval;
|
||||||
long lval;
|
long lval;
|
||||||
|
unsigned short monitor_mask;
|
||||||
|
|
||||||
for (aao->nord = 0; aao->nord < aao->nelm; aao->nord++)
|
for (aao->nord = 0; aao->nord < aao->nelm; aao->nord++)
|
||||||
{
|
{
|
||||||
@ -37,10 +36,8 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
{
|
{
|
||||||
if (streamScanf (record, format, &dval) != OK)
|
if (streamScanf(record, format, &dval) == ERROR)
|
||||||
{
|
goto end;
|
||||||
return aao->nord ? OK : ERROR;
|
|
||||||
}
|
|
||||||
switch (aao->ftvl)
|
switch (aao->ftvl)
|
||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
@ -50,7 +47,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
((epicsFloat32 *)aao->bptr)[aao->nord] = (epicsFloat32)dval;
|
((epicsFloat32 *)aao->bptr)[aao->nord] = (epicsFloat32)dval;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"readData %s: can't convert from double to %s\n",
|
"readData %s: can't convert from double to %s\n",
|
||||||
record->name, pamapdbfType[aao->ftvl].strvalue);
|
record->name, pamapdbfType[aao->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -61,10 +58,8 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
case DBF_ENUM:
|
case DBF_ENUM:
|
||||||
{
|
{
|
||||||
if (streamScanf (record, format, &lval) != OK)
|
if (streamScanf(record, format, &lval) == ERROR)
|
||||||
{
|
goto end;
|
||||||
return aao->nord ? OK : ERROR;
|
|
||||||
}
|
|
||||||
switch (aao->ftvl)
|
switch (aao->ftvl)
|
||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
@ -73,6 +68,12 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
((epicsFloat32 *)aao->bptr)[aao->nord] = (epicsFloat32)lval;
|
((epicsFloat32 *)aao->bptr)[aao->nord] = (epicsFloat32)lval;
|
||||||
break;
|
break;
|
||||||
|
#ifdef DBF_INT64
|
||||||
|
case DBF_INT64:
|
||||||
|
case DBF_UINT64:
|
||||||
|
((epicsInt64 *)aao->bptr)[aao->nord] = (epicsInt64)lval;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
((epicsInt32 *)aao->bptr)[aao->nord] = (epicsInt32)lval;
|
((epicsInt32 *)aao->bptr)[aao->nord] = (epicsInt32)lval;
|
||||||
@ -87,7 +88,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
((epicsInt8 *)aao->bptr)[aao->nord] = (epicsInt8)lval;
|
((epicsInt8 *)aao->bptr)[aao->nord] = (epicsInt8)lval;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"readData %s: can't convert from long to %s\n",
|
"readData %s: can't convert from long to %s\n",
|
||||||
record->name, pamapdbfType[aao->ftvl].strvalue);
|
record->name, pamapdbfType[aao->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -99,30 +100,30 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
switch (aao->ftvl)
|
switch (aao->ftvl)
|
||||||
{
|
{
|
||||||
case DBF_STRING:
|
case DBF_STRING:
|
||||||
if (streamScanfN (record, format,
|
if (streamScanfN(record, format,
|
||||||
(char *)aao->bptr + aao->nord * MAX_STRING_SIZE,
|
(char *)aao->bptr + aao->nord * MAX_STRING_SIZE,
|
||||||
MAX_STRING_SIZE) != OK)
|
MAX_STRING_SIZE) == ERROR)
|
||||||
{
|
goto end;
|
||||||
return aao->nord ? OK : ERROR;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case DBF_CHAR:
|
case DBF_CHAR:
|
||||||
case DBF_UCHAR:
|
case DBF_UCHAR:
|
||||||
memset (aao->bptr, 0, aao->nelm);
|
{
|
||||||
|
ssize_t length;
|
||||||
aao->nord = 0;
|
aao->nord = 0;
|
||||||
if (streamScanfN (record, format,
|
if ((length = streamScanfN(record, format,
|
||||||
(char *)aao->bptr, aao->nelm) != OK)
|
(char *)aao->bptr, aao->nelm)) == ERROR)
|
||||||
{
|
{
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
((char*)aao->bptr)[aao->nelm] = 0;
|
if (length < (ssize_t)aao->nelm)
|
||||||
for (lval = aao->nelm;
|
{
|
||||||
lval >= 0 && ((char*)aao->bptr)[lval] == 0;
|
((char*)aao->bptr)[length] = 0;
|
||||||
lval--);
|
}
|
||||||
aao->nord = lval+1;
|
aao->nord = (long)length;
|
||||||
return OK;
|
goto end_no_check;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"readData %s: can't convert from string to %s\n",
|
"readData %s: can't convert from string to %s\n",
|
||||||
record->name, pamapdbfType[aao->ftvl].strvalue);
|
record->name, pamapdbfType[aao->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -131,7 +132,7 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
errlogSevPrintf (errlogMajor,
|
errlogSevPrintf(errlogMajor,
|
||||||
"readData %s: can't convert from %s to %s\n",
|
"readData %s: can't convert from %s to %s\n",
|
||||||
record->name, pamapdbfType[format->type].strvalue,
|
record->name, pamapdbfType[format->type].strvalue,
|
||||||
pamapdbfType[aao->ftvl].strvalue);
|
pamapdbfType[aao->ftvl].strvalue);
|
||||||
@ -139,12 +140,44 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
end:
|
||||||
|
if (aao->nord == 0) return ERROR;
|
||||||
|
end_no_check:
|
||||||
|
if (record->pact) return OK;
|
||||||
|
/* In @init handler, no processing, enforce monitor updates. */
|
||||||
|
monitor_mask = recGblResetAlarms(aao);
|
||||||
|
#if defined(VERSION_INT) || EPICS_MODIFICATION >= 12
|
||||||
|
if (aao->mpst == aaoPOST_Always)
|
||||||
|
monitor_mask |= DBE_VALUE;
|
||||||
|
if (aao->apst == aaoPOST_Always)
|
||||||
|
monitor_mask |= DBE_LOG;
|
||||||
|
if ((aao->mpst == aaoPOST_OnChange) ||
|
||||||
|
(aao->apst == aaoPOST_OnChange))
|
||||||
|
{
|
||||||
|
unsigned int hash = epicsMemHash(aao->bptr,
|
||||||
|
aao->nord * dbValueSize(aao->ftvl), 0);
|
||||||
|
if (hash != aao->hash)
|
||||||
|
{
|
||||||
|
if (aao->mpst == aaoPOST_OnChange)
|
||||||
|
monitor_mask |= DBE_VALUE;
|
||||||
|
if (aao->apst == aaoPOST_OnChange)
|
||||||
|
monitor_mask |= DBE_LOG;
|
||||||
|
aao->hash = hash;
|
||||||
|
db_post_events(aao, &aao->hash, DBE_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
monitor_mask |= DBE_VALUE | DBE_LOG;
|
||||||
|
#endif
|
||||||
|
if (monitor_mask)
|
||||||
|
db_post_events(aao, aao->bptr, monitor_mask);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long writeData (dbCommon *record, format_t *format)
|
static long writeData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
aaoRecord *aao = (aaoRecord *) record;
|
aaoRecord *aao = (aaoRecord *)record;
|
||||||
double dval;
|
double dval;
|
||||||
long lval;
|
long lval;
|
||||||
unsigned long nowd;
|
unsigned long nowd;
|
||||||
@ -163,6 +196,14 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
case DBF_FLOAT:
|
case DBF_FLOAT:
|
||||||
dval = ((epicsFloat32 *)aao->bptr)[nowd];
|
dval = ((epicsFloat32 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
|
#ifdef DBF_INT64
|
||||||
|
case DBF_INT64:
|
||||||
|
dval = ((epicsInt64 *)aao->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
case DBF_UINT64:
|
||||||
|
dval = ((epicsUInt64 *)aao->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
dval = ((epicsInt32 *)aao->bptr)[nowd];
|
dval = ((epicsInt32 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
@ -170,10 +211,10 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
dval = ((epicsUInt32 *)aao->bptr)[nowd];
|
dval = ((epicsUInt32 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_SHORT:
|
case DBF_SHORT:
|
||||||
|
case DBF_ENUM:
|
||||||
dval = ((epicsInt16 *)aao->bptr)[nowd];
|
dval = ((epicsInt16 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_USHORT:
|
case DBF_USHORT:
|
||||||
case DBF_ENUM:
|
|
||||||
dval = ((epicsUInt16 *)aao->bptr)[nowd];
|
dval = ((epicsUInt16 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_CHAR:
|
case DBF_CHAR:
|
||||||
@ -183,12 +224,12 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
dval = ((epicsUInt8 *)aao->bptr)[nowd];
|
dval = ((epicsUInt8 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to double\n",
|
"writeData %s: can't convert from %s to double\n",
|
||||||
record->name, pamapdbfType[aao->ftvl].strvalue);
|
record->name, pamapdbfType[aao->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (streamPrintf (record, format, dval))
|
if (streamPrintf(record, format, dval))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -198,6 +239,14 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
switch (aao->ftvl)
|
switch (aao->ftvl)
|
||||||
{
|
{
|
||||||
|
#ifdef DBF_INT64
|
||||||
|
case DBF_INT64:
|
||||||
|
lval = ((epicsInt64 *)aao->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
case DBF_UINT64:
|
||||||
|
lval = ((epicsUInt64 *)aao->bptr)[nowd];
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
lval = ((epicsInt32 *)aao->bptr)[nowd];
|
lval = ((epicsInt32 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
@ -205,10 +254,10 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
lval = ((epicsUInt32 *)aao->bptr)[nowd];
|
lval = ((epicsUInt32 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_SHORT:
|
case DBF_SHORT:
|
||||||
|
case DBF_ENUM:
|
||||||
lval = ((epicsInt16 *)aao->bptr)[nowd];
|
lval = ((epicsInt16 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_USHORT:
|
case DBF_USHORT:
|
||||||
case DBF_ENUM:
|
|
||||||
lval = ((epicsUInt16 *)aao->bptr)[nowd];
|
lval = ((epicsUInt16 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
case DBF_CHAR:
|
case DBF_CHAR:
|
||||||
@ -218,12 +267,12 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
lval = ((epicsUInt8 *)aao->bptr)[nowd];
|
lval = ((epicsUInt8 *)aao->bptr)[nowd];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to long\n",
|
"writeData %s: can't convert from %s to long\n",
|
||||||
record->name, pamapdbfType[aao->ftvl].strvalue);
|
record->name, pamapdbfType[aao->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (streamPrintf (record, format, lval))
|
if (streamPrintf(record, format, lval))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -232,7 +281,7 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
switch (aao->ftvl)
|
switch (aao->ftvl)
|
||||||
{
|
{
|
||||||
case DBF_STRING:
|
case DBF_STRING:
|
||||||
if (streamPrintf (record, format,
|
if (streamPrintf(record, format,
|
||||||
((char *)aao->bptr) + nowd * MAX_STRING_SIZE))
|
((char *)aao->bptr) + nowd * MAX_STRING_SIZE))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
break;
|
break;
|
||||||
@ -247,12 +296,12 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
{
|
{
|
||||||
((char *)aao->bptr)[aao->nelm-1] = 0;
|
((char *)aao->bptr)[aao->nelm-1] = 0;
|
||||||
}
|
}
|
||||||
if (streamPrintf (record, format,
|
if (streamPrintf(record, format,
|
||||||
((char *)aao->bptr)))
|
((char *)aao->bptr)))
|
||||||
return ERROR;
|
return ERROR;
|
||||||
return OK;
|
return OK;
|
||||||
default:
|
default:
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to string\n",
|
"writeData %s: can't convert from %s to string\n",
|
||||||
record->name, pamapdbfType[aao->ftvl].strvalue);
|
record->name, pamapdbfType[aao->ftvl].strvalue);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -261,7 +310,7 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"writeData %s: can't convert from %s to %s\n",
|
"writeData %s: can't convert from %s to %s\n",
|
||||||
record->name, pamapdbfType[aao->ftvl].strvalue,
|
record->name, pamapdbfType[aao->ftvl].strvalue,
|
||||||
pamapdbfType[format->type].strvalue);
|
pamapdbfType[format->type].strvalue);
|
||||||
@ -272,20 +321,19 @@ static long writeData (dbCommon *record, format_t *format)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long initRecord (dbCommon *record)
|
static long initRecord(dbCommon *record)
|
||||||
{
|
{
|
||||||
static const int typesize[] = {MAX_STRING_SIZE,1,1,2,2,4,4,4,8,2};
|
aaoRecord *aao = (aaoRecord *)record;
|
||||||
aaoRecord *aao = (aaoRecord *) record;
|
|
||||||
|
|
||||||
aao->bptr = calloc(aao->nelm, typesize[aao->ftvl]);
|
aao->bptr = calloc(aao->nelm, dbValueSize(aao->ftvl));
|
||||||
if (aao->bptr == NULL)
|
if (aao->bptr == NULL)
|
||||||
{
|
{
|
||||||
errlogSevPrintf (errlogFatal,
|
errlogSevPrintf(errlogFatal,
|
||||||
"initRecord %s: can't allocate memory for data array\n",
|
"initRecord %s: can't allocate memory for data array\n",
|
||||||
record->name);
|
record->name);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
return streamInitRecord (record, &aao->out, readData, writeData) == ERROR ?
|
return streamInitRecord(record, &aao->out, readData, writeData) == ERROR ?
|
||||||
ERROR : OK;
|
ERROR : OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is an EPICS record Interface for StreamDevice. *
|
* This is an EPICS record Interface for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -18,98 +18,89 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
#include <math.h>
|
#include "aiRecord.h"
|
||||||
#include <menuConvert.h>
|
|
||||||
#include <aiRecord.h>
|
|
||||||
#include "devStream.h"
|
#include "devStream.h"
|
||||||
#include <epicsExport.h>
|
|
||||||
|
|
||||||
#ifdef vxWorks
|
static long readData(dbCommon *record, format_t *format)
|
||||||
#include <private/mathP.h>
|
|
||||||
#define isinf(x) isInf(x)
|
|
||||||
#define isnan(x) isNan(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static long readData (dbCommon *record, format_t *format)
|
|
||||||
{
|
{
|
||||||
aiRecord *ai = (aiRecord *) record;
|
aiRecord *ai = (aiRecord *)record;
|
||||||
|
double val;
|
||||||
|
|
||||||
switch (format->type)
|
switch (format->type)
|
||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
{
|
{
|
||||||
double val;
|
if (streamScanf(record, format, &val) == ERROR) return ERROR;
|
||||||
if (streamScanf (record, format, &val)) return ERROR;
|
break;
|
||||||
if (ai->aslo != 0.0 && ai->aslo != 1.0) val *= ai->aslo;
|
|
||||||
val += ai->aoff;
|
|
||||||
if (!(ai->smoo == 0.0 || ai->init || ai->udf || isinf(ai->val) || isnan(ai->val)))
|
|
||||||
val = ai->val * ai->smoo + val * (1.0 - ai->smoo);
|
|
||||||
ai->val = val;
|
|
||||||
return DO_NOT_CONVERT;
|
|
||||||
}
|
}
|
||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
{
|
{
|
||||||
long rval;
|
long rval;
|
||||||
if (streamScanf (record, format, &rval)) return ERROR;
|
if (streamScanf(record, format, &rval) == ERROR) return ERROR;
|
||||||
ai->rval = rval;
|
ai->rval = rval;
|
||||||
if (ai->linr == menuConvertNO_CONVERSION)
|
if (ai->linr == 0)
|
||||||
{
|
{
|
||||||
/* allow integers with more than 32 bits */
|
/* allow integers with more than 32 bits */
|
||||||
double val;
|
|
||||||
if (format->type == DBF_ULONG)
|
if (format->type == DBF_ULONG)
|
||||||
val = (unsigned long)rval;
|
val = (unsigned long)rval;
|
||||||
else
|
else
|
||||||
val = rval;
|
val = rval;
|
||||||
if (ai->aslo != 0.0 && ai->aslo != 1.0) val *= ai->aslo;
|
break;
|
||||||
ai->val = val + ai->aoff;
|
|
||||||
return DO_NOT_CONVERT;
|
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return ERROR;
|
||||||
}
|
}
|
||||||
return ERROR;
|
if (ai->aslo != 0.0 && ai->aslo != 1.0) val *= ai->aslo;
|
||||||
|
val += ai->aoff;
|
||||||
|
if (!(ai->smoo == 0.0 || ai->init || ai->udf || isinf(ai->val) || isnan(ai->val)))
|
||||||
|
val = ai->val * ai->smoo + val * (1.0 - ai->smoo);
|
||||||
|
ai->val = val;
|
||||||
|
return DO_NOT_CONVERT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long writeData (dbCommon *record, format_t *format)
|
static long writeData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
aiRecord *ai = (aiRecord *) record;
|
aiRecord *ai = (aiRecord *)record;
|
||||||
|
|
||||||
|
double val = ai->val - ai->aoff;
|
||||||
|
if (ai->aslo != 0.0 && ai->aslo != 1.0) val /= ai->aslo;
|
||||||
|
|
||||||
switch (format->type)
|
switch (format->type)
|
||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
{
|
{
|
||||||
double val = ai->val - ai->aoff;
|
return streamPrintf(record, format, val);
|
||||||
if (ai->aslo != 0.0 && ai->aslo != 1.0) val /= ai->aslo;
|
|
||||||
return streamPrintf (record, format, val);
|
|
||||||
}
|
}
|
||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
{
|
{
|
||||||
if (ai->linr == menuConvertNO_CONVERSION)
|
if (ai->linr == 0)
|
||||||
{
|
{
|
||||||
/* allow more bits than 32 */
|
/* allow more bits than 32 */
|
||||||
return streamPrintf (record, format, (unsigned long)ai->val);
|
return streamPrintf(record, format, (unsigned long)val);
|
||||||
}
|
}
|
||||||
return streamPrintf (record, format, (unsigned long)ai->rval);
|
return streamPrintf(record, format, (unsigned long)ai->rval);
|
||||||
}
|
}
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
{
|
{
|
||||||
if (ai->linr == menuConvertNO_CONVERSION)
|
if (ai->linr == 0)
|
||||||
{
|
{
|
||||||
/* allow more bits than 32 */
|
/* allow more bits than 32 */
|
||||||
return streamPrintf (record, format, (long)ai->val);
|
return streamPrintf(record, format, (long)val);
|
||||||
}
|
}
|
||||||
return streamPrintf (record, format, (long)ai->rval);
|
return streamPrintf(record, format, (long)ai->rval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long initRecord (dbCommon *record)
|
static long initRecord(dbCommon *record)
|
||||||
{
|
{
|
||||||
aiRecord *ai = (aiRecord *) record;
|
aiRecord *ai = (aiRecord *)record;
|
||||||
|
|
||||||
return streamInitRecord (record, &ai->inp, readData, writeData) == ERROR ?
|
return streamInitRecord(record, &ai->inp, readData, writeData) == ERROR ?
|
||||||
ERROR : OK;
|
ERROR : OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is an EPICS record Interface for StreamDevice. *
|
* This is an EPICS record Interface for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -18,90 +18,132 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
#include <menuConvert.h>
|
#include "aoRecord.h"
|
||||||
#include <aoRecord.h>
|
#include "menuConvert.h"
|
||||||
|
#include "cvtTable.h"
|
||||||
#include "devStream.h"
|
#include "devStream.h"
|
||||||
#include <epicsExport.h>
|
|
||||||
|
|
||||||
static long readData (dbCommon *record, format_t *format)
|
static long readData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
aoRecord *ao = (aoRecord *) record;
|
aoRecord *ao = (aoRecord *)record;
|
||||||
|
double val;
|
||||||
|
unsigned short monitor_mask;
|
||||||
|
|
||||||
switch (format->type)
|
switch (format->type)
|
||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
{
|
{
|
||||||
double val;
|
if (streamScanf(record, format, &val) == ERROR) return ERROR;
|
||||||
if (streamScanf (record, format, &val)) return ERROR;
|
break;
|
||||||
if (ao->aslo != 0.0 && ao->aslo != 1.0) val *= ao->aslo;
|
|
||||||
ao->val = val + ao->aoff;
|
|
||||||
return DO_NOT_CONVERT;
|
|
||||||
}
|
}
|
||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
{
|
{
|
||||||
long rval;
|
long rval;
|
||||||
if (streamScanf (record, format, &rval)) return ERROR;
|
if (streamScanf(record, format, &rval) == ERROR) return ERROR;
|
||||||
ao->rbv = rval;
|
ao->rbv = rval;
|
||||||
ao->rval = rval;
|
ao->rval = rval;
|
||||||
if (ao->linr == menuConvertNO_CONVERSION)
|
if (format->type == DBF_ULONG)
|
||||||
{
|
val = (unsigned long)rval;
|
||||||
/* allow integers with more than 32 bits */
|
else
|
||||||
double val;
|
val = rval;
|
||||||
if (format->type == DBF_ULONG)
|
break;
|
||||||
val = (unsigned long)rval;
|
val += ao->roff;
|
||||||
else
|
if (ao->linr == menuConvertNO_CONVERSION) {
|
||||||
val = rval;
|
; /*do nothing*/
|
||||||
if (ao->aslo != 0.0 && ao->aslo != 1.0) val *= ao->aslo;
|
} else if ((ao->linr == menuConvertLINEAR)
|
||||||
ao->val = val + ao->aoff;
|
#ifndef EPICS_3_13
|
||||||
return DO_NOT_CONVERT;
|
|| (ao->linr == menuConvertSLOPE)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
val = val * ao->eslo + ao->eoff;
|
||||||
|
} else {
|
||||||
|
if (cvtRawToEngBpt(&val, ao->linr, 0,
|
||||||
|
(void *)&ao->pbrk, &ao->lbrk) == ERROR) return ERROR;
|
||||||
}
|
}
|
||||||
return OK;
|
}
|
||||||
|
default:
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
if (ao->aslo != 0.0) val *= ao->aslo;
|
||||||
|
val += ao->aoff;
|
||||||
|
ao->val = val;
|
||||||
|
if (record->pact) return DO_NOT_CONVERT;
|
||||||
|
/* In @init handler, no processing, enforce monitor updates. */
|
||||||
|
ao->omod = ao->oval != val;
|
||||||
|
ao->orbv = ao->oval = val;
|
||||||
|
monitor_mask = recGblResetAlarms(record);
|
||||||
|
if (!(fabs(ao->mlst - val) <= ao->mdel))
|
||||||
|
{
|
||||||
|
monitor_mask |= DBE_VALUE;
|
||||||
|
ao->mlst = val;
|
||||||
|
}
|
||||||
|
if (!(fabs(ao->alst - val) <= ao->adel))
|
||||||
|
{
|
||||||
|
monitor_mask |= DBE_LOG;
|
||||||
|
ao->alst = val;
|
||||||
|
}
|
||||||
|
if (monitor_mask)
|
||||||
|
db_post_events(record, &ao->val, monitor_mask);
|
||||||
|
if (ao->omod) monitor_mask |= (DBE_VALUE|DBE_LOG);
|
||||||
|
if (monitor_mask)
|
||||||
|
{
|
||||||
|
ao->omod = FALSE;
|
||||||
|
db_post_events (record, &ao->oval, monitor_mask);
|
||||||
|
if (ao->oraw != ao->rval)
|
||||||
|
{
|
||||||
|
db_post_events(record, &ao->rval, monitor_mask | DBE_VALUE | DBE_LOG);
|
||||||
|
ao->oraw = ao->rval;
|
||||||
|
}
|
||||||
|
if (ao->orbv != ao->rbv)
|
||||||
|
{
|
||||||
|
db_post_events(record, &ao->rbv, monitor_mask | DBE_VALUE | DBE_LOG);
|
||||||
|
ao->orbv = ao->rbv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ERROR;
|
return DO_NOT_CONVERT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long writeData (dbCommon *record, format_t *format)
|
static long writeData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
aoRecord *ao = (aoRecord *) record;
|
aoRecord *ao = (aoRecord *)record;
|
||||||
|
|
||||||
double val = (INIT_RUN ? ao->val : ao->oval) - ao->aoff;
|
double val = (INIT_RUN ? ao->val : ao->oval) - ao->aoff;
|
||||||
if (ao->aslo != 0.0 && ao->aslo != 1.0) val /= ao->aslo;
|
if (ao->aslo != 0.0 && ao->aslo != 1.0) val /= ao->aslo;
|
||||||
|
|
||||||
switch (format->type)
|
switch (format->type)
|
||||||
{
|
{
|
||||||
case DBF_DOUBLE:
|
case DBF_DOUBLE:
|
||||||
{
|
{
|
||||||
return streamPrintf (record, format, val);
|
return streamPrintf(record, format, val);
|
||||||
}
|
}
|
||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
{
|
{
|
||||||
if (ao->linr == menuConvertNO_CONVERSION)
|
if (ao->linr == 0)
|
||||||
{
|
{
|
||||||
/* allow integers with more than 32 bits */
|
/* allow integers with more than 32 bits */
|
||||||
return streamPrintf (record, format, (unsigned long)val);
|
return streamPrintf(record, format, (unsigned long)val);
|
||||||
}
|
}
|
||||||
return streamPrintf (record, format, (unsigned long)ao->rval);
|
return streamPrintf(record, format, (unsigned long)ao->rval);
|
||||||
}
|
}
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
{
|
{
|
||||||
if (ao->linr == menuConvertNO_CONVERSION)
|
if (ao->linr == 0)
|
||||||
{
|
{
|
||||||
/* allow integers with more than 32 bits */
|
/* allow integers with more than 32 bits */
|
||||||
return streamPrintf (record, format, (long)val);
|
return streamPrintf(record, format, (long)val);
|
||||||
}
|
}
|
||||||
return streamPrintf (record, format, (long)ao->rval);
|
return streamPrintf(record, format, (long)ao->rval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long initRecord (dbCommon *record)
|
static long initRecord(dbCommon *record)
|
||||||
{
|
{
|
||||||
aoRecord *ao = (aoRecord *) record;
|
aoRecord *ao = (aoRecord *)record;
|
||||||
|
|
||||||
return streamInitRecord (record, &ao->out, readData, writeData);
|
return streamInitRecord(record, &ao->out, readData, writeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
* (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||||
* *
|
* *
|
||||||
* This is an EPICS record Interface for StreamDevice. *
|
* This is an EPICS record Interface for StreamDevice. *
|
||||||
* Please refer to the HTML files in ../doc/ for a detailed *
|
* Please refer to the HTML files in ../docs/ for a detailed *
|
||||||
* documentation. *
|
* documentation. *
|
||||||
* *
|
* *
|
||||||
* If you do any changes in this file, you are not allowed to *
|
* If you do any changes in this file, you are not allowed to *
|
||||||
@ -18,14 +18,12 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
||||||
#include <string.h>
|
#include "biRecord.h"
|
||||||
#include <biRecord.h>
|
|
||||||
#include "devStream.h"
|
#include "devStream.h"
|
||||||
#include <epicsExport.h>
|
|
||||||
|
|
||||||
static long readData (dbCommon *record, format_t *format)
|
static long readData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
biRecord *bi = (biRecord *) record;
|
biRecord *bi = (biRecord *)record;
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
||||||
switch (format->type)
|
switch (format->type)
|
||||||
@ -33,21 +31,21 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
{
|
{
|
||||||
if (streamScanf (record, format, &val)) return ERROR;
|
if (streamScanf(record, format, &val) == ERROR) return ERROR;
|
||||||
if (bi->mask) val &= bi->mask;
|
if (bi->mask) val &= bi->mask;
|
||||||
bi->rval = val;
|
bi->rval = val;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
case DBF_ENUM:
|
case DBF_ENUM:
|
||||||
{
|
{
|
||||||
if (streamScanf (record, format, &val)) return ERROR;
|
if (streamScanf(record, format, &val) == ERROR) return ERROR;
|
||||||
bi->val = (val != 0);
|
bi->val = (val != 0);
|
||||||
return DO_NOT_CONVERT;
|
return DO_NOT_CONVERT;
|
||||||
}
|
}
|
||||||
case DBF_STRING:
|
case DBF_STRING:
|
||||||
{
|
{
|
||||||
char buffer[sizeof(bi->znam)];
|
char buffer[sizeof(bi->znam)];
|
||||||
if (streamScanfN (record, format, buffer, sizeof(buffer)))
|
if (streamScanfN(record, format, buffer, sizeof(buffer)) == ERROR)
|
||||||
return ERROR;
|
return ERROR;
|
||||||
if (strcmp (bi->znam, buffer) == 0)
|
if (strcmp (bi->znam, buffer) == 0)
|
||||||
{
|
{
|
||||||
@ -64,35 +62,35 @@ static long readData (dbCommon *record, format_t *format)
|
|||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long writeData (dbCommon *record, format_t *format)
|
static long writeData(dbCommon *record, format_t *format)
|
||||||
{
|
{
|
||||||
biRecord *bi = (biRecord *) record;
|
biRecord *bi = (biRecord *)record;
|
||||||
|
|
||||||
switch (format->type)
|
switch (format->type)
|
||||||
{
|
{
|
||||||
case DBF_ULONG:
|
case DBF_ULONG:
|
||||||
case DBF_LONG:
|
case DBF_LONG:
|
||||||
{
|
{
|
||||||
return streamPrintf (record, format, bi->rval);
|
return streamPrintf(record, format, bi->rval);
|
||||||
}
|
}
|
||||||
case DBF_ENUM:
|
case DBF_ENUM:
|
||||||
{
|
{
|
||||||
return streamPrintf (record, format, (long)bi->val);
|
return streamPrintf(record, format, (long)bi->val);
|
||||||
}
|
}
|
||||||
case DBF_STRING:
|
case DBF_STRING:
|
||||||
{
|
{
|
||||||
return streamPrintf (record, format,
|
return streamPrintf(record, format,
|
||||||
bi->val ? bi->onam : bi->znam);
|
bi->val ? bi->onam : bi->znam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long initRecord (dbCommon *record)
|
static long initRecord(dbCommon *record)
|
||||||
{
|
{
|
||||||
biRecord *bi = (biRecord *) record;
|
biRecord *bi = (biRecord *)record;
|
||||||
|
|
||||||
return streamInitRecord (record, &bi->inp, readData, writeData) == ERROR ?
|
return streamInitRecord(record, &bi->inp, readData, writeData) == ERROR ?
|
||||||
ERROR : OK;
|
ERROR : OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|