ADTF Substream Watchdog
Loading...
Searching...
No Matches
Configuration File Format

The Substream Watchdog is configured via a JSON configuration file that is specified in its config_file property.

This file contains three main sections:

Signals

The first section specifies the input signals that are used for monitoring certain conditions. These are defined via elements in the signals list element that contain the following attributes:

  • name (required): An identifier that can be used to reference the input signal in expressions. This is also the name that is used for the output substream that contains the value of this signal.
  • substream (required): Specifies the substream that provides the data of the signal.
  • timeout (required): A timeout after which the signal will be reset to the default value. Supported units are: h, m, s, ms, us and ns
  • element (optional):
    • If specified, then the value of the given element will be used as signal value. In this case the default attribute is required to be set as well.
    • if not specified, then the signal value will contain a boolean value telling whether the signal was received within timeout or not. Keep in mind that you need to connect a timer runner to the check_timeouts runner port that will trigger the reevaluation of the timeout conditions independently of the input triggers.
  • default (optional): Defines the value that is reported when the signal was not updated within timeout. Supported values are integers, floats, booleans, ‘'undefined’,'NaN','Infinity'and'-Infinity'`

Example Signals

{
"signals":
[
// A signal to check if an update for a signal/substream is received within a given timeout.
{
"name": "pdu1_received",
"substream": "bus1.pdu1",
"timeout": "300ms"
},
// A signals that provides the value of an element of a structure.
{
"name": "element1_value",
"substream": "bus1.pdu1",
"element": "element1",
"timeout": "3s",
"default": 1
},
{
"name": "element2_value",
"substream": "bus2.pdu1",
"element": "element2",
"timeout": "3s",
"default": 1
}
]
}

Expressions

The second element defines expressions that are evaluated whenever the state/value of one of its referenced signals or referenced expressions changes. These are defined via elements in the expressions list element that contain the following attributes:

  • name (required): The name of the expression that can be used to reference its result (in other expressions). This is also used as the name of the output substream providing the result of the expression in case that output_type is specified.
  • value (required): The expression itself, please see Expression Syntax for a detailed description.
  • output_type (optional): When specified, then the result of the expression is also published via an output substream. Supported types are bool, uint64, int64, double and tristate.

Example Expressions

{
"signals":
[
// Signals defined in the example above.
],
"expressions":
[
// An expression multiplying the value of a signal by two.
{
"name": "element1_by2",
"value": "element1_value * 2",
"output_type": "uint64"
},
// An expression calculating the sum of two signals.
{
"name": "sum",
"value": "element1_value + element2_value",
"output_type": "uint64"
},
// An expression referencing the result of another expression and comparing it to some value.
{
"name": "element1_by2_gt_5",
"value": "element1_by2 > 5",
"output_type": "bool"
},
// An expression that checks if a given expression was not fulfilled within a given time frame. Mind that `was()` checks whether the condition was fulfilled at least once, not continuously.
{
"name": "normal_operation_mode",
"value": "!was(!?pdu1_received, 5m)"
}
]
}

Test Cases

Test cases allow you to define a series of phases to check for complex test scenarios. These are defined via elements in the test_cases list element that contain the following attributes:

  • name (required): The name of the test case. The state will be published via a substream with this name.
  • phases (required): A list of phases where each element contains the following attributes:
    • condition (required): This expression models the environmental conditions which must be fulfilled for the test to be decidable.
    • acceptance (optional): This expression models the functionality or behavior under test. Default is true, meaning that the phase does not verify any behavior yet.

The basic check that is performed is, whether condition -> acceptance (material conditional) holds true for the entire input sequence.

By using multiple phases, both required input sequences and sequences of expected behavior can be modeled.

The transition from one phase to the next happens when condition && acceptance of the current phase is fulfilled. A test case is considered as being completed successfully when this check is also passed for its final phase.

A phase is considered as failed when condition && !acceptance is fulfilled. A failure in any phase counts as a failure for the whole test case. Keep in mind that a test case can both fail and succeed eventually within a single input sequence, see Test Case Results.

The conditions of adjacent phases must be fulfilled in contiguous time intervals. E.g. a transition from speed <= 50 to speed > 50 between two phases is possible but a transition from speed <= 50 to speed > 100 will fail to match because there will be a point of time in between where neither condition is fulfilled. Conditions may overlap / be fulfillable at the same time, but this results in non-deterministic evaluation.

The modeled sequence is continuously checked for all possible matches in the input sequence. There is no risk of missing a match only because another partial match is still being evaluated, in this case both (all) possible matches keep being tracked.

Keep in mind that designing these test cases requires trade offs between having few matches, too many false positives or too many false negatives. You need to know which types of errors your test case permits, to decide whether failures or successes are significant.

Test Case Results

The result type transmitted via the corresponding substream contains two elements:

  • failure: This tells whether one of the phases has failed at least once.
  • success: This tells whether the last phase has succeeded at least once.

Example Test Cases

{
"signals":
[
{
"name": "speed",
"substream": "bus1.pdu1",
"element": "speed_element",
"timeout": "300ms",
"default": 0
},
{
"name": "brake_pedal",
"substream": "bus1.pdu1",
"element": "brake_pedal_element",
"timeout": "300ms",
"default": 0
},
{
"name": "cruise_control_available",
"substream": "bus1.pdu1",
"element": "cc_available_element",
"timeout": "300ms",
"default": false
},
{
"name": "cruise_control_active",
"substream": "bus1.pdu1",
"element": "cc_active_element",
"timeout": "300ms",
"default": false
}
],
"expressions":
[
{
"name": "cc_high_speed_environment",
"value": "speed > 100 && ?cruise_control_available"
},
{
"name": "brake_pedal_pressed",
"value": "brake_pedal > 0.1"
}
],
"test_cases":
[
// A test case that checks if the cruise control is deactivated while keeping the brake pedal pressed
{
"name": "cc_deactivated_upon_braking_keep_pressed_high_speed",
"phases":
[
{
"condition": "?cc_high_speed_environment && ?cruise_control_active && !?brake_pedal_pressed"
},
{
"condition": "?cc_high_speed_environment && ?brake_pedal_pressed",
// Fail if cruise control did not deactivate within a 500ms grace period.
"acceptance": "!?cruise_control_active || !wait(500ms)"
}
]
},
// A test case that checks if the cruise control is deactivated when tipping the brake pedal for less than 300 ms
{
"name": "cc_deactivated_after_brake_was_tipped_high_speed",
"phases":
[
{
"condition": "?cc_high_speed_environment && ?cruise_control_active && !?brake_pedal_pressed"
},
{
"condition": "?cc_high_speed_environment && ?brake_pedal_pressed && timeout(300ms)"
},
{
"condition": "?cc_high_speed_environment && !?brake_pedal_pressed",
// Fail if cruise control did not deactivate within a 500ms grace period.
"acceptance": "!?cruise_control_active || !wait(500ms)"
}
]
}
]
}

Recorder Control

You can control one ore more recorders with the help of the recorders section in the configuration file. The Substream Watchdog filter will create an interface binding client pin for each recorder listed. You can both control the state of the recorder and add markers based on expressions and test cases.

Example Recorder

{
"recorders":
[
{
// This will be the name of the interface client pin.
"name": "rec1",
// When the evaluation of this expression changes to true, recording is started. Once it evaluates to false again, recording will be stopped.
// This is an optional element. If it is missing, the state of the recorder will not be changed.
"recording_expression": "signal_a_gt_5",
// The markers section allows you to create markers based either on expressions or test cases.
"markers":
[
// This is an example for an expression based marker.
{
// The marker is added whenever the evaluation of the referenced expression changes to true.
// The expression needs to be defined in the `expressions` section.
"expression": "cruise_control_active",
// The name of the marker.
"name": "my_marker_name",
// Some additional information, optional.
"additional": "Some additional information"
},
// This is an example for a test case based marker.
{
// This is the reference to the test case which should be monitored
"test_case": "cc_deactivated_upon_braking_keep_pressed_high_speed",
// The success element (optional) creates a marker when the test case is completed successfully the first time.
"success": {
"name": "test succeded",
"additional": "Some additional information"
},
// The failure element (optional) creates a marker when the test case is fails the first time.
"failure": {
"name": "test failed",
"additional": "Some additional information"
}
}
]
}
]
}

Expression Syntax

logic literals

  • true:
  • false:
  • undefined: This implies that currently a decision cannot be made, but may yield a result later on.

Numeric Literals

  • floating point values: 1.2, -1.3e+3, 1.3E-5
  • decimal: 123, -456
  • octal: 0123, -0654
  • hexadecimal: 0x123, -0x654

Logic operators

  • <=>: logic equal: if one operand is undefined the result is undefined as well.
  • !, not: logic not: if the operand is undefined the result is undefined as well.
  • &&, and: logic AND: if one operand is undefined the result is undefined as well.
  • ||, or: logic AND: if one operand is true the result is true even if the other operand is undefined.
  • ^^, xor: logic XOR: if one operand is undefined the result is undefined as well.
  • ?: boolean signal marker: prefix a signal or expression name with ? to treat it as a logical value in conditions.

Bitwise operators

  • ~, bit_not: binary not
  • &, bit_and: binary and
  • |, bit_or: binary or
  • ^, bit_xor: binary XOR

Numerical comparison operators

  • =, ==: number equal
  • !=, <>: number not equal
  • <=: number less or equal
  • <: number less
  • >=: number greater or equal
  • >: number greater

Numerical operators

  • +: addition
  • -: subtraction
  • *: multiplication
  • /: division

Temporal functions

General purpose

  • was(<logic>, <time>): Yields true when the expression parameter evaluated to true at least once within the given time period going back from "now", otherwise false.

Within phases of a test case

  • wait(<time>): Yields undefined for the given time period starting from when the current phase was entered, afterwards returns true. Typical usage: condition || wait(300ms) means to wait for up to 300 ms for condition to become true, afterwards the whole expression my return false depending on condition. This is mostly used in the acceptance expression of a phase to model delayed system reactions.
  • timeout(<time>): Yields true for the given time period starting from when the current phase was entered, afterwards returns false. Typical usage: condition && timeout(300ms) means that condition may succeed within 300 ms but the expression always returns false afterwards. This is mostly used in the condition expression a phase to limit the maximum duration of a phase.

Numerical functions

  • round(<numeric>)
  • ceil(<numeric>)
  • floor(<numeric>)
  • bit(<numeric>, <numeric>): Selects the given bit from the second parameter.

Predicates

  • is_nan(<numeric>): returns whether the parameter is a floating point NaN or not.