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) are configured only through per-variable parameters and the Settings field stays empty.

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:

ProtocolDriver
Raw CAN FramesPEAK CAN Adapter
XCP on CANPEAK CAN Adapter
XCP on TCPTCP 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 StreamTCP Client
Simulation SignalsSimulation
Virtual VariablesVirtual Variables Host

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

CAN bus monitoring: maps standard (11-bit) CAN frames to variables by their identifier — no higher-layer parsing. Read-only; extended (29-bit) frames are ignored.

The protocol has no settings of its own.

Comm params pre-fill: canId="0x100";offset="0";byteOrder="le"

ParameterDefaultMeaning
canId011-bit CAN identifier in hexadecimal, e.g. 0x100
offset0index of the first frame data byte to read
byteOrderlebyte order: le (little-endian), be (big-endian)

Beware: canId is interpreted as hexadecimal even without the 0x prefixcanId=100 means 0x100 (decimal 256), not one hundred. The value is not checked against the 11-bit range; an out-of-range id or a typo (which silently becomes zero) only shows up as the variable never receiving data. For byteOrder only the listed tokens count — anything else silently means le. An offset past the end of the frame yields all zeros.

Supports all numeric types of scalar variables including float and double (the width comes from the variable's data type; missing bytes of a short frame are zero-padded). Matrix, string and enum variables are not served.

XCP on CAN

Technical name (stored in the project): XcpProtocol

A simplified XCP master (ASAM MCD-1 XCP) over CAN. Reads ECU memory either by polling (SHORT_UPLOAD) or by DAQ — the ECU streams the values itself (both 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. No 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;timeoutMs=1000;daqTimestamps=slave

Protocol settings:

ParameterDefaultMeaning
masterId— (mandatory)CAN id of master → slave frames, hexadecimal
slaveId— (mandatory)CAN id of slave → master frames; must differ from masterId
extendedIdsfalsetrue = both ids are 29-bit (extended)
timeoutMs1000per-command response timeout in ms
daqTimestampsslavetime-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) are polled and written as a chain of several 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 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.
  • timeoutMs applies per command; on a timeout the transaction is retried up to twice, so the worst-case wait is roughly three times as long.
  • Invalid protocol settings (missing/non-hex id, id outside the CAN range, timeoutMs ≤ 0) 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: timeoutMs=1000;daqTimestamps=slave

Protocol settings:

ParameterDefaultMeaning
timeoutMs1000per-command response timeout in ms
daqTimestampsslavetime-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 supported 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.
  • Timeouts of the TCP connection itself (connectionTimeoutMs, reconnects) are configured on the TCP Client driver; timeoutMs here only covers the XCP command/response exchange.

Trying it without hardware: the open-source XCPlite slave works as a free test ECU on localhost. Two ready-made projects ship in the QInsight Examples folder: XcpTcp_XCPlite_Daq01.qproj (a minimal DAQ-only project — four variables streamed from the ECU) and XcpTcp_XCPlite_Test01.qproj (DAQ measurement plus calibration writes). Build the XCPlite hello_xcp example, run it, and open either project.

XCP polling, DAQ, and STIM

Both XCP protocols configure variables the same way and offer two ways of reading them (polling 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):

ParameterDefaultMeaning
address— (mandatory)32-bit ECU memory address, hexadecimal (0x…) or decimal
addressExtension0address-space qualifier (decimal)
directionreadread, write, readWrite
eventRefname of the event the variable is bound to (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.

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"

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 keyMeaning
directionDAQ marks the event as an ECU event channel
daqIdthe 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" without daqId (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 daqId points 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 daqTimestamps setting. The default slave places 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 value master ignores 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 eventRef and must have direction="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.

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;timeoutMs=1000;retries=2

Protocol settings:

ParameterDefaultMeaning
mode— (mandatory)rtu (Serial Port), or tcp (TCP Client)
unitId1slave/unit address
timeoutMs1000response timeout in ms
retries2number of request retries

Per-variable parameters:

ParameterDefaultMeaning
registerTypeholdingRegistercoil, discreteInput, inputRegister, holdingRegister
address— (mandatory)zero-based start address, decimal or 0x…
wordOrderbigregister order of multi-register values: big, little
directionreadread, write, readWrite; discreteInput and inputRegister are read-only
eventRefperiodic event supplying the poll interval (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:

  • retries is the number of retries on top of the first attempt (default 2 = up to 3 transmissions) and timeoutMs applies to each attempt separately.
  • unitId is decimal. address may be hex (0x64) but is shown in decimal (100) after the project is saved — it is the same value.
  • registerType also accepts the shortened aliases discrete, input, holding; wordOrder accepts be/le.
  • Each polled variable is read by its own separate request in the period of its event; eventRef must name an existing periodic event.
  • 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) and inputRegister (read-only); the bit tables coil/discreteInput are 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); the configurator enforces a uniform 246 B limit,
  • wordOrder does 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:

ParameterDefaultMeaning
mode— (mandatory)rtu (Serial Port), or tcp (TCP Server)
unitId1the slave's own address
respondToAnyUnittcp: true, rtu: falserespond 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) the direction must stay read — 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 respondToAnyUnit in the table applies when the parameter is omitted — the pre-filled template however contains false, so for the TCP "respond to anyone" behaviour set true yourself. Values are true/false (not 1/0).

JSON Signal Stream

Technical name (stored in the project): JsonSignalProtocol

Decodes newline-delimited text lines with JSON objects {"name": "...", "value": ..., "t": ...} into variable values. Read-only. The optional t field (source time in seconds) is used to reconstruct timestamps.

The protocol has no settings of its own. Per-variable parameters:

ParameterDefaultMeaning
idvariable namesignal name in the JSON name field (aliases name, signal, signalName)

Supports numeric, string, bool, and enum variables. When several aliases are given at once, the precedence is name > signal > signalName > id. Signal names are matched case-insensitively. Unparsable lines, messages without name/value and values not convertible to the variable's type are dropped without any message — when a signal stays empty, first check the exact name match in the name field.

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. The signal shape is selected by the signal parameter:

SignalShape
stepstaircase sine ±750, period 15 s (the value changes once per second)
noisystepsine ±1000, period 7.5 s, with ±50 noise
walk1random walk around 0 (step ±0.5, mean-reverting)
walk2random walk around 10 (step ±1.0, mean-reverting)
walk3random walk around −5 (step ±0.3, mean-reverting)

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). Only numeric scalar variables are generated — string, bool, enum and Matrix are skipped with a warning in the log.

The protocol has no settings of its own. Per-variable parameters:

ParameterDefaultMeaning
signalby variable typesignal shape (see the table above)
eventRefperiodic event defining the generation rate; a variable without it is not generated
directionReadcommunication direction
idsignal identifier (informational)

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. 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. Variable parameters:

ParameterDefaultMeaning
idvariable namesignal identifier (informational)

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 Filtering a signal with a script.

Protocols are plugins — for a custom protocol see Custom extensions.