Writing Values
This chapter covers the configuration syntax for every element type a definition can declare: parameters, entities, structs, lists, unions, and references.
The running example is the SensorEcu definition, which models the sensor acquisition part of a body ECU.
The complete configuration, for orientation; the sections below take it apart:
{
$definition: "SensorEcu@1.2",
ecu: {
name: "FrontBodyEcu",
shortName: "FBE_01",
selfTest: true,
adcBaseAddress: "0x4000_1000",
sampleTime: {
value: 50,
$comment: "Reduced for the oil temperature plausibility check.",
$description: "Sample Time \n\n\
* Markdown \n\
* Support"
},
sensors: [
{
name: "OilTemp",
input: {
$type: "SensorEcu::AnalogInput",
channel: 3,
voltageRange: "RANGE_10V"
},
inputFilter: {
cutoff: "10 Hz",
order: 2
},
calibration: {
offset: -40.0,
factor: 0.125
}
},
{
id: "ignition",
sampleDivider: 4,
input: {
$type: "SensorEcu::DigitalInput",
pin: 12,
inverted: true
}
}
],
errorHook: "SensFail_ReportDtc",
monitoredSensorRef: "/SensorEcu/FrontBodyEcu/OilTemp",
failsafeSensorRef: {
refTarget: "id:ignition",
$description: "Fall back to the ignition signal when the monitored sensor fails."
}
,
sensorGroups: [
{
name: "Powertrain",
memberRefs: ["/SensorEcu/FrontBodyEcu/OilTemp"],
subGroups: [
{
name: "Ignition",
memberRefs: ["id:ignition"]
}
]
}
]
}
}
Parameters
A parameter takes its value directly:
shortName: "FBE_01",
selfTest: true,
adcBaseAddress: "0x4000_1000",
The definition decides the type and the constraints.
For sampleTime the definition declares a u16 with a range and a unit:
adcBaseAddress: {
title: "ADC register base address",
multiplicity: "1..1",
u32: {
min: 0x40000000,
max: 0x4FFFFFFF,
display: "hex"
}
},
sampleTime: {
description: "Time between two acquisition cycles.",
u16: {
min: 1,
max: "10 s",
unit: "ms",
default: 100
}
},
-
Integer and float parameters are checked against
min/max. Hover shows the range and theunit. -
Integer parameters also accept hex strings:
adcBaseAddress: "0x4000_1000". Underscores group digits for readability. Use this when the definition displays the value as hex (register addresses, CAN identifiers). -
Integer strings group decimal digits with underscores too:
"1_000_000","1_500 kHz". -
Integer and float parameters with a
unitaccept unit strings, normalized to the base unit:inputFilter: { cutoff: "10 Hz", order: 2 },Completion inside the string offers the units the parameter takes.
-
Float parameters also accept plain strings (
"1.5e-3"). An integer string takes an exponent as well, when the value is whole ("1e3","1.5e3 Hz"). -
String parameters may constrain length (
minLength/maxLength), a regexpattern, or a list of allowed literals. -
Enum parameters take one of their literals as a string:
voltageRange: "Range10V". -
An optional parameter with a
defaultcan be omitted, a required one stays required despite itsdefault. The default is the fallback for whoever reads the value. A value the merged export has to hold belongs in a configuration or a default file.
The Object Form
Every parameter also accepts an object form that carries metadata next to the value:
sampleTime: {
value: 50,
$comment: "Reduced for the oil temperature plausibility check.",
$description: "Sample Time \n\n\
* Markdown \n\
* Support"
},
Inside the object, value holds the actual value (for reference parameters it is refTarget instead), and $description, $comment, and annotation keys may accompany it.
Use the object form when a value deserves an explanation or an annotation; stay with the bare form otherwise.
Entities
An entity is a JSON object and the addressable building block of a configuration. It may carry an identity:
{
id: "ignition",
sampleDivider: 4,
input: {
$type: "SensorEcu::DigitalInput",
pin: 12,
inverted: true
}
}
-
namenames the entity within its surroundings;ididentifies it globally. Both match^[A-Za-z][A-Za-z0-9_]*$. -
Set either
nameorid, never both; anidalso serves as the name. -
The identity is what reference paths point at and what merging matches on. An entity in a list always requires a
nameorid. Only an entity in a single-value relation (maxof 1) may stay anonymous; it is then addressed by its type name.
Entities Named by One of Their Values
Some definitions derive the identity from a parameter the entity carries anyway, so you write the value and no name.
Completion and hover tell you which one: the definition declares nameSource or idSource on the entity.
{
$definition: "Bus@1.0",
namespaces: [
{
// No 'name': the entity is called 'com__vector__Engine', mangled from this value.
fqn: "com::vector::Engine",
signals: [
{
symbol: "engine_rpm"
},
],
},
],
}
The namespace above is called comvectorEngine: the name is the value with every character outside [A-Za-z0-9_] replaced by _.
That mangled form, not the value you wrote, is what a reference path and a fragment $path spell, and what a contribution in another file merges under.
Writing an explicit name or id anyway still wins, and changing the source value renames the entity.
Structs
A struct is a plain JSON object of its fields, without identity:
calibration: {
offset: -40.0,
factor: 0.125
}
Structs group values that belong together.
You cannot give them a name and references cannot point at them.
Lists and Multiplicity
The definition’s multiplicity decides how many elements a property takes.
A list property (max greater than 1) is written as a JSON array, here the sensors list of the running example:
sensors: [
{
name: "OilTemp",
input: {
$type: "SensorEcu::AnalogInput",
channel: 3,
voltageRange: "RANGE_10V"
},
inputFilter: {
cutoff: "10 Hz",
order: 2
},
calibration: {
offset: -40.0,
factor: 0.125
}
},
{
id: "ignition",
sampleDivider: 4,
input: {
$type: "SensorEcu::DigitalInput",
pin: 12,
inverted: true
}
}
],
-
Too few or too many elements is an error against
min..max. -
For a parameter list with a single value you may drop the brackets and write the scalar directly. Entity and struct lists always need the array.
Unions
A union property accepts one of several alternative types.
The input of a sensor is either an analog or a digital input:
input: {
description: "The electrical input of the sensor.",
multiplicity: "1..1",
union: {
typeRefs: [
"SensorEcu::AnalogInput",
"SensorEcu::DigitalInput"
]
}
},
In the configuration, a $type discriminator selects the alternative.
Its value is the full type path DefinitionName::TypeName:
{
name: "OilTemp",
input: {
$type: "SensorEcu::AnalogInput",
channel: 3,
voltageRange: "RANGE_10V"
},
inputFilter: {
cutoff: "10 Hz",
order: 2
},
calibration: {
offset: -40.0,
factor: 0.125
}
},
When the alternatives are primitive types (for example an integer or a string), no $type is needed or allowed: write the bare value, and its JSON type picks the alternative.
If a value would match several alternatives, validation reports the ambiguity and asks for $type.
References
A reference parameter connects one entity to another. Its value is a path string from the definition root to the target entity:
monitoredSensorRef: "/SensorEcu/FrontBodyEcu/OilTemp",
The path is built from entity identities, not from property names: each segment is the entity’s name, else its id, else its type name.
Here /SensorEcu/FrontBodyEcu/OilTemp walks definition SensorEcu, the ecu entity named FrontBodyEcu, and the sensor named OilTemp.
The definition restricts what a reference may point at (refTargetTypes); pointing at anything else, or at a non-existing path, is an error.
In the IDE, completion offers the valid targets, and "go to definition" jumps to the referenced entity.
Linker Symbols
A linkerSymbol parameter takes the name of a code symbol as a string, for example the C callback the ECU calls on a sensor failure:
errorHook: "SensFail_ReportDtc",
Confµgami checks that it is a plausible symbol name for the declared language; whether the symbol exists is the linker’s business, not the configuration’s.
File Paths
A filePath parameter takes the path to a file or folder as a string:
build: {
linkerScript: "linker/app.ld",
outputDir: "${env:FIRMWARE_OUT:out}",
},
Here outputDir uses the environment variable FIRMWARE_OUT, or out when it is not set.
The definition decides:
-
which folder a relative path starts from: the workspace root, the CfgSpace root or the folder of the configuration file
-
whether an absolute path is allowed
-
whether
${env:NAME}and${env:NAME:default}are expanded -
what the path must point to: an existing file, an existing folder, or nothing yet
-
optionally, a pattern the path must match, such as
*.ld
Every value follows the same rules:
-
/is the separator, a\is an error. -
The path must not be empty.
-
A trailing
/marks a folder and is allowed only where the definition accepts a folder.
The merged model holds the path relative to the CfgSpace root, unless the definition keeps it as written. So a path written relative to its own file names the same target as one written relative to the CfgSpace root.
In the IDE, completion offers the folders and the accepted files, hover shows the resolved path, and "go to definition" opens an existing file. A file created or deleted on disk shows in the diagnostics with the next edit.
-
Type Reference in the developer manual lists every definition-side option behind these value types.