A protocol file describes the communication with one device type. It contains protocols for each function of the device type and variables which affect how the commands in a protocol work. It does not contain information about the individual device or the used communication bus.
Each device type should have its own protocol file.
I suggest to choose a file name that contains the name of the device type.
Don't use spaces in the file name and keep it short.
The file will be referenced by its name in the INP
or OUT
link of the records which use it.
The protocol file must be stored in one of the directories listed
in the environment variable STREAM_PROTOCOL_PATH
(see chapter Setup).
The protocol file is a plain text file.
Everything not enclosed in quotes
(single '
or double "
) is not case sensitive.
This includes the names of commands,
protocols and variables.
There may be any amount of whitespaces (space, tab, newline, ...) or
comments between names, quoted strings and special
characters, such as ={};
.
A comment is everything starting from an unquoted #
until the end of the line.
# This is an example protocol file Terminator = CR LF; # Frequency is a float # use ai and ao records getFrequency { out "FREQ?"; in "%f"; } setFrequency { out "FREQ %f"; @init { getFrequency; } } # Switch is an enum, either OFF or ON # use bi and bo records getSwitch { out "SW?"; in "SW %{OFF|ON}"; } setSwitch { out "SW %{OFF|ON}"; @init { getSwitch; } } # Connect a stringout record to this to get # a generic command interface. # After processing finishes, the record contains the reply. debug { ExtraInput = Ignore; out "%s"; in "%39c" }
For each function of the device type, define one protocol.
A protocol consists of a name followed by a body in braces {}
.
The name must be unique within the protocol file.
It is used to reference the protocol in the
INP
or OUT
link of the record,
thus keep it short.
It should describe the function of the protocol.
It must not contain spaces or any of the characters
,;={}()$'"\#
.
The protocol body contains a sequence of commands and
optionally variable assignments separated by
;
.
To save some typing, a previously defined protocol can be called inside
another protocol like a command without parameters.
The protocol name is replaced by the commands in the referenced protocol.
However, this does not include any
variable assignments or
exception handlers from the referenced protocol.
See the @init
handlers in the above example.
The StreamDevice protocol is not a programming language. It has neither loops nor conditionals (in this version of StreamDevice). However, if an error occurs, e.g. a timeout or a mismatch in input parsing, an exception handler can be called to clean up.
Seven different commands can be used in a protocol:
out
, in
, wait
, event
,
exec
, disconnect
, and connect
.
Most protocols will consist only of a single out
command to
write some value,
or an out
command followed by an in
command to
read a value.
But there can be any number of commands in a protocol.
out string;
in string;
in
command.
If a device, for example, acknowledges a setting, use an
in
command to check the acknowledge, even though
it contains no user data.
wait milliseconds;
event(eventcode) milliseconds;
eventcode
with some timeout.
What an event actually means depends on the used
bus.
Some buses do not support events at all, some provide many different
events.
If the bus supports only one event, (eventcode)
is dispensable.
exec string;
disconnect;
in
or out
command will automatically
reconnect.
Only records reading in
"I/O Intr" mode
will not cause a reconnect.
connect milliseconds;
milliseconds
timeout.
Since connection is handled automatically, this command is normally not
needed.
It may be useful after a disconnect
.
In a StreamDevice protocol file, strings can be written as quoted literals (single quotes or double quotes), as a sequence of bytes values, or as a combination of both.
Examples for quoted literals are:
"That's a string."
'Say "Hello"'
There is no difference between double quoted and single quoted literals, it just makes it easier to use quotes of the other type in a string. To break long strings into multiple lines of the protocol file, close the quotes before the line break and reopen them in the next line. Don't use a line break inside quotes.
As arguments of out
or in
commands, string literals can contain
format converters.
A format converter starts with %
and works similar
to formats in the C functions printf() and scanf().
StreamDevice uses the backslash character \
to
define some escape sequences in quoted string literals:
\"
, \'
, \%
, and \\
mean literal "
, '
, %
, and
\
.
\a
means alarm bell (ASCII code 7).
\b
means backspace (ASCII code 8).
\t
means tab (ASCII code 9).
\n
means new line (ASCII code 10).
\r
means carriage return (ASCII code 13).
\e
means escape (ASCII code 27).
\x
followed by up to two hexadecimal digits means a byte with
that hex value.
\0
followed by up to three octal digits means a byte with
that octal value.
\1
to \9
followed by up to two more decimal
digits means a byte with that decimal value.
\?
in the argument string of an in
command matches any input byte
\$
followed by the name of a
protocol varible is replaced by the contents of that
variable.
For non-printable characters, it is often easier to write sequences of
byte values instead of escaped quoted string literals.
A byte is written as an unquoted decimal, hexadecimal, or octal
number in the range of -128 to 255 (-0x80 to 0xff, -0200 to 0377).
StreamDevice also defines some symbolic names for frequently
used byte codes as aliases for the numeric byte value:
EOT
means end of transmission (ASCII code 4).
ACK
means acknowledge (ASCII code 6).
BEL
means bell (ASCII code 7).
BS
means backspace (ASCII code 8).
HT
or TAB
mean horizontal tabulator
(ASCII code 9).
LF
or NL
mean line feed /
new line (ASCII code 10).
CR
means carriage return (ASCII code 13).
ESC
means escape (ASCII code 27).
DEL
means delete (ASCII code 127).
SKIP
in the argument string of an in
command matches any input byte.
A single string can be built from several quoted literals and byte values by writing them separated by whitespaces or comma.
The following lines represent the same string:
"Hello world\r\n"
'Hello',0x20,"world",CR,LF
72 101 108 108 111 32 119 111 114 108 100 13 10
StreamDevice uses three types of variables in a protocol file.
System variables influence the behavior
of in
and out
commands.
Protocol arguments work like function
arguments and can be specified in the INP
or
OUT
link of the record.
User variables can be defined and used
in the protocol as abbreviations for often used values.
System and user variables can be set in the global context of the
protocol file or locally inside protocols.
When set globally, a variable keeps its value until overwritten.
When set locally, a variable is valid inside the protocol only.
To set a variable use the syntax:
variable = value;
Set variables can be referenced outside of
quoted strings by
$variable
or ${variable}
and inside quoted strings by
\$variable
or \${variable}
.
The reference will be replaced by the value of the variable at
this point.
This is a list of system variables, their default settings and what they influence.
LockTimeout = 5000;
out
command in a protocol.WriteTimeout = 100;
out
commands.ReplyTimeout = 1000;
in
commands.LockTimeout
should be larger than
ReplyTimeout
.
ReadTimeout = 100;
in
commands.Terminator
or InTerminator
is defined, a read timeout is not an error but a valid input
termination.
PollPeriod = $ReplyTimeout;
in
command in
I/O Intr
mode (see chapter
Record Processing).in
command at
the moment.
How many milliseconds to wait after last poll or last received
input before polling again?
If not set the same value as for ReplyTimeout
is
used.
Terminator = "";
out
and in
commands.CR LF
.
The value of the Terminator
variable is automatically
appended to any output.
It is also used to find the end of input.
It is removed before the input is passed to the in
command.
OutTerminator = $Terminator;
out
commands.InTerminator = $Terminator;
in
commands.Terminator
or InTerminator
is defined, a read timeout is not an error but a valid input
termination.
MaxInput = 0;
in
commands.0
means "infinite".
Separator = "";
out
and in
commands.Separator
is a
space, it matches any number of any whitespace characters in
an in
command.
ExtraInput = Error;
Error
or Ignore
.
Affects in
commands.ExtraInput = Ignore;
Sometimes, protocols differ only very little. In that case it can be convenient to write only one protocol and use protocol arguments for the difference. For example a motor controller for the 3 axes X, Y, Z requires three protocols to set a position.
moveX { out "X GOTO %d"; } moveY { out "Y GOTO %d"; } moveZ { out "Z GOTO %d"; }
It also needs three versions of any other protocol. That means basically writing everything three times. To make this easier, protocol arguments can be used:
move { out "\$1 GOTO %d"; }
Now, the protocol can be references in the OUT
link
of three different records as move(X)
,
move(Y)
and move(Z)
.
Up to 9 parameters, referenced as $1
... $9
can be specified in parentheses, separated by comma.
The variable $0
is replaced by the name of the protocol.
User defined variables are just a means to save some typing. Once set, a user variable can be referenced later in the protocol.
f = "FREQ"; # sets f to "FREQ" (including the quotes) f1 = $f " %f"; # sets f1 to "FREQ %f" getFrequency { out $f "?"; # same as: out "FREQ?"; in $f1; # same as: in "FREQ %f"; } setFrequency { out $f1; # same as: out "FREQ %f"; }
When an error happens, an exception handler may be called.
Exception handlers are a kind of sub-protocols in a protocol.
They consist of the same set of commands and are intended to
reset the device or to finish the protocol cleanly in case of
communication problems.
Like variables, exception handlers can be defined globally or
locally.
Globally defined handlers are used for all following protocols
unless overwritten by a local handler.
There is a fixed set of exception handler names starting with
@
.
@mismatch
in
command.@writetimeout
out
command.out
commands in the handler are
also likely to fail in this case.
@replytimeout
in
command.in
commands in the handler are
also likely to fail in this case.
@readtimeout
in
command.@init
iocInit
during record
initialization.
It can be used to initialize an output record with a value read from
the device.
Also see chapter Record Processing.
setPosition { out "POS %f"; @init { out "POS?"; in "POS %f"; } }
After executing the exception handler, the protocol terminates. If any exception occurs within an exception handler, no other handler is called but the protocol terminates immediately. An exception handler uses all system variable settings from the protocol in which the exception occurred.
Dirk Zimoch, 2006