Compare commits

..

36 Commits

Author SHA1 Message Date
20dde4c1d8 typo
Some checks failed
StreamDevice / Native Linux with 3.14 (push) Has been cancelled
StreamDevice / Native Linux with 3.15 (push) Has been cancelled
StreamDevice / Native Linux with clang (push) Has been cancelled
StreamDevice / OSX (push) Has been cancelled
StreamDevice / Native Linux (WError) (push) Has been cancelled
StreamDevice / Cross mingw64 DLL (push) Has been cancelled
StreamDevice / RTEMS 4.10 (push) Has been cancelled
StreamDevice / Cross mingw64 static (push) Has been cancelled
StreamDevice / vs2019 DLL (push) Has been cancelled
StreamDevice / vs2019 static (push) Has been cancelled
2025-05-27 17:09:16 +02:00
f61e6404f5 checksums after regsub must check original input 2025-05-27 16:57:58 +02:00
9080d6ca8e typo fixed 2025-05-23 15:28:52 +02:00
13e7f2d3dc Merge pull request #95 from henriquesimoes/scalcout-doc
Document stream-base.dbd usage when sCalcout is not needed
2025-05-22 18:42:22 +02:00
e87e093c84 in recent asyn versions vxi11 is optional 2025-05-06 14:48:59 +02:00
7debc86514 added checksum for Spellman High Voltage Supplies MPS series 2025-01-10 15:47:22 +01:00
668d1d5255 add some per-record debugging 2024-06-06 13:49:15 +02:00
ae5ca0c45b allow to use the StreamDebugClass without file name or line number 2024-06-06 11:29:09 +02:00
b00099973f don't need the wrapper function 2024-06-06 11:29:09 +02:00
5bf5cb9a67 example terminal.tcl uses LF terminator 2024-06-06 11:29:09 +02:00
f6848f0503 Update .ci 2024-03-20 10:17:54 +01:00
1496089bc8 Bugfix: make sure not to lose teminating 0 byte in StreamBuffer::replace() 2024-03-19 09:38:11 +01:00
a090cd4d8f fix header file path 2024-03-18 17:43:45 +01:00
2b3e4189c1 Document stream-base.dbd usage when scalcout is not needed
Having StreamDevice built with scalcout support does not require that
the application also depend on calc if it does not use this record
type. But this is only true if we load `stream-base.dbd` instead of
`stream.dbd`. Therefore, this alternative database definition should be
documented in the setup page.
2023-06-26 10:43:59 -03:00
211f689cdf decuments recently added checksums 2022-11-21 17:34:20 +01:00
793675bb12 fix leybold sum 2022-11-21 17:11:42 +01:00
922294bf6a strncasecmp is still not reliably available in Vxworks 6 2022-10-07 12:20:23 +02:00
942c4779c9 add GHA config 2022-10-05 14:25:08 +02:00
8ceee295ae Removed hardcode CHECKRELEASE in configure/Makefile 2022-10-05 14:25:08 +02:00
c30e2a4e31 vxWorks 6.9 has stdint.h and strncasecmp, RTEMS 5 has strncasecmp 2022-10-05 14:24:34 +02:00
fc67fb8721 Fix cplusplus linkage error with extern C 2022-07-11 15:44:16 +02:00
c123c5c8f7 Quiet warning with -Wformat-security
Best practice is to only use constant format strings,
which ansiEscape() almost is.
2022-07-11 15:43:26 +02:00
8746dea7cf fix HTML example to use correct line terminator CR LF 2022-07-11 15:43:26 +02:00
2915830b02 fix some rendering problems when printing 2022-07-11 15:43:26 +02:00
fdfa4d4695 fix makepdf for newer wkhtmltopdf version 2022-07-11 15:43:26 +02:00
4d717288da fix compile problem with EPICS 3.13 on vxWorks 6 2022-07-11 15:43:26 +02:00
94721c2b0e fix crash due to length underflow 2021-11-11 11:49:32 +01:00
bf0e755913 add new checksum: bitsum 2021-11-11 11:49:32 +01:00
51e4a0749d make "ifdef CALC" also consider SYNAPPS variable
change the ifdefs to the same expression used in CONFIG_STREAM
2021-11-05 11:42:48 +01:00
4cdace3ffe make "stream" in DBD and other file names explicit
The LIBRARY_* variables may specify *multiple* libraries.
(So they can't be used as part of file names.)
2021-11-05 11:42:48 +01:00
d19b16d096 fix strncpy warning 2021-11-05 11:21:21 +01:00
b1e0d63c6b Canonical handling of user include files 2021-11-05 10:14:21 +01:00
d1b43b879c strncasecmp does exist when compiling for Windows on MinGW 2021-11-05 10:13:58 +01:00
6b0ee5e946 Conditionally use tirpc if defined 2021-09-21 13:01:32 +01:00
a0d1b35862 Add preprocessor definition for static PCRE 2021-09-21 12:58:20 +01:00
dfbd308d46 32 bit Windows needs wrapper for calling convention reasons 2021-09-01 10:13:58 +02:00
28 changed files with 781 additions and 282 deletions

1
.ci Submodule

Submodule .ci added at dead44c3cb

12
.ci-local/defaults.set Normal file
View File

@ -0,0 +1,12 @@
MODULES=calc asyn
# EPICS Base
BASE_DIRNAME=base
BASE_REPONAME=epics-base
BASE_REPOOWNER=epics-base
BASE_VARNAME=EPICS_BASE
BASE_RECURSIVE=no
ASYN_REPOOWNER=epics-modules
CALC_REPOOWNER=epics-modules

164
.github/workflows/ci-scripts-build.yml vendored Normal file
View File

@ -0,0 +1,164 @@
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# This is YAML - indentation levels are crucial
# Workflow name, shared by all branches
name: StreamDevice
# Trigger on pushes and PRs to any branch
on:
push:
paths-ignore:
- 'docs/*'
- '.gitattributes'
- '.gitignore'
- '**/*.html'
- '**/*.md'
pull_request:
paths-ignore:
- 'docs/*'
- '.gitattributes'
- '.gitignore'
- '**/*.html'
- '**/*.md'
env:
SETUP_PATH: .ci-local:.ci
EPICS_TEST_IMPRECISE_TIMING: YES
jobs:
native:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
BASE: ${{ matrix.base }}
WINE: ${{ matrix.wine }}
RTEMS: ${{ matrix.rtems }}
RTEMS_TARGET: ${{ matrix.rtems_target }}
TEST: ${{ matrix.test }}
EXTRA: ${{ matrix.extra }}
VV: "1"
strategy:
fail-fast: false
matrix:
include:
- name: Native Linux (WError)
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "7.0"
extra: "CMD_CPPFLAGS=-Werror"
pcre: apt
- name: Cross mingw64 DLL
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "7.0"
wine: "64"
pcre: no
- name: Cross mingw64 static
os: ubuntu-20.04
cmp: gcc
configuration: static
base: "7.0"
wine: "64"
pcre: no
- name: RTEMS 4.10
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "7.0"
rtems: "4.10"
rtems_target: RTEMS-pc386-qemu
pcre: no
- name: Native Linux with clang
os: ubuntu-20.04
cmp: clang
configuration: default
base: "7.0"
pcre: apt
- name: Native Linux with 3.15
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "3.15"
pcre: apt
- name: Native Linux with 3.14
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "3.14"
pcre: apt
- name: OSX
os: macos-latest
cmp: clang
configuration: default
base: "7.0"
pcre: no
- name: vs2019 DLL
os: windows-2019
cmp: vs2019
configuration: debug
base: "7.0"
pcre: no
extra: "CMD_CFLAGS=-analysis CMD_CXXFLAGS=-analysis"
- name: vs2019 static
os: windows-2019
cmp: vs2019
configuration: static-debug
base: "7.0"
pcre: no
extra: "CMD_CFLAGS=-analysis CMD_CXXFLAGS=-analysis"
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@master
- name: "apt-get install"
run: |
sudo apt-get update
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
if: runner.os == 'Linux'
- name: Reset RELEASE
shell: bash
# 'make' on Mac doesn't understand "undefine PCRE"
# so replace the whole file
run: |
cat <<EOF > configure/RELEASE
-include \$(TOP)/../RELEASE.local
-include \$(TOP)/../RELEASE.\$(EPICS_HOST_ARCH).local
-include \$(TOP)/configure/RELEASE.local
EOF
- name: Prepare and compile dependencies
run: python .ci/cue.py prepare
- name: "apt-get install pcre"
if: matrix.pcre == 'apt'
shell: bash
run: |
sudo apt-get -y install libpcre3-dev
cat <<EOF >> configure/CONFIG_SITE.local
PCRE_INCLUDE=/usr/include
PCRE_LIB=/usr/lib
EOF
- name: Build main module
run: python .ci/cue.py build

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule ".ci"]
path = .ci
url = https://github.com/epics-base/ci-scripts.git

View File

@ -24,11 +24,11 @@ HEADERS += src/StreamFormat.h
HEADERS += src/StreamFormatConverter.h HEADERS += src/StreamFormatConverter.h
HEADERS += src/StreamBuffer.h HEADERS += src/StreamBuffer.h
HEADERS += src/StreamError.h HEADERS += src/StreamError.h
HEADERS += src/StreamVersion.h
HEADERS += src/StreamProtocol.h HEADERS += src/StreamProtocol.h
HEADERS += src/StreamBusInterface.h HEADERS += src/StreamBusInterface.h
HEADERS += src/StreamCore.h HEADERS += src/StreamCore.h
HEADERS += src/MacroMagic.h HEADERS += src/MacroMagic.h
HEADERS += $(COMMON_DIR)/StreamVersion.h
CPPFLAGS += -DSTREAM_INTERNAL -I$(COMMON_DIR) CPPFLAGS += -DSTREAM_INTERNAL -I$(COMMON_DIR)

View File

@ -1,14 +1,29 @@
#CONFIG # CONFIG - Load build configuration data
include $(TOP)/configure/CONFIG_APP #
# Add any changes to make definitions here # Do not make changes to this file!
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040 # Allow user to override where the build rules come from
#CROSS_COMPILER_TARGET_ARCHS = RULES = $(EPICS_BASE)
# Use this when your IOC and the host use different paths # RELEASE files point to other application tops
# to access the application. Typically this will be include $(TOP)/configure/RELEASE
# used with the Microsoft FTP server or with NFS mounts. Use -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH)
# is indicated by failure of the cdCommands script on -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
# vxWorks. You must rebuild in the iocBoot directory ifdef T_A
# before this takes effect. -include $(TOP)/configure/RELEASE.Common.$(T_A)
#IOCS_APPL_TOP = <the top of the application as seen by the IOC> -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif

View File

@ -1,26 +0,0 @@
# 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

40
configure/CONFIG_SITE Normal file
View File

@ -0,0 +1,40 @@
# CONFIG_SITE
-include $(SUPPORT)/configure/CONFIG_SITE
# Make any application-specific changes to the EPICS build
# configuration variables in this file.
#
# Host/target specific settings can be specified in files named
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# CHECK_RELEASE controls the consistency checking of the support
# applications pointed to by the RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building even if conflicts are found.
CHECK_RELEASE = YES
# Set this when you only want to compile this application
# for a subset of the cross-compiled target architectures
# that Base is built for.
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</absolute/path/to/install/top>
# Set this when the IOC and build host use different paths
# to the install location. This may be needed to boot from
# a Microsoft FTP server say, or on some NFS configurations.
#IOCS_APPL_TOP = </IOC's/absolute/path/to/install/top>
# These allow developers to override the CONFIG_SITE variable
# settings without having to modify the configure/CONFIG_SITE
# file itself.
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local

View File

@ -2,11 +2,7 @@
TOP=.. TOP=..
include $(TOP)/configure/CONFIG_APP include $(TOP)/configure/CONFIG
# Set the following to NO to disable consistency checking of
# the support applications defined in $(TOP)/configure/RELEASE
CHECK_RELEASE = YES
TARGETS = $(CONFIG_TARGETS) TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@ -485,6 +485,12 @@ than 9.
<p> <p>
This is not a normal "converter", because no user data is converted. This is not a normal "converter", because no user data is converted.
Instead, a checksum is calculated from the input or output. Instead, a checksum is calculated from the input or output.
<span class="new">
Any pre-processing of input, e.g. by the <a href="#regsub">regsub</a> converter
is ignored for the calculation of the checksum.
</span>
</p>
<p>
The <em>width</em> field is the byte number from which to start The <em>width</em> field is the byte number from which to start
calculating the checksum. calculating the checksum.
Default is 0, i.e. the first byte of the input or output of the current Default is 0, i.e. the first byte of the input or output of the current
@ -594,6 +600,18 @@ In input, the next byte or bytes must match the checksum.
href="https://en.wikipedia.org/wiki/Longitudinal_redundancy_check">Wikipedia</a>.</dd> href="https://en.wikipedia.org/wiki/Longitudinal_redundancy_check">Wikipedia</a>.</dd>
<dt><code>%&lt;hexlrc&gt;</code></dt> <dt><code>%&lt;hexlrc&gt;</code></dt>
<dd>One byte. The LRC for the hex digits. (Other characters are ignored.)</dd> <dd>One byte. The LRC for the hex digits. (Other characters are ignored.)</dd>
<dt><code>%&lt;leybold&gt;</code></dt>
<dd>One byte. Used by some Leybold products. 255-bytesum%255 (+32 if result would be <32)</dd>
<dt><code>%&lt;brksCryo&gt;</code></dt>
<dd>One byte. Used by Brooks Cryopumps.</dd>
<dt><code>%&lt;CPI&gt;</code></dt>
<dd>One byte. Used by TRIUMF CPI RF amplifier.</dd>
<dt><code>%&lt;bitsum&gt;</code> or <code>%&lt;bitsum8&gt;</code></dt>
<dd>One byte. Number of 1 bits in all characters.</dd>
<dt><code>%&lt;bitsum16&gt;</code></dt>
<dd>Two bytes. Number of 1 bits in all characters.</dd>
<dt><code>%&lt;bitsum32&gt;</code></dt>
<dd>Four bytes. Number of 1 bits in all characters.</dd>
</dl> </dl>
<a name="regex"></a> <a name="regex"></a>
@ -699,10 +717,14 @@ However if an empty string is matched, searching advances by 1 character in orde
avoid matching the same empty string again.</span> avoid matching the same empty string again.</span>
</p> </p>
<p> <p>
In input this converter pre-processes data received from the device before In input, this converter pre-processes data received from the device before
following converters read it. following converters read it.
Converters preceding this one will read unmodified input. Converters preceding this one will read unmodified input.
Thus place this converter before those whose input should be pre-processed. Thus place this converter before those whose input should be pre-processed.
<span class="new">
However, <a href="#chksum">checksum</a> converters will always use the unmodified
input as sent by the device because the modified input would not match the checksum.
</span>
</p> </p>
<p> <p>
In output it post-processes data already formatted by preceding converters In output it post-processes data already formatted by preceding converters

View File

@ -1,10 +1,22 @@
#/bin/sh #/bin/sh
if ! wkhtmltopdf -V >/dev/null 2>&1 wkhtmltopdf --enable-local-file-access -V >/dev/null 2>&1
then case $? in
127)
echo "wkhtmltopdf not installed." >&2 echo "wkhtmltopdf not installed." >&2
echo "See https://wkhtmltopdf.org" >&2 echo "See https://wkhtmltopdf.org" >&2
exit 1 exit 1
fi ;;
0)
# have (and need) --enable-local-file-access
ENABLE_FILE_ACCESS=--enable-local-file-access
;;
1)
# have no (and need no) --enable-local-file-access
;;
*)
# Some error but I don't know what it means. Try anyway.
;;
esac
PAGES=" PAGES="
index.html index.html
@ -43,5 +55,5 @@ osinterface.html
" "
rm -f stream.pdf rm -f stream.pdf
wkhtmltopdf --print-media-type --dpi 1200 --zoom 0.85 --page-size Letter \ wkhtmltopdf --print-media-type --page-size Letter \
$PAGES stream.pdf $ENABLE_FILE_ACCESS $PAGES stream.pdf

View File

@ -85,7 +85,7 @@ Make sure that the <em>asyn</em> library can be found by adding the path to the
ASYN=/home/epics/asyn4-30 ASYN=/home/epics/asyn4-30
</pre> </pre>
<h4>Support for <em>sCalcout</em> record</h4> <h4 id="scalcout">Support for <em>sCalcout</em> record</h4>
<p> <p>
The <a The <a
href="https://htmlpreview.github.io/?https://raw.githubusercontent.com/epics-modules/calc/R3-6-1/documentation/sCalcoutRecord.html" href="https://htmlpreview.github.io/?https://raw.githubusercontent.com/epics-modules/calc/R3-6-1/documentation/sCalcoutRecord.html"
@ -109,7 +109,10 @@ modules. Release R2-8 or newer is recommended.
</p> </p>
<p> <p>
Support for the <em>sCalcout</em> is optional. <em>StreamDevice</em> works Support for the <em>sCalcout</em> is optional. <em>StreamDevice</em> works
as well without <em>sCalcout</em> or <em>SynApps</em>. as well without <em>sCalcout</em> or <em>SynApps</em>. If your application does
not need this record support, you may load <kbd>stream-base.dbd</kbd> instead of
<kbd>stream.dbd</kbd>, making it optional to include <em>calc</em> as an
application dependency.
</p> </p>
<h4>Support for regular expression matching</h4> <h4>Support for regular expression matching</h4>
@ -185,13 +188,14 @@ Regular expressions are optional. If you don't want them, you don't need this.
Go to the <em>StreamDevice</em> directory Go to the <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 and an example IOC application. <em>StreamDevice</em> database definition files and an example IOC application.
</p> </p>
<p> <p>
To use <em>StreamDevice</em>, your own application must be built with the To use <em>StreamDevice</em>, your own application must be built with the
<em>stream</em> and <em>asyn</em> (and optionally <em>pcre</em>) libraries <em>stream</em> and <em>asyn</em> (and optionally <em>pcre</em>) libraries
and must load <kbd>asyn.dbd</kbd> and <kbd>stream.dbd</kbd>. and must load <kbd>asyn.dbd</kbd> and <kbd>stream.dbd</kbd> (or alternatively
<kbd>stream-base.dbd</kbd>; see <a href="#scalcout">Support for sCalcout record</a>).
</p> </p>
<p> <p>
Include the following lines in your application <kbd>Makefile</kbd>: Include the following lines in your application <kbd>Makefile</kbd>:
@ -385,35 +389,45 @@ See the <a href="protocol.html">next chapter</a> for protocol files in depth.
Generation of debug and error messages is controlled with two shell variables, Generation of debug and error messages is controlled with two shell variables,
<code>streamDebug</code> and <code>streamError</code>. <code>streamDebug</code> and <code>streamError</code>.
Setting those variables to 1 (actually to any number but 0) enables the Setting those variables to 1 (actually to any number but 0) enables the
messages. messages. A few noisy and rarely useful debug messages are only enabled when
setting <code>streamDebug</code> to 2.
Per default debug messages are switched off and error messages are switched on. Per default debug messages are switched off and error messages are switched on.
Errors occuring while loading protocol files are always shown. Errors occuring while loading protocol files are always shown.
</p> </p>
<p> <p>
Warning: Enabling debug messages can create a lot of output! Warning: Enabling debug messages this way can create a lot of output!
At the moment, there is no way to set filters on debug or error messages. Therefore, some limited debugging can be enabled per record, independent of
the <code>streamDebug</code> variable using the <code>.TPRO</code> field of
the record. Currently, setting <code>.TPRO</code> to 1 or 2 enables some
basic information about the processing of a record and its i/o.
</p> </p>
<p> <p>
Debug output can be redirected to a file with the command Debug output can be redirected to a file with the command
<code>streamSetLogfile("<var>filename</var>")</code>. <code>streamSetLogfile("<var>filename</var>")</code>.
When called without a filename, debug output is directed back If the file already exists, it will be overwritten, not appended to.
to the console. While debug messages are only written to the defined log file, error messages
are still printed to <var>stderr</var> too.
Calling <code>streamSetLogfile</code> without a filename directs debug output
back to <var>stderr</var> and closes the log file.
</p> </p>
<p> <p>
By default the debug/error output is set to be colored if the terminal allows By default, error messages to the console are printed in red color if
it but this can be set to always colored or never colored by setting <var>stderr</var> is a tty at startup time, using ANSI color codes. Some
<code>streamDebugColored</code> to 1 or 0 respectively. terminals may not support this properly.
The variable <code>streamDebugColored</code> can be set to 0 or 1 to
disable or enable colored error messages explicitly.
Error messages written to a log file do not use colors.
</p> </p>
<p> <p>
Error and debug messages are prefixed with a time stamp unless the variable Error and debug messages are prefixed with a time stamp unless the variable
<code>streamMsgTimeStamped</code> is set to 0. <code>streamMsgTimeStamped</code> is set to 0.
</p> </p>
<p> <p>
When a device is disconnected StreamDevice can produce many repeated timeout when a device is unresponsive, StreamDevice may produce many repeated timeout
messages. To reduce this logging you can set <code>streamErrorDeadTime</code> messages. To reduce this, you can set <code>streamErrorDeadTime</code>
to an integer number of seconds. When this is set repeated timeout messages to an integer number of seconds. In this case, repeated timeout messages
will not be printed in the specified dead time after the last message. The will not be printed during the specified dead time after the last printed
default dead time is 0, resulting in every message being printed. message. The default dead time is 0, resulting in every message being printed.
</p> </p>
<h3>Example (vxWorks):</h3> <h3>Example (vxWorks):</h3>

View File

@ -1,90 +1,104 @@
a:link {color: #0000D0;} a:link { color: #0000D0; }
a:visited {color: #0000D0;} a:visited { color: #0000D0; }
a:hover {color: #FF0000;} a:hover { color: #FF0000; }
body { body {
margin-right:1em; margin-right: 1em;
margin-left:15em; margin-left: 15em;
margin-top:75px; margin-top: 75px;
padding-top:1px; padding-top: 1px;
font-family: Helvetica, Arial, sans-serif; font-family: Helvetica, Arial, sans-serif;
font-size: 100%; font-size: 100%;
background-color:#ffffff; background-color: #ffffff;
} }
a[name] { position:relative; top:-11ex;} a[name] {
position: relative;
top: -11ex;
}
pre, tt, kbd, code {
font-size: 95%;
font-family: Mono, "Lucida Console", Courier, monospace;
}
pre { pre {
background-color:#f4f4f4; background-color: #f4f4f4;
padding:1ex; padding: 1ex;
border:1px solid #000000; border: 1px solid #000000;
white-space:pre; white-space: pre;
margin:2ex; margin: 2ex;
page-break-inside:avoid; page-break-inside: avoid;
font-size: 85%;
white-space: pre-wrap;
} }
kbd { kbd {
font-weight:bold; font-weight: bold;
}
code {
color: #008000;
} }
dt { dt {
margin-top:0.5ex; margin-top: 0.5ex;
} }
h1 { h1 {
font-size:250%; font-size: 250%;
margin-top:0; margin-top: 0;
font-style:italic; font-style: italic;
font-weight:bold; font-weight: bold;
font-family:"Times New Roman", serif; font-family: "Times New Roman", Times, serif;
text-align:center; text-align: center;
position:fixed; position: fixed;
top:0; top: 0;
left:0; left: 0;
width:100%; width: 100%;
line-height:190%; line-height: 190%;
background-color:white; background-color: white;
border-width:0; border-width: 0;
border-bottom:3px solid #1b4486; border-bottom: 3px solid #1b4486;
white-space:nowrap; white-space: nowrap;
background-image:url(PSI.png); background-image: url(PSI.png);
background-repeat:no-repeat; background-repeat: no-repeat;
background-position:10px 5px; background-position: 10px 5px;
text-shadow:.1em .1em .1em darkgray; text-shadow: .1em .1em .1em lightgray;
box-shadow:0 .3em .1em -.2em darkgray; box-shadow: 0 .3em .1em -.2em darkgray;
} }
h2 { h2 {
font-size:150%; font-size: 140%;
margin-bottom:0.5ex; margin-bottom: 0.5ex;
} }
h3 { h3 {
font-size:120%; font-size: 120%;
margin-bottom:0.25ex; margin-bottom: 0.25ex;
} }
h4 { h4 {
font-size:100%; font-size: 100%;
margin-bottom:0.25ex; margin-bottom: 0.25ex;
} }
h1, h2, h3, h4 { h1, h2, h3, h4 {
page-break-after:avoid; page-break-after: avoid;
} }
p { p {
margin-top:0.75ex; margin-top: 0.75ex;
margin-bottom:0.75ex; margin-bottom: 0.75ex;
} }
body h1 + p { body h1 + p {
margin-top:1.5ex; margin-top: 1.5ex;
margin-bottom:0.75ex; margin-bottom: 0.75ex;
} }
footer { footer {
font-size:75%; font-size: 75%;
margin-top: 1em; margin-top: 1em;
border-top: 1px solid darkgray; border-top: 1px solid darkgray;
padding-top: 1em; padding-top: 1em;
@ -97,44 +111,40 @@ footer a:only-of-type {
} }
small { small {
font-size:75%; font-size: 75%;
}
code {
font-size: 125%;
color: #008000;
} }
.indent { .indent {
text-indent:-4ex; text-indent: -4ex;
margin-left:4ex; margin-left: 4ex;
margin-top:0.5ex; margin-top: 0.5ex;
text-align:left; text-align: left;
} }
.box { .box {
margin-left:1ex; margin-left: 1ex;
margin-right:1ex; margin-right: 1ex;
margin-top:0.5ex; margin-top: 0.5ex;
padding: 0 1ex; padding: 0 1ex;
border: 1px solid black; border: thin solid black;
text-align:left; text-align: left;
background-color:#f0f0f0; background-color: #f0f0f0;
page-break-inside: avoid;
} }
#navleft { #navleft {
position:fixed; position: fixed;
left:0; left: 0;
top:0; top: 0;
padding-top:70px; padding-top: 70px;
width:14em; width: 14em;
height:100%; height: 100%;
border-style:solid; border-style: solid;
border-color:black; border-color: black;
border-width:0 1px 0 0; border-width: 0 1px 0 0;
background-color:#e3eaf6; background-color: #e3eaf6;
overflow:hidden; overflow: hidden;
z-index:0; z-index: 0;
} }
.new { .new {
@ -142,17 +152,18 @@ code {
} }
a[target=ex]:after { a[target=ex]:after {
content:" " url(ex.png); content: " " url(ex.png);
} }
a[target=ex]:hover:after { a[target=ex]:hover:after {
content: " " url(exr.png); content: " " url(exr.png);
} }
@media print { @media print {
a:link {text-decoration:none;} a:link { text-decoration: none; }
a[target=ex]:after {content:" [" attr(href) "]";} a[target=ex]:after { content:" [" attr(href) "]"; font-size: 75%; }
body {margin:0 4em;} body { margin: 0 4em; }
h1 {position:relative; background-position:0 0;} h1 { position: relative; background-position: 0 0; }
#navleft {display:none;} #navleft { display: none; }
footer { display: none; }
} }

View File

@ -293,9 +293,10 @@ record (stringout, "$(DEVICE):clean_2") {<br>
<a name="web"></a> <a name="web"></a>
<h2>I need to read a web page</h2> <h2>I need to read a web page</h2>
<p> <p>
First you have to send a correctly formatted HTML request. First you have to send a correctly formatted HTML header for a GET request.
Note that this request must contain the full URL like Note that this header must contain the full URL like
"http://server/page" and must be terminated with <u>two</u> newlines. "http://server/page" and must be terminated with <u>two</u>
CR LF sequences (<code>"\r\n\r\n"</code> or <code>CR LF CR LF</code>).
The server should be the same as in the The server should be the same as in the
<a href="setup.html#sta"><code>drvAsynIPPortConfigure</code></a> <a href="setup.html#sta"><code>drvAsynIPPortConfigure</code></a>
command (if not using a http proxy). command (if not using a http proxy).
@ -313,17 +314,18 @@ Read the title of a web page.
get_title {<br> get_title {<br>
&nbsp;&nbsp;extrainput = ignore;<br> &nbsp;&nbsp;extrainput = ignore;<br>
&nbsp;&nbsp;replyTimeout = 1000;<br> &nbsp;&nbsp;replyTimeout = 1000;<br>
&nbsp;&nbsp;out "GET http://\$1\n\n";<br> &nbsp;&nbsp;out "GET http://\$1\r\n\r\n";<br>
&nbsp;&nbsp;in "%+.1/(?im)&lt;title&gt(.*)&lt\/title&gt;/";<br> &nbsp;&nbsp;in "%+.1/(?im)&lt;title&gt(.*)&lt\/title&gt;/";<br>
} }
</code> </code>
</p> </p>
<p> <p>
Terminate the request with two newlines, either explicit like here Terminate the request with two carriage return + newlines, either explicit
<u>or</u> using an like here <u>or</u> using an
<a href="protocol.html#sysvar"><code>outTerminator</code></a>. <a href="protocol.html#sysvar"><code>outTerminator</code></a>.
The URI (without http:// but including the web server host name) The URI (without http:// but including the web server host name)
is passed as <a href="protocol.html#argvar">argument</a> 1 to <code>\$1</code>. is passed as <a href="protocol.html#argvar">argument</a> 1 to <code>\$1</code>
in this example.
Note that web servers may be slow, so allow some Note that web servers may be slow, so allow some
<a href="protocol.html#argvar"><code>replyTimeout</code></a>. <a href="protocol.html#argvar"><code>replyTimeout</code></a>.
</p> </p>
@ -390,7 +392,7 @@ Then we read the number.
get_title {<br> get_title {<br>
&nbsp;&nbsp;extrainput = ignore;<br> &nbsp;&nbsp;extrainput = ignore;<br>
&nbsp;&nbsp;replyTimeout = 1000;<br> &nbsp;&nbsp;replyTimeout = 1000;<br>
&nbsp;&nbsp;out "GET http://\$1\n\n";<br> &nbsp;&nbsp;out "GET http://\$1\r\n\r\n";<br>
&nbsp;&nbsp;in "%*/Interesting value:/%f more text";<br> &nbsp;&nbsp;in "%*/Interesting value:/%f more text";<br>
} }
</code> </code>

170
src/ChecksumConverter.cc Executable file → Normal file
View File

@ -20,39 +20,59 @@
* along with StreamDevice. If not, see https://www.gnu.org/licenses/. * along with StreamDevice. If not, see https://www.gnu.org/licenses/.
*************************************************************************/ *************************************************************************/
#if defined(vxWorks) #ifdef vxWorks
#include <version.h> #include <version.h>
#if defined(_WRS_VXWORKS_MAJOR) && _WRS_VXWORKS_MAJOR > 6 || (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR > 8) /* VxWorks has strncasecmp since version 6
#include <stdint.h> but availability depends on configuration.
#define PRIX32 "X" We cannot know.
#define PRIu32 "u" */
#define NEED_strncasecmp
/* VxWorks does not have inttypes.h and uint32_t differs between versions */
#if defined(_WRS_VXWORKS_MAJOR) && (_WRS_VXWORKS_MAJOR > 6 || (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 9))
#define PRIX32 "X"
#define PRIu32 "u"
#else
#define PRIX32 "lX"
#define PRIu32 "lu"
#endif
#define PRIX8 "X"
#elif defined(_MSC_VER) && _MSC_VER < 1700
/* Visual Studio 2010 does not have inttypes.h */
#define PRIX32 "X"
#define PRIu32 "u"
#define PRIX8 "X"
#else #else
#define PRIX32 "lX" #define __STDC_FORMAT_MACROS
#define PRIu32 "lu" #include <inttypes.h>
#endif #endif
#define PRIX8 "X"
#define uint_fast8_t uint8_t
#define int_fast8_t int8_t
#elif defined(_MSC_VER) && _MSC_VER < 1700 /* Visual Studio 2010 does not have inttypes.h */
#include <stdint.h>
#define PRIX32 "X"
#define PRIu32 "u"
#define PRIX8 "X"
#else
#define __STDC_FORMAT_MACROS
#include <stdint.h>
#include <inttypes.h>
#endif
#include <ctype.h>
#if defined(vxWorks) || defined(_WIN32) || defined(__rtems__) #include <ctype.h>
// These systems have no strncasecmp #include <stdlib.h>
static int strncasecmp(const char *s1, const char *s2, size_t n)
{ #if defined(__rtems__)
int r=0; #include <rtems.h>
while (n && (r = toupper(*s1)-toupper(*s2)) == 0) { n--; s1++; s2++; }; #if __RTEMS_MAJOR__ < 5
return r; /* RTEMS has strncasecmp since version 5 */
#define NEED_strncasecmp
#endif
#endif
#ifdef _MSC_VER
/* Windows strncasecmp has a different name. */
#define strncasecmp _strnicmp
#endif
#ifdef NEED_strncasecmp
// Have no strncasecmp but avoid compiler errors in case it exists in future versions
extern "C" {
static int mystrncasecmp(const char *s1, const char *s2, size_t n)
{
int r=0;
while (n && (r = toupper(*s1)-toupper(*s2)) == 0) { n--; s1++; s2++; };
return r;
}
} }
#define strncasecmp mystrncasecmp
#endif #endif
#include "StreamFormatConverter.h" #include "StreamFormatConverter.h"
@ -83,6 +103,33 @@ 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 uint32_t bitsum(const uint8_t* data, size_t len, uint32_t sum)
{
// number of set bits in each byte
const uint8_t table[256] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
while (len--)
{
sum += table[*data++];
}
return sum;
}
static uint32_t crc_0x07(const uint8_t* data, size_t len, uint32_t crc) 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)
@ -501,6 +548,7 @@ static uint32_t leybold(const uint8_t* data, size_t len, uint32_t sum)
sum += *data++; sum += *data++;
} }
sum = ~sum; sum = ~sum;
sum &= 0xff;
if (sum < 32) sum+=32; if (sum < 32) sum+=32;
return sum; return sum;
} }
@ -568,6 +616,16 @@ static uint32_t hexlrc(const uint8_t* data, size_t len, uint32_t sum)
return sum; return sum;
} }
// Checksum used by Spellman High Voltage Supplies MPS
static uint32_t hv_mps(const uint8_t* data, size_t len, uint32_t sum)
{
while (len--)
{
sum += *data++;
}
return (~sum & 0x7F) | 0x40;
}
struct checksum struct checksum
{ {
const char* name; const char* name;
@ -612,20 +670,25 @@ static checksum checksumMap[] =
{"leybold", leybold, 0x00, 0x00, 1}, // 0x22 {"leybold", leybold, 0x00, 0x00, 1}, // 0x22
{"brksCryo",brksCryo, 0x00, 0x00, 1}, // 0x4A {"brksCryo",brksCryo, 0x00, 0x00, 1}, // 0x4A
{"lrc", lrc, 0x00, 0x00, 1}, // 0x23 {"lrc", lrc, 0x00, 0x00, 1}, // 0x23
{"hexlrc", hexlrc, 0x00, 0x00, 1} // 0xA7 {"hexlrc", hexlrc, 0x00, 0x00, 1}, // 0xA7
{"bitsum", bitsum, 0x00, 0x00, 1}, // 0x21
{"bitsum8", bitsum, 0x00, 0x00, 1}, // 0x21
{"bitsum16",bitsum, 0x0000, 0x0000, 2}, // 0x0021
{"bitsum32",bitsum, 0x00000000, 0x00000000, 4}, // 0x00000021
{"hv_mps", hv_mps, 0xFF, 0x00, 1} // 0x63
}; };
static uint32_t 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 scanFormat);
bool printPseudo(const StreamFormat&, StreamBuffer&); bool printPseudo(const StreamFormat&, StreamBuffer&);
ssize_t scanPseudo(const StreamFormat&, StreamBuffer&, size_t& cursor); ssize_t scanPseudo(const StreamFormat&, StreamBuffer&, size_t& cursor);
}; };
int ChecksumConverter:: int ChecksumConverter::
parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool) parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool scanFormat)
{ {
const char* p = strchr(source, '>'); const char* p = strchr(source, '>');
if (!p) if (!p)
@ -679,7 +742,7 @@ parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
info.append(&xorout, sizeof(xorout)); info.append(&xorout, sizeof(xorout));
info.append(fnum); info.append(fnum);
source = p+1; source = p+1;
return pseudo_format; return scanFormat ? needs_original_format : pseudo_format;
} }
} }
@ -694,11 +757,16 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
const char* info = format.info; const char* info = format.info;
uint32_t init = extract<uint32_t>(info); uint32_t init = extract<uint32_t>(info);
uint32_t xorout = extract<uint32_t>(info); uint32_t xorout = extract<uint32_t>(info);
uint_fast8_t fnum = extract<uint8_t>(info); uint8_t fnum = extract<uint8_t>(info);
size_t start = format.width; size_t start = format.width;
size_t length = output.length()-format.width; size_t length = output.length();
if (format.prec > 0) length -= format.prec; if (length >= start) length -= start;
else length = 0;
if (format.prec > 0) {
if (length >= (size_t)format.prec) length -= format.prec;
else length = 0;
}
debug("ChecksumConverter %s: output to check: \"%s\"\n", debug("ChecksumConverter %s: output to check: \"%s\"\n",
checksumMap[fnum].name, output.expand(start,length)()); checksumMap[fnum].name, output.expand(start,length)());
@ -710,8 +778,8 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
debug("ChecksumConverter %s: output checksum is 0x%" PRIX32 "\n", debug("ChecksumConverter %s: output checksum is 0x%" PRIX32 "\n",
checksumMap[fnum].name, sum); checksumMap[fnum].name, sum);
uint_fast8_t i; uint8_t i;
uint_fast8_t outchar; uint8_t outchar;
if (format.flags & sign_flag) // decimal if (format.flags & sign_flag) // decimal
{ {
@ -770,15 +838,19 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
uint32_t init = extract<uint32_t>(info); uint32_t init = extract<uint32_t>(info);
uint32_t xorout = extract<uint32_t>(info); uint32_t xorout = extract<uint32_t>(info);
size_t start = format.width; size_t start = format.width;
uint_fast8_t fnum = extract<uint8_t>(info); uint8_t fnum = extract<uint8_t>(info);
size_t length = cursor-format.width; size_t length = cursor;
if (length >= start) length -= start;
else length = 0;
if (format.prec > 0) {
if (length >= (size_t)format.prec) length -= format.prec;
else length = 0;
}
if (format.prec > 0) length -= format.prec; debug("ChecksumConverter %s: input to check: \"%s\"\n",
debug("ChecksumConverter %s: input to check: \"%s\n",
checksumMap[fnum].name, input.expand(start,length)()); checksumMap[fnum].name, input.expand(start,length)());
uint_fast8_t nDigits = uint8_t nDigits =
// 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 :
@ -787,8 +859,8 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
if ((ssize_t)( input.length() - cursor ) < expectedLength) if ((ssize_t)( input.length() - cursor ) < expectedLength)
{ {
debug("ChecksumConverter %s: Input '%s' too short for checksum\n", debug("ChecksumConverter %s: Input '%s' too short (%zu-%zu<%zu) for checksum\n",
checksumMap[fnum].name, input.expand(cursor)()); checksumMap[fnum].name, input.expand(cursor)(), input.length(), cursor, expectedLength);
return -1; return -1;
} }
@ -821,7 +893,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
else else
if (format.flags & alt_flag) // lsb first (little endian) if (format.flags & alt_flag) // lsb first (little endian)
{ {
uint_fast8_t i; uint8_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
@ -864,8 +936,8 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
} }
else // msb first (big endian) else // msb first (big endian)
{ {
int_fast8_t i; int8_t i;
uint_fast8_t j; uint8_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

View File

@ -27,12 +27,12 @@ include $(TOP)/configure/CONFIG
-include CONFIG_STREAM -include CONFIG_STREAM
-include ../CONFIG_STREAM -include ../CONFIG_STREAM
LIBRARY_DEFAULT = stream LIBRARY_IOC = stream
DBD += $(LIBRARY_DEFAULT).dbd DBD += stream.dbd
DBD += $(LIBRARY_DEFAULT)-base.dbd DBD += stream-base.dbd
ifdef CALC ifneq ($(words $(CALC) $(SYNAPPS)), 0)
DBD += $(LIBRARY_DEFAULT)-scalcout.dbd DBD += stream-scalcout.dbd
endif endif
ifdef ASYN ifdef ASYN
@ -42,7 +42,7 @@ $(warning Asyn not included! Didn't you set ASYN in your RELEASE file?)
endif endif
ifeq ($(LOADABLE_MODULE),YES) ifeq ($(LOADABLE_MODULE),YES)
SRCS += $(LIBRARY_DEFAULT)_registerRecordDeviceDriver.cpp SRCS += stream_registerRecordDeviceDriver.cpp
endif endif
SRCS += $(BUSSES:%=%Interface.cc) SRCS += $(BUSSES:%=%Interface.cc)
SRCS += $(FORMATS:%=%Converter.cc) SRCS += $(FORMATS:%=%Converter.cc)
@ -60,6 +60,9 @@ ifneq ($(words $(PCRE_LIB) $(PCRE_INCLUDE)),0)
LIB_SYS_LIBS_DEFAULT += pcre LIB_SYS_LIBS_DEFAULT += pcre
LIB_SYS_LIBS_WIN32 += $(PCRE_LIB)\\pcre LIB_SYS_LIBS_WIN32 += $(PCRE_LIB)\\pcre
SHRLIB_DEPLIB_DIRS += $(PCRE_LIB) SHRLIB_DEPLIB_DIRS += $(PCRE_LIB)
ifdef ENABLE_STATIC
CPPFLAGS += -DPCRE_STATIC
endif
endif endif
endif endif
@ -98,28 +101,28 @@ streamReferences: ../CONFIG_STREAM
$(PERL) ../makeref.pl Converter $(FORMATS) >> $@ $(PERL) ../makeref.pl Converter $(FORMATS) >> $@
# create stream-base.dbd from all RECORDTYPES except scalcout record # create stream-base.dbd from all RECORDTYPES except scalcout record
$(COMMON_DIR)/$(LIBRARY_DEFAULT)-base.dbd: ../CONFIG_STREAM $(COMMON_DIR)/stream-base.dbd: ../CONFIG_STREAM
$(PERL) ../makedbd.pl $(if $(ASYN),--with-asyn) $(if $(BASE_3_14),,-3.13) $(filter-out scalcout, $(RECORDTYPES)) > $@ $(PERL) ../makedbd.pl $(if $(ASYN),--with-asyn) $(if $(BASE_3_14),,-3.13) $(filter-out scalcout, $(RECORDTYPES)) > $@
$(LIBRARY_DEFAULT)-base.dbd$(DEP): ../CONFIG_STREAM stream-base.dbd$(DEP): ../CONFIG_STREAM
echo $(LIBRARY_DEFAULT)-base.dbd: $< > $@ echo stream-base.dbd: $< > $@
STREAM_DBD_FILES = $(LIBRARY_DEFAULT)-base.dbd STREAM_DBD_FILES = stream-base.dbd
ifdef CALC ifneq ($(words $(CALC) $(SYNAPPS)), 0)
# create stream-scalcout.dbd for scalcout record # create stream-scalcout.dbd for scalcout record
$(COMMON_DIR)/$(LIBRARY_DEFAULT)-scalcout.dbd: ../CONFIG_STREAM $(COMMON_DIR)/stream-scalcout.dbd: ../CONFIG_STREAM
$(PERL) ../makedbd.pl --rec-only scalcout > $@ $(PERL) ../makedbd.pl --rec-only scalcout > $@
$(LIBRARY_DEFAULT)-scalcout.dbd$(DEP): ../CONFIG_STREAM stream-scalcout.dbd$(DEP): ../CONFIG_STREAM
echo $(LIBRARY_DEFAULT)-scalcout.dbd: $< > $@ echo stream-scalcout.dbd: $< > $@
STREAM_DBD_FILES += $(LIBRARY_DEFAULT)-scalcout.dbd STREAM_DBD_FILES += stream-scalcout.dbd
endif endif
# create stream.dbd for all record types # create stream.dbd for all record types
$(COMMON_DIR)/$(LIBRARY_DEFAULT).dbd: ../CONFIG_STREAM $(COMMON_DIR)/stream.dbd: ../CONFIG_STREAM
$(PERL) ../makedbd.pl $(if $(ASYN),--with-asyn) $(if $(BASE_3_14),,-3.13) $(RECORDTYPES) > $@ $(PERL) ../makedbd.pl $(if $(ASYN),--with-asyn) $(if $(BASE_3_14),,-3.13) $(RECORDTYPES) > $@
$(LIBRARY_DEFAULT).dbd$(DEP): ../CONFIG_STREAM stream.dbd$(DEP): ../CONFIG_STREAM
echo $(LIBRARY_DEFAULT).dbd: $< > $@ echo stream.dbd: $< > $@

View File

@ -102,7 +102,7 @@ init(const void* s, ssize_t minsize)
} }
// How the buffer looks like: // How the buffer looks like:
// |----free-----|####used####|--------00--------| // |----junk-----|####used####|--------00--------|
///|<--- offs -->|<-- len --->|<- cap-offs-len ->| ///|<--- offs -->|<-- len --->|<- cap-offs-len ->|
// 0 offs offs+len cap // 0 offs offs+len cap
// |<-------------- minsize ---------------> // |<-------------- minsize --------------->
@ -254,39 +254,71 @@ replace(ssize_t remstart, ssize_t remlen, const void* ins, ssize_t inslen)
if (inslen < 0) inslen = 0; if (inslen < 0) inslen = 0;
size_t remend = remstart+remlen; size_t remend = remstart+remlen;
size_t newlen = len+inslen-remlen; size_t newlen = len+inslen-remlen;
// How the buffer looks like before and after:
// |---junk---|##content_start##|/////////remove_this////////|##content_end##|0000|
// |<- offs ->|<-- remstart --->|<--------- remlen --------->| | |
// | |<--------------------- len ---------------------------------->| |
// 0 offs offs+remstart offs+remend offs+len cap
//
// If content size stays the same, no need to move old content:
// |---junk---|##content_start##|+++++++inserted_text++++++++|##content_end##|0000|
// |<----- inslen==remlen ----->| newlen==len
//
// If content shrinks (need to clear end of buffer): |< clear this >|
// |---junk---|##content_start##|inserted_text|##content_end##|00000000000000|0000|
// 0 offs |<- inslen -->| |< len-newlen >|
// offs+newlen offs+len
//
// If content grows but still fits (make sure to keep at least one 0 byte at end):
// |---junk---|##content_start##|++++++++inserted_text++++++++++|##content_end##|0|
// |<- offs ->|<--------------------- newlen ---------------------------------->| |
// 0 offs offs+newlen<cap
//
// If content would overflow, moving to offs 0 may help:
// May need to clear end if newlen < offs+len: |<clear>|
// |##content_start##|++++++++inserted_text++++++++++|##content_end##|0000000|0000|
// |<--------------------- newlen ---------------------------------->| |
// newlen offs+len
//
// Otherwise we need to copy to a new buffer.
if (cap <= newlen) if (cap <= newlen)
{ {
// buffer too short // buffer too short, copy to new buffer
size_t newcap; size_t newcap;
for (newcap = sizeof(local)*2; newcap <= newlen; newcap *= 2); for (newcap = sizeof(local)*2; newcap <= newlen; newcap *= 2);
char* newbuffer = new char[newcap]; char* newbuffer = new char[newcap];
memcpy(newbuffer, buffer+offs, remstart); memcpy(newbuffer, buffer+offs, remstart); // copy content start
memcpy(newbuffer+remstart, ins, inslen); memcpy(newbuffer+remstart, ins, inslen); // insert
memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend); memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend); // copy content end
memset(newbuffer+newlen, 0, newcap-newlen); memset(newbuffer+newlen, 0, newcap-newlen); // clear buffer end
if (buffer != local) if (buffer != local)
{ delete[] buffer;
delete [] buffer;
}
buffer = newbuffer; buffer = newbuffer;
cap = newcap; cap = newcap;
offs = 0; offs = 0;
} }
else else
{ {
if (newlen+offs<=cap) if (offs+newlen < cap)
{ {
// move to start of buffer // modified content still fits with current offs, just move content end
memmove(buffer+offs+remstart+inslen, buffer+offs+remend, len-remend); if (newlen != len)
memcpy(buffer+offs+remstart, ins, inslen); memmove(buffer+offs+remstart+inslen, buffer+offs+remend, len-remend); // move old content end if necessary
if (newlen<len) memset(buffer+offs+newlen, 0, len-newlen); memcpy(buffer+offs+remstart, ins, inslen); // insert before
if (newlen < len)
memset(buffer+offs+newlen, 0, len-newlen); // clear buffer end if content shrunk
} }
else else
{ {
memmove(buffer,buffer+offs,remstart); // move content to start of buffer
memmove(buffer+remstart+inslen, buffer+offs+remend, len-remend); memmove(buffer, buffer+offs, remstart); // move content start to 0 offs
memcpy(buffer+remstart, ins, inslen); memmove(buffer+remstart+inslen, buffer+offs+remend, len-remend); // move content end
if (newlen<len) memset(buffer+newlen, 0, len-newlen); memcpy(buffer+remstart, ins, inslen); // insert in between
if (newlen < offs+len)
memset(buffer+newlen, 0, offs+len-newlen); // clear buffer end if necessary
offs = 0; offs = 0;
} }
} }
@ -358,7 +390,7 @@ dump() const
StreamBuffer result; StreamBuffer result;
size_t i; size_t i;
result.print("%" P "d,%" P "d,%" P "d:", offs, len, cap); result.print("%" P "d,%" P "d,%" P "d:", offs, len, cap);
if (offs) result.print(ansiEscape(ANSI_BG_WHITE)); if (offs) result.print("%s", ansiEscape(ANSI_BG_WHITE));
char c; char c;
for (i = 0; i < cap; i++) for (i = 0; i < cap; i++)
{ {

View File

@ -603,6 +603,7 @@ evalOut()
// flush all unread input // flush all unread input
unparsedInput = false; unparsedInput = false;
inputBuffer.clear(); inputBuffer.clear();
inputLine.clear();
if (!formatOutput()) if (!formatOutput())
{ {
finishProtocol(FormatError); finishProtocol(FormatError);
@ -1011,6 +1012,7 @@ readCallback(StreamIoStatus status,
finishProtocol(Fault); finishProtocol(Fault);
return 0; return 0;
} }
inputHook(input, size);
inputBuffer.append(input, size); inputBuffer.append(input, size);
debug("StreamCore::readCallback(%s) inputBuffer=\"%s\", size %" Z "u\n", debug("StreamCore::readCallback(%s) inputBuffer=\"%s\", size %" Z "u\n",
name(), inputBuffer.expand()(), inputBuffer.length()); name(), inputBuffer.expand()(), inputBuffer.length());
@ -1130,7 +1132,7 @@ readCallback(StreamIoStatus status,
inputBuffer.remove(end + termlen); inputBuffer.remove(end + termlen);
if (inputBuffer) if (inputBuffer)
{ {
debug("StreamCore::readCallback(%s) unpared input left: \"%s\"\n", debug("StreamCore::readCallback(%s) unparsed input left: \"%s\"\n",
name(), inputBuffer.expand()()); name(), inputBuffer.expand()());
unparsedInput = true; unparsedInput = true;
} }
@ -1182,6 +1184,7 @@ matchInput()
char command; char command;
const char* fieldName = NULL; const char* fieldName = NULL;
StreamBuffer formatstring; StreamBuffer formatstring;
ssize_t delta = 0;
consumedInput = 0; consumedInput = 0;
@ -1216,7 +1219,7 @@ normal_format:
debug("StreamCore::matchInput(%s): format = \"%%%s\"\n", debug("StreamCore::matchInput(%s): format = \"%%%s\"\n",
name(), formatstring()); name(), formatstring());
if (fmt.flags & skip_flag || fmt.type == pseudo_format) if (fmt.flags & skip_flag || fmt.type == pseudo_format || fmt.type == needs_original_format)
{ {
long ldummy; long ldummy;
double ddummy; double ddummy;
@ -1238,9 +1241,20 @@ normal_format:
scanString(fmt, inputLine(consumedInput), NULL, size); scanString(fmt, inputLine(consumedInput), NULL, size);
break; break;
case pseudo_format: case pseudo_format:
// pass complete input // pass complete input line for scan and/or re-write
size = inputLine.length();
consumed = StreamFormatConverter::find(fmt.conv)-> consumed = StreamFormatConverter::find(fmt.conv)->
scanPseudo(fmt, inputLine, consumedInput); scanPseudo(fmt, inputLine, consumedInput);
delta += inputLine.length() - size; // track length changes
debug("after rewrite delta=%zi\n", delta);
break;
case needs_original_format:
// pass original input with adjusted current position
debug("before checksum delta=%zi\n", delta);
consumedInput -= delta; // correct for length changes
consumed = StreamFormatConverter::find(fmt.conv)->
scanPseudo(fmt, inputBuffer, consumedInput);
consumedInput += delta;
break; break;
default: default:
error("INTERNAL ERROR (%s): illegal format.type 0x%02x\n", error("INTERNAL ERROR (%s): illegal format.type 0x%02x\n",

View File

@ -219,6 +219,7 @@ protected:
// virtual methods // virtual methods
virtual void protocolStartHook() {} virtual void protocolStartHook() {}
virtual void inputHook(const void* input, size_t size) {};
virtual void protocolFinishHook(ProtocolResult) {} virtual void protocolFinishHook(ProtocolResult) {}
virtual void startTimer(unsigned long timeout) = 0; virtual void startTimer(unsigned long timeout) = 0;
virtual bool formatValue(const StreamFormat&, const void* fieldaddress) = 0; virtual bool formatValue(const StreamFormat&, const void* fieldaddress) = 0;

View File

@ -25,6 +25,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#if defined(vxWorks) #if defined(vxWorks)
#include <symLib.h> #include <symLib.h>
@ -136,6 +137,7 @@ class Stream : protected StreamCore
#endif #endif
// StreamCore methods // StreamCore methods
void inputHook(const void* input, size_t size);
void protocolFinishHook(ProtocolResult); void protocolFinishHook(ProtocolResult);
void startTimer(unsigned long timeout); void startTimer(unsigned long timeout);
bool getFieldAddress(const char* fieldname, bool getFieldAddress(const char* fieldname,
@ -435,6 +437,14 @@ long streamReportRecord(const char* recordname)
return OK; return OK;
} }
#if defined(_WIN32) && !defined(_WIN64)
static const char* epicsThreadGetNameSelfWrapper(void)
{
return epicsThreadGetNameSelf();
}
#define epicsThreadGetNameSelf epicsThreadGetNameSelfWrapper
#endif
long Stream:: long Stream::
drvInit() drvInit()
{ {
@ -925,6 +935,10 @@ process()
debug("Stream::process(%s) start\n", name()); debug("Stream::process(%s) start\n", name());
status = NO_ALARM; status = NO_ALARM;
convert = OK; convert = OK;
if (record->tpro)
{
StreamDebugClass(record->name).print("start protocol '%s'\n", protocolname());
}
if (!startProtocol(record->proc == 2 ? StreamCore::StartInit : StreamCore::StartNormal)) if (!startProtocol(record->proc == 2 ? StreamCore::StartInit : StreamCore::StartNormal))
{ {
debug("Stream::process(%s): could not start %sprotocol, status=%s (%d)\n", debug("Stream::process(%s): could not start %sprotocol, status=%s (%d)\n",
@ -1019,11 +1033,26 @@ expire(const epicsTime&)
// StreamCore virtual methods //////////////////////////////////////////// // StreamCore virtual methods ////////////////////////////////////////////
void Stream::
inputHook(const void* input, size_t size)
{
if (record->tpro > 1)
{
StreamDebugClass(record->name).print("received \"%s\"\n",
StreamBuffer(input, size).expand()());
}
}
void Stream:: void Stream::
protocolFinishHook(ProtocolResult result) protocolFinishHook(ProtocolResult result)
{ {
debug("Stream::protocolFinishHook(%s, %s)\n", debug("Stream::protocolFinishHook(%s, %s)\n",
name(), toStr(result)); name(), toStr(result));
if (record->tpro)
{
StreamDebugClass(record->name).print("%s. out=\"%s\", in=\"%s\"\n",
toStr(result), outputLine.expand()(), inputLine.expand()());
}
switch (result) switch (result)
{ {
case Success: case Success:

View File

@ -171,8 +171,6 @@ print(const char* fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
const char* f = strrchr(file, '/');
if (f) f++; else f = file;
FILE* fp = StreamDebugFile ? StreamDebugFile : stderr; FILE* fp = StreamDebugFile ? StreamDebugFile : stderr;
if (streamMsgTimeStamped) if (streamMsgTimeStamped)
{ {
@ -184,7 +182,13 @@ print(const char* fmt, ...)
{ {
fprintf(fp, "%s ", StreamGetThreadNameFunction()); fprintf(fp, "%s ", StreamGetThreadNameFunction());
} }
fprintf(fp, "%s:%d: ", f, line); if (file) {
const char* f = strrchr(file, '/');
if (f) f++; else f = file;
fprintf(fp, "%s:", f);
if (line) fprintf(fp, "%d:", line);
fprintf(fp, " ");
}
vfprintf(fp, fmt, args); vfprintf(fp, fmt, args);
fflush(fp); fflush(fp);
va_end(args); va_end(args);

View File

@ -56,19 +56,15 @@ class StreamDebugClass
const char* file; const char* file;
int line; int line;
public: public:
StreamDebugClass(const char* file, int line) : StreamDebugClass(const char* file = NULL, int line = 0) :
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
StreamDebugObject(const char* file, int line)
{ return StreamDebugClass(file, line); }
#define error StreamError #define error StreamError
#define debug (!streamDebug)?0:StreamDebugObject(__FILE__,__LINE__).print #define debug (!streamDebug)?0:StreamDebugClass(__FILE__,__LINE__).print
#define debug2 (streamDebug<2)?0:StreamDebugObject(__FILE__,__LINE__).print #define debug2 (streamDebug<2)?0:StreamDebugClass(__FILE__,__LINE__).print
/* /*
* ANSI escape sequences for terminal output * ANSI escape sequences for terminal output

View File

@ -42,7 +42,8 @@ typedef enum {
enum_format, enum_format,
double_format, double_format,
string_format, string_format,
pseudo_format pseudo_format,
needs_original_format
} StreamFormatType; } StreamFormatType;
extern const char* StreamFormatTypeStr[]; extern const char* StreamFormatTypeStr[];

View File

@ -43,7 +43,7 @@ static long readData(dbCommon *record, format_t *format)
strncmp(so->oval, so->val, sizeof(so->val))) strncmp(so->oval, so->val, sizeof(so->val)))
{ {
monitor_mask |= DBE_VALUE | DBE_LOG; monitor_mask |= DBE_VALUE | DBE_LOG;
strncpy(so->oval, so->val, sizeof(so->val)); strncpy(so->oval, so->val, sizeof(so->oval));
} }
if (monitor_mask) if (monitor_mask)
db_post_events(record, so->val, monitor_mask); db_post_events(record, so->val, monitor_mask);

View File

@ -42,10 +42,12 @@ PROD_SRCS_vxWorks = -nil-
PROD_LIBS = stream PROD_LIBS = stream
ifdef ASYN ifdef ASYN
# edit asynRegistrars.dbd if necessary streamApp_DBD += asyn.dbd
streamApp_DBD += asynRegistrars.dbd streamApp_DBD += drvAsynIPPort.dbd
# add asynRecord.dbd if you like streamApp_DBD += drvAsynSerialPort.dbd
streamApp_DBD += asynRecord.dbd # vxi11 support is optional in recent asyn versions
#streamApp_DBD += drvVxi11.dbd
PROD_LIBS += asyn PROD_LIBS += asyn
# cygwin needs separate RPC library for asyn # cygwin needs separate RPC library for asyn
PROD_SYS_LIBS_cygwin32 += $(CYGWIN_RPC_LIB) PROD_SYS_LIBS_cygwin32 += $(CYGWIN_RPC_LIB)
@ -78,6 +80,13 @@ endif
PROD_LIBS += $(EPICS_BASE_IOC_LIBS) PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
# Some linux systems moved RPC related symbols to libtirpc
# Define TIRPC in configure/CONFIG_SITE in this case
ifeq ($(TIRPC),YES)
USR_INCLUDES_Linux += -I/usr/include/tirpc
PROD_SYS_LIBS_DEFAULT += tirpc
endif
# switch off annoying rset warnings in 3.16+ # switch off annoying rset warnings in 3.16+
CPPFLAGS += -DUSE_TYPED_RSET CPPFLAGS += -DUSE_TYPED_RSET

View File

@ -1,9 +0,0 @@
registrar(asynRegister)
registrar(asynInterposeFlushRegister)
registrar(asynInterposeEosRegister)
# asynDriver up to version 4-16 does not support serial port for Windows!
registrar(drvAsynSerialPortRegisterCommands)
registrar(drvAsynIPPortRegisterCommands)
registrar(drvAsynIPServerPortRegisterCommands)
registrar(vxi11RegisterCommands)

View File

@ -19,7 +19,7 @@
# along with StreamDevice. If not, see https://www.gnu.org/licenses/. # along with StreamDevice. If not, see https://www.gnu.org/licenses/.
#########################################################################/ #########################################################################/
terminator = CR LF; terminator = LF;
cmd { cmd {
out "%s"; out "%s";

View File

@ -52,7 +52,11 @@ set protocol {
out "jamcrc %s %9.1<jamcrc>"; in "jamcrc %=s %9.1<jamcrc>"; out "jamcrc %s %9.1<jamcrc>"; in "jamcrc %=s %9.1<jamcrc>";
out "adler32 %s %9.1<adler32>"; in "adler32 %=s %9.1<adler32>"; out "adler32 %s %9.1<adler32>"; in "adler32 %=s %9.1<adler32>";
out "hexsum8 %s %9.1<hexsum8>"; in "hexsum8 %=s %9.1<hexsum8>"; out "hexsum8 %s %9.1<hexsum8>"; in "hexsum8 %=s %9.1<hexsum8>";
out "bitsum %s %9.1<bitsum>"; in "bitsum %=s %9.1<bitsum>";
out "bitsum8 %s %9.1<bitsum8>"; in "bitsum8 %=s %9.1<bitsum8>";
out "bitsum16 %s %9.1<bitsum16>"; in "bitsum16 %=s %9.1<bitsum16>";
out "bitsum32 %s %9.1<bitsum32>"; in "bitsum32 %=s %9.1<bitsum32>";
out "sum %s %09.1<sum>"; in "sum %=s %09.1<sum>"; out "sum %s %09.1<sum>"; in "sum %=s %09.1<sum>";
out "sum8 %s %09.1<sum8>"; in "sum8 %=s %09.1<sum8>"; out "sum8 %s %09.1<sum8>"; in "sum8 %=s %09.1<sum8>";
out "sum16 %s %09.1<sum16>"; in "sum16 %=s %09.1<sum16>"; out "sum16 %s %09.1<sum16>"; in "sum16 %=s %09.1<sum16>";
@ -88,6 +92,10 @@ set protocol {
out "jamcrc %s %09.1<jamcrc>"; in "jamcrc %=s %09.1<jamcrc>"; out "jamcrc %s %09.1<jamcrc>"; in "jamcrc %=s %09.1<jamcrc>";
out "adler32 %s %09.1<adler32>"; in "adler32 %=s %09.1<adler32>"; out "adler32 %s %09.1<adler32>"; in "adler32 %=s %09.1<adler32>";
out "hexsum8 %s %09.1<hexsum8>"; in "hexsum8 %=s %09.1<hexsum8>"; out "hexsum8 %s %09.1<hexsum8>"; in "hexsum8 %=s %09.1<hexsum8>";
out "bitsum %s %09.1<bitsum>"; in "bitsum %=s %09.1<bitsum>";
out "bitsum8 %s %09.1<bitsum8>"; in "bitsum8 %=s %09.1<bitsum8>";
out "bitsum16 %s %09.1<bitsum16>"; in "bitsum16 %=s %09.1<bitsum16>";
out "bitsum32 %s %09.1<bitsum32>"; in "bitsum32 %=s %09.1<bitsum32>";
out "sum %s %-9.1<sum>"; in "sum %=s %-9.1<sum>"; out "sum %s %-9.1<sum>"; in "sum %=s %-9.1<sum>";
out "sum8 %s %-9.1<sum8>"; in "sum8 %=s %-9.1<sum8>"; out "sum8 %s %-9.1<sum8>"; in "sum8 %=s %-9.1<sum8>";
@ -124,6 +132,10 @@ set protocol {
out "jamcrc %s %-9.1<jamcrc>"; in "jamcrc %=s %-9.1<jamcrc>"; out "jamcrc %s %-9.1<jamcrc>"; in "jamcrc %=s %-9.1<jamcrc>";
out "adler32 %s %-9.1<adler32>"; in "adler32 %=s %-9.1<adler32>"; out "adler32 %s %-9.1<adler32>"; in "adler32 %=s %-9.1<adler32>";
out "hexsum8 %s %-9.1<hexsum8>"; in "hexsum8 %=s %-9.1<hexsum8>"; out "hexsum8 %s %-9.1<hexsum8>"; in "hexsum8 %=s %-9.1<hexsum8>";
out "bitsum %s %-9.1<bitsum>"; in "bitsum %=s %-9.1<bitsum>";
out "bitsum8 %s %-9.1<bitsum8>"; in "bitsum8 %=s %-9.1<bitsum8>";
out "bitsum16 %s %-9.1<bitsum16>"; in "bitsum16 %=s %-9.1<bitsum16>";
out "bitsum32 %s %-9.1<bitsum32>"; in "bitsum32 %=s %-9.1<bitsum32>";
out "sum %s %#9.1<sum>"; in "sum %=s %#9.1<sum>"; out "sum %s %#9.1<sum>"; in "sum %=s %#9.1<sum>";
out "sum8 %s %#9.1<sum8>"; in "sum8 %=s %#9.1<sum8>"; out "sum8 %s %#9.1<sum8>"; in "sum8 %=s %#9.1<sum8>";
@ -160,7 +172,11 @@ set protocol {
out "jamcrc %s %#9.1<jamcrc>"; in "jamcrc %=s %#9.1<jamcrc>"; out "jamcrc %s %#9.1<jamcrc>"; in "jamcrc %=s %#9.1<jamcrc>";
out "adler32 %s %#9.1<adler32>"; in "adler32 %=s %#9.1<adler32>"; out "adler32 %s %#9.1<adler32>"; in "adler32 %=s %#9.1<adler32>";
out "hexsum8 %s %#9.1<hexsum8>"; in "hexsum8 %=s %#9.1<hexsum8>"; out "hexsum8 %s %#9.1<hexsum8>"; in "hexsum8 %=s %#9.1<hexsum8>";
out "bitsum %s %#9.1<bitsum>"; in "bitsum %=s %#9.1<bitsum>";
out "bitsum8 %s %#9.1<bitsum8>"; in "bitsum8 %=s %#9.1<bitsum8>";
out "bitsum16 %s %#9.1<bitsum16>"; in "bitsum16 %=s %#9.1<bitsum16>";
out "bitsum32 %s %#9.1<bitsum32>"; in "bitsum32 %=s %#9.1<bitsum32>";
out "sum %s %#09.1<sum>"; in "sum %=s %#09.1<sum>"; out "sum %s %#09.1<sum>"; in "sum %=s %#09.1<sum>";
out "sum8 %s %#09.1<sum8>"; in "sum8 %=s %#09.1<sum8>"; out "sum8 %s %#09.1<sum8>"; in "sum8 %=s %#09.1<sum8>";
out "sum16 %s %#09.1<sum16>"; in "sum16 %=s %#09.1<sum16>"; out "sum16 %s %#09.1<sum16>"; in "sum16 %=s %#09.1<sum16>";
@ -196,7 +212,11 @@ set protocol {
out "jamcrc %s %#09.1<jamcrc>"; in "jamcrc %=s %#09.1<jamcrc>"; out "jamcrc %s %#09.1<jamcrc>"; in "jamcrc %=s %#09.1<jamcrc>";
out "adler32 %s %#09.1<adler32>"; in "adler32 %=s %#09.1<adler32>"; out "adler32 %s %#09.1<adler32>"; in "adler32 %=s %#09.1<adler32>";
out "hexsum8 %s %#09.1<hexsum8>"; in "hexsum8 %=s %#09.1<hexsum8>"; out "hexsum8 %s %#09.1<hexsum8>"; in "hexsum8 %=s %#09.1<hexsum8>";
out "bitsum %s %#09.1<bitsum>"; in "bitsum %=s %#09.1<bitsum>";
out "bitsum8 %s %#09.1<bitsum8>"; in "bitsum8 %=s %#09.1<bitsum8>";
out "bitsum16 %s %#09.1<bitsum16>"; in "bitsum16 %=s %#09.1<bitsum16>";
out "bitsum32 %s %#09.1<bitsum32>"; in "bitsum32 %=s %#09.1<bitsum32>";
out "sum %s %#-9.1<sum>"; in "sum %=s %#-9.1<sum>"; out "sum %s %#-9.1<sum>"; in "sum %=s %#-9.1<sum>";
out "sum8 %s %#-9.1<sum8>"; in "sum8 %=s %#-9.1<sum8>"; out "sum8 %s %#-9.1<sum8>"; in "sum8 %=s %#-9.1<sum8>";
out "sum16 %s %#-9.1<sum16>"; in "sum16 %=s %#-9.1<sum16>"; out "sum16 %s %#-9.1<sum16>"; in "sum16 %=s %#-9.1<sum16>";
@ -232,6 +252,13 @@ set protocol {
out "jamcrc %s %#-9.1<jamcrc>"; in "jamcrc %=s %#-9.1<jamcrc>"; out "jamcrc %s %#-9.1<jamcrc>"; in "jamcrc %=s %#-9.1<jamcrc>";
out "adler32 %s %#-9.1<adler32>"; in "adler32 %=s %#-9.1<adler32>"; out "adler32 %s %#-9.1<adler32>"; in "adler32 %=s %#-9.1<adler32>";
out "hexsum8 %s %#-9.1<hexsum8>"; in "hexsum8 %=s %#-9.1<hexsum8>"; out "hexsum8 %s %#-9.1<hexsum8>"; in "hexsum8 %=s %#-9.1<hexsum8>";
out "bitsum %s %#-9.1<bitsum>"; in "bitsum %=s %#-9.1<bitsum>";
out "bitsum8 %s %#-9.1<bitsum8>"; in "bitsum8 %=s %#-9.1<bitsum8>";
out "bitsum16 %s %#-9.1<bitsum16>"; in "bitsum16 %=s %#-9.1<bitsum16>";
out "bitsum32 %s %#-9.1<bitsum32>"; in "bitsum32 %=s %#-9.1<bitsum32>";
# Check combination of regsub and checksum. Always check what the device sees.
out "crc8 %s%#/[0-9]{2}/&:/ %9.1<crc8>"; in "crc8 %#/[0-9]{2}/&:/%s %9.1<crc8>"; out "%s";
out "DONE"; out "DONE";
} }
} }
@ -313,7 +340,15 @@ assure "adler32 123456789 \x09\x1E\x01\xDE\n"
send "adler32 123456789 \x09\x1E\x01\xDE\n" send "adler32 123456789 \x09\x1E\x01\xDE\n"
assure "hexsum8 123456789 \x2D\n" assure "hexsum8 123456789 \x2D\n"
send "hexsum8 123456789 \x2D\n" send "hexsum8 123456789 \x2D\n"
assure "bitsum 123456789 \x21\n"
send "bitsum 123456789 \x21\n"
assure "bitsum8 123456789 \x21\n"
send "bitsum8 123456789 \x21\n"
assure "bitsum16 123456789 \x00\x21\n"
send "bitsum16 123456789 \x00\x21\n"
assure "bitsum32 123456789 \x00\x00\x00\x21\n"
send "bitsum32 123456789 \x00\x00\x00\x21\n"
assure "sum 123456789 DD\n" assure "sum 123456789 DD\n"
send "sum 123456789 DD\n" send "sum 123456789 DD\n"
assure "sum8 123456789 DD\n" assure "sum8 123456789 DD\n"
@ -384,7 +419,15 @@ assure "adler32 123456789 091E01DE\n"
send "adler32 123456789 091E01DE\n" send "adler32 123456789 091E01DE\n"
assure "hexsum8 123456789 2D\n" assure "hexsum8 123456789 2D\n"
send "hexsum8 123456789 2D\n" send "hexsum8 123456789 2D\n"
assure "bitsum 123456789 21\n"
send "bitsum 123456789 21\n"
assure "bitsum8 123456789 21\n"
send "bitsum8 123456789 21\n"
assure "bitsum16 123456789 0021\n"
send "bitsum16 123456789 0021\n"
assure "bitsum32 123456789 00000021\n"
send "bitsum32 123456789 00000021\n"
assure "sum 123456789 \x3D\x3D\n" assure "sum 123456789 \x3D\x3D\n"
send "sum 123456789 \x3D\x3D\n" send "sum 123456789 \x3D\x3D\n"
assure "sum8 123456789 \x3D\x3D\n" assure "sum8 123456789 \x3D\x3D\n"
@ -455,7 +498,15 @@ assure "adler32 123456789 \x30\x39\x31\x3E\x30\x31\x3D\x3E\n"
send "adler32 123456789 \x30\x39\x31\x3E\x30\x31\x3D\x3E\n" send "adler32 123456789 \x30\x39\x31\x3E\x30\x31\x3D\x3E\n"
assure "hexsum8 123456789 \x32\x3D\n" assure "hexsum8 123456789 \x32\x3D\n"
send "hexsum8 123456789 \x32\x3D\n" send "hexsum8 123456789 \x32\x3D\n"
assure "bitsum 123456789 \x32\x31\n"
send "bitsum 123456789 \x32\x31\n"
assure "bitsum8 123456789 \x32\x31\n"
send "bitsum8 123456789 \x32\x31\n"
assure "bitsum16 123456789 \x30\x30\x32\x31\n"
send "bitsum16 123456789 \x30\x30\x32\x31\n"
assure "bitsum32 123456789 \x30\x30\x30\x30\x30\x30\x32\x31\n"
send "bitsum32 123456789 \x30\x30\x30\x30\x30\x30\x32\x31\n"
assure "sum 123456789 \xDD\n" assure "sum 123456789 \xDD\n"
send "sum 123456789 \xDD\n" send "sum 123456789 \xDD\n"
assure "sum8 123456789 \xDD\n" assure "sum8 123456789 \xDD\n"
@ -526,7 +577,15 @@ assure "adler32 123456789 \xDE\x01\x1E\x09\n"
send "adler32 123456789 \xDE\x01\x1E\x09\n" send "adler32 123456789 \xDE\x01\x1E\x09\n"
assure "hexsum8 123456789 \x2D\n" assure "hexsum8 123456789 \x2D\n"
send "hexsum8 123456789 \x2D\n" send "hexsum8 123456789 \x2D\n"
assure "bitsum 123456789 \x21\n"
send "bitsum 123456789 \x21\n"
assure "bitsum8 123456789 \x21\n"
send "bitsum8 123456789 \x21\n"
assure "bitsum16 123456789 \x21\x00\n"
send "bitsum16 123456789 \x21\x00\n"
assure "bitsum32 123456789 \x21\x00\x00\x00\n"
send "bitsum32 123456789 \x21\x00\x00\x00\n"
assure "sum 123456789 DD\n" assure "sum 123456789 DD\n"
send "sum 123456789 DD\n" send "sum 123456789 DD\n"
assure "sum8 123456789 DD\n" assure "sum8 123456789 DD\n"
@ -597,7 +656,15 @@ assure "adler32 123456789 DE011E09\n"
send "adler32 123456789 DE011E09\n" send "adler32 123456789 DE011E09\n"
assure "hexsum8 123456789 2D\n" assure "hexsum8 123456789 2D\n"
send "hexsum8 123456789 2D\n" send "hexsum8 123456789 2D\n"
assure "bitsum 123456789 21\n"
send "bitsum 123456789 21\n"
assure "bitsum8 123456789 21\n"
send "bitsum8 123456789 21\n"
assure "bitsum16 123456789 2100\n"
send "bitsum16 123456789 2100\n"
assure "bitsum32 123456789 21000000\n"
send "bitsum32 123456789 21000000\n"
assure "sum 123456789 \x3D\x3D\n" assure "sum 123456789 \x3D\x3D\n"
send "sum 123456789 \x3D\x3D\n" send "sum 123456789 \x3D\x3D\n"
assure "sum8 123456789 \x3D\x3D\n" assure "sum8 123456789 \x3D\x3D\n"
@ -668,6 +735,20 @@ assure "adler32 123456789 \x3D\x3E\x30\x31\x31\x3E\x30\x39\n"
send "adler32 123456789 \x3D\x3E\x30\x31\x31\x3E\x30\x39\n" send "adler32 123456789 \x3D\x3E\x30\x31\x31\x3E\x30\x39\n"
assure "hexsum8 123456789 \x32\x3D\n" assure "hexsum8 123456789 \x32\x3D\n"
send "hexsum8 123456789 \x32\x3D\n" send "hexsum8 123456789 \x32\x3D\n"
assure "bitsum 123456789 \x32\x31\n"
send "bitsum 123456789 \x32\x31\n"
assure "bitsum8 123456789 \x32\x31\n"
send "bitsum8 123456789 \x32\x31\n"
assure "bitsum16 123456789 \x32\x31\x30\x30\n"
send "bitsum16 123456789 \x32\x31\x30\x30\n"
assure "bitsum32 123456789 \x32\x31\x30\x30\x30\x30\x30\x30\n"
send "bitsum32 123456789 \x32\x31\x30\x30\x30\x30\x30\x30\n"
# check regsub and checksums
assure "crc8 12:34:56:78:9 \x07\n" ;# modified output string and checksum
send "crc8 123456789 \xF4\n" ;# original input string and checksum
assure "12:34:56:78:9\n" ;# modified input string
assure "DONE\n" assure "DONE\n"
finish finish