You can give arguments to a protocol.
In the INP
or OUT
link, write:
field (OUT, "@protocolfile protocol(arg1,arg2,arg3) bus")
In the protocol, reference arguments as $1 $2 $3
or inside strings
as "\$1 \$2 \$3"
.
moveaxis {out "move\$1 %.6f";}
field (OUT, "@motor.proto moveaxis(X) motor1")
readpressure {out 0x02 0x00 $1; in 0x82 0x00 $1 "%2r";}
field (INP, "@vacuumgauge.proto readpressure(0x84) gauge3")
Use I/O Intr
processing.
The record receives any input and processes only when the input matches.
read {in "new value = %f";}
record (ai, "$(RECORD)") {
field (DTYP, "stream")
field (INP, "@$(DEVICETYPE).proto read $(BUS)")
field (SCAN, "I/O Intr")
}
Here is the value: 3.1415
Use as many in
commands as you get input lines.
read_value {in "Here is the value:"; in "%f";}
There is more than one solution to this problem. Different approaches have different requirements.
Use array records (e.g. waveform, aao).
array_out {separator=", "; out "an array: (%.2f)";}
The format %.2f
is repeated for each element of the array.
All elements are separated by ", "
.
Output will look like this:
an array: (3.14, 17.30, -12.34)
Use a calcout record and field references in the format.
write_ABC {out "A=%(A).2f B=%(B).6f C=%(C).0f";}
You must specify a valid expression in the CALC
field
even if you don't use it.
record (calcout, "$(RECORD)") {
field (INPA, "$(A_RECORD)")
field (INPB, "$(B_RECORD)")
field (INPC, "$(C_RECORD)")
field (CALC, "0")
field (DTYP, "stream")
field (OUT, "@$(DEVICETYPE).proto write_ABC $(BUS)")
}
Use record references in the format.
acquire {out 'ACQUIRE "%(\$1:directory)s/%s",%(\$1:time).3f;';}
You can specify a record name or record.FIELD in parentheses directly
after the %
.
To avoid plain record names in protocol files use
protocol arguments like \$1
.
In the link, specify the record name or just the basename of the
other records (device name) in parentheses.
record (stringout, "$(DEVICE):getimage") {
field (DTYP, "stream")
field (OUT, "@$(DEVICETYPE).proto acquire($(DEVICE)) $(BUS)")
}
Again, there is more than one solution to this problem.
Use array records (e.g. waveform,
aai).
array_in {separator=","; in "array = (%f)";}
The format %f
is repeated for each element of the array.
A ","
is expected beween element.
Input may look like this:
array = (3.14, 17.30, -12.34)
Use I/O Intr
processing
and value skipping (%*
)
read_A {out "GET A,B"; in "A=%f, B=%*f";}
read_B {in "A=%*f, B=%f";}
record (ai, "$(DEVICE):A") {
field (DTYP, "stream")
field (INP, "@$(DEVICETYPE).proto read_A $(BUS)")
field (SCAN, "1 second")
}
record (ai, "$(DEVICE):B") {
field (DTYP, "stream")
field (INP, "@$(DEVICETYPE).proto read_B $(BUS)")
field (SCAN, "I/O Intr")
}
Record A actively requests values every second.
The reply contains values A and B.
Record A filters only value A from the input and ignores value B
by using the *
flag.
Nevertheless, a complete syntax check is performed: B must be a
valid floating point number.
Record B is I/O Intr
and gets (a copy of) any input, including
input that was directed to record A.
If it finds a matching string it ignores value A, reads value B and
then processes.
Any non-matching input is ignored by record B.
Use record references in the format. To avoid record names in protocol files, use protocol arguments.
read_AB {out "GET A,B"; in "A=%f, B=%(\$1)f";}
record (ai, "$(DEVICE):A") {
field (DTYP, "stream")
field (INP, "@$(DEVICETYPE).proto read_AB($(DEVICE):B) $(BUS)")
field (SCAN, "1 second")
}
record (ai, "$(DEVICE):B") {
}
Whenever record A reads input, it stores the first value in its own VAL field as usual and the second in the VAL field of record B. Because the VAL field of record B has the PP attribute, this automatically processes record B.
Use a @mismatch
exception handler and
record references in the format.
To avoid record names in protocol files, use
protocol arguments.
When asked "CURRENT?
", the device send something like
"CURRENT 3.24 A
" or a message like
"device switched off
".
read_current {out "CURRENT?"; in "CURRENT %f A"; @mismatch {in "%(\1)39c";}}
record (ai, "$(DEVICE):readcurrent") {
field (DTYP, "stream")
field (INP, "@$(DEVICETYPE).proto read_current($(DEVICE):message) $(BUS)")
}
record (stringin, "$(DEVICE):message") {
}
After processing the readcurrent record, you can see from SEVR/STAT if the read was successful or not. With some more records, you can clean the message record if SEVR is not INVALID.
record (calcout, "$(DEVICE):clean_1") {
field (INPA, "$(DEVICE):readcurrent.SEVR CP")
field (CALC, "A!=2")
field (OOPT, "When Non-zero")
field (OUT, "$(DEVICE):clean_2.PROC")
}
record (stringout, "$(DEVICE):clean_2") {
field (VAL, "OK")
field (OUT, "$(DEVICE):message PP")
}
Dirk Zimoch, 2007