Protocols
A protocol decodes the data coming from a driver and
hands it to variables. Protocol settings are entered in the Settings
field in the key=value;key=value form; per-variable parameters go into
the Comm params field when a variable is assigned to the protocol.
Protocols with their own settings have the Settings field automatically
pre-filled with default values when added (the Pre-filled line under each
below). These are only defaults — always overwrite them to match your real
setup (e.g. masterId/slaveId for XCP, mode for Modbus). Protocols
with no settings of their own (Raw CAN Frames, JSON Signal Stream,
Simulation Signals, Virtual Variables, Data Log Pass-Through, Data Log
Replay) are configured only through per-variable parameters and the
Settings field stays empty. An unknown key in the Settings field is
reported by every protocol as a warning in the log, together with the keys
the protocol reads — a typo does not disappear into a silently used
default.
The Comm params field is also pre-filled when a variable is assigned
to a protocol — with the protocol's own template containing placeholders
(e.g. canId="0x100" for Raw CAN). Always replace the placeholders with
real values. A faulty Comm param (missing mandatory parameter, wrong
format) removes the variable from communication: a warning appears in the
log and the variable simply stays empty — the protocol itself keeps
running. Unknown keys are ignored without any message; keys are
case-insensitive and values may be quoted.
The protocol must match the driver's data type — the usual pairs:
| Protocol | Driver |
|---|---|
| Raw CAN Frames | PEAK CAN Adapter |
| XCP on CAN | PEAK CAN Adapter |
| XCP on TCP | TCP Client |
Modbus Master (mode=rtu) | Serial Port (COM) |
Modbus Master (mode=tcp) | TCP Client |
Modbus Slave (mode=rtu) | Serial Port (COM) |
Modbus Slave (mode=tcp) | TCP Server |
| JSON Signal Stream | TCP Client |
| Simulation Signals | Simulation |
| Virtual Variables | Virtual Variables Host |
| Data Log Pass-Through | Data Log Recorder (added automatically) |
| Data Log Replay | Data Log Replay (added automatically) |
Project Configuration enforces this: protocols that cannot work with the selected driver are greyed out in the protocol list, with a tooltip explaining what they need.
Raw CAN Frames
Technical name (stored in the project): RawCanProtocol
Raw CAN frames mapped to variables by identifier, in both directions, with no higher-layer parsing (J1939, CANopen). Meant for bus monitoring and for simple devices that send values in fixed bytes of a frame.
- Reading: every received frame with a given
canIdupdates the variables with directionreadorreadWritebound to it. The value is taken from the frame bytes starting atoffset, in the width of the variable's type and in thebyteOrder. Several variables can read one frame with differentoffsets (e.g. a value in bytes 0–3 and a time in bytes 4–7). - Writing: a write into a variable with direction
writeorreadWritesends one frame with itscanId: the value sits atoffsetin the same width and byte order, the rest of the payload is zero, the frame length ends right after the value. - Identifiers: standard 11-bit and extended 29-bit. An id above
0x7FFis extended automatically; an extended frame whose id fits into 11 bits is forced withextended="true". A variable receives only frames with the same id and the same identifier type. - Timestamps: samples carry the adapter's receive time (PEAK provides microseconds), aligned with the PC clock on the first frame; after the adapter is reopened the alignment is redone.
The protocol has no settings of its own. Per-variable parameters:
| Parameter | Default | Meaning |
|---|---|---|
canId | mandatory | identifier in hexadecimal, e.g. 0x100 or 18DAF100; always hexadecimal, even without 0x |
offset | 0 | index of the first byte of the value in the frame payload, 0 to 7 |
byteOrder | le | byte order of the value: le (little-endian), be (big-endian) |
direction | read | read = the bus feeds the variable, write = QInsight sends a frame, readWrite = both |
extended | by id | true forces a 29-bit identifier for an id up to 0x7FF |
The Comm params template pre-fills direction="read";canId="0x100";offset="0";byteOrder="le";
0x100 is only a placeholder, replace it. A missing or unreadable
canId, an offset outside 0–7, an unknown byteOrder or direction
is reported as a warning in the log and the variable stays not
communicated — the former silent listening on id 0 is gone. A frame
shorter than the value is zero-padded.
Supports all numeric types of scalar variables including float and
double. Matrix, string and enum variables are not handled (reported once
in the log). An example with a Python generator on a Raspberry Pi is
Raw CAN frames from a Raspberry Pi.
XCP on CAN
Technical name (stored in the project): XcpProtocol
A simplified XCP master (ASAM MCD-1 XCP) over CAN. Reads ECU memory
by polling (SHORT_UPLOAD, UPLOAD for larger blocks), on
request with the Read button of a control (On Request event), or by
DAQ — the ECU streams the values itself (the modes are explained in
XCP polling, DAQ, and STIM
below, shared by both XCP variants). Operator writes go via SET_MTA +
DOWNLOAD, periodic stimulation of variables streams via STIM. It
transfers scalar variables as well as
Matrix variables (maps, curves, value
blocks) and uses block mode when the slave offers it
(Block mode). No seed & key (a protected calibration
disables writes; a protected DAQ resource falls back to polling). Byte order and
address granularity are taken from the slave's CONNECT response.
Pre-filled: masterId=0x200;slaveId=0x201;extendedIds=false;requestTimeoutMs=1000;requestRetries=2;daqTimestamps=slave
Protocol settings:
| Parameter | Default | Meaning |
|---|---|---|
masterId | — (mandatory) | CAN id of master → slave frames, hexadecimal |
slaveId | — (mandatory) | CAN id of slave → master frames; must differ from masterId |
extendedIds | false | true = both ids are 29-bit (extended) |
requestTimeoutMs | 1000 | per-command response timeout in ms |
requestRetries | 2 | command repetitions after a timeout (on top of the first attempt); 0 = no retry |
daqTimestamps | slave | time-axis source of DAQ samples: slave = ECU timestamps, master = PC receive time (see DAQ behaviour and diagnostics) |
Per-variable parameters are common to both XCP variants — see XCP polling, DAQ, and STIM.
CAN-specific behaviour:
- Values longer than 6–7 bytes (
Long/ULong/Double) and matrices travel in several packets (with block mode as anUPLOADburst orDOWNLOAD+DOWNLOAD_NEXTblocks, otherwise as a chain of individually acknowledged commands) and the transfer is not atomic — if the ECU changes the value meanwhile, the result may be inconsistent. (DAQ does not have this problem: the ECU samples the values consistently at its event.) - A classic CAN packet carries only 6–7 data bytes, so a large matrix means hundreds to thousands of frames — see Block mode.
- A DAQ packet on classic CAN carries at most 8 bytes including its header, so one packet holds only a few small values — the protocol automatically spreads the variables over more packets per cycle.
- Only slaves with BYTE address granularity are supported (the common case); any other granularity is rejected and the protocol stays Faulted.
requestTimeoutMsapplies per command; on a timeout the protocol sends SYNCH and repeats the command, at mostrequestRetriestimes — with the defaults the worst-case wait is roughly three times the timeout.- Invalid protocol settings (missing/non-hex id, id outside the CAN
range,
requestTimeoutMs≤ 0, negativerequestRetries) put the protocol into the Faulted state at start with the cause in the log.
XCP on TCP
Technical name (stored in the project): XcpTcpProtocol
The same simplified XCP master over XCP on Ethernet (TCP transport): polling or DAQ reads, operator writes and STIM, byte order and limits taken from the CONNECT response. The ECU is the TCP server; QInsight connects to it through the TCP Client driver — the IP address and port therefore belong to the driver settings, not to the protocol.
Pre-filled: requestTimeoutMs=1000;requestRetries=2;daqTimestamps=slave
Protocol settings:
| Parameter | Default | Meaning |
|---|---|---|
requestTimeoutMs | 1000 | per-command response timeout in ms |
requestRetries | 2 | command repetitions after a timeout (on top of the first attempt); 0 = no retry |
daqTimestamps | slave | time-axis source of DAQ samples: slave = ECU timestamps, master = PC receive time (see DAQ behaviour and diagnostics) |
Per-variable parameters are common to both XCP variants — see XCP polling, DAQ, and STIM.
TCP-specific behaviour:
- Ethernet allows large XCP packets, so every scalar value (up to
8 bytes, including
Double) is transferred in one packet, atomically — no chaining as on CAN — and one DAQ packet typically carries a whole group of variables at once. - A matrix up to 247 B (MAX_CTO − 1) is read with a single
SHORT_UPLOAD; a larger matrix travels in several packets and the transfer is not atomic (typically anUPLOADburst in block mode — a 1 KB map is one burst of five packets). - Establishing and recovering the TCP connection itself
(
connectionTimeoutMs,reconnectDelayMs,reconnectAttempts,keepAliveMs) is configured on the TCP Client driver;requestTimeoutMsandrequestRetrieshere only cover the XCP command/response exchange.
Trying it without hardware: the open-source
XCPlite slave works as a free
test ECU on localhost: build and run the XCPlite hello_xcp example and
set up the variables and DAQ events in QInsight from the A2L file XCPlite
generates (no ready-made XCPlite project ships in the Examples folder).
Examples with a real board are
XCP on TCP on a NUCLEO-H723ZG and
Two ECUs at once.
XCP polling, DAQ, and STIM
Both XCP protocols configure variables the same way and offer three ways of reading them (polling, reading on request, and DAQ) plus streamed writing (STIM). Which mode a variable uses is decided by the event it is bound to — nothing else in the configuration changes.
Per-variable parameters (the Comm params field):
| Parameter | Default | Meaning |
|---|---|---|
address | — (mandatory) | 32-bit ECU memory address, hexadecimal (0x…) or decimal |
addressExtension | 0 | address-space qualifier (decimal) |
direction | read | read, write, readWrite |
eventRef | — | name of the event the variable is bound to — periodic (polling), On Request (read by the Read button) or DAQ/STIM; mandatory for read/readWrite |
The pre-filled address="0x0" is just a placeholder — always replace it
with the real address from the ECU description (typically the
ECU_ADDRESS and ECU_ADDRESS_EXTENSION attributes in an A2L file).
The value width and data type are taken from the variable itself, so
they are not entered here. Older projects may still contain size and
dataType keys — they are accepted and validated against the variable's
type; a mismatch is a configuration error. For matrices see
Matrix variables over XCP.
Polling — the master asks
The default mode. The variable is bound to an ordinary periodic event; the master reads the address in the event's period (PC timing, one request/response per variable per cycle). Simple and universal — it works with every XCP slave — but each value costs a round-trip, so it does not scale to fast rates or many variables.
Event: Poll100ms (Period 100, Unit Milisec)
Comm params: address="0x39B68";addressExtension="1";direction="read";eventRef="Poll100ms"
On Request — reading on demand
A variable bound to an event of type OnRequest is neither polled nor read via DAQ — the master reads it once when the operator presses Read in a control (Single-Signal, Watch Table, Matrix). It suits calibration data that changes only at the operator's command, typically large maps: a block of thousands of bytes does not travel over the line every period for nothing.
Event: OnRequest (Type OnRequest)
Comm params: address="0x24014270";direction="readWrite";eventRef="OnRequest"
Reading on request works only while communication runs; a failed read
turns the Read button red. A variable with direction read or
readWrite may be a scalar or a matrix. The same event is also
supported by Modbus Master and
Simulation Signals.
DAQ — the ECU streams
In DAQ mode (Data Acquisition) the master only configures at connect what to sample and on which ECU event channel — from then on the ECU samples the values itself, at its own rate, and streams them without being asked. The gains over polling:
- speed — sampling at the ECU's own cycle (e.g. every 1 ms), far beyond what request/response polling can do,
- consistency — all values of one event channel are sampled at the same instant in the ECU, so they belong together,
- efficiency — no per-value requests; many variables cost almost nothing extra.
An ECU event channel is a point in the ECU program where the ECU
publishes fresh values — e.g. "every loop of the 1 ms task". The channel
numbers and names are listed in the ECU's A2L file (the EVENT entries)
or its documentation.
How to use DAQ: create a periodic event and fill in its Extra Params field (Home → Project Configuration → Events):
direction="DAQ";daqId="1"
| Extra Params key | Meaning |
|---|---|
direction | DAQ marks the event as an ECU event channel |
daqId | the ECU event channel number (0–65535, from the A2L) |
The two keys are only valid together. The event's Period does not drive anything in DAQ mode — it documents the channel's expected cycle and is checked against the value the ECU reports at connect (a mismatch logs a warning with both values).
Then bind variables to this event exactly like to any other — via
eventRef:
Event: Daq_mainloop (Period 1, Unit Milisec,
Extra Params: direction="DAQ";daqId="1")
Comm params: address="0x39B68";addressExtension="1";direction="read";eventRef="Daq_mainloop"
Variables bound to a DAQ event are streamed; variables bound to a normal periodic event keep polling. Both modes mix freely in one protocol — typical setups stream the fast measurements and poll (or write) the calibration parameters. Writes are not affected by DAQ at all.
DAQ behaviour and diagnostics
- Validation is strict. A typo in Extra Params never silently turns
DAQ off:
direction="DAQ"withoutdaqId(or the other way round), or a malformed entry, removes the variable from communication at project load with a log warning describing exactly what is wrong. An unknown key only logs a warning and is ignored. - The channel is verified at connect. The protocol asks the ECU for
the channel's name and cycle (when the slave supports the query),
writes the ECU name of the channel to the log — check it to be sure
the
daqIdpoints where you think — and compares the cycle with the event's Period. - Automatic fallback to polling. When the slave has no DAQ resource, protects it with seed & key, rejects the channel, or the DAQ setup fails, the affected variables automatically fall back to polling (the event's Period then drives the poll rate) and a warning explains why. The session keeps running either way.
- Timestamps of DAQ samples follow the
daqTimestampssetting. The defaultslaveplaces samples onto the time axis by the ECU timestamps — each sample then carries the exact sampling instant in the ECU, not the packet arrival time (a substantial difference with batched transfers). The timestamps are anchored to the PC clock and a slow ECU clock drift is compensated continuously; a sustained drift above ~0.3 % logs a diagnostic warning (usually a sign of a wrong clock source in the ECU). A slave without timestamps automatically falls back to the receive time. The valuemasterignores the ECU timestamps and samples always carry the PC receive time. - Overload is a warning, not a failure. When the ECU cannot keep up it drops samples and signals an overload; QInsight logs a warning and the measurement continues with the next samples. The same applies when the PC side cannot process a burst in time.
STIM — stimulation from the master
DAQ also has an opposite direction: STIM (stimulation). The master periodically streams the current values of writable variables to the ECU as a stream of data packets — no request/response per write. It suits smooth driving of ECU inputs, e.g. setpoints computed by a Python script or an operator slider.
The configuration mirrors DAQ — just with the opposite direction:
Event: Stim_mainloop (Period 10, Unit Milisec,
Extra Params: direction="STIM";daqId="2")
Comm params: address="0x39B70";direction="write";eventRef="Stim_mainloop"
- An event with Extra Params
direction="STIM";daqId="N"marks the ECU event channel that consumes the stimulation. Unlike DAQ, here the Period does drive the event: it is the interval at which the master transmits the packet stream (PC timing), so the event must be periodic with a positive period. - Variables are bound to the event via
eventRefand must havedirection="write"; only scalar variables can be stimulated. - Every period the current values of all the channel's variables are sent — the last operator or script write keeps streaming into the ECU until a new write replaces it.
Automatic fallback to direct writes: when the slave has no STIM
resource, protects it with seed & key, the channel fails validation, or
a value does not fit the STIM packet limits, the affected variables fall
back — with a warning — to plain on-change writes (SET_MTA +
DOWNLOAD) and the session keeps running. While stimulation is active,
writes of the stimulated variables travel exclusively through the
stream — no individual write commands are sent for them. DAQ, STIM, and
polling mix freely in one protocol.
Operator writes
Written values are entered in engineering units — the raw value for the ECU is computed by the inverse conversion of the presentation (see Writing values to the device); the protocol always sends raw to the ECU. Writes are blocked not only by a protected calibration but also when the slave offers no calibration resource at all.
A written value does not show in the controls right away — it appears once the device returns it in the next poll or Read. Successful writes are not logged; a failed write logs a warning.
Matrix variables over XCP
XCP also transfers Matrix variables (array, curve, map) — the whole block (axes and data) as one contiguous region of ECU memory:
addressis the start of the block, i.e. the first X-axis breakpoint (the first data value for an array without axes); the memory order is X axis → Y axis → data row by row,dataTypeis ignored for a matrix — the section types come from the variable's Layout; an optionalsizemust equal the whole block,- the variable's Endianness must match the ECU; the byte order from CONNECT is not applied to a matrix, a mismatch only logs a warning at connect,
- a matrix is read by polling (periodic event) or on request (On Request); binding it to a DAQ or STIM event is a configuration error,
- limit: the data section is at most 16,384 B (64 × 64 ×
float), axes on top — a 64 × 64 float map withushortaxes is 16,640 B, - writes send only the changed cells: adjacent or overlapping cells
are merged into one window and each window is written via
SET_MTA+DOWNLOAD(in blocks with block mode). A pasted row of 64 cells is a single transfer.
Block mode
At connect the protocol finds out whether the slave supports block
mode (a bit in the CONNECT response, MAX_BS and MIN_ST from
GET_COMM_MODE_INFO) and logs it:
XCP: block mode — slave yes, master yes (MAX_BS 255, MIN_ST 0 × 100 µs).
- Reading (slave block mode) — a larger block is read with one
SET_MTAandUPLOADbursts of up to 255 B; the slave answers with a run of packets without further requests. - Writing (master block mode) — data goes in blocks of
DOWNLOAD+DOWNLOAD_NEXT(at mostMAX_BSpackets and 255 B, spaced byMIN_ST), each block acknowledged once. A sequence error (ERR_SEQUENCE) repeats the block fromSET_MTA. - Without block mode larger transfers are chained packet by packet, each acknowledged — this works with every slave, only slower.
Block mode matters for transfers larger than one packet — mainly matrices, and on CAN also 8-byte scalars. It needs no configuration in QInsight.
Modbus Master (RTU/TCP)
Technical name (stored in the project): ModbusMasterProtocol
A Modbus master (client): periodically reads coils and registers and
writes values on operator request. Framing is rtu (CRC16, serial line)
or tcp (MBAP header).
Pre-filled: mode=rtu;unitId=1;requestTimeoutMs=1000;requestRetries=2
Protocol settings:
| Parameter | Default | Meaning |
|---|---|---|
mode | — (mandatory) | rtu (Serial Port), or tcp (TCP Client) |
unitId | 1 | slave/unit address |
requestTimeoutMs | 1000 | response timeout per request in ms |
requestRetries | 2 | request repetitions after a timeout (on top of the first attempt) |
Per-variable parameters:
| Parameter | Default | Meaning |
|---|---|---|
registerType | holdingRegister | coil, discreteInput, inputRegister, holdingRegister |
address | — (mandatory) | zero-based start address, decimal or 0x… |
wordOrder | big | register order of multi-register values: big, little |
direction | read | read, write, readWrite; discreteInput and inputRegister are read-only |
eventRef | — | periodic event supplying the poll interval, or an On Request event (read only by the Read button); mandatory for read variables |
The register count follows the variable's data type: 1 (Byte, SByte,
UShort, Short), 2 (UInt, Int, Float), 4 (ULong, Long,
Double). The bit tables (coil, discreteInput) always occupy 1 bit
regardless of the type; any non-zero value = ON. Only numeric scalar
variables can be mapped (bool, string and enum cannot).
More master behaviour notes:
requestRetriesis the number of retries on top of the first attempt (default 2 = up to 3 transmissions) andrequestTimeoutMsapplies to each attempt separately. The former namestimeoutMsandretriesare no longer read — the log shows an unknown-key warning.- A lost connection (unplugged converter, cable) is handled by the driver: the master pauses polling meanwhile and resumes on its own once the transport is back — see Reconnection.
unitIdis decimal.addressmay be hex (0x64) but is shown in decimal (100) after the project is saved — it is the same value.registerTypealso accepts the shortened aliasesdiscrete,input,holding;wordOrderacceptsbe/le.- Each polled variable is read by its own separate request in the period
of its event;
eventRefmust name an existing periodic event, or an On Request event — such a variable (scalar or matrix) is not polled and is read once by the Read button in a control (see XCP polling, DAQ, and STIM). - A written value shows in the controls only after the next read from the device.
- Invalid Comm params remove the variable from communication with a warning in the log.
Matrix variables
The Modbus Master also transfers
Matrix variables (array/curve/map) — the
whole block as a contiguous register range starting at address:
- only the register tables are allowed:
holdingRegister(read and write) andinputRegister(read-only); the bit tablescoil/discreteInputare rejected for a matrix, - register count = matrix size in bytes / 2 (rounded up); reads use a single FC03/FC04 request, writes send only the registers of the changed cells (FC06/FC16),
- size limit: the matrix is never split into multiple frames — a writable matrix may span at most 123 registers (246 B), a read-only matrix 125 registers (250 B); a larger matrix is rejected by the protocol with a warning in the log,
wordOrderdoes not apply to a matrix — the byte order is driven by the variable's Endianness (a register is 2 bytes, high byte first).
Modbus Slave (RTU/TCP)
Technical name (stored in the project): ModbusSlaveProtocol
A Modbus slave (server): serves variables as coils, discrete inputs, input and holding registers. A remote master reads the live variable values; a write from the master (FC 05/06/16) sets the variable value.
Pre-filled: mode=rtu;unitId=1;respondToAnyUnit=false
Protocol settings:
| Parameter | Default | Meaning |
|---|---|---|
mode | — (mandatory) | rtu (Serial Port), or tcp (TCP Server) |
unitId | 1 | the slave's own address |
respondToAnyUnit | tcp: true, rtu: false | respond regardless of the requested unit address |
Per-variable parameters are the same as for the master (registerType,
address, wordOrder); eventRef is not needed. Slave behaviour notes:
- For the read-only tables (
discreteInput,inputRegister) thedirectionmust stayread— any other direction is an error and the variable is not created. - The slave serves scalar variables only; Matrix variables are not mapped and a warning appears in the log.
- Each variable claims a contiguous address range; overlapping addresses are a startup error.
- A write from the master must cover the variable's whole range at once:
a multi-register value (
Float,Int,Double…) cannot be written register-by-register with FC06 — only with a single FC16 spanning the full range; a partial write is rejected as ILLEGAL DATA ADDRESS. Likewise a read touching an unmapped address (a gap between variables) is rejected as a whole. - The Default of
respondToAnyUnitin the table applies when the parameter is omitted — the pre-filled template however containsfalse, so for the TCP "respond to anyone" behaviour settrueyourself. Values aretrue/false(not1/0).
JSON Signal Stream
Technical name (stored in the project): JsonSignalProtocol
Text lines with JSON objects, one object per line, separated by \n —
the same shape in both directions:
{"name": "temp", "value": 23.4, "t": 12.345}
{"name": "state", "value": "RUNNING"}
{"name": "alarm", "value": true}
| Field | Required | Meaning |
|---|---|---|
name | yes | signal name; matched to a variable case-insensitively |
value | yes | number, string or bool; converted to the variable's type (a number into an integer variable is rounded, a string into an enum by name) |
t | no | source time in seconds (number or string); without it the receive time is used |
Other fields of a message are ignored. The protocol assembles the lines itself from the bytes the driver hands over, including a line split across two packets — so it runs on any byte-stream driver: TCP Client (QInsight connects to the device), TCP Server (the device connects to QInsight) and Serial Port.
Reading: messages from the device feed the variables with direction
read or readWrite. When the device sends t, the protocol aligns the
offset between device time and PC time on the first sample and stamps the
samples by t from then on; when t jumps back (device restart) the
offset is aligned again.
Writing: a write into a variable with direction write or readWrite
— from the watch table, another control or a script — sends the device a
line of the same shape, {"name": "setpoint", "value": 42}. The raw value
of the variable is sent; an engineering value entered through a
presentation is converted by QInsight beforehand. A device can therefore
be controlled too, without a second protocol.
What is dropped and how you find out: invalid JSON, a message without
name/value, a name with no readable variable and a value that cannot
be converted to the variable's type are dropped and the protocol reports
it in the log once per cause (the first bad line is quoted in the
message, an unknown name is reported once per name). When a signal stays
empty, look at the log first.
The protocol has no settings of its own. Per-variable parameters:
| Parameter | Default | Meaning |
|---|---|---|
name | variable name | signal name in the name field |
direction | read | read = the device sends, write = QInsight sends, readWrite = both |
The Comm params template pre-fills direction="read";name="<variable name>".
The keys id, signal and signalName of older projects are no longer
read; a variable without name is matched by its own name. A counterpart
for trying it without hardware — a Python script generating sines and
accepting writes — is in the JSON signals from a Python generator example.
Simulation Signals
Technical name (stored in the project): SimulDataProtocol
Generates simulated signals for testing without hardware — used
exclusively with the Simulation driver. Each variable is generated exactly
in the period of its event (eventRef), so different variables can run
at different rates; a variable on an On Request event is generated
once on every press of Read in a control. What gets generated into a
variable is selected by the signal parameter in its Comm params.
Operator writes and on-request reads are carried to the protocol by the
Simulation driver, so the simulated device behaves like a real one: the
controls show only what the protocol reads "from the device". A complete showcase of every signal
is the Simulation: all signals example.
Generated signals (scalar variables)
signal | Shape | Tuning in Comm params |
|---|---|---|
step | staircase sine ±750, the value changes once per second, 15 s period | — |
noisystep | staircase sine ±1000, 7.5 s period, ±50 noise on every sample | — |
walk1 | random walk around 0 (step ±0.5, mean reverting) | — |
walk2 | random walk around 10 (step ±1.0, mean reverting) | — |
walk3 | random walk around −5 (step ±0.3, mean reverting) | — |
laosstrain | pure sine — the excitation (strain) of the LAOS pair | amp (800), freq (0.5 Hz) |
laosstress | the response (stress): fundamental plus odd harmonics 3, 5, 7 and 9 with shifted phases; the harmonic content grows with the nonlinearity | amp (800), freq (0.5 Hz), nonlin (0) |
The walks (walk*) advance one step with every generated sample — a
variable with a faster event therefore wanders faster. Each variable owns
an independent generator instance (two variables with the same signal
run independently); the value is converted to the variable's type
(integer types are rounded and clamped to the type range).
The laosstrain / laosstress pair runs on the protocol's shared clock,
so an XY graph (stress against strain) draws a
closed Lissajous loop. The nonlinearity ranges from 0 to 2: harmonic k
has an amplitude proportional to nonlin^k, at 0 the response is a
clean phase-shifted sine and the loop deforms as the value grows.
Matrix signal (Matrix variable)
signal | Shape | Tuning in Comm params |
|---|---|---|
thermal | thermal field of a plate: 25 °C base, a hot spot orbiting the plate centre over a Gaussian footprint, ±0.3 °C noise per cell; the axes are positions in mm at a 10 mm pitch | amp = rise of the hot spot above the base (40 °C), freq = orbit rate (0.025 Hz, one orbit per 40 s) |
The matrix axes are written only with the first sample, so a user edit of
the axes survives further generation; only the data cells are refreshed.
The matrix is generated with direction read as well as readWrite; with
readWrite its cells can be edited from the
Matrix control and the edit lands directly in
the buffer (with the hold parameter set the generator is idle, so the
edit stays). Values are engineering values; the matrix presentation maps
them to raw.
Parameter variables
A scalar variable with one of the keys below in signal (and in general
every scalar variable with direction readWrite) is not generated.
It is a simulation parameter: the generators react to its current value
on every sample. It is written from the watch table, another control or
a script.
A parameter with direction read or readWrite is read back like on
a real device — in the period of its event the protocol announces its
current value with a fresh timestamp (nothing is generated), or announces
it once on Read with an On Request event. A written value thus shows in
the controls after the next read. A parameter with direction write is
never read and never shows in the controls. A parameter without a
periodic event logs the warning
Simulation: variable '…' has no periodic event ('…'); not polled.
signal | Meaning |
|---|---|
nonlin | nonlinearity of laosstress, 0 to 2 |
h1amp … h4amp | absolute amplitude of harmonic 1, 3, 5 and 7 of laosstress |
h1freq … h4freq | frequency of that harmonic in Hz; h1freq also drives laosstrain, so the loop stays closed |
h1phase … h4phase | phase of that harmonic in degrees |
hold | a non-zero value freezes the generation of the thermal matrix |
An existing parameter takes precedence over the formula: as soon as the
project contains e.g. h2amp, the amplitude of the 3rd harmonic follows
that parameter alone and nonlin no longer affects it. Without the
parameter the generator uses the Comm params value (amp, freq,
nonlin) or its default.
The init="…" key gives a parameter its power-on default: the
protocol writes it at every Start of the runtime, so the generators use
it without any script. The controls show the value with the next read
back — so set a parameter you want to see to readWrite with a periodic
event. Without init the variable keeps whatever value it has.
Variable parameters
The protocol has no settings of its own. Everything is entered in the variable's Comm params:
| Parameter | Default | Meaning |
|---|---|---|
signal | by variable type | signal shape or parameter key (see the tables above) |
eventRef | — | periodic event defining the generation rate (the read-back period for parameters), or an On Request event (one sample per Read); a variable without it is neither generated nor read |
direction | Read | read = generated signal; readWrite = parameter read back (scalar) or editable matrix; write = parameter that is never read |
amp | by signal | amplitude (laosstrain, laosstress) or hot-spot rise (thermal) |
freq | by signal | frequency in Hz (laos*) or orbit rate (thermal) |
nonlin | 0 | nonlinearity of laosstress when the project has no nonlin parameter variable |
init | — | power-on default of a parameter variable |
The Comm params template pre-fills signal="step". Without signal the
shape is chosen by value type (int → noisystep, float → step,
otherwise walk1); an unknown signal value falls back to the same
type-based choice with a warning. Only numeric variables are
generated — string, bool and enum are skipped with a warning in the log;
a Matrix is generated only with the thermal signal. multiplier from
older projects is ignored.
Virtual Variables
Technical name (stored in the project): VirtualDataProtocol
Carrier of virtual variables: variables whose values do not come from a device but are computed by Python scripts — typically filters, derived quantities and other computed signals. A variable assigned to this protocol behaves like any other communicated signal: it can be shown in controls, logged and replayed, and it counts towards the communicated-signal limit of the Free licence. Used exclusively with the Virtual Variables Host driver.
The protocol has no timer: a sample is born the moment a script writes
the variable (RawValue or EngValue). Every write = one sample,
timestamped at the moment of the write — even when the script writes the
same value again. Writes pass through a buffer, are published in write
order, and the script never waits for the rendering; when the script does
not write, no samples appear.
The protocol has no settings of its own and the variable has no parameters: Comm params stay empty, a virtual variable is identified by itself.
An on-change trigger of another script can be attached to a virtual variable to chain computations — just avoid a cycle (a script writing to the very variable whose trigger runs it). A complete walk-through with an exponential filter is the example Simulation: all signals.
Data Log Pass-Through
Technical name (stored in the project): PassThroughProtocol
Collector protocol of the Data Log Recorder driver: it hands the driver the values of the logged variables 1:1, exactly as their source protocol publishes them. QInsight adds it to the driver by itself and fills it with variables according to the Log to FileDataLogger checkbox of each variable — it is neither added nor assigned variables by hand. A variable logged through this protocol does not count towards the communicated-signal limit of the Free licence.
The protocol has no settings of its own and the variable has no parameters: both Settings and Comm params stay empty. How to switch logging on and the recording parameters are described in Logging data.
Data Log Replay
Technical name (stored in the project): DataLogReplayProtocol
Protocol of the Data Log Replay driver: it writes the values of the
replayed .qilog file into the project variables, keeping the original
timestamps. A record is matched to a variable by its Id, falling back to
the namespace + name pair. The Import button in the Runtime ribbon adds
it to the project together with the driver; it is not added by hand.
The protocol has no settings of its own and the variable has no parameters: both Settings and Comm params stay empty. Log messages (once per cause, not per record): the variable of a record does not exist in the project — the whole signal is skipped during replay; a record cannot be converted to the variable's type — only that record is skipped and the replay continues; the protocol is not running — records are dropped. Replay control and the driver parameters are described in Replaying a log.
Protocols are plugins — for a custom protocol see Custom extensions.

