Data contracts
DDD is a chain of parts that hand data to one another: the loader reads the description files from disk, the analysis resolves and checks what was read, and the backends turn the result into c code and into a2l. Those parts share no domain logic at all - the c backend has never heard of a2l, the analysis has never heard of either, and none of them reaches into the loader. What holds the chain together instead is a small set of data contracts: the exact descriptions of the json documents that enter and leave the tool, and of the resolved data that travels between the front end and the backends.
Every contract is described exactly once, as a pydantic model in the ddd.models package,
and that one description is shared by every producer and every consumer of the data. The
loader validates a file against it, the checks read the objects it produced, ddd schema
exports its json schema, and the reference at the bottom of this page is generated from it.
Two parts of DDD can therefore never disagree about a file format, and the schema an editor
validates a description file against while it is being typed is not a second, hand
maintained copy of the rules: it is derived from the rules themselves, so a field that
changes cannot leave its documentation or its schema behind.
The data dictionary on the right of the diagram is the same idea applied to data that does not have to be a file at all, and it is important enough to have a page of its own. The contracts on the left are the files a project actually contains, and they are described in prose, with examples, under file formats. What follows here is the discipline all of them are held to, and the generated reference for every model.
Validation at the boundary
A description file is written by a person, in an editor, usually while thinking about something else. It is therefore checked the moment it enters DDD, before anything reads a single field of it, and the resolved data dictionary is validated once more before it is handed to a backend. The point of validating at the boundary rather than at the point of use is where the problem gets reported: a missing datatype noticed while a jinja template is rendering says something about the template, whereas the same problem noticed at the boundary says which file, which declaration and which field.
A contract that is kept is not reported at all - the run says only what it checked. Here is one of the shipped demo components, checked on its own:
$ ddd check examples/demo/components/sensor_hub.ddd.json --standalone
ok: 6 variables in 1 component are consistent
A violated contract is a finding, not a crash. The loader turns every pydantic validation
error into a diagnostic of the schema check, located at the json path that carries the
offending value, and carries on reading whatever else it can:
$ ddd check misnamed.ddd.json # a component whose first two objects are misnamed
misnamed.ddd.json#component.interface[0].definition.name: error[schema]: String should match pattern '^[A-Za-z_][A-Za-z0-9_]*$' (got: '2Value')
misnamed.ddd.json#component.interface[1].definition.name: error[schema]: String should have at most 128 characters (got: 'ValueXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...)
2 errors
Both problems are in one file and both are reported by one run, because an author who has to
run the tool once per mistake stops running the tool. schema is one of the few checks
whose severity cannot be relaxed: a file DDD cannot read has nothing further to say about
itself, so downgrading the finding would only delay the failure.
Unknown fields are rejected
Every model refuses keys it does not know. A key DDD silently ignored would be worse than
one it refuses, because the author would go on believing the field had an effect: a mistyped
dimension instead of dimensions does not produce a smaller array, it produces a
scalar, and neither the generated code nor the a2l would ever hint at why.
$ ddd check mistyped.ddd.json # a declaration spelling 'dimension' for 'dimensions'
mistyped.ddd.json#component.interface[0].definition.dimension: error[schema]: Extra inputs are not permitted (got: [4])
1 error
The same rule applies at the top level of a file: a document naming none of the seven
description kinds - project, component, types, units, sections,
constants, rasters - or several of them at once, is refused rather than guessed at.
Identifiers are constrained
Anything DDD will later write into a c file or into an a2l file as a name - a project
name, a component name, an object name, an enum name, an enumerator, an a2l display
identifier - has to match ^[A-Za-z_][A-Za-z0-9_]*$ and may be at most 128 characters
long. The pattern is the c identifier rule, because a name that is not one cannot become a
variable. The length is the tighter of the two limits DDD has to satisfy: c compilers are
generous, but ASAP2 1.6.1 caps an identifier at 128 characters, and a name that cannot be
put into the a2l is of no use in a project that generates one.
Constraining a value rather than passing it through also keeps one description file from
being able to damage somebody else’s build. The a2l FORMAT string is checked against
^%\d*\.\d+$ for exactly that reason: it is written into a quoted a2l literal, and a
quote or a backslash in it would unbalance the string so that no calibration tool would
parse the file at all - a whole delivery lost to one typo in one description. For the same
reason a preprocessor condition may not contain a line break, /*, */, // or
#: it is emitted verbatim into #if and into the trailing #endif comment of every
generated file, and a comment marker there would close that trailer early and leave whatever
follows it as live code.
Numbers must be finite
Every number DDD reads - a limit, an initial value, a conversion factor or offset - is
refused if it is infinite or NaN. Neither survives the trip to an output, since there is no c
literal and no a2l number for either, and NaN is actively dangerous on the way there: every
comparison against it is false, so a NaN limit passes every range check in silence instead
of failing one. Python’s json reader accepts NaN, Infinity and -Infinity even
though json itself does not, so the loader refuses them explicitly, before pydantic ever
sees the document:
$ ddd check infinity.ddd.json # a file whose json holds Infinity
infinity.ddd.json: error[json-syntax]: 'Infinity' is not valid json; DDD has no representation for it
1 error
Whole numbers are kept whole for a related reason: a number is read as an int first and
only then as a float, because the range of a 64 bit datatype does not survive a float, and a
limit rendered as 18446744073709551616 - one more than uint64 can hold - is a value the
calibration tool would refuse.
Nothing changes behind a caller’s back
Every contract model is frozen: once a document has been validated, no part of DDD modifies it. The analysis therefore cannot quietly “fix up” a consumer’s declaration to match the producer’s, and a backend cannot normalise something on its way into a template. Where a derived value is needed - the limits a datatype and a conversion imply, the shape a curve takes from its axis - it is computed into the data dictionary, which is a separate document, so that the difference between what an author wrote and what DDD concluded stays visible instead of being overwritten.
Publishing the schemas
Because the contracts are pydantic models, their json schema is derived mechanically -
including the field documentation and the rejection of unknown properties - and
ddd schema prints it:
ddd schema project
ddd schema component
ddd schema types
ddd schema units
ddd schema sections
ddd schema rasters
ddd schema constants
ddd schema dictionary
ddd schema all -o schemas
ddd schema component -o .vscode/ddd_component.schema.json
Pointing an editor at those files gives the whole team the validation and the hover
documentation of the contract while a description file is being written, which is where a
typo is cheapest to fix. Writing them out with -o keeps the line endings exactly as
generated, so a schema checked in from Windows does not differ from the same schema checked
in from linux.
Reference
The following is generated from the contracts themselves. Each model carries three things,
which answer three different questions. The field list says what may be written and what
it means. The json schema says exactly what a validator will accept - the precise
pattern, length and range every field is held to - and is the fragment an editor uses. The
entity relationship diagram says how the models fit together, which neither of the other
two shows: that a Declaration holds exactly one of the six kinds of data object, and that
the same Limits and A2lObjectOptions hang off every one of them. Where a field carries
an alias, the alias is the key that belongs in the json file - $schema, not
schema_reference.
Project description
- pydantic model ProjectFile[source]
Root object of a
*.ddd.jsonproject description.projectis the top level key that makes this a project file rather than a component or a types file; DDD decides what a file is from that key alone, so exactly one of them appears here.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.project.Project" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Project</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>includes</td><td port="includes">tuple[str, ...]</td></tr><tr><td>plugins</td><td port="plugins">tuple[str, ...]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>point_counts</td><td port="point_counts">PointCounts | None</td></tr></table>>,
tooltip="ddd.models.project.Project

A project is a named list of components and/or sub-projects.
"];
"ddd.models.project.ProjectFile" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ProjectFile</b></td></tr><tr><td>schema_reference</td><td port="schema_reference">str | None</td></tr><tr><td>project</td><td port="project">Project</td></tr></table>>,
tooltip="ddd.models.project.ProjectFile

Root object of a ``*.ddd.json`` project description.

``project`` is the top level \
key that makes this a project file rather than a component
or a types file; DDD decides what a file is from that key alone, \
so exactly one of them
appears here.
"];
"ddd.models.project.ProjectFile":project:e -> "ddd.models.project.Project":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-9fff27b5c329d9fb42b5cf843734c857818a6b03.png)
Show JSON schema
{ "title": "DDD project description", "description": "Root object of a ``*.ddd.json`` project description.\n\n``project`` is the top level key that makes this a project file rather than a component\nor a types file; DDD decides what a file is from that key alone, so exactly one of them\nappears here.", "type": "object", "properties": { "$schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Editor binding to a schema written by ``ddd schema -o``; not interpreted by DDD.", "title": "$Schema" }, "project": { "$ref": "#/$defs/Project", "description": "The project this file describes; the key that identifies the file as a project." } }, "$defs": { "PointCounts": { "description": "Where an interpolation object stores its number of axis points, if anywhere.", "enum": [ "none", "leading" ], "title": "PointCounts", "type": "string" }, "Project": { "additionalProperties": false, "description": "A project is a named list of components and/or sub-projects.", "properties": { "name": { "description": "Name of the project; also the a2l project and module name.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the project.", "title": "Description", "type": "string" }, "includes": { "default": [], "description": "Paths to component, types, units, sections, constants, rasters or sub-project files,\nrelative to this file.\n\nShell style wildcards (``*``, ``?``, ``[...]``, ``**``) are expanded; the kind of every\nincluded file is detected from its top level key. An entry that names an existing file is\nthat file whatever characters it holds, so a path under a directory somebody called\n``proj [v2]`` is a path and not a character class; only an entry naming no file is\nexpanded as a pattern.", "items": { "type": "string" }, "title": "Includes", "type": "array" }, "plugins": { "default": [], "description": "Plugins that extend DDD for this project, in the order their hooks run.\n\nEach entry is a ``.py`` path relative to this file - a plugin the project keeps in its\nown repository - or a dotted module name imported from the environment - one installed as\na distribution. A plugin acts on a project because the project names it, never because\nit happens to be installed. A sub-project may name plugins too; the set in play is the\nunion, because the blocks a plugin interprets may sit in any component.", "items": { "minLength": 1, "type": "string" }, "title": "Plugins", "type": "array" }, "extensions": { "description": "The settings of each plugin, keyed by plugin name: ``{\"layout\": {\"max_key\": 4095}}``.\n\nValidated against the plugin's project model, defaults filled in, and carried into the\ndictionary so that a comparison over an archived dump still knows them. A plugin's\nsettings are stated by one project file; a second file stating them is a ``schema``\nfinding, the way a second file declaring a section is refused.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "point_counts": { "anyOf": [ { "$ref": "#/$defs/PointCounts" }, { "type": "null" } ], "default": null, "description": "Where the project's curves, maps and axes store their point counts: ``\"leading\"``\nahead of the data, or ``\"none\"``. Unstated, it is ``\"none\"``.\n\nThe default a component's own ``point_counts`` overrides. It belongs to the firmware's\ninterpolation library, which is why it is stated here and not on each object; one project\nfile of a tree states it, and a second one stating another value is refused." } }, "required": [ "name" ], "title": "Project", "type": "object" } }, "additionalProperties": false, "required": [ "project" ] }
- Fields:
project (ddd.models.project.Project)
- pydantic model Project[source]
A project is a named list of components and/or sub-projects.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.project.Project" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Project</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>includes</td><td port="includes">tuple[str, ...]</td></tr><tr><td>plugins</td><td port="plugins">tuple[str, ...]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>point_counts</td><td port="point_counts">PointCounts | None</td></tr></table>>,
tooltip="ddd.models.project.Project

A project is a named list of components and/or sub-projects.
"];
}](_images/graphviz-18d5a0449ba79e451bb3ab61a5d1f134ef50b64f.png)
Show JSON schema
{ "title": "Project", "description": "A project is a named list of components and/or sub-projects.", "type": "object", "properties": { "name": { "description": "Name of the project; also the a2l project and module name.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the project.", "title": "Description", "type": "string" }, "includes": { "default": [], "description": "Paths to component, types, units, sections, constants, rasters or sub-project files,\nrelative to this file.\n\nShell style wildcards (``*``, ``?``, ``[...]``, ``**``) are expanded; the kind of every\nincluded file is detected from its top level key. An entry that names an existing file is\nthat file whatever characters it holds, so a path under a directory somebody called\n``proj [v2]`` is a path and not a character class; only an entry naming no file is\nexpanded as a pattern.", "items": { "type": "string" }, "title": "Includes", "type": "array" }, "plugins": { "default": [], "description": "Plugins that extend DDD for this project, in the order their hooks run.\n\nEach entry is a ``.py`` path relative to this file - a plugin the project keeps in its\nown repository - or a dotted module name imported from the environment - one installed as\na distribution. A plugin acts on a project because the project names it, never because\nit happens to be installed. A sub-project may name plugins too; the set in play is the\nunion, because the blocks a plugin interprets may sit in any component.", "items": { "minLength": 1, "type": "string" }, "title": "Plugins", "type": "array" }, "extensions": { "description": "The settings of each plugin, keyed by plugin name: ``{\"layout\": {\"max_key\": 4095}}``.\n\nValidated against the plugin's project model, defaults filled in, and carried into the\ndictionary so that a comparison over an archived dump still knows them. A plugin's\nsettings are stated by one project file; a second file stating them is a ``schema``\nfinding, the way a second file declaring a section is refused.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "point_counts": { "anyOf": [ { "$ref": "#/$defs/PointCounts" }, { "type": "null" } ], "default": null, "description": "Where the project's curves, maps and axes store their point counts: ``\"leading\"``\nahead of the data, or ``\"none\"``. Unstated, it is ``\"none\"``.\n\nThe default a component's own ``point_counts`` overrides. It belongs to the firmware's\ninterpolation library, which is why it is stated here and not on each object; one project\nfile of a tree states it, and a second one stating another value is refused." } }, "$defs": { "PointCounts": { "description": "Where an interpolation object stores its number of axis points, if anywhere.", "enum": [ "none", "leading" ], "title": "PointCounts", "type": "string" } }, "additionalProperties": false, "required": [ "name" ] }
- Fields:
description (str)extensions (dict[str, dict[str, Any]])includes (tuple[str, ...])name (str)plugins (tuple[str, ...])point_counts (ddd.models.objects.PointCounts | None)
- field name: Identifier [Required]
Name of the project; also the a2l project and module name.
- field description: str = ''
Free text describing the project.
- field includes: tuple[str, ...] = ()
Paths to component, types, units, sections, constants, rasters or sub-project files, relative to this file.
Shell style wildcards (
*,?,[...],**) are expanded; the kind of every included file is detected from its top level key. An entry that names an existing file is that file whatever characters it holds, so a path under a directory somebody calledproj [v2]is a path and not a character class; only an entry naming no file is expanded as a pattern.Paths to component, types, units, sections, constants, rasters or sub-project files, relative to this file.
Shell style wildcards (
*,?,[...],**) are expanded; the kind of every included file is detected from its top level key. An entry that names an existing file is that file whatever characters it holds, so a path under a directory somebody calledproj [v2]is a path and not a character class; only an entry naming no file is expanded as a pattern.
- field plugins: tuple[Annotated[str, StringConstraints(min_length=1)], ...] = ()
Plugins that extend DDD for this project, in the order their hooks run.
Each entry is a
.pypath relative to this file - a plugin the project keeps in its own repository - or a dotted module name imported from the environment - one installed as a distribution. A plugin acts on a project because the project names it, never because it happens to be installed. A sub-project may name plugins too; the set in play is the union, because the blocks a plugin interprets may sit in any component.Plugins that extend DDD for this project, in the order their hooks run.
Each entry is a
.pypath relative to this file - a plugin the project keeps in its own repository - or a dotted module name imported from the environment - one installed as a distribution. A plugin acts on a project because the project names it, never because it happens to be installed. A sub-project may name plugins too; the set in play is the union, because the blocks a plugin interprets may sit in any component.
- field extensions: dict[PluginName, dict[str, Any]] [Optional]
The settings of each plugin, keyed by plugin name:
{"layout": {"max_key": 4095}}.Validated against the plugin’s project model, defaults filled in, and carried into the dictionary so that a comparison over an archived dump still knows them. A plugin’s settings are stated by one project file; a second file stating them is a
schemafinding, the way a second file declaring a section is refused.The settings of each plugin, keyed by plugin name:
{"layout": {"max_key": 4095}}.Validated against the plugin’s project model, defaults filled in, and carried into the dictionary so that a comparison over an archived dump still knows them. A plugin’s settings are stated by one project file; a second file stating them is a
schemafinding, the way a second file declaring a section is refused.
- field point_counts: PointCounts | None = None
Where the project’s curves, maps and axes store their point counts:
"leading"ahead of the data, or"none". Unstated, it is"none".The default a component’s own
point_countsoverrides. It belongs to the firmware’s interpolation library, which is why it is stated here and not on each object; one project file of a tree states it, and a second one stating another value is refused.Where the project’s curves, maps and axes store their point counts:
"leading"ahead of the data, or"none". Unstated, it is"none".The default a component’s own
point_countsoverrides. It belongs to the firmware’s interpolation library, which is why it is stated here and not on each object; one project file of a tree states it, and a second one stating another value is refused.
Software component description
- pydantic model ComponentFile[source]
Root object of a
*.ddd.jsonsoftware component description.componentis the top level key that makes this a component file rather than a project or a types file; DDD decides what a file is from that key alone, so exactly one of them appears here.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.component.Component" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Component</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>point_counts</td><td port="point_counts">PointCounts | None</td></tr><tr><td>interface</td><td port="interface">tuple[Declaration, ...]</td></tr><tr><td>types</td><td port="types">Optional[tuple[StructType | ScalarType | ExternalType, ...]]</td></tr><tr><td>constants</td><td port="constants">Optional[tuple[ConstantDeclaration, ...]]</td></tr></table>>,
tooltip="ddd.models.component.Component

The interface specification of one software component.
"];
"ddd.models.component.Declaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Declaration</b></td></tr><tr><td>scope</td><td port="scope">Scope</td></tr><tr><td>condition</td><td port="condition">str | None</td></tr><tr><td>definition</td><td port="definition">Measurement | Parameter | ValueBlock | Curve | Map | Axis</td></tr></table>>,
tooltip="ddd.models.component.Declaration

One entry of the ``interface`` list of a component.
"];
"ddd.models.component.Component":interface:e -> "ddd.models.component.Declaration":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.constants.ConstantDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ConstantDeclaration</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">Union[int, float]</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.constants.ConstantDeclaration

One named number, declared once and named wherever the project needs it.
"];
"ddd.models.component.Component":constants:e -> "ddd.models.constants.ConstantDeclaration":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.ExternalType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ExternalType</b></td></tr><tr><td>type</td><td port="type">Literal['external']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>header</td><td port="header">str</td></tr></table>>,
tooltip="ddd.models.types.ExternalType

A name for a c type that DDD does not declare: a hand written header defines it.

\
DDD generates no typedef for it and knows neither its layout nor its meaning - which is
the point: a driver's status word or \
an operating system's handle already has one
authoritative definition, and a copy of it in the description would drift. Only \
a
structure member may name one, as opaque storage that reaches the generated structure
verbatim; such a member states no \
unit, conversion or limits, because DDD does not check
meaning it cannot see.
"];
"ddd.models.component.Component":types:e -> "ddd.models.types.ExternalType":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.ScalarType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ScalarType</b></td></tr><tr><td>type</td><td port="type">Literal['scalar']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">IdentityConversion | LinearConversion | EnumConversion | StringConversion</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr></table>>,
tooltip="ddd.models.types.ScalarType

A name for what a number means, so components agree by naming rather than by copying.
&#\
xA;Three components consuming an engine speed each used to write out the datatype, the unit,
the scaling and the limits, leaving \
DDD to notice when one of them was wrong. If all three
say ``Speed_t`` instead, there is nothing left to disagree about - which \
is checking turned
into construction.

It fixes exactly the four things that make two declarations interchangeable, \
and nothing
else. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:
they are properties \
of one object rather than of the type, and two measurements of the same
type may well differ in whether an interrupt writes \
one of them.
"];
"ddd.models.component.Component":types:e -> "ddd.models.types.ScalarType":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.StructType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StructType</b></td></tr><tr><td>type</td><td port="type">Literal['struct']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>members</td><td port="members">tuple[Member, ...]</td></tr></table>>,
tooltip="ddd.models.types.StructType

One structured datatype: a name and the members it lays out, in order.
"];
"ddd.models.component.Component":types:e -> "ddd.models.types.StructType":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.component.ComponentFile" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ComponentFile</b></td></tr><tr><td>schema_reference</td><td port="schema_reference">str | None</td></tr><tr><td>component</td><td port="component">Component</td></tr></table>>,
tooltip="ddd.models.component.ComponentFile

Root object of a ``*.ddd.json`` software component description.

``component`` \
is the top level key that makes this a component file rather than a project
or a types file; DDD decides what a file is from \
that key alone, so exactly one of them
appears here.
"];
"ddd.models.component.ComponentFile":component:e -> "ddd.models.component.Component":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Axis" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Axis</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.AXIS]</td></tr><tr><td>size</td><td port="size">Union[int, str]</td></tr><tr><td>input</td><td port="input">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.Axis

Shared axis points; several curves and maps may be interpolated over one axis.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Axis":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Curve</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.CURVE]</td></tr><tr><td>axis</td><td port="axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Curve

A one dimensional calibratable table.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Curve":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Map</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MAP]</td></tr><tr><td>x_axis</td><td port="x_axis">str</td></tr><tr><td>y_axis</td><td port="y_axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Map

A two dimensional calibratable table, stored as ``[y][x]``.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Map":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Measurement</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MEASUREMENT]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.Measurement

An online value: the software writes it, a calibration tool measures it and may write it.&#\
xA;
A tool writing one through its address is one of the reasons to declare a measurement
``volatile``, alongside an interrupt, \
a second core and a peripheral.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Measurement":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Parameter</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.PARAMETER]</td></tr></table>>,
tooltip="ddd.models.objects.Parameter

A single calibratable constant.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Parameter":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ValueBlock</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.VALUE_BLOCK]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.ValueBlock

An array of calibratable constants.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.ValueBlock":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Axis":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.Member" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Member</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>member</td><td port="member">MemberKind</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr><tr><td>bits</td><td port="bits">Optional[int]</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr></table>>,
tooltip="ddd.models.types.Member

One member of a structure, in the order the structure declares it.

Order is significant: \
it is the order the c struct is generated in, and therefore the order
the compiler lays out. Reordering members of a released \
structure moves every address after
the change, which is why a comparison against a baseline reports it.
"];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.Member":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.StructType":members:e -> "ddd.models.types.Member":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-69273cd62d353877ecd4b57d6a0b1817ed30a1d5.png)
Show JSON schema
{ "title": "DDD component description", "description": "Root object of a ``*.ddd.json`` software component description.\n\n``component`` is the top level key that makes this a component file rather than a project\nor a types file; DDD decides what a file is from that key alone, so exactly one of them\nappears here.", "type": "object", "properties": { "$schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Editor binding to a schema written by ``ddd schema -o``; not interpreted by DDD.", "title": "$Schema" }, "component": { "$ref": "#/$defs/Component", "description": "The component this file describes; the key that identifies the file as a component." } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Axis": { "additionalProperties": false, "description": "Shared axis points; several curves and maps may be interpolated over one axis.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "axis", "title": "Kind", "type": "string" }, "size": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ], "description": "Number of axis points: an integer of at least 1, or the name of a declared constant.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "title": "Size" }, "input": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement that indexes the axis; the a2l input quantity.\n\nA plain one: an instance of a declared structure is of kind ``measurement`` and is\nrefused here as any other wrong kind is, because it reaches the a2l as one record per\nvalue-holding member and none of its own.", "title": "Input" } }, "required": [ "name", "volatile", "kind", "size" ], "title": "Axis", "type": "object" }, "Component": { "additionalProperties": false, "description": "The interface specification of one software component.", "properties": { "name": { "description": "Name of the component; every component of a project needs a distinct one.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the component, offered to the c templates.", "title": "Description", "type": "string" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Default measurement raster for every variable this component produces.\n\nThe common case stated once: a component updates nearly all of its measurements in one\ntask, and repeating that on several hundred definitions would bury the handful of\nexceptions, which state their own ``raster``. It applies to what this component\nproduces and to nothing it reads - the raster follows the producer - and it reaches no\ncalibration object, since no daq list carries one.", "title": "Raster" }, "point_counts": { "anyOf": [ { "$ref": "#/$defs/PointCounts" }, { "type": "null" } ], "default": null, "description": "Where the curves, maps and axes this component defines store their point counts,\noverriding the project's default.\n\nIt follows the producer, as ``raster`` does: the component that defines a table is the one\nwhose routines interpolate over it. It reaches nothing this component reads, and nothing\nthat is not a curve, a map or an axis." }, "interface": { "description": "The data interface: everything the component produces, consumes or keeps to itself.\n\nRequired with no default, so that a component with nothing to declare says so with an\nempty list rather than by a key that might merely have been forgotten - the same\nreasoning that makes ``volatile`` and ``kind`` required on a definition.", "items": { "$ref": "#/$defs/Declaration" }, "title": "Interface", "type": "array" }, "types": { "anyOf": [ { "items": { "discriminator": { "mapping": { "external": "#/$defs/ExternalType", "scalar": "#/$defs/ScalarType", "struct": "#/$defs/StructType" }, "propertyName": "type" }, "oneOf": [ { "$ref": "#/$defs/StructType" }, { "$ref": "#/$defs/ScalarType" }, { "$ref": "#/$defs/ExternalType" } ] }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "description": "Declared types this component publishes, each entry exactly as a types file writes it.\n\nDeclaring them here co-locates a library's contract in one file; it does not scope it.\nThe names join the same project wide namespace as the types of the standalone files,\nevery consistency check applies to them unchanged, and any component of the project may\nname them. Types shared between several components, with no single owner to live inside,\nstay in a standalone types file.", "title": "Types" }, "constants": { "anyOf": [ { "items": { "$ref": "#/$defs/ConstantDeclaration" }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "description": "Declared constants this component publishes, each entry exactly as a constants file\nwrites it.\n\nCo-located for the reason ``types`` may be, and no more scoped than they are: the names\njoin the same project wide namespace as the constants of a constants file, and any\nshape of any component names one where it would state a number. ``units``, ``sections``\nand ``rasters`` remain project wide vocabularies and have no place inside a component.", "title": "Constants" } }, "required": [ "name", "interface" ], "title": "Component", "type": "object" }, "ConstantDeclaration": { "additionalProperties": false, "description": "One named number, declared once and named wherever the project needs it.", "properties": { "name": { "description": "The name a shape writes where it would state a number: ``PRESSURE_CELLS``.\n\nAn identifier, because the name reaches the generated code as an identifier of its own;\nthe templates receive every declared constant to emit.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "The value, a number: a whole number of either sign, or one written with a point.\n\nA literal only: an expression would put a parser and an evaluation order into a\ndescription format, and a constant cannot name another constant, so what cannot be\nwritten cannot cycle. How it is written settles what it is - ``2`` is a whole number,\nand anything carrying a point or an exponent is fractional, so ``2.0`` and ``1e3`` both\nare - because that is what the author is picking: the type, not the format. The\noutputs carry the number in its shortest spelling that reads back as the same number, a\nwhole number without a point and any other with a point or an exponent, so ``2.50``\nreaches the generated code as ``2.5`` and ``1e3`` as ``1000.0``.\nA whole number is bounded by what a 64 bit target can express, signed or unsigned, and\na fractional one must be finite: ``inf`` and ``nan`` name nothing a description can\nstate, and would reach a template as those words.\n\nNothing here requires the value to be a size. A constant that a shape names has to be\na whole number of at least 1, the same rule a dimension written as a literal obeys, but\nthat is checked where the shape names it - the declaration is not the place, because a\nconstant may be declared to be emitted and never dimension anything.", "title": "Value" }, "description": { "default": "", "description": "What the constant stands for, e.g. ``cells of the pressure manifold``.\n\nThis is where the meaning of a number is written down once, instead of being implied by\nevery object that happens to use it.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "ConstantDeclaration", "type": "object" }, "Curve": { "additionalProperties": false, "description": "A one dimensional calibratable table.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "curve", "title": "Kind", "type": "string" }, "axis": { "description": "Name of the axis object the curve is interpolated over.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Axis", "type": "string" } }, "required": [ "name", "volatile", "kind", "axis" ], "title": "Curve", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "Declaration": { "additionalProperties": false, "description": "One entry of the ``interface`` list of a component.", "properties": { "scope": { "$ref": "#/$defs/Scope", "description": "Direction of the declaration, which is what makes the interfaces check each other.\n\nExactly one component may produce a name - declare it ``output`` or ``local`` - and that\ncomponent's definition is the one the project uses. Every ``input`` declaring the same\nname has to agree with it on datatype, unit, conversion, limits and shape." }, "condition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "C preprocessor expression wrapping the generated declaration, e.g. ``defined(FEAT_X)``.\n\nOne expression, written as it would appear after ``#if``. It is emitted verbatim into the\ngenerated files, so it cannot span lines, cannot end in ``\\`` and cannot contain ``#``,\n``//``, ``/*`` or ``*/`` - each of which would let a description file put arbitrary\ndirectives, or live code, into somebody else's build.", "title": "Condition" }, "definition": { "description": "The data object being declared; its ``kind`` decides which keys it carries.", "discriminator": { "mapping": { "axis": "#/$defs/Axis", "curve": "#/$defs/Curve", "map": "#/$defs/Map", "measurement": "#/$defs/Measurement", "parameter": "#/$defs/Parameter", "value_block": "#/$defs/ValueBlock" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/Measurement" }, { "$ref": "#/$defs/Parameter" }, { "$ref": "#/$defs/ValueBlock" }, { "$ref": "#/$defs/Curve" }, { "$ref": "#/$defs/Map" }, { "$ref": "#/$defs/Axis" } ], "title": "Definition" } }, "required": [ "scope", "definition" ], "title": "Declaration", "type": "object" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "ExternalType": { "additionalProperties": false, "description": "A name for a c type that DDD does not declare: a hand written header defines it.\n\nDDD generates no typedef for it and knows neither its layout nor its meaning - which is\nthe point: a driver's status word or an operating system's handle already has one\nauthoritative definition, and a copy of it in the description would drift. Only a\nstructure member may name one, as opaque storage that reaches the generated structure\nverbatim; such a member states no unit, conversion or limits, because DDD does not check\nmeaning it cannot see.", "properties": { "type": { "const": "external", "description": "Says this entry names an external type rather than declaring one of DDD's own.", "title": "Type", "type": "string" }, "name": { "description": "The type's c identifier, as the defining header spells it.\n\nEvery type of a project needs a distinct name, and the rules are those of the declared\ntypes: it cannot read as a base datatype, and it shares the project wide namespace with\nthe structures and the scalars.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "header": { "description": "The header that defines the type, spelled the way the generated inclusion writes it.\n\n``my_driver.h`` for the quoted form, ``<os_types.h>`` for the angle form; a subdirectory\npath such as ``drivers/status.h`` is allowed in either. The spelling is written out\nexactly as it stands, so one that would unbalance the line is refused here rather than\nhanded to a compiler: no whitespace, no quote of its own - the quoted form is written\nbare - and, for the angle form, exactly one pair of angle brackets wrapping the whole\nname.", "minLength": 1, "title": "Header", "type": "string" } }, "required": [ "type", "name", "header" ], "title": "ExternalType", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "Map": { "additionalProperties": false, "description": "A two dimensional calibratable table, stored as ``[y][x]``.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "map", "title": "Kind", "type": "string" }, "x_axis": { "description": "Name of the axis whose index runs fastest; the last dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "X Axis", "type": "string" }, "y_axis": { "description": "Name of the axis selecting the row; the first dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Y Axis", "type": "string" } }, "required": [ "name", "volatile", "kind", "x_axis", "y_axis" ], "title": "Map", "type": "object" }, "Measurement": { "additionalProperties": false, "description": "An online value: the software writes it, a calibration tool measures it and may write it.\n\nA tool writing one through its address is one of the reasons to declare a measurement\n``volatile``, alongside an interrupt, a second core and a peripheral.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "measurement", "title": "Kind", "type": "string" }, "dimensions": { "default": [], "description": "Array dimensions; empty for a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, in a\nconstants file or in a component - ``[3, 4]`` and ``[\"PRESSURE_CELLS\", 4]`` are both\nshapes.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" } }, "required": [ "name", "volatile", "kind" ], "title": "Measurement", "type": "object" }, "Member": { "additionalProperties": false, "description": "One member of a structure, in the order the structure declares it.\n\nOrder is significant: it is the order the c struct is generated in, and therefore the order\nthe compiler lays out. Reordering members of a released structure moves every address after\nthe change, which is why a comparison against a baseline reports it.", "properties": { "name": { "description": "Name of the member, unique within its structure.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "member": { "$ref": "#/$defs/MemberKind", "description": "Which shape this member has, and with it which other keys the member may carry.\n\n* ``value`` needs ``datatype`` or ``typename`` and may add ``dimensions``,\n* ``bits`` needs ``datatype`` and ``bits``.\n\nA key belonging to the other shape is refused rather than ignored: ``bits`` together with\n``dimensions`` has no single meaning - c has no array of bitfields - and quietly dropping\none of the two would put a structure in the generated c that this file does not describe." }, "description": { "default": "", "description": "Free text describing the member, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of this member, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated, here exactly as on a declaration." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a declared type, stated instead of ``datatype``.\n\nA ``value`` member may name a structure, which nests it, a scalar type, which fixes what\nits number means, or an external type, which makes it opaque storage a hand written header\ndefines. A ``bits`` member states a base integer ``datatype``: a bitfield has no room for\na structure, and a scalar type would carry limits the width contradicts.", "title": "Typename" }, "dimensions": { "default": [], "description": "Array dimensions of a ``value`` member, in c declaration order; empty for a scalar.\n\n``[4, 2]`` is declared as ``[4][2]``, the last dimension running fastest in memory.\nEach dimension is an integer of at least 1, or the name of a constant the project\ndeclares, exactly as on a declaration - the spelling, that is, since the 10 000 000\nelement cap is a declaration's and a map's alone: an array here is weighed in the leaves\nits structure may hold, and a member holding a value is one leaf however long its array.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" }, "bits": { "anyOf": [ { "exclusiveMinimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "description": "Width of a ``bits`` member, in bits; required on one, refused on the other.\n\nIt has to fit the datatype carrying it - at most 16 in a ``uint16`` - and that datatype\nhas to be an integer, since c allows a bitfield in nothing else.", "title": "Bits" }, "unit": { "default": "", "description": "Physical unit of this member, e.g. ``\"degC\"``.\n\nWritten here, or fixed by a scalar type this member names, and never both. Which of the\ntwo to reach for is a question of whether the answer is shared: a unit written here says it\nfor this member of this structure, and a ``Temperature_t`` says it for everything that\nnames it, across every component of the project.", "title": "Unit", "type": "string" }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How this member's raw value maps to a physical one: identity, linear, an enumeration,\nor text read from the bytes (``string``).\n\nRequired on a member whose storage is a base ``datatype``, exactly as on a definition;\na member naming a scalar ``typename`` states none, the type fixing it.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of this member; derived from its storage and conversion if omitted.\n\nFor a ``bits`` member the derivation uses the *width*, not the datatype carrying it: a two\nbit field offered to a calibration tool as ``0 .. 65535`` invites somebody to enter a value\nthe field cannot hold and the software then reads back something else." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this member asks of the a2l file once the structure is flattened into it.\n\nPer member rather than per structure, because that is the granularity the a2l ends up with:\neach member becomes an object of its own, so keeping one of them out of the file, or giving\none of them a display format, is a decision about that member alone." } }, "required": [ "name", "member" ], "title": "Member", "type": "object" }, "MemberKind": { "description": "What shape a structure member has.\n\nStated rather than inferred from which keys are present: a file that omits a key by mistake\nshould be told which member shape it failed to describe, not silently become another one.\nA forgotten ``bits`` would otherwise turn a one bit flag into a full width member and move\nevery offset after it.", "enum": [ "value", "bits" ], "title": "MemberKind", "type": "string" }, "Parameter": { "additionalProperties": false, "description": "A single calibratable constant.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "parameter", "title": "Kind", "type": "string" } }, "required": [ "name", "volatile", "kind" ], "title": "Parameter", "type": "object" }, "PointCounts": { "description": "Where an interpolation object stores its number of axis points, if anywhere.", "enum": [ "none", "leading" ], "title": "PointCounts", "type": "string" }, "ScalarType": { "additionalProperties": false, "description": "A name for what a number means, so components agree by naming rather than by copying.\n\nThree components consuming an engine speed each used to write out the datatype, the unit,\nthe scaling and the limits, leaving DDD to notice when one of them was wrong. If all three\nsay ``Speed_t`` instead, there is nothing left to disagree about - which is checking turned\ninto construction.\n\nIt fixes exactly the four things that make two declarations interchangeable, and nothing\nelse. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:\nthey are properties of one object rather than of the type, and two measurements of the same\ntype may well differ in whether an interrupt writes one of them.", "properties": { "type": { "const": "scalar", "description": "Says this entry names a scalar rather than describing a structure.", "title": "Type", "type": "string" }, "name": { "description": "Name of the type; every type of a project needs a distinct one.\n\nRefused if it reads as a base datatype, for the reason a structure's name is.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "$ref": "#/$defs/Datatype", "description": "Storage of the value: one of the base datatypes.\n\nA base datatype rather than another declared type, so that a scalar type cannot be defined\nin terms of a second one. A chain of names would have to be resolved, could form a cycle,\nand buys nothing a reader of the one entry could not already see." }, "unit": { "default": "", "description": "Physical unit of the value, e.g. ``\"rpm\"``.", "title": "Unit", "type": "string" }, "conversion": { "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired: fixing what a value means is the one job a scalar type has, and the identity\nis part of the answer rather than a silence to interpret.", "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ], "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits, in the unit above; derived from datatype and conversion if omitted." } }, "required": [ "type", "name", "datatype", "conversion" ], "title": "ScalarType", "type": "object" }, "Scope": { "description": "Direction of a variable with respect to the declaring component.", "enum": [ "input", "output", "local" ], "title": "Scope", "type": "string" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" }, "StructType": { "additionalProperties": false, "description": "One structured datatype: a name and the members it lays out, in order.", "properties": { "type": { "const": "struct", "description": "Says this entry describes a structure; stated on every entry of a types file.", "title": "Type", "type": "string" }, "name": { "description": "Name of the structure; every type of a project needs a distinct one.\n\nRefused if it spells a base datatype, compared without regard to case: a type called\n``uint16``, or ``UINT16``, wears the name of storage it is not, and every declaration\nnaming it would read like a typo.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the structure, offered to the c templates.", "title": "Description", "type": "string" }, "members": { "description": "The members, in the order they are laid out.", "items": { "$ref": "#/$defs/Member" }, "minItems": 1, "title": "Members", "type": "array" } }, "required": [ "type", "name", "members" ], "title": "StructType", "type": "object" }, "ValueBlock": { "additionalProperties": false, "description": "An array of calibratable constants.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "value_block", "title": "Kind", "type": "string" }, "dimensions": { "description": "Array dimensions in c declaration order; a value block is never a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, mixed\nfreely.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "minItems": 1, "title": "Dimensions", "type": "array" } }, "required": [ "name", "volatile", "kind", "dimensions" ], "title": "ValueBlock", "type": "object" } }, "additionalProperties": false, "required": [ "component" ] }
- Fields:
component (ddd.models.component.Component)
- pydantic model Component[source]
The interface specification of one software component.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.component.Component" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Component</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>point_counts</td><td port="point_counts">PointCounts | None</td></tr><tr><td>interface</td><td port="interface">tuple[Declaration, ...]</td></tr><tr><td>types</td><td port="types">Optional[tuple[StructType | ScalarType | ExternalType, ...]]</td></tr><tr><td>constants</td><td port="constants">Optional[tuple[ConstantDeclaration, ...]]</td></tr></table>>,
tooltip="ddd.models.component.Component

The interface specification of one software component.
"];
"ddd.models.component.Declaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Declaration</b></td></tr><tr><td>scope</td><td port="scope">Scope</td></tr><tr><td>condition</td><td port="condition">str | None</td></tr><tr><td>definition</td><td port="definition">Measurement | Parameter | ValueBlock | Curve | Map | Axis</td></tr></table>>,
tooltip="ddd.models.component.Declaration

One entry of the ``interface`` list of a component.
"];
"ddd.models.component.Component":interface:e -> "ddd.models.component.Declaration":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.constants.ConstantDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ConstantDeclaration</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">Union[int, float]</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.constants.ConstantDeclaration

One named number, declared once and named wherever the project needs it.
"];
"ddd.models.component.Component":constants:e -> "ddd.models.constants.ConstantDeclaration":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.ExternalType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ExternalType</b></td></tr><tr><td>type</td><td port="type">Literal['external']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>header</td><td port="header">str</td></tr></table>>,
tooltip="ddd.models.types.ExternalType

A name for a c type that DDD does not declare: a hand written header defines it.

\
DDD generates no typedef for it and knows neither its layout nor its meaning - which is
the point: a driver's status word or \
an operating system's handle already has one
authoritative definition, and a copy of it in the description would drift. Only \
a
structure member may name one, as opaque storage that reaches the generated structure
verbatim; such a member states no \
unit, conversion or limits, because DDD does not check
meaning it cannot see.
"];
"ddd.models.component.Component":types:e -> "ddd.models.types.ExternalType":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.ScalarType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ScalarType</b></td></tr><tr><td>type</td><td port="type">Literal['scalar']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">IdentityConversion | LinearConversion | EnumConversion | StringConversion</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr></table>>,
tooltip="ddd.models.types.ScalarType

A name for what a number means, so components agree by naming rather than by copying.
&#\
xA;Three components consuming an engine speed each used to write out the datatype, the unit,
the scaling and the limits, leaving \
DDD to notice when one of them was wrong. If all three
say ``Speed_t`` instead, there is nothing left to disagree about - which \
is checking turned
into construction.

It fixes exactly the four things that make two declarations interchangeable, \
and nothing
else. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:
they are properties \
of one object rather than of the type, and two measurements of the same
type may well differ in whether an interrupt writes \
one of them.
"];
"ddd.models.component.Component":types:e -> "ddd.models.types.ScalarType":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.StructType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StructType</b></td></tr><tr><td>type</td><td port="type">Literal['struct']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>members</td><td port="members">tuple[Member, ...]</td></tr></table>>,
tooltip="ddd.models.types.StructType

One structured datatype: a name and the members it lays out, in order.
"];
"ddd.models.component.Component":types:e -> "ddd.models.types.StructType":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Axis</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.AXIS]</td></tr><tr><td>size</td><td port="size">Union[int, str]</td></tr><tr><td>input</td><td port="input">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.Axis

Shared axis points; several curves and maps may be interpolated over one axis.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Axis":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Curve</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.CURVE]</td></tr><tr><td>axis</td><td port="axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Curve

A one dimensional calibratable table.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Curve":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Map</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MAP]</td></tr><tr><td>x_axis</td><td port="x_axis">str</td></tr><tr><td>y_axis</td><td port="y_axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Map

A two dimensional calibratable table, stored as ``[y][x]``.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Map":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Measurement</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MEASUREMENT]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.Measurement

An online value: the software writes it, a calibration tool measures it and may write it.&#\
xA;
A tool writing one through its address is one of the reasons to declare a measurement
``volatile``, alongside an interrupt, \
a second core and a peripheral.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Measurement":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Parameter</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.PARAMETER]</td></tr></table>>,
tooltip="ddd.models.objects.Parameter

A single calibratable constant.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Parameter":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ValueBlock</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.VALUE_BLOCK]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.ValueBlock

An array of calibratable constants.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.ValueBlock":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Axis":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.Member" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Member</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>member</td><td port="member">MemberKind</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr><tr><td>bits</td><td port="bits">Optional[int]</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr></table>>,
tooltip="ddd.models.types.Member

One member of a structure, in the order the structure declares it.

Order is significant: \
it is the order the c struct is generated in, and therefore the order
the compiler lays out. Reordering members of a released \
structure moves every address after
the change, which is why a comparison against a baseline reports it.
"];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.Member":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.StructType":members:e -> "ddd.models.types.Member":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-a5dfdf11660a13febb64b3cf4aefa0a4d3454514.png)
Show JSON schema
{ "title": "Component", "description": "The interface specification of one software component.", "type": "object", "properties": { "name": { "description": "Name of the component; every component of a project needs a distinct one.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the component, offered to the c templates.", "title": "Description", "type": "string" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Default measurement raster for every variable this component produces.\n\nThe common case stated once: a component updates nearly all of its measurements in one\ntask, and repeating that on several hundred definitions would bury the handful of\nexceptions, which state their own ``raster``. It applies to what this component\nproduces and to nothing it reads - the raster follows the producer - and it reaches no\ncalibration object, since no daq list carries one.", "title": "Raster" }, "point_counts": { "anyOf": [ { "$ref": "#/$defs/PointCounts" }, { "type": "null" } ], "default": null, "description": "Where the curves, maps and axes this component defines store their point counts,\noverriding the project's default.\n\nIt follows the producer, as ``raster`` does: the component that defines a table is the one\nwhose routines interpolate over it. It reaches nothing this component reads, and nothing\nthat is not a curve, a map or an axis." }, "interface": { "description": "The data interface: everything the component produces, consumes or keeps to itself.\n\nRequired with no default, so that a component with nothing to declare says so with an\nempty list rather than by a key that might merely have been forgotten - the same\nreasoning that makes ``volatile`` and ``kind`` required on a definition.", "items": { "$ref": "#/$defs/Declaration" }, "title": "Interface", "type": "array" }, "types": { "anyOf": [ { "items": { "discriminator": { "mapping": { "external": "#/$defs/ExternalType", "scalar": "#/$defs/ScalarType", "struct": "#/$defs/StructType" }, "propertyName": "type" }, "oneOf": [ { "$ref": "#/$defs/StructType" }, { "$ref": "#/$defs/ScalarType" }, { "$ref": "#/$defs/ExternalType" } ] }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "description": "Declared types this component publishes, each entry exactly as a types file writes it.\n\nDeclaring them here co-locates a library's contract in one file; it does not scope it.\nThe names join the same project wide namespace as the types of the standalone files,\nevery consistency check applies to them unchanged, and any component of the project may\nname them. Types shared between several components, with no single owner to live inside,\nstay in a standalone types file.", "title": "Types" }, "constants": { "anyOf": [ { "items": { "$ref": "#/$defs/ConstantDeclaration" }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "description": "Declared constants this component publishes, each entry exactly as a constants file\nwrites it.\n\nCo-located for the reason ``types`` may be, and no more scoped than they are: the names\njoin the same project wide namespace as the constants of a constants file, and any\nshape of any component names one where it would state a number. ``units``, ``sections``\nand ``rasters`` remain project wide vocabularies and have no place inside a component.", "title": "Constants" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Axis": { "additionalProperties": false, "description": "Shared axis points; several curves and maps may be interpolated over one axis.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "axis", "title": "Kind", "type": "string" }, "size": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ], "description": "Number of axis points: an integer of at least 1, or the name of a declared constant.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "title": "Size" }, "input": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement that indexes the axis; the a2l input quantity.\n\nA plain one: an instance of a declared structure is of kind ``measurement`` and is\nrefused here as any other wrong kind is, because it reaches the a2l as one record per\nvalue-holding member and none of its own.", "title": "Input" } }, "required": [ "name", "volatile", "kind", "size" ], "title": "Axis", "type": "object" }, "ConstantDeclaration": { "additionalProperties": false, "description": "One named number, declared once and named wherever the project needs it.", "properties": { "name": { "description": "The name a shape writes where it would state a number: ``PRESSURE_CELLS``.\n\nAn identifier, because the name reaches the generated code as an identifier of its own;\nthe templates receive every declared constant to emit.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "The value, a number: a whole number of either sign, or one written with a point.\n\nA literal only: an expression would put a parser and an evaluation order into a\ndescription format, and a constant cannot name another constant, so what cannot be\nwritten cannot cycle. How it is written settles what it is - ``2`` is a whole number,\nand anything carrying a point or an exponent is fractional, so ``2.0`` and ``1e3`` both\nare - because that is what the author is picking: the type, not the format. The\noutputs carry the number in its shortest spelling that reads back as the same number, a\nwhole number without a point and any other with a point or an exponent, so ``2.50``\nreaches the generated code as ``2.5`` and ``1e3`` as ``1000.0``.\nA whole number is bounded by what a 64 bit target can express, signed or unsigned, and\na fractional one must be finite: ``inf`` and ``nan`` name nothing a description can\nstate, and would reach a template as those words.\n\nNothing here requires the value to be a size. A constant that a shape names has to be\na whole number of at least 1, the same rule a dimension written as a literal obeys, but\nthat is checked where the shape names it - the declaration is not the place, because a\nconstant may be declared to be emitted and never dimension anything.", "title": "Value" }, "description": { "default": "", "description": "What the constant stands for, e.g. ``cells of the pressure manifold``.\n\nThis is where the meaning of a number is written down once, instead of being implied by\nevery object that happens to use it.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "ConstantDeclaration", "type": "object" }, "Curve": { "additionalProperties": false, "description": "A one dimensional calibratable table.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "curve", "title": "Kind", "type": "string" }, "axis": { "description": "Name of the axis object the curve is interpolated over.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Axis", "type": "string" } }, "required": [ "name", "volatile", "kind", "axis" ], "title": "Curve", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "Declaration": { "additionalProperties": false, "description": "One entry of the ``interface`` list of a component.", "properties": { "scope": { "$ref": "#/$defs/Scope", "description": "Direction of the declaration, which is what makes the interfaces check each other.\n\nExactly one component may produce a name - declare it ``output`` or ``local`` - and that\ncomponent's definition is the one the project uses. Every ``input`` declaring the same\nname has to agree with it on datatype, unit, conversion, limits and shape." }, "condition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "C preprocessor expression wrapping the generated declaration, e.g. ``defined(FEAT_X)``.\n\nOne expression, written as it would appear after ``#if``. It is emitted verbatim into the\ngenerated files, so it cannot span lines, cannot end in ``\\`` and cannot contain ``#``,\n``//``, ``/*`` or ``*/`` - each of which would let a description file put arbitrary\ndirectives, or live code, into somebody else's build.", "title": "Condition" }, "definition": { "description": "The data object being declared; its ``kind`` decides which keys it carries.", "discriminator": { "mapping": { "axis": "#/$defs/Axis", "curve": "#/$defs/Curve", "map": "#/$defs/Map", "measurement": "#/$defs/Measurement", "parameter": "#/$defs/Parameter", "value_block": "#/$defs/ValueBlock" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/Measurement" }, { "$ref": "#/$defs/Parameter" }, { "$ref": "#/$defs/ValueBlock" }, { "$ref": "#/$defs/Curve" }, { "$ref": "#/$defs/Map" }, { "$ref": "#/$defs/Axis" } ], "title": "Definition" } }, "required": [ "scope", "definition" ], "title": "Declaration", "type": "object" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "ExternalType": { "additionalProperties": false, "description": "A name for a c type that DDD does not declare: a hand written header defines it.\n\nDDD generates no typedef for it and knows neither its layout nor its meaning - which is\nthe point: a driver's status word or an operating system's handle already has one\nauthoritative definition, and a copy of it in the description would drift. Only a\nstructure member may name one, as opaque storage that reaches the generated structure\nverbatim; such a member states no unit, conversion or limits, because DDD does not check\nmeaning it cannot see.", "properties": { "type": { "const": "external", "description": "Says this entry names an external type rather than declaring one of DDD's own.", "title": "Type", "type": "string" }, "name": { "description": "The type's c identifier, as the defining header spells it.\n\nEvery type of a project needs a distinct name, and the rules are those of the declared\ntypes: it cannot read as a base datatype, and it shares the project wide namespace with\nthe structures and the scalars.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "header": { "description": "The header that defines the type, spelled the way the generated inclusion writes it.\n\n``my_driver.h`` for the quoted form, ``<os_types.h>`` for the angle form; a subdirectory\npath such as ``drivers/status.h`` is allowed in either. The spelling is written out\nexactly as it stands, so one that would unbalance the line is refused here rather than\nhanded to a compiler: no whitespace, no quote of its own - the quoted form is written\nbare - and, for the angle form, exactly one pair of angle brackets wrapping the whole\nname.", "minLength": 1, "title": "Header", "type": "string" } }, "required": [ "type", "name", "header" ], "title": "ExternalType", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "Map": { "additionalProperties": false, "description": "A two dimensional calibratable table, stored as ``[y][x]``.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "map", "title": "Kind", "type": "string" }, "x_axis": { "description": "Name of the axis whose index runs fastest; the last dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "X Axis", "type": "string" }, "y_axis": { "description": "Name of the axis selecting the row; the first dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Y Axis", "type": "string" } }, "required": [ "name", "volatile", "kind", "x_axis", "y_axis" ], "title": "Map", "type": "object" }, "Measurement": { "additionalProperties": false, "description": "An online value: the software writes it, a calibration tool measures it and may write it.\n\nA tool writing one through its address is one of the reasons to declare a measurement\n``volatile``, alongside an interrupt, a second core and a peripheral.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "measurement", "title": "Kind", "type": "string" }, "dimensions": { "default": [], "description": "Array dimensions; empty for a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, in a\nconstants file or in a component - ``[3, 4]`` and ``[\"PRESSURE_CELLS\", 4]`` are both\nshapes.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" } }, "required": [ "name", "volatile", "kind" ], "title": "Measurement", "type": "object" }, "Member": { "additionalProperties": false, "description": "One member of a structure, in the order the structure declares it.\n\nOrder is significant: it is the order the c struct is generated in, and therefore the order\nthe compiler lays out. Reordering members of a released structure moves every address after\nthe change, which is why a comparison against a baseline reports it.", "properties": { "name": { "description": "Name of the member, unique within its structure.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "member": { "$ref": "#/$defs/MemberKind", "description": "Which shape this member has, and with it which other keys the member may carry.\n\n* ``value`` needs ``datatype`` or ``typename`` and may add ``dimensions``,\n* ``bits`` needs ``datatype`` and ``bits``.\n\nA key belonging to the other shape is refused rather than ignored: ``bits`` together with\n``dimensions`` has no single meaning - c has no array of bitfields - and quietly dropping\none of the two would put a structure in the generated c that this file does not describe." }, "description": { "default": "", "description": "Free text describing the member, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of this member, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated, here exactly as on a declaration." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a declared type, stated instead of ``datatype``.\n\nA ``value`` member may name a structure, which nests it, a scalar type, which fixes what\nits number means, or an external type, which makes it opaque storage a hand written header\ndefines. A ``bits`` member states a base integer ``datatype``: a bitfield has no room for\na structure, and a scalar type would carry limits the width contradicts.", "title": "Typename" }, "dimensions": { "default": [], "description": "Array dimensions of a ``value`` member, in c declaration order; empty for a scalar.\n\n``[4, 2]`` is declared as ``[4][2]``, the last dimension running fastest in memory.\nEach dimension is an integer of at least 1, or the name of a constant the project\ndeclares, exactly as on a declaration - the spelling, that is, since the 10 000 000\nelement cap is a declaration's and a map's alone: an array here is weighed in the leaves\nits structure may hold, and a member holding a value is one leaf however long its array.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" }, "bits": { "anyOf": [ { "exclusiveMinimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "description": "Width of a ``bits`` member, in bits; required on one, refused on the other.\n\nIt has to fit the datatype carrying it - at most 16 in a ``uint16`` - and that datatype\nhas to be an integer, since c allows a bitfield in nothing else.", "title": "Bits" }, "unit": { "default": "", "description": "Physical unit of this member, e.g. ``\"degC\"``.\n\nWritten here, or fixed by a scalar type this member names, and never both. Which of the\ntwo to reach for is a question of whether the answer is shared: a unit written here says it\nfor this member of this structure, and a ``Temperature_t`` says it for everything that\nnames it, across every component of the project.", "title": "Unit", "type": "string" }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How this member's raw value maps to a physical one: identity, linear, an enumeration,\nor text read from the bytes (``string``).\n\nRequired on a member whose storage is a base ``datatype``, exactly as on a definition;\na member naming a scalar ``typename`` states none, the type fixing it.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of this member; derived from its storage and conversion if omitted.\n\nFor a ``bits`` member the derivation uses the *width*, not the datatype carrying it: a two\nbit field offered to a calibration tool as ``0 .. 65535`` invites somebody to enter a value\nthe field cannot hold and the software then reads back something else." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this member asks of the a2l file once the structure is flattened into it.\n\nPer member rather than per structure, because that is the granularity the a2l ends up with:\neach member becomes an object of its own, so keeping one of them out of the file, or giving\none of them a display format, is a decision about that member alone." } }, "required": [ "name", "member" ], "title": "Member", "type": "object" }, "MemberKind": { "description": "What shape a structure member has.\n\nStated rather than inferred from which keys are present: a file that omits a key by mistake\nshould be told which member shape it failed to describe, not silently become another one.\nA forgotten ``bits`` would otherwise turn a one bit flag into a full width member and move\nevery offset after it.", "enum": [ "value", "bits" ], "title": "MemberKind", "type": "string" }, "Parameter": { "additionalProperties": false, "description": "A single calibratable constant.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "parameter", "title": "Kind", "type": "string" } }, "required": [ "name", "volatile", "kind" ], "title": "Parameter", "type": "object" }, "PointCounts": { "description": "Where an interpolation object stores its number of axis points, if anywhere.", "enum": [ "none", "leading" ], "title": "PointCounts", "type": "string" }, "ScalarType": { "additionalProperties": false, "description": "A name for what a number means, so components agree by naming rather than by copying.\n\nThree components consuming an engine speed each used to write out the datatype, the unit,\nthe scaling and the limits, leaving DDD to notice when one of them was wrong. If all three\nsay ``Speed_t`` instead, there is nothing left to disagree about - which is checking turned\ninto construction.\n\nIt fixes exactly the four things that make two declarations interchangeable, and nothing\nelse. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:\nthey are properties of one object rather than of the type, and two measurements of the same\ntype may well differ in whether an interrupt writes one of them.", "properties": { "type": { "const": "scalar", "description": "Says this entry names a scalar rather than describing a structure.", "title": "Type", "type": "string" }, "name": { "description": "Name of the type; every type of a project needs a distinct one.\n\nRefused if it reads as a base datatype, for the reason a structure's name is.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "$ref": "#/$defs/Datatype", "description": "Storage of the value: one of the base datatypes.\n\nA base datatype rather than another declared type, so that a scalar type cannot be defined\nin terms of a second one. A chain of names would have to be resolved, could form a cycle,\nand buys nothing a reader of the one entry could not already see." }, "unit": { "default": "", "description": "Physical unit of the value, e.g. ``\"rpm\"``.", "title": "Unit", "type": "string" }, "conversion": { "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired: fixing what a value means is the one job a scalar type has, and the identity\nis part of the answer rather than a silence to interpret.", "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ], "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits, in the unit above; derived from datatype and conversion if omitted." } }, "required": [ "type", "name", "datatype", "conversion" ], "title": "ScalarType", "type": "object" }, "Scope": { "description": "Direction of a variable with respect to the declaring component.", "enum": [ "input", "output", "local" ], "title": "Scope", "type": "string" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" }, "StructType": { "additionalProperties": false, "description": "One structured datatype: a name and the members it lays out, in order.", "properties": { "type": { "const": "struct", "description": "Says this entry describes a structure; stated on every entry of a types file.", "title": "Type", "type": "string" }, "name": { "description": "Name of the structure; every type of a project needs a distinct one.\n\nRefused if it spells a base datatype, compared without regard to case: a type called\n``uint16``, or ``UINT16``, wears the name of storage it is not, and every declaration\nnaming it would read like a typo.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the structure, offered to the c templates.", "title": "Description", "type": "string" }, "members": { "description": "The members, in the order they are laid out.", "items": { "$ref": "#/$defs/Member" }, "minItems": 1, "title": "Members", "type": "array" } }, "required": [ "type", "name", "members" ], "title": "StructType", "type": "object" }, "ValueBlock": { "additionalProperties": false, "description": "An array of calibratable constants.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "value_block", "title": "Kind", "type": "string" }, "dimensions": { "description": "Array dimensions in c declaration order; a value block is never a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, mixed\nfreely.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "minItems": 1, "title": "Dimensions", "type": "array" } }, "required": [ "name", "volatile", "kind", "dimensions" ], "title": "ValueBlock", "type": "object" } }, "additionalProperties": false, "required": [ "name", "interface" ] }
- Fields:
constants (tuple[ddd.models.constants.ConstantDeclaration, ...] | None)description (str)interface (tuple[ddd.models.component.Declaration, ...])name (str)point_counts (ddd.models.objects.PointCounts | None)raster (str | None)types (tuple[ddd.models.types.StructType | ddd.models.types.ScalarType | ddd.models.types.ExternalType, ...] | None)
- field name: Identifier [Required]
Name of the component; every component of a project needs a distinct one.
- field description: str = ''
Free text describing the component, offered to the c templates.
- field raster: RasterName | None = None
Default measurement raster for every variable this component produces.
The common case stated once: a component updates nearly all of its measurements in one task, and repeating that on several hundred definitions would bury the handful of exceptions, which state their own
raster. It applies to what this component produces and to nothing it reads - the raster follows the producer - and it reaches no calibration object, since no daq list carries one.Default measurement raster for every variable this component produces.
The common case stated once: a component updates nearly all of its measurements in one task, and repeating that on several hundred definitions would bury the handful of exceptions, which state their own
raster. It applies to what this component produces and to nothing it reads - the raster follows the producer - and it reaches no calibration object, since no daq list carries one.
- field point_counts: PointCounts | None = None
Where the curves, maps and axes this component defines store their point counts, overriding the project’s default.
It follows the producer, as
rasterdoes: the component that defines a table is the one whose routines interpolate over it. It reaches nothing this component reads, and nothing that is not a curve, a map or an axis.Where the curves, maps and axes this component defines store their point counts, overriding the project’s default.
It follows the producer, as
rasterdoes: the component that defines a table is the one whose routines interpolate over it. It reaches nothing this component reads, and nothing that is not a curve, a map or an axis.
- field interface: tuple[Declaration, ...] [Required]
The data interface: everything the component produces, consumes or keeps to itself.
Required with no default, so that a component with nothing to declare says so with an empty list rather than by a key that might merely have been forgotten - the same reasoning that makes
volatileandkindrequired on a definition.The data interface: everything the component produces, consumes or keeps to itself.
Required with no default, so that a component with nothing to declare says so with an empty list rather than by a key that might merely have been forgotten - the same reasoning that makes
volatileandkindrequired on a definition.
- field types: Annotated[tuple[AnyType, ...], Field(min_length=1)] | None = None
Declared types this component publishes, each entry exactly as a types file writes it.
Declaring them here co-locates a library’s contract in one file; it does not scope it. The names join the same project wide namespace as the types of the standalone files, every consistency check applies to them unchanged, and any component of the project may name them. Types shared between several components, with no single owner to live inside, stay in a standalone types file.
Declared types this component publishes, each entry exactly as a types file writes it.
Declaring them here co-locates a library’s contract in one file; it does not scope it. The names join the same project wide namespace as the types of the standalone files, every consistency check applies to them unchanged, and any component of the project may name them. Types shared between several components, with no single owner to live inside, stay in a standalone types file.
- field constants: Annotated[tuple[ConstantDeclaration, ...], Field(min_length=1)] | None = None
Declared constants this component publishes, each entry exactly as a constants file writes it.
Co-located for the reason
typesmay be, and no more scoped than they are: the names join the same project wide namespace as the constants of a constants file, and any shape of any component names one where it would state a number.units,sectionsandrastersremain project wide vocabularies and have no place inside a component.Declared constants this component publishes, each entry exactly as a constants file writes it.
Co-located for the reason
typesmay be, and no more scoped than they are: the names join the same project wide namespace as the constants of a constants file, and any shape of any component names one where it would state a number.units,sectionsandrastersremain project wide vocabularies and have no place inside a component.
- pydantic model Declaration[source]
One entry of the
interfacelist of a component.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.component.Declaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Declaration</b></td></tr><tr><td>scope</td><td port="scope">Scope</td></tr><tr><td>condition</td><td port="condition">str | None</td></tr><tr><td>definition</td><td port="definition">Measurement | Parameter | ValueBlock | Curve | Map | Axis</td></tr></table>>,
tooltip="ddd.models.component.Declaration

One entry of the ``interface`` list of a component.
"];
"ddd.models.objects.Axis" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Axis</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.AXIS]</td></tr><tr><td>size</td><td port="size">Union[int, str]</td></tr><tr><td>input</td><td port="input">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.Axis

Shared axis points; several curves and maps may be interpolated over one axis.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Axis":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Curve</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.CURVE]</td></tr><tr><td>axis</td><td port="axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Curve

A one dimensional calibratable table.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Curve":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Map</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MAP]</td></tr><tr><td>x_axis</td><td port="x_axis">str</td></tr><tr><td>y_axis</td><td port="y_axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Map

A two dimensional calibratable table, stored as ``[y][x]``.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Map":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Measurement</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MEASUREMENT]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.Measurement

An online value: the software writes it, a calibration tool measures it and may write it.&#\
xA;
A tool writing one through its address is one of the reasons to declare a measurement
``volatile``, alongside an interrupt, \
a second core and a peripheral.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Measurement":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Parameter</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.PARAMETER]</td></tr></table>>,
tooltip="ddd.models.objects.Parameter

A single calibratable constant.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.Parameter":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ValueBlock</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.VALUE_BLOCK]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.ValueBlock

An array of calibratable constants.
"];
"ddd.models.component.Declaration":definition:e -> "ddd.models.objects.ValueBlock":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Axis":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Curve":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-5dbd7e42174e5d86b5d2b9d2f762dd9cefe3598d.png)
Show JSON schema
{ "title": "Declaration", "description": "One entry of the ``interface`` list of a component.", "type": "object", "properties": { "scope": { "$ref": "#/$defs/Scope", "description": "Direction of the declaration, which is what makes the interfaces check each other.\n\nExactly one component may produce a name - declare it ``output`` or ``local`` - and that\ncomponent's definition is the one the project uses. Every ``input`` declaring the same\nname has to agree with it on datatype, unit, conversion, limits and shape." }, "condition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "C preprocessor expression wrapping the generated declaration, e.g. ``defined(FEAT_X)``.\n\nOne expression, written as it would appear after ``#if``. It is emitted verbatim into the\ngenerated files, so it cannot span lines, cannot end in ``\\`` and cannot contain ``#``,\n``//``, ``/*`` or ``*/`` - each of which would let a description file put arbitrary\ndirectives, or live code, into somebody else's build.", "title": "Condition" }, "definition": { "description": "The data object being declared; its ``kind`` decides which keys it carries.", "discriminator": { "mapping": { "axis": "#/$defs/Axis", "curve": "#/$defs/Curve", "map": "#/$defs/Map", "measurement": "#/$defs/Measurement", "parameter": "#/$defs/Parameter", "value_block": "#/$defs/ValueBlock" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/Measurement" }, { "$ref": "#/$defs/Parameter" }, { "$ref": "#/$defs/ValueBlock" }, { "$ref": "#/$defs/Curve" }, { "$ref": "#/$defs/Map" }, { "$ref": "#/$defs/Axis" } ], "title": "Definition" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Axis": { "additionalProperties": false, "description": "Shared axis points; several curves and maps may be interpolated over one axis.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "axis", "title": "Kind", "type": "string" }, "size": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ], "description": "Number of axis points: an integer of at least 1, or the name of a declared constant.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "title": "Size" }, "input": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement that indexes the axis; the a2l input quantity.\n\nA plain one: an instance of a declared structure is of kind ``measurement`` and is\nrefused here as any other wrong kind is, because it reaches the a2l as one record per\nvalue-holding member and none of its own.", "title": "Input" } }, "required": [ "name", "volatile", "kind", "size" ], "title": "Axis", "type": "object" }, "Curve": { "additionalProperties": false, "description": "A one dimensional calibratable table.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "curve", "title": "Kind", "type": "string" }, "axis": { "description": "Name of the axis object the curve is interpolated over.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Axis", "type": "string" } }, "required": [ "name", "volatile", "kind", "axis" ], "title": "Curve", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "Map": { "additionalProperties": false, "description": "A two dimensional calibratable table, stored as ``[y][x]``.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "map", "title": "Kind", "type": "string" }, "x_axis": { "description": "Name of the axis whose index runs fastest; the last dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "X Axis", "type": "string" }, "y_axis": { "description": "Name of the axis selecting the row; the first dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Y Axis", "type": "string" } }, "required": [ "name", "volatile", "kind", "x_axis", "y_axis" ], "title": "Map", "type": "object" }, "Measurement": { "additionalProperties": false, "description": "An online value: the software writes it, a calibration tool measures it and may write it.\n\nA tool writing one through its address is one of the reasons to declare a measurement\n``volatile``, alongside an interrupt, a second core and a peripheral.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "measurement", "title": "Kind", "type": "string" }, "dimensions": { "default": [], "description": "Array dimensions; empty for a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, in a\nconstants file or in a component - ``[3, 4]`` and ``[\"PRESSURE_CELLS\", 4]`` are both\nshapes.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" } }, "required": [ "name", "volatile", "kind" ], "title": "Measurement", "type": "object" }, "Parameter": { "additionalProperties": false, "description": "A single calibratable constant.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "parameter", "title": "Kind", "type": "string" } }, "required": [ "name", "volatile", "kind" ], "title": "Parameter", "type": "object" }, "Scope": { "description": "Direction of a variable with respect to the declaring component.", "enum": [ "input", "output", "local" ], "title": "Scope", "type": "string" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" }, "ValueBlock": { "additionalProperties": false, "description": "An array of calibratable constants.", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "value_block", "title": "Kind", "type": "string" }, "dimensions": { "description": "Array dimensions in c declaration order; a value block is never a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, mixed\nfreely.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "minItems": 1, "title": "Dimensions", "type": "array" } }, "required": [ "name", "volatile", "kind", "dimensions" ], "title": "ValueBlock", "type": "object" } }, "additionalProperties": false, "required": [ "scope", "definition" ] }
- Fields:
condition (str | None)definition (ddd.models.objects.Measurement | ddd.models.objects.Parameter | ddd.models.objects.ValueBlock | ddd.models.objects.Curve | ddd.models.objects.Map | ddd.models.objects.Axis)scope (ddd.models.component.Scope)
- field scope: Scope [Required]
Direction of the declaration, which is what makes the interfaces check each other.
Exactly one component may produce a name - declare it
outputorlocal- and that component’s definition is the one the project uses. Everyinputdeclaring the same name has to agree with it on datatype, unit, conversion, limits and shape.Direction of the declaration, which is what makes the interfaces check each other.
Exactly one component may produce a name - declare it
outputorlocal- and that component’s definition is the one the project uses. Everyinputdeclaring the same name has to agree with it on datatype, unit, conversion, limits and shape.
- field condition: str | None = None
C preprocessor expression wrapping the generated declaration, e.g.
defined(FEAT_X).One expression, written as it would appear after
#if. It is emitted verbatim into the generated files, so it cannot span lines, cannot end in\and cannot contain#,//,/*or*/- each of which would let a description file put arbitrary directives, or live code, into somebody else’s build.C preprocessor expression wrapping the generated declaration, e.g.
defined(FEAT_X).One expression, written as it would appear after
#if. It is emitted verbatim into the generated files, so it cannot span lines, cannot end in\and cannot contain#,//,/*or*/- each of which would let a description file put arbitrary directives, or live code, into somebody else’s build.
- field definition: AnyDataObject [Required]
The data object being declared; its
kinddecides which keys it carries.
Structured datatype description
The types file, whose entries are told apart by a stated type:
a structure, a scalar type naming what a number means, and an external type naming a c type a
hand written header defines and DDD only carries. A member states which shape it has and
carries only the keys that shape needs; what it never carries is a bit position or an offset,
because c leaves both to the compiler.
- pydantic model TypesFile[source]
Root object of a
*.ddd.jsontype description.typesis the top level key that makes this a types file rather than a project or a component file; DDD decides what a file is from that key alone, so exactly one of them appears here.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.types.ExternalType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ExternalType</b></td></tr><tr><td>type</td><td port="type">Literal['external']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>header</td><td port="header">str</td></tr></table>>,
tooltip="ddd.models.types.ExternalType

A name for a c type that DDD does not declare: a hand written header defines it.

\
DDD generates no typedef for it and knows neither its layout nor its meaning - which is
the point: a driver's status word or \
an operating system's handle already has one
authoritative definition, and a copy of it in the description would drift. Only \
a
structure member may name one, as opaque storage that reaches the generated structure
verbatim; such a member states no \
unit, conversion or limits, because DDD does not check
meaning it cannot see.
"];
"ddd.models.types.Member" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Member</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>member</td><td port="member">MemberKind</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr><tr><td>bits</td><td port="bits">Optional[int]</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr></table>>,
tooltip="ddd.models.types.Member

One member of a structure, in the order the structure declares it.

Order is significant: \
it is the order the c struct is generated in, and therefore the order
the compiler lays out. Reordering members of a released \
structure moves every address after
the change, which is why a comparison against a baseline reports it.
"];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.Member":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ScalarType</b></td></tr><tr><td>type</td><td port="type">Literal['scalar']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">IdentityConversion | LinearConversion | EnumConversion | StringConversion</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr></table>>,
tooltip="ddd.models.types.ScalarType

A name for what a number means, so components agree by naming rather than by copying.
&#\
xA;Three components consuming an engine speed each used to write out the datatype, the unit,
the scaling and the limits, leaving \
DDD to notice when one of them was wrong. If all three
say ``Speed_t`` instead, there is nothing left to disagree about - which \
is checking turned
into construction.

It fixes exactly the four things that make two declarations interchangeable, \
and nothing
else. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:
they are properties \
of one object rather than of the type, and two measurements of the same
type may well differ in whether an interrupt writes \
one of them.
"];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.StructType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StructType</b></td></tr><tr><td>type</td><td port="type">Literal['struct']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>members</td><td port="members">tuple[Member, ...]</td></tr></table>>,
tooltip="ddd.models.types.StructType

One structured datatype: a name and the members it lays out, in order.
"];
"ddd.models.types.StructType":members:e -> "ddd.models.types.Member":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.types.TypesFile" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>TypesFile</b></td></tr><tr><td>schema_reference</td><td port="schema_reference">str | None</td></tr><tr><td>types</td><td port="types">tuple[StructType | ScalarType | ExternalType, ...]</td></tr></table>>,
tooltip="ddd.models.types.TypesFile

Root object of a ``*.ddd.json`` type description.

``types`` is the top level key that \
makes this a types file rather than a project or a
component file; DDD decides what a file is from that key alone, so exactly \
one of them
appears here.
"];
"ddd.models.types.TypesFile":types:e -> "ddd.models.types.ExternalType":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.types.TypesFile":types:e -> "ddd.models.types.ScalarType":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.types.TypesFile":types:e -> "ddd.models.types.StructType":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-604d7c191bcb4e22388b1b4461c0dc6acdec3ce7.png)
Show JSON schema
{ "title": "DDD type description", "description": "Root object of a ``*.ddd.json`` type description.\n\n``types`` is the top level key that makes this a types file rather than a project or a\ncomponent file; DDD decides what a file is from that key alone, so exactly one of them\nappears here.", "type": "object", "properties": { "$schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Editor binding to a schema written by ``ddd schema -o``; not interpreted by DDD.", "title": "$Schema" }, "types": { "description": "The types this file declares, and possibly none.\n\nA file declaring none loads, and is reported as ``empty-vocabulary``. A structure needs a\nmember all the same: an empty structure is not c.", "items": { "discriminator": { "mapping": { "external": "#/$defs/ExternalType", "scalar": "#/$defs/ScalarType", "struct": "#/$defs/StructType" }, "propertyName": "type" }, "oneOf": [ { "$ref": "#/$defs/StructType" }, { "$ref": "#/$defs/ScalarType" }, { "$ref": "#/$defs/ExternalType" } ] }, "title": "Types", "type": "array" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "ExternalType": { "additionalProperties": false, "description": "A name for a c type that DDD does not declare: a hand written header defines it.\n\nDDD generates no typedef for it and knows neither its layout nor its meaning - which is\nthe point: a driver's status word or an operating system's handle already has one\nauthoritative definition, and a copy of it in the description would drift. Only a\nstructure member may name one, as opaque storage that reaches the generated structure\nverbatim; such a member states no unit, conversion or limits, because DDD does not check\nmeaning it cannot see.", "properties": { "type": { "const": "external", "description": "Says this entry names an external type rather than declaring one of DDD's own.", "title": "Type", "type": "string" }, "name": { "description": "The type's c identifier, as the defining header spells it.\n\nEvery type of a project needs a distinct name, and the rules are those of the declared\ntypes: it cannot read as a base datatype, and it shares the project wide namespace with\nthe structures and the scalars.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "header": { "description": "The header that defines the type, spelled the way the generated inclusion writes it.\n\n``my_driver.h`` for the quoted form, ``<os_types.h>`` for the angle form; a subdirectory\npath such as ``drivers/status.h`` is allowed in either. The spelling is written out\nexactly as it stands, so one that would unbalance the line is refused here rather than\nhanded to a compiler: no whitespace, no quote of its own - the quoted form is written\nbare - and, for the angle form, exactly one pair of angle brackets wrapping the whole\nname.", "minLength": 1, "title": "Header", "type": "string" } }, "required": [ "type", "name", "header" ], "title": "ExternalType", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "Member": { "additionalProperties": false, "description": "One member of a structure, in the order the structure declares it.\n\nOrder is significant: it is the order the c struct is generated in, and therefore the order\nthe compiler lays out. Reordering members of a released structure moves every address after\nthe change, which is why a comparison against a baseline reports it.", "properties": { "name": { "description": "Name of the member, unique within its structure.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "member": { "$ref": "#/$defs/MemberKind", "description": "Which shape this member has, and with it which other keys the member may carry.\n\n* ``value`` needs ``datatype`` or ``typename`` and may add ``dimensions``,\n* ``bits`` needs ``datatype`` and ``bits``.\n\nA key belonging to the other shape is refused rather than ignored: ``bits`` together with\n``dimensions`` has no single meaning - c has no array of bitfields - and quietly dropping\none of the two would put a structure in the generated c that this file does not describe." }, "description": { "default": "", "description": "Free text describing the member, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of this member, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated, here exactly as on a declaration." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a declared type, stated instead of ``datatype``.\n\nA ``value`` member may name a structure, which nests it, a scalar type, which fixes what\nits number means, or an external type, which makes it opaque storage a hand written header\ndefines. A ``bits`` member states a base integer ``datatype``: a bitfield has no room for\na structure, and a scalar type would carry limits the width contradicts.", "title": "Typename" }, "dimensions": { "default": [], "description": "Array dimensions of a ``value`` member, in c declaration order; empty for a scalar.\n\n``[4, 2]`` is declared as ``[4][2]``, the last dimension running fastest in memory.\nEach dimension is an integer of at least 1, or the name of a constant the project\ndeclares, exactly as on a declaration - the spelling, that is, since the 10 000 000\nelement cap is a declaration's and a map's alone: an array here is weighed in the leaves\nits structure may hold, and a member holding a value is one leaf however long its array.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" }, "bits": { "anyOf": [ { "exclusiveMinimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "description": "Width of a ``bits`` member, in bits; required on one, refused on the other.\n\nIt has to fit the datatype carrying it - at most 16 in a ``uint16`` - and that datatype\nhas to be an integer, since c allows a bitfield in nothing else.", "title": "Bits" }, "unit": { "default": "", "description": "Physical unit of this member, e.g. ``\"degC\"``.\n\nWritten here, or fixed by a scalar type this member names, and never both. Which of the\ntwo to reach for is a question of whether the answer is shared: a unit written here says it\nfor this member of this structure, and a ``Temperature_t`` says it for everything that\nnames it, across every component of the project.", "title": "Unit", "type": "string" }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How this member's raw value maps to a physical one: identity, linear, an enumeration,\nor text read from the bytes (``string``).\n\nRequired on a member whose storage is a base ``datatype``, exactly as on a definition;\na member naming a scalar ``typename`` states none, the type fixing it.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of this member; derived from its storage and conversion if omitted.\n\nFor a ``bits`` member the derivation uses the *width*, not the datatype carrying it: a two\nbit field offered to a calibration tool as ``0 .. 65535`` invites somebody to enter a value\nthe field cannot hold and the software then reads back something else." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this member asks of the a2l file once the structure is flattened into it.\n\nPer member rather than per structure, because that is the granularity the a2l ends up with:\neach member becomes an object of its own, so keeping one of them out of the file, or giving\none of them a display format, is a decision about that member alone." } }, "required": [ "name", "member" ], "title": "Member", "type": "object" }, "MemberKind": { "description": "What shape a structure member has.\n\nStated rather than inferred from which keys are present: a file that omits a key by mistake\nshould be told which member shape it failed to describe, not silently become another one.\nA forgotten ``bits`` would otherwise turn a one bit flag into a full width member and move\nevery offset after it.", "enum": [ "value", "bits" ], "title": "MemberKind", "type": "string" }, "ScalarType": { "additionalProperties": false, "description": "A name for what a number means, so components agree by naming rather than by copying.\n\nThree components consuming an engine speed each used to write out the datatype, the unit,\nthe scaling and the limits, leaving DDD to notice when one of them was wrong. If all three\nsay ``Speed_t`` instead, there is nothing left to disagree about - which is checking turned\ninto construction.\n\nIt fixes exactly the four things that make two declarations interchangeable, and nothing\nelse. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:\nthey are properties of one object rather than of the type, and two measurements of the same\ntype may well differ in whether an interrupt writes one of them.", "properties": { "type": { "const": "scalar", "description": "Says this entry names a scalar rather than describing a structure.", "title": "Type", "type": "string" }, "name": { "description": "Name of the type; every type of a project needs a distinct one.\n\nRefused if it reads as a base datatype, for the reason a structure's name is.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "$ref": "#/$defs/Datatype", "description": "Storage of the value: one of the base datatypes.\n\nA base datatype rather than another declared type, so that a scalar type cannot be defined\nin terms of a second one. A chain of names would have to be resolved, could form a cycle,\nand buys nothing a reader of the one entry could not already see." }, "unit": { "default": "", "description": "Physical unit of the value, e.g. ``\"rpm\"``.", "title": "Unit", "type": "string" }, "conversion": { "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired: fixing what a value means is the one job a scalar type has, and the identity\nis part of the answer rather than a silence to interpret.", "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ], "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits, in the unit above; derived from datatype and conversion if omitted." } }, "required": [ "type", "name", "datatype", "conversion" ], "title": "ScalarType", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" }, "StructType": { "additionalProperties": false, "description": "One structured datatype: a name and the members it lays out, in order.", "properties": { "type": { "const": "struct", "description": "Says this entry describes a structure; stated on every entry of a types file.", "title": "Type", "type": "string" }, "name": { "description": "Name of the structure; every type of a project needs a distinct one.\n\nRefused if it spells a base datatype, compared without regard to case: a type called\n``uint16``, or ``UINT16``, wears the name of storage it is not, and every declaration\nnaming it would read like a typo.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the structure, offered to the c templates.", "title": "Description", "type": "string" }, "members": { "description": "The members, in the order they are laid out.", "items": { "$ref": "#/$defs/Member" }, "minItems": 1, "title": "Members", "type": "array" } }, "required": [ "type", "name", "members" ], "title": "StructType", "type": "object" } }, "additionalProperties": false, "required": [ "types" ] }
- Fields:
types (tuple[ddd.models.types.StructType | ddd.models.types.ScalarType | ddd.models.types.ExternalType, ...])
- field types: tuple[AnyType, ...] [Required]
The types this file declares, and possibly none.
A file declaring none loads, and is reported as
empty-vocabulary. A structure needs a member all the same: an empty structure is not c.The types this file declares, and possibly none.
A file declaring none loads, and is reported as
empty-vocabulary. A structure needs a member all the same: an empty structure is not c.
- pydantic model StructType[source]
One structured datatype: a name and the members it lays out, in order.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.types.Member" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Member</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>member</td><td port="member">MemberKind</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr><tr><td>bits</td><td port="bits">Optional[int]</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr></table>>,
tooltip="ddd.models.types.Member

One member of a structure, in the order the structure declares it.

Order is significant: \
it is the order the c struct is generated in, and therefore the order
the compiler lays out. Reordering members of a released \
structure moves every address after
the change, which is why a comparison against a baseline reports it.
"];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.Member":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.StructType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StructType</b></td></tr><tr><td>type</td><td port="type">Literal['struct']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>members</td><td port="members">tuple[Member, ...]</td></tr></table>>,
tooltip="ddd.models.types.StructType

One structured datatype: a name and the members it lays out, in order.
"];
"ddd.models.types.StructType":members:e -> "ddd.models.types.Member":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-11bfdaa576dd3f9ad3b740dbbb9251b5316e49b0.png)
Show JSON schema
{ "title": "StructType", "description": "One structured datatype: a name and the members it lays out, in order.", "type": "object", "properties": { "type": { "const": "struct", "description": "Says this entry describes a structure; stated on every entry of a types file.", "title": "Type", "type": "string" }, "name": { "description": "Name of the structure; every type of a project needs a distinct one.\n\nRefused if it spells a base datatype, compared without regard to case: a type called\n``uint16``, or ``UINT16``, wears the name of storage it is not, and every declaration\nnaming it would read like a typo.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing the structure, offered to the c templates.", "title": "Description", "type": "string" }, "members": { "description": "The members, in the order they are laid out.", "items": { "$ref": "#/$defs/Member" }, "minItems": 1, "title": "Members", "type": "array" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "Member": { "additionalProperties": false, "description": "One member of a structure, in the order the structure declares it.\n\nOrder is significant: it is the order the c struct is generated in, and therefore the order\nthe compiler lays out. Reordering members of a released structure moves every address after\nthe change, which is why a comparison against a baseline reports it.", "properties": { "name": { "description": "Name of the member, unique within its structure.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "member": { "$ref": "#/$defs/MemberKind", "description": "Which shape this member has, and with it which other keys the member may carry.\n\n* ``value`` needs ``datatype`` or ``typename`` and may add ``dimensions``,\n* ``bits`` needs ``datatype`` and ``bits``.\n\nA key belonging to the other shape is refused rather than ignored: ``bits`` together with\n``dimensions`` has no single meaning - c has no array of bitfields - and quietly dropping\none of the two would put a structure in the generated c that this file does not describe." }, "description": { "default": "", "description": "Free text describing the member, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of this member, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated, here exactly as on a declaration." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a declared type, stated instead of ``datatype``.\n\nA ``value`` member may name a structure, which nests it, a scalar type, which fixes what\nits number means, or an external type, which makes it opaque storage a hand written header\ndefines. A ``bits`` member states a base integer ``datatype``: a bitfield has no room for\na structure, and a scalar type would carry limits the width contradicts.", "title": "Typename" }, "dimensions": { "default": [], "description": "Array dimensions of a ``value`` member, in c declaration order; empty for a scalar.\n\n``[4, 2]`` is declared as ``[4][2]``, the last dimension running fastest in memory.\nEach dimension is an integer of at least 1, or the name of a constant the project\ndeclares, exactly as on a declaration - the spelling, that is, since the 10 000 000\nelement cap is a declaration's and a map's alone: an array here is weighed in the leaves\nits structure may hold, and a member holding a value is one leaf however long its array.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" }, "bits": { "anyOf": [ { "exclusiveMinimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "description": "Width of a ``bits`` member, in bits; required on one, refused on the other.\n\nIt has to fit the datatype carrying it - at most 16 in a ``uint16`` - and that datatype\nhas to be an integer, since c allows a bitfield in nothing else.", "title": "Bits" }, "unit": { "default": "", "description": "Physical unit of this member, e.g. ``\"degC\"``.\n\nWritten here, or fixed by a scalar type this member names, and never both. Which of the\ntwo to reach for is a question of whether the answer is shared: a unit written here says it\nfor this member of this structure, and a ``Temperature_t`` says it for everything that\nnames it, across every component of the project.", "title": "Unit", "type": "string" }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How this member's raw value maps to a physical one: identity, linear, an enumeration,\nor text read from the bytes (``string``).\n\nRequired on a member whose storage is a base ``datatype``, exactly as on a definition;\na member naming a scalar ``typename`` states none, the type fixing it.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of this member; derived from its storage and conversion if omitted.\n\nFor a ``bits`` member the derivation uses the *width*, not the datatype carrying it: a two\nbit field offered to a calibration tool as ``0 .. 65535`` invites somebody to enter a value\nthe field cannot hold and the software then reads back something else." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this member asks of the a2l file once the structure is flattened into it.\n\nPer member rather than per structure, because that is the granularity the a2l ends up with:\neach member becomes an object of its own, so keeping one of them out of the file, or giving\none of them a display format, is a decision about that member alone." } }, "required": [ "name", "member" ], "title": "Member", "type": "object" }, "MemberKind": { "description": "What shape a structure member has.\n\nStated rather than inferred from which keys are present: a file that omits a key by mistake\nshould be told which member shape it failed to describe, not silently become another one.\nA forgotten ``bits`` would otherwise turn a one bit flag into a full width member and move\nevery offset after it.", "enum": [ "value", "bits" ], "title": "MemberKind", "type": "string" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "type", "name", "members" ] }
- Fields:
description (str)members (tuple[ddd.models.types.Member, ...])name (str)type (Literal['struct'])
- field type: Literal['struct'] [Required]
Says this entry describes a structure; stated on every entry of a types file.
- field name: TypeName [Required]
Name of the structure; every type of a project needs a distinct one.
Refused if it spells a base datatype, compared without regard to case: a type called
uint16, orUINT16, wears the name of storage it is not, and every declaration naming it would read like a typo.Name of the structure; every type of a project needs a distinct one.
Refused if it spells a base datatype, compared without regard to case: a type called
uint16, orUINT16, wears the name of storage it is not, and every declaration naming it would read like a typo.
- field description: str = ''
Free text describing the structure, offered to the c templates.
- pydantic model Member[source]
One member of a structure, in the order the structure declares it.
Order is significant: it is the order the c struct is generated in, and therefore the order the compiler lays out. Reordering members of a released structure moves every address after the change, which is why a comparison against a baseline reports it.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.types.Member" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Member</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>member</td><td port="member">MemberKind</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr><tr><td>bits</td><td port="bits">Optional[int]</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr></table>>,
tooltip="ddd.models.types.Member

One member of a structure, in the order the structure declares it.

Order is significant: \
it is the order the c struct is generated in, and therefore the order
the compiler lays out. Reordering members of a released \
structure moves every address after
the change, which is why a comparison against a baseline reports it.
"];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.types.Member":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.Member":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-7a5befffbd279594e75dc69e68d64a0fa9e1e105.png)
Show JSON schema
{ "title": "Member", "description": "One member of a structure, in the order the structure declares it.\n\nOrder is significant: it is the order the c struct is generated in, and therefore the order\nthe compiler lays out. Reordering members of a released structure moves every address after\nthe change, which is why a comparison against a baseline reports it.", "type": "object", "properties": { "name": { "description": "Name of the member, unique within its structure.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "member": { "$ref": "#/$defs/MemberKind", "description": "Which shape this member has, and with it which other keys the member may carry.\n\n* ``value`` needs ``datatype`` or ``typename`` and may add ``dimensions``,\n* ``bits`` needs ``datatype`` and ``bits``.\n\nA key belonging to the other shape is refused rather than ignored: ``bits`` together with\n``dimensions`` has no single meaning - c has no array of bitfields - and quietly dropping\none of the two would put a structure in the generated c that this file does not describe." }, "description": { "default": "", "description": "Free text describing the member, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of this member, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated, here exactly as on a declaration." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a declared type, stated instead of ``datatype``.\n\nA ``value`` member may name a structure, which nests it, a scalar type, which fixes what\nits number means, or an external type, which makes it opaque storage a hand written header\ndefines. A ``bits`` member states a base integer ``datatype``: a bitfield has no room for\na structure, and a scalar type would carry limits the width contradicts.", "title": "Typename" }, "dimensions": { "default": [], "description": "Array dimensions of a ``value`` member, in c declaration order; empty for a scalar.\n\n``[4, 2]`` is declared as ``[4][2]``, the last dimension running fastest in memory.\nEach dimension is an integer of at least 1, or the name of a constant the project\ndeclares, exactly as on a declaration - the spelling, that is, since the 10 000 000\nelement cap is a declaration's and a map's alone: an array here is weighed in the leaves\nits structure may hold, and a member holding a value is one leaf however long its array.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" }, "bits": { "anyOf": [ { "exclusiveMinimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "description": "Width of a ``bits`` member, in bits; required on one, refused on the other.\n\nIt has to fit the datatype carrying it - at most 16 in a ``uint16`` - and that datatype\nhas to be an integer, since c allows a bitfield in nothing else.", "title": "Bits" }, "unit": { "default": "", "description": "Physical unit of this member, e.g. ``\"degC\"``.\n\nWritten here, or fixed by a scalar type this member names, and never both. Which of the\ntwo to reach for is a question of whether the answer is shared: a unit written here says it\nfor this member of this structure, and a ``Temperature_t`` says it for everything that\nnames it, across every component of the project.", "title": "Unit", "type": "string" }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How this member's raw value maps to a physical one: identity, linear, an enumeration,\nor text read from the bytes (``string``).\n\nRequired on a member whose storage is a base ``datatype``, exactly as on a definition;\na member naming a scalar ``typename`` states none, the type fixing it.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of this member; derived from its storage and conversion if omitted.\n\nFor a ``bits`` member the derivation uses the *width*, not the datatype carrying it: a two\nbit field offered to a calibration tool as ``0 .. 65535`` invites somebody to enter a value\nthe field cannot hold and the software then reads back something else." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this member asks of the a2l file once the structure is flattened into it.\n\nPer member rather than per structure, because that is the granularity the a2l ends up with:\neach member becomes an object of its own, so keeping one of them out of the file, or giving\none of them a display format, is a decision about that member alone." } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "MemberKind": { "description": "What shape a structure member has.\n\nStated rather than inferred from which keys are present: a file that omits a key by mistake\nshould be told which member shape it failed to describe, not silently become another one.\nA forgotten ``bits`` would otherwise turn a one bit flag into a full width member and move\nevery offset after it.", "enum": [ "value", "bits" ], "title": "MemberKind", "type": "string" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "member" ] }
- Fields:
a2l (ddd.models.objects.A2lObjectOptions)bits (int | None)conversion (ddd.models.conversion.IdentityConversion | ddd.models.conversion.LinearConversion | ddd.models.conversion.EnumConversion | ddd.models.conversion.StringConversion | None)datatype (ddd.models.common.Datatype | None)description (str)dimensions (tuple[int | str, ...])limits (ddd.models.objects.Limits | None)member (ddd.models.types.MemberKind)name (str)typename (str | None)unit (str)
- field name: Identifier [Required]
Name of the member, unique within its structure.
- field member: MemberKind [Required]
Which shape this member has, and with it which other keys the member may carry.
valueneedsdatatypeortypenameand may adddimensions,bitsneedsdatatypeandbits.
A key belonging to the other shape is refused rather than ignored:
bitstogether withdimensionshas no single meaning - c has no array of bitfields - and quietly dropping one of the two would put a structure in the generated c that this file does not describe.Which shape this member has, and with it which other keys the member may carry.
valueneedsdatatypeortypenameand may adddimensions,bitsneedsdatatypeandbits.
A key belonging to the other shape is refused rather than ignored:
bitstogether withdimensionshas no single meaning - c has no array of bitfields - and quietly dropping one of the two would put a structure in the generated c that this file does not describe.
- field description: str = ''
Free text describing the member, offered to the c templates.
- field datatype: Datatype | None = None
Storage of this member, one of the eleven base datatypes.
Exactly one of
datatypeandtypenameis stated, here exactly as on a declaration.
- field typename: TypeName | None = None
Name of a declared type, stated instead of
datatype.A
valuemember may name a structure, which nests it, a scalar type, which fixes what its number means, or an external type, which makes it opaque storage a hand written header defines. Abitsmember states a base integerdatatype: a bitfield has no room for a structure, and a scalar type would carry limits the width contradicts.Name of a declared type, stated instead of
datatype.A
valuemember may name a structure, which nests it, a scalar type, which fixes what its number means, or an external type, which makes it opaque storage a hand written header defines. Abitsmember states a base integerdatatype: a bitfield has no room for a structure, and a scalar type would carry limits the width contradicts.
- field dimensions: tuple[Dimension, ...] = ()
Array dimensions of a
valuemember, in c declaration order; empty for a scalar.[4, 2]is declared as[4][2], the last dimension running fastest in memory. Each dimension is an integer of at least 1, or the name of a constant the project declares, exactly as on a declaration - the spelling, that is, since the 10 000 000 element cap is a declaration’s and a map’s alone: an array here is weighed in the leaves its structure may hold, and a member holding a value is one leaf however long its array.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.Array dimensions of a
valuemember, in c declaration order; empty for a scalar.[4, 2]is declared as[4][2], the last dimension running fastest in memory. Each dimension is an integer of at least 1, or the name of a constant the project declares, exactly as on a declaration - the spelling, that is, since the 10 000 000 element cap is a declaration’s and a map’s alone: an array here is weighed in the leaves its structure may hold, and a member holding a value is one leaf however long its array.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.
- field bits: PositiveInt | None = None
Width of a
bitsmember, in bits; required on one, refused on the other.It has to fit the datatype carrying it - at most 16 in a
uint16- and that datatype has to be an integer, since c allows a bitfield in nothing else.Width of a
bitsmember, in bits; required on one, refused on the other.It has to fit the datatype carrying it - at most 16 in a
uint16- and that datatype has to be an integer, since c allows a bitfield in nothing else.
- field unit: str = ''
Physical unit of this member, e.g.
"degC".Written here, or fixed by a scalar type this member names, and never both. Which of the two to reach for is a question of whether the answer is shared: a unit written here says it for this member of this structure, and a
Temperature_tsays it for everything that names it, across every component of the project.Physical unit of this member, e.g.
"degC".Written here, or fixed by a scalar type this member names, and never both. Which of the two to reach for is a question of whether the answer is shared: a unit written here says it for this member of this structure, and a
Temperature_tsays it for everything that names it, across every component of the project.
- field conversion: Conversion | None = None
How this member’s raw value maps to a physical one: identity, linear, an enumeration, or text read from the bytes (
string).Required on a member whose storage is a base
datatype, exactly as on a definition; a member naming a scalartypenamestates none, the type fixing it.How this member’s raw value maps to a physical one: identity, linear, an enumeration, or text read from the bytes (
string).Required on a member whose storage is a base
datatype, exactly as on a definition; a member naming a scalartypenamestates none, the type fixing it.
- field limits: Limits | None = None
Physical limits of this member; derived from its storage and conversion if omitted.
For a
bitsmember the derivation uses the width, not the datatype carrying it: a two bit field offered to a calibration tool as0 .. 65535invites somebody to enter a value the field cannot hold and the software then reads back something else.Physical limits of this member; derived from its storage and conversion if omitted.
For a
bitsmember the derivation uses the width, not the datatype carrying it: a two bit field offered to a calibration tool as0 .. 65535invites somebody to enter a value the field cannot hold and the software then reads back something else.
- field a2l: A2lObjectOptions = A2lObjectOptions(export=None, format=None, display_identifier=None)
What this member asks of the a2l file once the structure is flattened into it.
Per member rather than per structure, because that is the granularity the a2l ends up with: each member becomes an object of its own, so keeping one of them out of the file, or giving one of them a display format, is a decision about that member alone.
What this member asks of the a2l file once the structure is flattened into it.
Per member rather than per structure, because that is the granularity the a2l ends up with: each member becomes an object of its own, so keeping one of them out of the file, or giving one of them a display format, is a decision about that member alone.
- pydantic model ScalarType[source]
A name for what a number means, so components agree by naming rather than by copying.
Three components consuming an engine speed each used to write out the datatype, the unit, the scaling and the limits, leaving DDD to notice when one of them was wrong. If all three say
Speed_tinstead, there is nothing left to disagree about - which is checking turned into construction.It fixes exactly the four things that make two declarations interchangeable, and nothing else.
kind,dimensions,init,volatileanda2lstay on the variable: they are properties of one object rather than of the type, and two measurements of the same type may well differ in whether an interrupt writes one of them.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.types.ScalarType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ScalarType</b></td></tr><tr><td>type</td><td port="type">Literal['scalar']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>datatype</td><td port="datatype">Datatype</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>conversion</td><td port="conversion">IdentityConversion | LinearConversion | EnumConversion | StringConversion</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr></table>>,
tooltip="ddd.models.types.ScalarType

A name for what a number means, so components agree by naming rather than by copying.
&#\
xA;Three components consuming an engine speed each used to write out the datatype, the unit,
the scaling and the limits, leaving \
DDD to notice when one of them was wrong. If all three
say ``Speed_t`` instead, there is nothing left to disagree about - which \
is checking turned
into construction.

It fixes exactly the four things that make two declarations interchangeable, \
and nothing
else. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:
they are properties \
of one object rather than of the type, and two measurements of the same
type may well differ in whether an interrupt writes \
one of them.
"];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.types.ScalarType":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-38173496c790e8d016848d886ebc6e3c8657101c.png)
Show JSON schema
{ "title": "ScalarType", "description": "A name for what a number means, so components agree by naming rather than by copying.\n\nThree components consuming an engine speed each used to write out the datatype, the unit,\nthe scaling and the limits, leaving DDD to notice when one of them was wrong. If all three\nsay ``Speed_t`` instead, there is nothing left to disagree about - which is checking turned\ninto construction.\n\nIt fixes exactly the four things that make two declarations interchangeable, and nothing\nelse. ``kind``, ``dimensions``, ``init``, ``volatile`` and ``a2l`` stay on the variable:\nthey are properties of one object rather than of the type, and two measurements of the same\ntype may well differ in whether an interrupt writes one of them.", "type": "object", "properties": { "type": { "const": "scalar", "description": "Says this entry names a scalar rather than describing a structure.", "title": "Type", "type": "string" }, "name": { "description": "Name of the type; every type of a project needs a distinct one.\n\nRefused if it reads as a base datatype, for the reason a structure's name is.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "datatype": { "$ref": "#/$defs/Datatype", "description": "Storage of the value: one of the base datatypes.\n\nA base datatype rather than another declared type, so that a scalar type cannot be defined\nin terms of a second one. A chain of names would have to be resolved, could form a cycle,\nand buys nothing a reader of the one entry could not already see." }, "unit": { "default": "", "description": "Physical unit of the value, e.g. ``\"rpm\"``.", "title": "Unit", "type": "string" }, "conversion": { "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired: fixing what a value means is the one job a scalar type has, and the identity\nis part of the answer rather than a silence to interpret.", "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ], "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits, in the unit above; derived from datatype and conversion if omitted." } }, "$defs": { "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "type", "name", "datatype", "conversion" ] }
- Fields:
conversion (ddd.models.conversion.IdentityConversion | ddd.models.conversion.LinearConversion | ddd.models.conversion.EnumConversion | ddd.models.conversion.StringConversion)datatype (ddd.models.common.Datatype)description (str)limits (ddd.models.objects.Limits | None)name (str)type (Literal['scalar'])unit (str)
- field type: Literal['scalar'] [Required]
Says this entry names a scalar rather than describing a structure.
- field name: TypeName [Required]
Name of the type; every type of a project needs a distinct one.
Refused if it reads as a base datatype, for the reason a structure’s name is.
- field description: str = ''
Free text describing what the type is, offered to the c templates.
- field datatype: Datatype [Required]
Storage of the value: one of the base datatypes.
A base datatype rather than another declared type, so that a scalar type cannot be defined in terms of a second one. A chain of names would have to be resolved, could form a cycle, and buys nothing a reader of the one entry could not already see.
Storage of the value: one of the base datatypes.
A base datatype rather than another declared type, so that a scalar type cannot be defined in terms of a second one. A chain of names would have to be resolved, could form a cycle, and buys nothing a reader of the one entry could not already see.
- field unit: str = ''
Physical unit of the value, e.g.
"rpm".
- field conversion: Conversion [Required]
How a raw value maps to a physical one: identity, linear scaling, an enumeration, or text read from the bytes (
string).Required: fixing what a value means is the one job a scalar type has, and the identity is part of the answer rather than a silence to interpret.
How a raw value maps to a physical one: identity, linear scaling, an enumeration, or text read from the bytes (
string).Required: fixing what a value means is the one job a scalar type has, and the identity is part of the answer rather than a silence to interpret.
- pydantic model ExternalType[source]
A name for a c type that DDD does not declare: a hand written header defines it.
DDD generates no typedef for it and knows neither its layout nor its meaning - which is the point: a driver’s status word or an operating system’s handle already has one authoritative definition, and a copy of it in the description would drift. Only a structure member may name one, as opaque storage that reaches the generated structure verbatim; such a member states no unit, conversion or limits, because DDD does not check meaning it cannot see.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.types.ExternalType" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ExternalType</b></td></tr><tr><td>type</td><td port="type">Literal['external']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>header</td><td port="header">str</td></tr></table>>,
tooltip="ddd.models.types.ExternalType

A name for a c type that DDD does not declare: a hand written header defines it.

\
DDD generates no typedef for it and knows neither its layout nor its meaning - which is
the point: a driver's status word or \
an operating system's handle already has one
authoritative definition, and a copy of it in the description would drift. Only \
a
structure member may name one, as opaque storage that reaches the generated structure
verbatim; such a member states no \
unit, conversion or limits, because DDD does not check
meaning it cannot see.
"];
}](_images/graphviz-4fa71c7c5aa7ee42f31b5a5a81424c2367e941a4.png)
Show JSON schema
{ "title": "ExternalType", "description": "A name for a c type that DDD does not declare: a hand written header defines it.\n\nDDD generates no typedef for it and knows neither its layout nor its meaning - which is\nthe point: a driver's status word or an operating system's handle already has one\nauthoritative definition, and a copy of it in the description would drift. Only a\nstructure member may name one, as opaque storage that reaches the generated structure\nverbatim; such a member states no unit, conversion or limits, because DDD does not check\nmeaning it cannot see.", "type": "object", "properties": { "type": { "const": "external", "description": "Says this entry names an external type rather than declaring one of DDD's own.", "title": "Type", "type": "string" }, "name": { "description": "The type's c identifier, as the defining header spells it.\n\nEvery type of a project needs a distinct name, and the rules are those of the declared\ntypes: it cannot read as a base datatype, and it shares the project wide namespace with\nthe structures and the scalars.", "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "description": { "default": "", "description": "Free text describing what the type is, offered to the c templates.", "title": "Description", "type": "string" }, "header": { "description": "The header that defines the type, spelled the way the generated inclusion writes it.\n\n``my_driver.h`` for the quoted form, ``<os_types.h>`` for the angle form; a subdirectory\npath such as ``drivers/status.h`` is allowed in either. The spelling is written out\nexactly as it stands, so one that would unbalance the line is refused here rather than\nhanded to a compiler: no whitespace, no quote of its own - the quoted form is written\nbare - and, for the angle form, exactly one pair of angle brackets wrapping the whole\nname.", "minLength": 1, "title": "Header", "type": "string" } }, "additionalProperties": false, "required": [ "type", "name", "header" ] }
- Fields:
description (str)header (str)name (str)type (Literal['external'])
- field type: Literal['external'] [Required]
Says this entry names an external type rather than declaring one of DDD’s own.
- field name: TypeName [Required]
The type’s c identifier, as the defining header spells it.
Every type of a project needs a distinct name, and the rules are those of the declared types: it cannot read as a base datatype, and it shares the project wide namespace with the structures and the scalars.
The type’s c identifier, as the defining header spells it.
Every type of a project needs a distinct name, and the rules are those of the declared types: it cannot read as a base datatype, and it shares the project wide namespace with the structures and the scalars.
- field description: str = ''
Free text describing what the type is, offered to the c templates.
- field header: IncludeSpelling [Required]
The header that defines the type, spelled the way the generated inclusion writes it.
my_driver.hfor the quoted form,<os_types.h>for the angle form; a subdirectory path such asdrivers/status.his allowed in either. The spelling is written out exactly as it stands, so one that would unbalance the line is refused here rather than handed to a compiler: no whitespace, no quote of its own - the quoted form is written bare - and, for the angle form, exactly one pair of angle brackets wrapping the whole name.The header that defines the type, spelled the way the generated inclusion writes it.
my_driver.hfor the quoted form,<os_types.h>for the angle form; a subdirectory path such asdrivers/status.his allowed in either. The spelling is written out exactly as it stands, so one that would unbalance the line is refused here rather than handed to a compiler: no whitespace, no quote of its own - the quoted form is written bare - and, for the angle form, exactly one pair of angle brackets wrapping the whole name.
Data objects
The definition of a declaration is a tagged union discriminated on kind, and kind
is required on every definition - a measurement states "kind": "measurement" like every
other. A defaulted discriminator would leave a bare definition matching more than one variant
in the published schema, which an editor validating the file reports as an ambiguity; stating
it keeps the schema and the loader in agreement. ddd.models.DataObject holds what all six
kinds have in common, and the six models after it document only what their own kind adds;
the json schema shown with each of them is nevertheless the complete document a declaration
of that kind is validated against. volatile is one of the common fields, and one of the five
an author always has to write - the others are name, kind, the storage (exactly one of
datatype and typename) and, whenever datatype is the one stated, conversion. It
carries no
default because there is no answer DDD could derive from the rest of the description, so a
definition that leaves it out is a schema finding like any other missing field.
- pydantic model DataObject[source]
Attributes shared by every kind of data object.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.DataObject" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>DataObject</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">ObjectKind</td></tr></table>>,
tooltip="ddd.models.objects.DataObject

Attributes shared by every kind of data object.
"];
"ddd.models.objects.DataObject":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.DataObject":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.DataObject":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.DataObject":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.DataObject":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.DataObject":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-5ae479127cacaff95fc0cab70c4481fb149cf60c.png)
Show JSON schema
{ "title": "DataObject", "description": "Attributes shared by every kind of data object.", "type": "object", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "$ref": "#/$defs/ObjectKind", "description": "Which sort of object this is; stated on every definition.\n\nIt also decides which further keys the definition may carry: ``dimensions`` on a\nmeasurement or a value block, ``size`` and ``input`` on an axis, ``axis`` on a curve,\n``x_axis`` and ``y_axis`` on a map, and none of them on a parameter." } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "ObjectKind": { "description": "What sort of data object a definition describes.", "enum": [ "measurement", "parameter", "value_block", "curve", "map", "axis" ], "title": "ObjectKind", "type": "string" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "volatile", "kind" ] }
- Fields:
a2l (ddd.models.objects.A2lObjectOptions)conversion (ddd.models.conversion.IdentityConversion | ddd.models.conversion.LinearConversion | ddd.models.conversion.EnumConversion | ddd.models.conversion.StringConversion | None)datatype (ddd.models.common.Datatype | None)description (str)extensions (dict[str, dict[str, Any]])id (str | None)init (ddd.models.objects.InitValue | None)kind (ddd.models.objects.ObjectKind)limits (ddd.models.objects.Limits | None)name (str)raster (str | None)section (str | None)typename (str | None)unit (str)volatile (bool)
- field name: Identifier [Required]
C identifier of the object; also its name in the a2l.
- field id: ObjectId | None = None
Identity of this object, which survives its name.
Written by the component that produces the object and by nothing else: a consumer stating one is refused as
consumer-identity, on the reasoning that makessectionandinitproducer keys. It links this object to itself in an earlier delivery, so thatddd comparereports a rename as a rename rather than as a removal and an unrelated addition, and so that a name freed by a rename cannot be quietly claimed by something else.Nothing inside a project reads it: the producer and its consumers go on binding by name, and the generated c and a2l never mention it. Optional, so that a project adopts it one component at a time;
missing-idsays where it has not.Identity of this object, which survives its name.
Written by the component that produces the object and by nothing else: a consumer stating one is refused as
consumer-identity, on the reasoning that makessectionandinitproducer keys. It links this object to itself in an earlier delivery, so thatddd comparereports a rename as a rename rather than as a removal and an unrelated addition, and so that a name freed by a rename cannot be quietly claimed by something else.Nothing inside a project reads it: the producer and its consumers go on binding by name, and the generated c and a2l never mention it. Optional, so that a project adopts it one component at a time;
missing-idsays where it has not.
- field extensions: dict[PluginName, dict[str, Any]] [Optional]
Blocks owned by the project’s plugins, keyed by plugin name.
{"layout": {"key": 12, "version": 3}}: what a plugin the project names needs to know about this object and DDD does not. Each block is validated against the model of the plugin that owns it and carried into the dictionary in resolved form; a block naming no loaded plugin isunknown-extension. Only the producing declaration states one - a consumer stating one isconsumer-extension, on the reasoning that makessectionandidproducer keys: a block says what the object is.Blocks owned by the project’s plugins, keyed by plugin name.
{"layout": {"key": 12, "version": 3}}: what a plugin the project names needs to know about this object and DDD does not. Each block is validated against the model of the plugin that owns it and carried into the dictionary in resolved form; a block naming no loaded plugin isunknown-extension. Only the producing declaration states one - a consumer stating one isconsumer-extension, on the reasoning that makessectionandidproducer keys: a block says what the object is.
- field datatype: Datatype | None = None
Storage of one element, one of the eleven base datatypes.
Exactly one of
datatypeandtypenameis stated. Two keys rather than one union, so that the published schema saysdatatypeis one of eleven values - an editor completes and documents exactly them, and a mistyped one is refused as it is typed - and so that a declaration tells its reader at a glance whether storage is base or declared.Storage of one element, one of the eleven base datatypes.
Exactly one of
datatypeandtypenameis stated. Two keys rather than one union, so that the published schema saysdatatypeis one of eleven values - an editor completes and documents exactly them, and a mistyped one is refused as it is typed - and so that a declaration tells its reader at a glance whether storage is base or declared.
- field typename: TypeName | None = None
Name of a type the project declares, stated instead of
datatype.Naming a structure is what makes this object a structured one; naming a scalar type is what lets several components agree about a value by naming it rather than by each copying out its unit, its scaling and its limits - and a declaration that names a type may not restate any of them.
Name of a type the project declares, stated instead of
datatype.Naming a structure is what makes this object a structured one; naming a scalar type is what lets several components agree about a value by naming it rather than by each copying out its unit, its scaling and its limits - and a declaration that names a type may not restate any of them.
- field description: str = ''
What the object is, offered to the c templates and used as the a2l long identifier.
- field unit: str = ''
Physical unit, e.g.
"Hz".Free text, so DDD does not know by itself that
rpmand1/minare the same thing: every component declaring this object has to spell it the same way, and where the project has a units file the spelling is checked against the unit vocabulary too (unknown-unit). Refused beside astringconversion: text has no unit, and one stated there would reach the a2l as the unit of a computation method that cannot exist.Physical unit, e.g.
"Hz".Free text, so DDD does not know by itself that
rpmand1/minare the same thing: every component declaring this object has to spell it the same way, and where the project has a units file the spelling is checked against the unit vocabulary too (unknown-unit). Refused beside astringconversion: text has no unit, and one stated there would reach the a2l as the unit of a computation method that cannot exist.
- field section: Annotated[str, StringConstraints(pattern=SECTION_NAME_PATTERN)] | None = None
Linker section the object is placed in, named in the project’s sections file.
A storage key like
init: the producer states it, a consumer stating one claims storage it does not own (consumer-storage), and a structured object is placed whole. Left out, the object goes wherever the toolchain’s defaults put it.Linker section the object is placed in, named in the project’s sections file.
A storage key like
init: the producer states it, a consumer stating one claims storage it does not own (consumer-storage), and a structured object is placed whole. Left out, the object goes wherever the toolchain’s defaults put it.
- field raster: RasterName | None = None
Measurement raster the object is updated in, named in the project’s rasters file.
A producer key like
section: the producing component’s task is what updates the value, so a consumer stating one is refused asconsumer-raster, and a structured variable carries one raster for all of its members. Left out, the producing component’s default applies; left out there too, the a2l describes the object without saying which daq event carries it, and the calibration tool decides.At the top level rather than inside
a2l, although only that backend reads it today: which task updates a value is an engineering claim about the data, the waysectionis, and not a presentation choice.Spelled the way a declaration spells it - printable ASCII, no space, at most eight characters - so a name no rasters file could ever declare is refused where it is written rather than reported as
unknown-raster, which sends the reader looking for a declaration that could not exist. The same rule asectionreference has always been held to.Measurement raster the object is updated in, named in the project’s rasters file.
A producer key like
section: the producing component’s task is what updates the value, so a consumer stating one is refused asconsumer-raster, and a structured variable carries one raster for all of its members. Left out, the producing component’s default applies; left out there too, the a2l describes the object without saying which daq event carries it, and the calibration tool decides.At the top level rather than inside
a2l, although only that backend reads it today: which task updates a value is an engineering claim about the data, the waysectionis, and not a presentation choice.Spelled the way a declaration spells it - printable ASCII, no space, at most eight characters - so a name no rasters file could ever declare is refused where it is written rather than reported as
unknown-raster, which sends the reader looking for a declaration that could not exist. The same rule asectionreference has always been held to.
- field init: InitValue | None = None
Raw initial value, in the stored domain rather than the physical one.
nullleaves the object zero initialised by the startup code. For an array shaped object, either a nested list matching the shape exactly, or a single scalar, which initialises every element with that value. A string object may state its init as text instead: printable ASCII, shorter than the dimension so that the terminating zero fits.Raw initial value, in the stored domain rather than the physical one.
nullleaves the object zero initialised by the startup code. For an array shaped object, either a nested list matching the shape exactly, or a single scalar, which initialises every element with that value. A string object may state its init as text instead: printable ASCII, shorter than the dimension so that the terminating zero fits.
- field conversion: Conversion | None = None
How a raw value maps to a physical one: identity, linear scaling, an enumeration, or text read from the bytes (
string).Required wherever storage is named by
datatype, although the identity would be derivable: raw equalling physical is an engineering claim about the data, not a formatting accident, and a forgotten scaling on a fixed point value displays raw counts without anything looking broken. A definition naming atypenamestates no conversion - the type fixes it.kindmay be left out when the keys make it unambiguous:factororoffsetmeanslinear,enumeratorsornamemeansenum, and{}meansidentity. Astringalways states itskind, having no key of its own to be recognised by.How a raw value maps to a physical one: identity, linear scaling, an enumeration, or text read from the bytes (
string).Required wherever storage is named by
datatype, although the identity would be derivable: raw equalling physical is an engineering claim about the data, not a formatting accident, and a forgotten scaling on a fixed point value displays raw counts without anything looking broken. A definition naming atypenamestates no conversion - the type fixes it.kindmay be left out when the keys make it unambiguous:factororoffsetmeanslinear,enumeratorsornamemeansenum, and{}meansidentity. Astringalways states itskind, having no key of its own to be recognised by.
- field limits: Limits | None = None
Physical limits of the object, in the unit given by
unit.Omitted, they are derived from
datatypeandconversion: the whole range the storage can hold, converted. State them to say that the software handles less than that, which is what stops a calibration tool offering a value the software cannot take. Refused beside astringconversion: the range of text is the byte range of its datatype, and stated limits would offer a tool a range over character codes.Physical limits of the object, in the unit given by
unit.Omitted, they are derived from
datatypeandconversion: the whole range the storage can hold, converted. State them to say that the software handles less than that, which is what stops a calibration tool offering a value the software cannot take. Refused beside astringconversion: the range of text is the byte range of its datatype, and stated limits would offer a tool a range over character codes.
- field a2l: A2lObjectOptions = A2lObjectOptions(export=None, format=None, display_identifier=None)
What this object asks of the a2l file: whether to export it, how to display it.
Only the a2l backend reads it, so a project that generates no a2l can leave it out entirely.
What this object asks of the a2l file: whether to export it, how to display it.
Only the a2l backend reads it, so a project that generates no a2l can leave it out entirely.
- field volatile: bool [Required]
Whether the c declaration carries
volatile; stated on every definition.Required, with no default, and on every kind rather than on measurements alone. Both follow from what the qualifier does, which is to forbid the compiler to assume it already knows the value.
A measurement needs it when something outside the reading component’s control writes the variable - an interrupt, a second core, a peripheral, or a calibration tool writing through its address. A calibration object needs it when the calibration tool is to change the value in a running ecu: without it the compiler is entitled to use the initialiser in place of a read wherever it can see it - within one translation unit at every optimisation level,
-O0included, and across them under link time optimisation - and, where the load does survive, to serve two reads from one of them. Either way the tool writes a new value the software does not pick up.Interface rather than storage, because it reaches every component that reads the object: their header declares it
extern volatile, which is what tells their code not to cache the value and not to expect two reads to agree. Every declaration of one object therefore has to say the same thing, and a disagreement is an error.There is no default because there is no answer DDD could derive - unlike
limits, which follow from the datatype and the conversion. The two answers have different costs and only the project knows which it is paying:truekeeps a value tunable and, on a typical toolchain, moves a calibration object out of read-only memory;falsekeeps it in flash and lets the optimiser cache it. Saying nothing would pick one of them silently, and the one it picked would be wrong roughly as often as not.Whether the c declaration carries
volatile; stated on every definition.Required, with no default, and on every kind rather than on measurements alone. Both follow from what the qualifier does, which is to forbid the compiler to assume it already knows the value.
A measurement needs it when something outside the reading component’s control writes the variable - an interrupt, a second core, a peripheral, or a calibration tool writing through its address. A calibration object needs it when the calibration tool is to change the value in a running ecu: without it the compiler is entitled to use the initialiser in place of a read wherever it can see it - within one translation unit at every optimisation level,
-O0included, and across them under link time optimisation - and, where the load does survive, to serve two reads from one of them. Either way the tool writes a new value the software does not pick up.Interface rather than storage, because it reaches every component that reads the object: their header declares it
extern volatile, which is what tells their code not to cache the value and not to expect two reads to agree. Every declaration of one object therefore has to say the same thing, and a disagreement is an error.There is no default because there is no answer DDD could derive - unlike
limits, which follow from the datatype and the conversion. The two answers have different costs and only the project knows which it is paying:truekeeps a value tunable and, on a typical toolchain, moves a calibration object out of read-only memory;falsekeeps it in flash and lets the optimiser cache it. Saying nothing would pick one of them silently, and the one it picked would be wrong roughly as often as not.
- field kind: ObjectKind [Required]
Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.
- pydantic model Measurement[source]
An online value: the software writes it, a calibration tool measures it and may write it.
A tool writing one through its address is one of the reasons to declare a measurement
volatile, alongside an interrupt, a second core and a peripheral.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Measurement" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Measurement</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MEASUREMENT]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.Measurement

An online value: the software writes it, a calibration tool measures it and may write it.&#\
xA;
A tool writing one through its address is one of the reasons to declare a measurement
``volatile``, alongside an interrupt, \
a second core and a peripheral.
"];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Measurement":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Measurement":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-ce969b8be47c23a6c2229faa6de597a44a28304b.png)
Show JSON schema
{ "title": "Measurement", "description": "An online value: the software writes it, a calibration tool measures it and may write it.\n\nA tool writing one through its address is one of the reasons to declare a measurement\n``volatile``, alongside an interrupt, a second core and a peripheral.", "type": "object", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "measurement", "title": "Kind", "type": "string" }, "dimensions": { "default": [], "description": "Array dimensions; empty for a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, in a\nconstants file or in a component - ``[3, 4]`` and ``[\"PRESSURE_CELLS\", 4]`` are both\nshapes.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "title": "Dimensions", "type": "array" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "volatile", "kind" ] }
- Fields:
dimensions (tuple[Dimension, ...])kind (Literal[ObjectKind.MEASUREMENT])
- field kind: Literal[ObjectKind.MEASUREMENT] [Required]
Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.
- field dimensions: tuple[Dimension, ...] = ()
Array dimensions; empty for a scalar.
Each an integer of at least 1, or the name of a constant the project declares, in a constants file or in a component -
[3, 4]and["PRESSURE_CELLS", 4]are both shapes.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.Array dimensions; empty for a scalar.
Each an integer of at least 1, or the name of a constant the project declares, in a constants file or in a component -
[3, 4]and["PRESSURE_CELLS", 4]are both shapes.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.
- pydantic model Parameter[source]
A single calibratable constant.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Parameter" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Parameter</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.PARAMETER]</td></tr></table>>,
tooltip="ddd.models.objects.Parameter

A single calibratable constant.
"];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Parameter":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Parameter":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-15de6bd650d72445eabe020d2ab2c969fde779f0.png)
Show JSON schema
{ "title": "Parameter", "description": "A single calibratable constant.", "type": "object", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "parameter", "title": "Kind", "type": "string" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "volatile", "kind" ] }
- Fields:
kind (Literal[ObjectKind.PARAMETER])
- field kind: Literal[ObjectKind.PARAMETER] [Required]
Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.
- pydantic model ValueBlock[source]
An array of calibratable constants.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.ValueBlock" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ValueBlock</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.VALUE_BLOCK]</td></tr><tr><td>dimensions</td><td port="dimensions">tuple[Union[int, str], ...]</td></tr></table>>,
tooltip="ddd.models.objects.ValueBlock

An array of calibratable constants.
"];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.ValueBlock":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-c9b56a9b30e709c022e7bb6cace80e08de61781b.png)
Show JSON schema
{ "title": "ValueBlock", "description": "An array of calibratable constants.", "type": "object", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "value_block", "title": "Kind", "type": "string" }, "dimensions": { "description": "Array dimensions in c declaration order; a value block is never a scalar.\n\nEach an integer of at least 1, or the name of a constant the project declares, mixed\nfreely.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "items": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ] }, "minItems": 1, "title": "Dimensions", "type": "array" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "volatile", "kind", "dimensions" ] }
- Fields:
dimensions (Annotated[tuple[Dimension, ...], Field(min_length=1)])kind (Literal[ObjectKind.VALUE_BLOCK])
- field kind: Literal[ObjectKind.VALUE_BLOCK] [Required]
Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.
- field dimensions: Annotated[tuple[Dimension, ...], Field(min_length=1)] [Required]
Array dimensions in c declaration order; a value block is never a scalar.
Each an integer of at least 1, or the name of a constant the project declares, mixed freely.
A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.Array dimensions in c declaration order; a value block is never a scalar.
Each an integer of at least 1, or the name of a constant the project declares, mixed freely.
A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.- Constraints:
min_length = 1
- pydantic model Axis[source]
Shared axis points; several curves and maps may be interpolated over one axis.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Axis" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Axis</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.AXIS]</td></tr><tr><td>size</td><td port="size">Union[int, str]</td></tr><tr><td>input</td><td port="input">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.Axis

Shared axis points; several curves and maps may be interpolated over one axis.
"];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Axis":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Axis":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-d225680e3678e51eec8107b60ddd373fd519cf0b.png)
Show JSON schema
{ "title": "Axis", "description": "Shared axis points; several curves and maps may be interpolated over one axis.", "type": "object", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "axis", "title": "Kind", "type": "string" }, "size": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": 1, "type": "integer" }, { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" } ], "description": "Number of axis points: an integer of at least 1, or the name of a declared constant.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "title": "Size" }, "input": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement that indexes the axis; the a2l input quantity.\n\nA plain one: an instance of a declared structure is of kind ``measurement`` and is\nrefused here as any other wrong kind is, because it reaches the a2l as one record per\nvalue-holding member and none of its own.", "title": "Input" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "volatile", "kind", "size" ] }
- Fields:
input (Identifier | None)kind (Literal[ObjectKind.AXIS])size (Dimension)
- field kind: Literal[ObjectKind.AXIS] [Required]
Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.
- field size: Dimension [Required]
Number of axis points: an integer of at least 1, or the name of a declared constant.
A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.Number of axis points: an integer of at least 1, or the name of a declared constant.
A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.
- field input: Identifier | None = None
Measurement that indexes the axis; the a2l input quantity.
A plain one: an instance of a declared structure is of kind
measurementand is refused here as any other wrong kind is, because it reaches the a2l as one record per value-holding member and none of its own.Measurement that indexes the axis; the a2l input quantity.
A plain one: an instance of a declared structure is of kind
measurementand is refused here as any other wrong kind is, because it reaches the a2l as one record per value-holding member and none of its own.
- pydantic model Curve[source]
A one dimensional calibratable table.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Curve" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Curve</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.CURVE]</td></tr><tr><td>axis</td><td port="axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Curve

A one dimensional calibratable table.
"];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Curve":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Curve":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-1e266b16e48cec2724bceea38c786e11d8ef692c.png)
Show JSON schema
{ "title": "Curve", "description": "A one dimensional calibratable table.", "type": "object", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "curve", "title": "Kind", "type": "string" }, "axis": { "description": "Name of the axis object the curve is interpolated over.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Axis", "type": "string" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "volatile", "kind", "axis" ] }
- Fields:
axis (Identifier)kind (Literal[ObjectKind.CURVE])
- field kind: Literal[ObjectKind.CURVE] [Required]
Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.
- field axis: Identifier [Required]
Name of the axis object the curve is interpolated over.
- pydantic model Map[source]
A two dimensional calibratable table, stored as
[y][x].![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
"ddd.models.objects.Map" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Map</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>id</td><td port="id">Optional[str]</td></tr><tr><td>extensions</td><td port="extensions">dict[str, dict[str, Any]]</td></tr><tr><td>datatype</td><td port="datatype">Datatype | None</td></tr><tr><td>typename</td><td port="typename">Optional[str]</td></tr><tr><td>description</td><td port="description">str</td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>section</td><td port="section">Optional[str]</td></tr><tr><td>raster</td><td port="raster">Optional[str]</td></tr><tr><td>init</td><td port="init">InitValue | None</td></tr><tr><td>conversion</td><td port="conversion">Optional[IdentityConversion | LinearConversion | EnumConversion | StringConversion]</td></tr><tr><td>limits</td><td port="limits">Limits | None</td></tr><tr><td>a2l</td><td port="a2l">A2lObjectOptions</td></tr><tr><td>volatile</td><td port="volatile">bool</td></tr><tr><td>kind</td><td port="kind">Literal[ObjectKind.MAP]</td></tr><tr><td>x_axis</td><td port="x_axis">str</td></tr><tr><td>y_axis</td><td port="y_axis">str</td></tr></table>>,
tooltip="ddd.models.objects.Map

A two dimensional calibratable table, stored as ``[y][x]``.
"];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.EnumConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.IdentityConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.LinearConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":conversion:e -> "ddd.models.conversion.StringConversion":_root:w [arrowhead=noneteeodot,
arrowtail=nonenone];
"ddd.models.objects.Map":a2l:e -> "ddd.models.objects.A2lObjectOptions":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
"ddd.models.objects.Map":limits:e -> "ddd.models.objects.Limits":_root:w [arrowhead=noneteetee,
arrowtail=nonenone];
}](_images/graphviz-b16fbb8fcae6f171937c8259ffe116352a70da44.png)
Show JSON schema
{ "title": "Map", "description": "A two dimensional calibratable table, stored as ``[y][x]``.", "type": "object", "properties": { "name": { "description": "C identifier of the object; also its name in the a2l.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "id": { "anyOf": [ { "pattern": "^[abcdefghjkmnpqrstvwxyz0123456789]{12}$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Identity of this object, which survives its name.\n\nWritten by the component that produces the object and by nothing else: a consumer stating\none is refused as ``consumer-identity``, on the reasoning that makes ``section`` and\n``init`` producer keys. It links this object to itself in an earlier delivery, so that\n``ddd compare`` reports a rename as a rename rather than as a removal and an unrelated\naddition, and so that a name freed by a rename cannot be quietly claimed by something\nelse.\n\nNothing inside a project reads it: the producer and its consumers go on binding by name,\nand the generated c and a2l never mention it. Optional, so that a project adopts it one\ncomponent at a time; ``missing-id`` says where it has not.", "title": "Id" }, "extensions": { "description": "Blocks owned by the project's plugins, keyed by plugin name.\n\n``{\"layout\": {\"key\": 12, \"version\": 3}}``: what a plugin the project names needs to know\nabout this object and DDD does not. Each block is validated against the model of the\nplugin that owns it and carried into the dictionary in resolved form; a block naming no\nloaded plugin is ``unknown-extension``. Only the producing declaration states one - a\nconsumer stating one is ``consumer-extension``, on the reasoning that makes ``section``\nand ``id`` producer keys: a block says what the object *is*.", "patternProperties": { "^[a-z][a-z0-9_]*$": { "additionalProperties": true, "type": "object" } }, "title": "Extensions", "type": "object" }, "datatype": { "anyOf": [ { "$ref": "#/$defs/Datatype" }, { "type": "null" } ], "default": null, "description": "Storage of one element, one of the eleven base datatypes.\n\nExactly one of ``datatype`` and ``typename`` is stated. Two keys rather than one union,\nso that the published schema says ``datatype`` is one of eleven values - an editor\ncompletes and documents exactly them, and a mistyped one is refused as it is typed - and\nso that a declaration tells its reader at a glance whether storage is base or declared." }, "typename": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^(?!(?:[Bb][Oo][Oo][Ll][Ee][Aa][Nn]|[Ff][Ll][Oo][Aa][Tt]32|[Ff][Ll][Oo][Aa][Tt]64|[Ss][Ii][Nn][Tt]16|[Ss][Ii][Nn][Tt]32|[Ss][Ii][Nn][Tt]64|[Ss][Ii][Nn][Tt]8|[Uu][Ii][Nn][Tt]16|[Uu][Ii][Nn][Tt]32|[Uu][Ii][Nn][Tt]64|[Uu][Ii][Nn][Tt]8)$)[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Name of a type the project declares, stated instead of ``datatype``.\n\nNaming a structure is what makes this object a structured one; naming a scalar type is\nwhat lets several components agree about a value by naming it rather than by each copying\nout its unit, its scaling and its limits - and a declaration that names a type may not\nrestate any of them.", "title": "Typename" }, "description": { "default": "", "description": "What the object is, offered to the c templates and used as the a2l long identifier.", "title": "Description", "type": "string" }, "unit": { "default": "", "description": "Physical unit, e.g. ``\"Hz\"``.\n\nFree text, so DDD does not know by itself that ``rpm`` and ``1/min`` are the same thing:\nevery component declaring this object has to spell it the same way, and where the project\nhas a units file the spelling is checked against the unit vocabulary too (``unknown-unit``).\nRefused beside a ``string`` conversion: text has no unit, and one stated there would\nreach the a2l as the unit of a computation method that cannot exist.", "title": "Unit", "type": "string" }, "section": { "anyOf": [ { "pattern": "^[A-Za-z0-9_.$]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Linker section the object is placed in, named in the project's sections file.\n\nA storage key like ``init``: the producer states it, a consumer stating one claims\nstorage it does not own (``consumer-storage``), and a structured object is placed whole.\nLeft out, the object goes wherever the toolchain's defaults put it.", "title": "Section" }, "raster": { "anyOf": [ { "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Measurement raster the object is updated in, named in the project's rasters file.\n\nA producer key like ``section``: the producing component's task is what updates the\nvalue, so a consumer stating one is refused as ``consumer-raster``, and a structured\nvariable carries one raster for all of its members. Left out, the producing component's\ndefault applies; left out there too, the a2l describes the object without saying which\ndaq event carries it, and the calibration tool decides.\n\nAt the top level rather than inside ``a2l``, although only that backend reads it today:\nwhich task updates a value is an engineering claim about the data, the way ``section``\nis, and not a presentation choice.\n\nSpelled the way a declaration spells it - printable ASCII, no space, at most eight\ncharacters - so a name no rasters file could ever declare is refused where it is\nwritten rather than reported as ``unknown-raster``, which sends the reader looking for\na declaration that could not exist. The same rule a ``section`` reference has always\nbeen held to.", "title": "Raster" }, "init": { "anyOf": [ { "$ref": "#/$defs/InitValue" }, { "type": "null" } ], "default": null, "description": "Raw initial value, in the stored domain rather than the physical one.\n\n``null`` leaves the object zero initialised by the startup code. For an array shaped\nobject, either a nested list matching the shape exactly, or a single scalar, which\ninitialises every element with that value. A string object may state its init as text\ninstead: printable ASCII, shorter than the dimension so that the terminating zero fits." }, "conversion": { "anyOf": [ { "discriminator": { "mapping": { "enum": "#/$defs/EnumConversion", "identity": "#/$defs/IdentityConversion", "linear": "#/$defs/LinearConversion", "string": "#/$defs/StringConversion" }, "propertyName": "kind" }, "oneOf": [ { "$ref": "#/$defs/IdentityConversion" }, { "$ref": "#/$defs/LinearConversion" }, { "$ref": "#/$defs/EnumConversion" }, { "$ref": "#/$defs/StringConversion" } ] }, { "type": "null" } ], "default": null, "description": "How a raw value maps to a physical one: identity, linear scaling, an enumeration, or\ntext read from the bytes (``string``).\n\nRequired wherever storage is named by ``datatype``, although the identity would be\nderivable: raw equalling physical is an engineering claim about the data, not a\nformatting accident, and a forgotten scaling on a fixed point value displays raw counts\nwithout anything looking broken. A definition naming a ``typename`` states no conversion\n- the type fixes it. ``kind`` may be left out when the keys make it unambiguous:\n``factor`` or ``offset`` means ``linear``, ``enumerators`` or ``name`` means ``enum``,\nand ``{}`` means ``identity``. A ``string`` always states its ``kind``, having no key of\nits own to be recognised by.", "title": "Conversion" }, "limits": { "anyOf": [ { "$ref": "#/$defs/Limits" }, { "type": "null" } ], "default": null, "description": "Physical limits of the object, in the unit given by ``unit``.\n\nOmitted, they are derived from ``datatype`` and ``conversion``: the whole range the\nstorage can hold, converted. State them to say that the software handles less than that,\nwhich is what stops a calibration tool offering a value the software cannot take.\nRefused beside a ``string`` conversion: the range of text is the byte range of its\ndatatype, and stated limits would offer a tool a range over character codes." }, "a2l": { "$ref": "#/$defs/A2lObjectOptions", "default": { "export": null, "format": null, "display_identifier": null }, "description": "What this object asks of the a2l file: whether to export it, how to display it.\n\nOnly the a2l backend reads it, so a project that generates no a2l can leave it out\nentirely." }, "volatile": { "description": "Whether the c declaration carries ``volatile``; stated on every definition.\n\nRequired, with no default, and on every kind rather than on measurements alone. Both\nfollow from what the qualifier does, which is to forbid the compiler to assume it already\nknows the value.\n\nA measurement needs it when something outside the reading component's control writes the\nvariable - an interrupt, a second core, a peripheral, or a calibration tool writing\nthrough its address. A calibration object needs it when the calibration tool is to change\nthe value in a running ecu: without it the compiler is entitled to use the initialiser in\nplace of a read wherever it can see it - within one translation unit at every optimisation\nlevel, ``-O0`` included, and across them under link time optimisation - and, where the\nload does survive, to serve two reads from one of them. Either way the tool writes a new\nvalue the software does not pick up.\n\nInterface rather than storage, because it reaches every component that reads the object:\ntheir header declares it ``extern volatile``, which is what tells their code not to cache\nthe value and not to expect two reads to agree. Every declaration of one object therefore\nhas to say the same thing, and a disagreement is an error.\n\nThere is no default because there is no answer DDD could derive - unlike ``limits``, which\nfollow from the datatype and the conversion. The two answers have different costs and only\nthe project knows which it is paying: ``true`` keeps a value tunable and, on a typical\ntoolchain, moves a calibration object out of read-only memory; ``false`` keeps it in flash\nand lets the optimiser cache it. Saying nothing would pick one of them silently, and the\none it picked would be wrong roughly as often as not.", "title": "Volatile", "type": "boolean" }, "kind": { "const": "map", "title": "Kind", "type": "string" }, "x_axis": { "description": "Name of the axis whose index runs fastest; the last dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "X Axis", "type": "string" }, "y_axis": { "description": "Name of the axis selecting the row; the first dimension of the c array.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Y Axis", "type": "string" } }, "$defs": { "A2lObjectOptions": { "additionalProperties": false, "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "title": "A2lObjectOptions", "type": "object" }, "Datatype": { "description": "The base datatypes DDD can allocate storage for.", "enum": [ "boolean", "uint8", "sint8", "uint16", "sint16", "uint32", "sint32", "uint64", "sint64", "float32", "float64" ], "title": "Datatype", "type": "string" }, "EnumConversion": { "additionalProperties": false, "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "required": [ "name", "enumerators" ], "title": "EnumConversion", "type": "object" }, "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" }, "IdentityConversion": { "additionalProperties": false, "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "title": "IdentityConversion", "type": "object" }, "InitElement": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "InitScalar": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "boolean" }, { "type": "number" } ] }, "InitValue": { "anyOf": [ { "$ref": "#/$defs/InitScalar" }, { "type": "string" }, { "items": { "$ref": "#/$defs/InitElement" }, "type": "array" } ] }, "Limits": { "additionalProperties": false, "description": "Physical lower/upper limit of a data object.", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "required": [ "min", "max" ], "title": "Limits", "type": "object" }, "LinearConversion": { "additionalProperties": false, "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "title": "LinearConversion", "type": "object" }, "StringConversion": { "additionalProperties": false, "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "required": [ "kind" ], "title": "StringConversion", "type": "object" } }, "additionalProperties": false, "required": [ "name", "volatile", "kind", "x_axis", "y_axis" ] }
- Fields:
kind (Literal[ObjectKind.MAP])x_axis (Identifier)y_axis (Identifier)
- field kind: Literal[ObjectKind.MAP] [Required]
Which sort of object this is; stated on every definition.
It also decides which further keys the definition may carry:
dimensionson a measurement or a value block,sizeandinputon an axis,axison a curve,x_axisandy_axison a map, and none of them on a parameter.
- field x_axis: Identifier [Required]
Name of the axis whose index runs fastest; the last dimension of the c array.
- field y_axis: Identifier [Required]
Name of the axis selecting the row; the first dimension of the c array.
- pydantic model Limits[source]
Physical lower/upper limit of a data object.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.objects.Limits" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Limits</b></td></tr><tr><td>min</td><td port="min">Union[int, float]</td></tr><tr><td>max</td><td port="max">Union[int, float]</td></tr></table>>,
tooltip="ddd.models.objects.Limits

Physical lower/upper limit of a data object.
"];
}](_images/graphviz-6c62081c77701c4b055b57eb4743e97da6bec55a.png)
Show JSON schema
{ "title": "Limits", "description": "Physical lower/upper limit of a data object.", "type": "object", "properties": { "min": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Smallest physical value the object may take.", "title": "Min" }, "max": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "Largest physical value the object may take; at least ``min``.", "title": "Max" } }, "additionalProperties": false, "required": [ "min", "max" ] }
- Fields:
max (int | float)min (int | float)
- field min: Number [Required]
Smallest physical value the object may take.
- Constraints:
func = <function within_64_bits at 0x7ff820e26200>
json_schema_input_type = PydanticUndefined
- field max: Number [Required]
Largest physical value the object may take; at least
min.- Constraints:
func = <function within_64_bits at 0x7ff820e26200>
json_schema_input_type = PydanticUndefined
- pydantic model A2lObjectOptions[source]
What a declaration asks of the a2l backend. Only that backend interprets it.
Nothing here changes the generated c or the meaning of the object; a project that generates no a2l can leave the whole block out.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.objects.A2lObjectOptions" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>A2lObjectOptions</b></td></tr><tr><td>export</td><td port="export">bool | None</td></tr><tr><td>format</td><td port="format">Optional[str]</td></tr><tr><td>display_identifier</td><td port="display_identifier">Optional[str]</td></tr></table>>,
tooltip="ddd.models.objects.A2lObjectOptions

What a declaration asks of the a2l backend. Only that backend interprets it.
&#\
xA;Nothing here changes the generated c or the meaning of the object; a project that
generates no a2l can leave the whole block \
out.
"];
}](_images/graphviz-2a505a34ef96867f0cf5ca9fb448d1e27245a066.png)
Show JSON schema
{ "title": "A2lObjectOptions", "description": "What a declaration asks of the a2l backend. Only that backend interprets it.\n\nNothing here changes the generated c or the meaning of the object; a project that\ngenerates no a2l can leave the whole block out.", "type": "object", "properties": { "export": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "Whether the object belongs in the a2l file; omitted, it does.\n\nThe one a2l option any component may state, not only the producer. Which signals a\ncalibration engineer needs to see is not a property of whoever happens to write the\nvariable: a component reading a value from a library it does not own has as good a claim\nto measuring it.\n\nStated by several, the answer is yes if any of them says so, and an object nobody\nmentions is exported: see \"Who asks for an export\" on the definition page.", "title": "Export" }, "format": { "anyOf": [ { "pattern": "^%[0-9]*\\.[0-9]+$", "type": "string" }, { "type": "null" } ], "default": null, "description": "a2l ``FORMAT`` string, e.g. ``\"%8.3\"``: total width, then decimal places.\n\nRefused beside a ``string`` conversion, which has no decimals to display.", "title": "Format" }, "display_identifier": { "anyOf": [ { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "type": "string" }, { "type": "null" } ], "default": null, "description": "Alternative name shown by the calibration tool.", "title": "Display Identifier" } }, "additionalProperties": false }
- Fields:
display_identifier (str | None)export (bool | None)format (str | None)
- field export: bool | None = None
Whether the object belongs in the a2l file; omitted, it does.
The one a2l option any component may state, not only the producer. Which signals a calibration engineer needs to see is not a property of whoever happens to write the variable: a component reading a value from a library it does not own has as good a claim to measuring it.
Stated by several, the answer is yes if any of them says so, and an object nobody mentions is exported: see “Who asks for an export” on the definition page.
Whether the object belongs in the a2l file; omitted, it does.
The one a2l option any component may state, not only the producer. Which signals a calibration engineer needs to see is not a property of whoever happens to write the variable: a component reading a value from a library it does not own has as good a claim to measuring it.
Stated by several, the answer is yes if any of them says so, and an object nobody mentions is exported: see “Who asks for an export” on the definition page.
- field format: A2lFormat | None = None
a2l
FORMATstring, e.g."%8.3": total width, then decimal places.Refused beside a
stringconversion, which has no decimals to display.
- field display_identifier: Identifier | None = None
Alternative name shown by the calibration tool.
Conversions
The conversion of a data object is a second tagged union, also discriminated on
kind - but here kind may be left out when the shape of the block makes it
unambiguous: a block carrying enumerators or a name is an enum, one carrying
factor or offset is linear, and an empty one is the identity. A string is the one
kind that is never inferred: it has no key of its own, so {"kind": "string"} says it.
The published schema says so too: the conversion is the one union it publishes as anyOf,
since an empty block would otherwise match two variants at once.
- pydantic model IdentityConversion[source]
physical == raw; stated like any other conversion,{}its shortest spelling.Not a default: a definition naming storage by
datatypestates this one where raw and physical are the same number, so that the claim is written down rather than left to silence.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.IdentityConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>IdentityConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['identity']</td></tr></table>>,
tooltip="ddd.models.conversion.IdentityConversion

``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.&#\
xA;
Not a default: a definition naming storage by ``datatype`` states this one where raw and
physical are the same number, \
so that the claim is written down rather than left to
silence.
"];
}](_images/graphviz-0e7cb2b194968aa11b1e6628a5089af13f0d6e49.png)
Show JSON schema
{ "title": "IdentityConversion", "description": "``physical == raw``; stated like any other conversion, ``{}`` its shortest spelling.\n\nNot a default: a definition naming storage by ``datatype`` states this one where raw and\nphysical are the same number, so that the claim is written down rather than left to\nsilence.", "type": "object", "properties": { "kind": { "const": "identity", "default": "identity", "description": "The tag of this kind, which may be left out: an empty block is the identity.", "title": "Kind", "type": "string" } }, "additionalProperties": false }
- Fields:
kind (Literal['identity'])
- field kind: Literal['identity'] = 'identity'
The tag of this kind, which may be left out: an empty block is the identity.
- pydantic model LinearConversion[source]
physical = raw * factor + offset, the scaling of a fixed point value.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.LinearConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>LinearConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['linear']</td></tr><tr><td>factor</td><td port="factor">float</td></tr><tr><td>offset</td><td port="offset">float</td></tr></table>>,
tooltip="ddd.models.conversion.LinearConversion

``physical = raw * factor + offset``, the scaling of a fixed point value.
"];
}](_images/graphviz-493c55bd52633200d9b43d8860ac202593d1043b.png)
Show JSON schema
{ "title": "LinearConversion", "description": "``physical = raw * factor + offset``, the scaling of a fixed point value.", "type": "object", "properties": { "kind": { "const": "linear", "default": "linear", "description": "The tag of this kind, which may be left out: a block stating ``factor`` or ``offset``\nis linear.", "title": "Kind", "type": "string" }, "factor": { "default": 1.0, "description": "Scaling; must not be zero, or nothing could be converted back.", "title": "Factor", "type": "number" }, "offset": { "default": 0.0, "description": "What raw zero stands for, in the physical unit.", "title": "Offset", "type": "number" } }, "additionalProperties": false }
- Fields:
factor (float)kind (Literal['linear'])offset (float)
- field kind: Literal['linear'] = 'linear'
The tag of this kind, which may be left out: a block stating
factororoffsetis linear.The tag of this kind, which may be left out: a block stating
factororoffsetis linear.
- field factor: Real = 1.0
Scaling; must not be zero, or nothing could be converted back.
- Constraints:
allow_inf_nan = False
- field offset: Real = 0.0
What raw zero stands for, in the physical unit.
- Constraints:
allow_inf_nan = False
- pydantic model EnumConversion[source]
A verbal conversion table; the raw value is the physical value.
Accepts both the explicit form:
{"kind": "enum", "name": "StateA", "enumerators": [{"name": "STATE_OFF", "value": 0}]}
and the mapping shorthand:
{"kind": "enum", "name": "StateA", "enumerators": {"STATE_OFF": 0}}
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.EnumConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>EnumConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['enum']</td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>enumerators</td><td port="enumerators">tuple[Enumerator, ...]</td></tr></table>>,
tooltip="ddd.models.conversion.EnumConversion

A verbal conversion table; the raw value *is* the physical value.

Accepts \
both the explicit form::

 {\"kind\": \"enum\", \"name\": \"StateA\",
 \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": \
0}]}

and the mapping shorthand::

 {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}
"];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
"ddd.models.conversion.EnumConversion":enumerators:e -> "ddd.models.conversion.Enumerator":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-ca28d717a1477b588f8dbc333895db6f86bb208d.png)
Show JSON schema
{ "title": "EnumConversion", "description": "A verbal conversion table; the raw value *is* the physical value.\n\nAccepts both the explicit form::\n\n {\"kind\": \"enum\", \"name\": \"StateA\",\n \"enumerators\": [{\"name\": \"STATE_OFF\", \"value\": 0}]}\n\nand the mapping shorthand::\n\n {\"kind\": \"enum\", \"name\": \"StateA\", \"enumerators\": {\"STATE_OFF\": 0}}", "type": "object", "properties": { "kind": { "const": "enum", "default": "enum", "description": "The tag of this kind, which may be left out: a block stating ``enumerators`` or a\n``name`` is an enum.", "title": "Kind", "type": "string" }, "name": { "description": "C identifier of the generated ``typedef enum``; shared enums must agree everywhere.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "enumerators": { "anyOf": [ { "items": { "$ref": "#/$defs/Enumerator" }, "minItems": 1, "type": "array" }, { "additionalProperties": { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, "description": "The enumerators as a ``{\"NAME\": value}`` mapping.", "minProperties": 1, "propertyNames": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "type": "object" } ], "description": "The named values, either as objects or as a ``{\"NAME\": value}`` mapping.\n\nTwo of them may not carry the same name, which the mapping form cannot express twice and\nthe list form can: the generated enumeration would not compile, and a calibration tool\nreading the generated table of labels would have two answers for one. Two names sharing a\n*value* is a different matter - it is the C idiom for an alias, reported as\n``enum-duplicate-value`` rather than refused.", "title": "Enumerators" } }, "$defs": { "Enumerator": { "additionalProperties": false, "description": "One named value of an enum conversion, and what that value means.", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "Enumerator", "type": "object" } }, "additionalProperties": false, "required": [ "name", "enumerators" ] }
- Fields:
enumerators (tuple[ddd.models.conversion.Enumerator, ...])kind (Literal['enum'])name (str)
- field kind: Literal['enum'] = 'enum'
The tag of this kind, which may be left out: a block stating
enumeratorsor anameis an enum.The tag of this kind, which may be left out: a block stating
enumeratorsor anameis an enum.
- field name: Identifier [Required]
C identifier of the generated
typedef enum; shared enums must agree everywhere.
- field enumerators: Annotated[tuple[Enumerator, ...], Field(min_length=1, json_schema_extra=_publish_mapping_form)] [Required]
The named values, either as objects or as a
{"NAME": value}mapping.Two of them may not carry the same name, which the mapping form cannot express twice and the list form can: the generated enumeration would not compile, and a calibration tool reading the generated table of labels would have two answers for one. Two names sharing a value is a different matter - it is the C idiom for an alias, reported as
enum-duplicate-valuerather than refused.The named values, either as objects or as a
{"NAME": value}mapping.Two of them may not carry the same name, which the mapping form cannot express twice and the list form can: the generated enumeration would not compile, and a calibration tool reading the generated table of labels would have two answers for one. Two names sharing a value is a different matter - it is the C idiom for an alias, reported as
enum-duplicate-valuerather than refused.
- pydantic model Enumerator[source]
One named value of an enum conversion, and what that value means.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.Enumerator" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Enumerator</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.conversion.Enumerator

One named value of an enum conversion, and what that value means.
"];
}](_images/graphviz-c25d7aa10c4afcd5d7e97c01d60b6f11beadbc22.png)
Show JSON schema
{ "title": "Enumerator", "description": "One named value of an enum conversion, and what that value means.", "type": "object", "properties": { "name": { "description": "C identifier of the enumerator; enumerators of all enums share one c namespace.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "description": "The raw value; two enumerators of one enum sharing one is reported as a warning.\n\n``enum-duplicate-value``, a warning rather than a refusal, because it is legal c and\noccasionally meant as an alias - but the a2l table then offers a calibration tool two\nnames for one reading.\n\nBounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no\nstorage could ever represent is refused here rather than overflowing a comparison once\nit is checked against the c ``int`` every enumerator has to fit, or against the\ndatatype carrying it.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": -9223372036854775808, "title": "Value", "type": "integer" }, "description": { "default": "", "description": "What the value means; documentation, not interface.", "title": "Description", "type": "string" } }, "additionalProperties": false, "required": [ "name", "value" ] }
- Fields:
description (str)name (str)value (int)
- field name: Identifier [Required]
C identifier of the enumerator; enumerators of all enums share one c namespace.
- field value: Annotated[int, Field(strict=True, ge=ENUMERATOR_VALUE_MIN, le=ENUMERATOR_VALUE_MAX)] [Required]
The raw value; two enumerators of one enum sharing one is reported as a warning.
enum-duplicate-value, a warning rather than a refusal, because it is legal c and occasionally meant as an alias - but the a2l table then offers a calibration tool two names for one reading.Bounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no storage could ever represent is refused here rather than overflowing a comparison once it is checked against the c
intevery enumerator has to fit, or against the datatype carrying it.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.The raw value; two enumerators of one enum sharing one is reported as a warning.
enum-duplicate-value, a warning rather than a refusal, because it is legal c and occasionally meant as an alias - but the a2l table then offers a calibration tool two names for one reading.Bounded to what 64 bits can hold - no datatype DDD offers stores more - so a value no storage could ever represent is refused here rather than overflowing a comparison once it is checked against the c
intevery enumerator has to fit, or against the datatype carrying it.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.
- field description: str = ''
What the value means; documentation, not interface.
- pydantic model StringConversion[source]
Bytes read as text: each element of the array holds one character code.
Stated on a
uint8orsint8array of one dimension; the rules sit beside the datatype because the same pair is written in three places.kindis required here, unlike on the other three kinds: a string has no key of its own to be inferred from, and{}is the identity.The two mappings are the identity on one byte, so that the derived limits of a string are the raw range of its datatype - which is what the a2l record states - and nothing that ranges a conversion has to know that a string exists. A byte has no reading of its own, so no reading is produced for it, as for the identity.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.conversion.StringConversion" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>StringConversion</b></td></tr><tr><td>kind</td><td port="kind">Literal['string']</td></tr></table>>,
tooltip="ddd.models.conversion.StringConversion

Bytes read as text: each element of the array holds one character code.

\
Stated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the
datatype because the same pair is written \
in three places. ``kind`` is required here,
unlike on the other three kinds: a string has no key of its own to be inferred from,&#\
xA;and ``{}`` is the identity.

The two mappings are the identity on one byte, so that the derived limits of a string
\
are the raw range of its datatype - which is what the a2l record states - and nothing
that ranges a conversion has to know that \
a string exists. A byte has no reading of its
own, so no reading is produced for it, as for the identity.
"];
}](_images/graphviz-492a1e515a1631c53339a9c8cb68ab0a294da2b4.png)
Show JSON schema
{ "title": "StringConversion", "description": "Bytes read as text: each element of the array holds one character code.\n\nStated on a ``uint8`` or ``sint8`` array of one dimension; the rules sit beside the\ndatatype because the same pair is written in three places. ``kind`` is required here,\nunlike on the other three kinds: a string has no key of its own to be inferred from,\nand ``{}`` is the identity.\n\nThe two mappings are the identity on one byte, so that the derived limits of a string\nare the raw range of its datatype - which is what the a2l record states - and nothing\nthat ranges a conversion has to know that a string exists. A byte has no reading of its\nown, so no reading is produced for it, as for the identity.", "type": "object", "properties": { "kind": { "const": "string", "description": "The tag of this kind, which is required: a string has no key of its own to be\nrecognised by, so nothing else would tell it from the identity.", "title": "Kind", "type": "string" } }, "additionalProperties": false, "required": [ "kind" ] }
- Fields:
kind (Literal['string'])
- field kind: Literal['string'] [Required]
The tag of this kind, which is required: a string has no key of its own to be recognised by, so nothing else would tell it from the identity.
The tag of this kind, which is required: a string has no key of its own to be recognised by, so nothing else would tell it from the identity.
Unit vocabulary
The units file. Declaring the vocabulary is opt-in, and a project with a units file - even one declaring nothing - has every stated unit checked against what its units files declare.
- pydantic model UnitsFile[source]
Root object of a
*.ddd.jsonunit vocabulary description.unitsis the top level key that makes this a units file rather than a project, a component or a types file; DDD decides what a file is from that key alone. The file is listed in theincludesof a project like any other description.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.units.UnitDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>UnitDeclaration</b></td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.units.UnitDeclaration

One unit of the vocabulary, with what it stands for.
"];
"ddd.models.units.UnitsFile" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>UnitsFile</b></td></tr><tr><td>schema_reference</td><td port="schema_reference">str | None</td></tr><tr><td>units</td><td port="units">tuple[UnitDeclaration, ...]</td></tr></table>>,
tooltip="ddd.models.units.UnitsFile

Root object of a ``*.ddd.json`` unit vocabulary description.

``units`` is the top level \
key that makes this a units file rather than a project, a
component or a types file; DDD decides what a file is from that key \
alone. The file is
listed in the ``includes`` of a project like any other description.
"];
"ddd.models.units.UnitsFile":units:e -> "ddd.models.units.UnitDeclaration":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-d7ee4c11866093868dbca0a930cdf1724a48c147.png)
Show JSON schema
{ "title": "DDD unit vocabulary", "description": "Root object of a ``*.ddd.json`` unit vocabulary description.\n\n``units`` is the top level key that makes this a units file rather than a project, a\ncomponent or a types file; DDD decides what a file is from that key alone. The file is\nlisted in the ``includes`` of a project like any other description.", "type": "object", "properties": { "$schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Editor binding to a schema written by ``ddd schema -o``; not interpreted by DDD.", "title": "$Schema" }, "units": { "description": "The units this project spells, in any order, and possibly none.\n\nA file listing none loads, and is reported as ``empty-vocabulary``. Like any units file it\nopts the project into the unit check: every stated unit is checked, against a vocabulary this\nfile adds nothing to.", "items": { "anyOf": [ { "description": "A spelling on its own, for a unit that needs no description.", "minLength": 1, "type": "string" }, { "$ref": "#/$defs/UnitDeclaration" } ] }, "title": "Units", "type": "array" } }, "$defs": { "UnitDeclaration": { "additionalProperties": false, "description": "One unit of the vocabulary, with what it stands for.", "properties": { "unit": { "description": "The spelling, exactly as every description file writes it: ``Nm``, ``rpm``, ``degC``.\n\nCase counts - ``mV`` and ``MV`` are different units - and the empty string is not an\nentry, because a dimensionless value states no unit at all.", "minLength": 1, "title": "Unit", "type": "string" }, "description": { "default": "", "description": "What the unit stands for, e.g. ``torque, newton metre``.\n\nThis is where the vocabulary of a project is written down once, instead of being implied\nby every object that happens to use it.", "title": "Description", "type": "string" } }, "required": [ "unit" ], "title": "UnitDeclaration", "type": "object" } }, "additionalProperties": false, "required": [ "units" ] }
- Fields:
units (tuple[ddd.models.units.UnitDeclaration, ...])
- field units: Annotated[tuple[Unit, ...], Field(json_schema_extra=_publish_bare_spellings)] [Required]
The units this project spells, in any order, and possibly none.
A file listing none loads, and is reported as
empty-vocabulary. Like any units file it opts the project into the unit check: every stated unit is checked, against a vocabulary this file adds nothing to.The units this project spells, in any order, and possibly none.
A file listing none loads, and is reported as
empty-vocabulary. Like any units file it opts the project into the unit check: every stated unit is checked, against a vocabulary this file adds nothing to.
- pydantic model UnitDeclaration[source]
One unit of the vocabulary, with what it stands for.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.units.UnitDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>UnitDeclaration</b></td></tr><tr><td>unit</td><td port="unit">str</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.units.UnitDeclaration

One unit of the vocabulary, with what it stands for.
"];
}](_images/graphviz-381964254088be8e6732125ded52b500668e4bc5.png)
Show JSON schema
{ "title": "UnitDeclaration", "description": "One unit of the vocabulary, with what it stands for.", "type": "object", "properties": { "unit": { "description": "The spelling, exactly as every description file writes it: ``Nm``, ``rpm``, ``degC``.\n\nCase counts - ``mV`` and ``MV`` are different units - and the empty string is not an\nentry, because a dimensionless value states no unit at all.", "minLength": 1, "title": "Unit", "type": "string" }, "description": { "default": "", "description": "What the unit stands for, e.g. ``torque, newton metre``.\n\nThis is where the vocabulary of a project is written down once, instead of being implied\nby every object that happens to use it.", "title": "Description", "type": "string" } }, "additionalProperties": false, "required": [ "unit" ] }
- Fields:
description (str)unit (str)
- field unit: Annotated[str, StringConstraints(min_length=1)] [Required]
The spelling, exactly as every description file writes it:
Nm,rpm,degC.Case counts -
mVandMVare different units - and the empty string is not an entry, because a dimensionless value states no unit at all.The spelling, exactly as every description file writes it:
Nm,rpm,degC.Case counts -
mVandMVare different units - and the empty string is not an entry, because a dimensionless value states no unit at all.- Constraints:
min_length = 1
- field description: str = ''
What the unit stands for, e.g.
torque, newton metre.This is where the vocabulary of a project is written down once, instead of being implied by every object that happens to use it.
What the unit stands for, e.g.
torque, newton metre.This is where the vocabulary of a project is written down once, instead of being implied by every object that happens to use it.
Memory sections
The sections file. What a section declares is what the checks need to weigh a placement: who may write it, and how strictly it aligns.
- pydantic model SectionsFile[source]
Root object of a
*.ddd.jsonmemory section description.sectionsis the top level key that makes this a sections file; DDD decides what a file is from that key alone. The file is listed in theincludesof a project like any other description.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.sections.SectionDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>SectionDeclaration</b></td></tr><tr><td>section</td><td port="section">str</td></tr><tr><td>access</td><td port="access">SectionAccess</td></tr><tr><td>alignment</td><td port="alignment">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.sections.SectionDeclaration

One linker section, with the properties the checks need.
"];
"ddd.models.sections.SectionsFile" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>SectionsFile</b></td></tr><tr><td>schema_reference</td><td port="schema_reference">str | None</td></tr><tr><td>sections</td><td port="sections">tuple[SectionDeclaration, ...]</td></tr></table>>,
tooltip="ddd.models.sections.SectionsFile

Root object of a ``*.ddd.json`` memory section description.

``sections`` is the \
top level key that makes this a sections file; DDD decides what a
file is from that key alone. The file is listed in the ``\
includes`` of a project like
any other description.
"];
"ddd.models.sections.SectionsFile":sections:e -> "ddd.models.sections.SectionDeclaration":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-98204aa948c5d120b49095a6a8909cddc8be8cdb.png)
Show JSON schema
{ "title": "DDD memory sections", "description": "Root object of a ``*.ddd.json`` memory section description.\n\n``sections`` is the top level key that makes this a sections file; DDD decides what a\nfile is from that key alone. The file is listed in the ``includes`` of a project like\nany other description.", "type": "object", "properties": { "$schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Editor binding to a schema written by ``ddd schema -o``; not interpreted by DDD.", "title": "$Schema" }, "sections": { "description": "The sections this project places data in, and possibly none.\n\nA file declaring none loads, and is reported as ``empty-vocabulary``.", "items": { "$ref": "#/$defs/SectionDeclaration" }, "title": "Sections", "type": "array" } }, "$defs": { "SectionAccess": { "description": "What the running software may do with a section, which is all DDD can check.", "enum": [ "read-write", "read-only" ], "title": "SectionAccess", "type": "string" }, "SectionDeclaration": { "additionalProperties": false, "description": "One linker section, with the properties the checks need.", "properties": { "section": { "description": "The name as the linker script spells it: ``.calib``, ``.nvm``.\n\nA linker name rather than a C identifier, so a leading dot is a normal spelling: letters,\ndigits, ``.``, ``_`` and ``$``, and nothing that could end the string literal the generated\nc writes it into.", "minLength": 1, "pattern": "^[A-Za-z0-9_.$]+$", "title": "Section", "type": "string" }, "access": { "$ref": "#/$defs/SectionAccess", "description": "``read-write`` or ``read-only``, from the running software's point of view." }, "alignment": { "description": "The alignment the section guarantees, in bytes; a power of two.\n\nWhat it is checked against: an object whose datatype needs stricter alignment than the\nsection guarantees would be padded or faulting, and either is worth a finding. Bounded\nto what 64 bits can hold: an alignment no address on a real target could satisfy is\nrefused here rather than accepted as a power of two nothing could ever place.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": 1, "title": "Alignment", "type": "integer" }, "description": { "default": "", "description": "Free text saying what the section is for, e.g. ``calibration flash behind the\nemulation overlay``.", "title": "Description", "type": "string" } }, "required": [ "section", "access", "alignment" ], "title": "SectionDeclaration", "type": "object" } }, "additionalProperties": false, "required": [ "sections" ] }
- Fields:
sections (tuple[ddd.models.sections.SectionDeclaration, ...])
- field sections: tuple[SectionDeclaration, ...] [Required]
The sections this project places data in, and possibly none.
A file declaring none loads, and is reported as
empty-vocabulary.
- pydantic model SectionDeclaration[source]
One linker section, with the properties the checks need.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.sections.SectionDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>SectionDeclaration</b></td></tr><tr><td>section</td><td port="section">str</td></tr><tr><td>access</td><td port="access">SectionAccess</td></tr><tr><td>alignment</td><td port="alignment">int</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.sections.SectionDeclaration

One linker section, with the properties the checks need.
"];
}](_images/graphviz-4e8d04593601c7b8f28e2d74022d14b467a4253d.png)
Show JSON schema
{ "title": "SectionDeclaration", "description": "One linker section, with the properties the checks need.", "type": "object", "properties": { "section": { "description": "The name as the linker script spells it: ``.calib``, ``.nvm``.\n\nA linker name rather than a C identifier, so a leading dot is a normal spelling: letters,\ndigits, ``.``, ``_`` and ``$``, and nothing that could end the string literal the generated\nc writes it into.", "minLength": 1, "pattern": "^[A-Za-z0-9_.$]+$", "title": "Section", "type": "string" }, "access": { "$ref": "#/$defs/SectionAccess", "description": "``read-write`` or ``read-only``, from the running software's point of view." }, "alignment": { "description": "The alignment the section guarantees, in bytes; a power of two.\n\nWhat it is checked against: an object whose datatype needs stricter alignment than the\nsection guarantees would be padded or faulting, and either is worth a finding. Bounded\nto what 64 bits can hold: an alignment no address on a real target could satisfy is\nrefused here rather than accepted as a power of two nothing could ever place.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 18446744073709551615, "minimum": 1, "title": "Alignment", "type": "integer" }, "description": { "default": "", "description": "Free text saying what the section is for, e.g. ``calibration flash behind the\nemulation overlay``.", "title": "Description", "type": "string" } }, "$defs": { "SectionAccess": { "description": "What the running software may do with a section, which is all DDD can check.", "enum": [ "read-write", "read-only" ], "title": "SectionAccess", "type": "string" } }, "additionalProperties": false, "required": [ "section", "access", "alignment" ] }
- Fields:
access (ddd.models.sections.SectionAccess)alignment (int)description (str)section (str)
- field section: Annotated[str, StringConstraints(min_length=1, pattern=SECTION_NAME_PATTERN)] [Required]
The name as the linker script spells it:
.calib,.nvm.A linker name rather than a C identifier, so a leading dot is a normal spelling: letters, digits,
.,_and$, and nothing that could end the string literal the generated c writes it into.The name as the linker script spells it:
.calib,.nvm.A linker name rather than a C identifier, so a leading dot is a normal spelling: letters, digits,
.,_and$, and nothing that could end the string literal the generated c writes it into.
- field access: SectionAccess [Required]
read-writeorread-only, from the running software’s point of view.
- field alignment: int [Required]
The alignment the section guarantees, in bytes; a power of two.
What it is checked against: an object whose datatype needs stricter alignment than the section guarantees would be padded or faulting, and either is worth a finding. Bounded to what 64 bits can hold: an alignment no address on a real target could satisfy is refused here rather than accepted as a power of two nothing could ever place.
A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.The alignment the section guarantees, in bytes; a power of two.
What it is checked against: an object whose datatype needs stricter alignment than the section guarantees would be padded or faulting, and either is worth a finding. Bounded to what 64 bits can hold: an alignment no address on a real target could satisfy is refused here rather than accepted as a power of two nothing could ever place.
A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.
- field description: str = ''
Free text saying what the section is for, e.g.
calibration flash behind the emulation overlay.Free text saying what the section is for, e.g.
calibration flash behind the emulation overlay.
Constant vocabulary
The constants file. A shape names one of these where it would state a number, so the size lives in one place.
- pydantic model ConstantsFile[source]
Root object of a
*.ddd.jsonconstant vocabulary description.constantsis the top level key that makes this a constants file rather than a project, a component or a types file; DDD decides what a file is from that key alone. The file is listed in theincludesof a project like any other description.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.constants.ConstantDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ConstantDeclaration</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">Union[int, float]</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.constants.ConstantDeclaration

One named number, declared once and named wherever the project needs it.
"];
"ddd.models.constants.ConstantsFile" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ConstantsFile</b></td></tr><tr><td>schema_reference</td><td port="schema_reference">str | None</td></tr><tr><td>constants</td><td port="constants">tuple[ConstantDeclaration, ...]</td></tr></table>>,
tooltip="ddd.models.constants.ConstantsFile

Root object of a ``*.ddd.json`` constant vocabulary description.

``constants`` \
is the top level key that makes this a constants file rather than a
project, a component or a types file; DDD decides what a \
file is from that key alone.
The file is listed in the ``includes`` of a project like any other description.
"];
"ddd.models.constants.ConstantsFile":constants:e -> "ddd.models.constants.ConstantDeclaration":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-c26890fd78ee7239cadaf2f4969a89cb63e461a2.png)
Show JSON schema
{ "title": "DDD constant vocabulary", "description": "Root object of a ``*.ddd.json`` constant vocabulary description.\n\n``constants`` is the top level key that makes this a constants file rather than a\nproject, a component or a types file; DDD decides what a file is from that key alone.\nThe file is listed in the ``includes`` of a project like any other description.", "type": "object", "properties": { "$schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Editor binding to a schema written by ``ddd schema -o``; not interpreted by DDD.", "title": "$Schema" }, "constants": { "description": "The constants this project names, in any order, and possibly none.\n\nA file declaring none loads, and is reported as ``empty-vocabulary``.", "items": { "$ref": "#/$defs/ConstantDeclaration" }, "title": "Constants", "type": "array" } }, "$defs": { "ConstantDeclaration": { "additionalProperties": false, "description": "One named number, declared once and named wherever the project needs it.", "properties": { "name": { "description": "The name a shape writes where it would state a number: ``PRESSURE_CELLS``.\n\nAn identifier, because the name reaches the generated code as an identifier of its own;\nthe templates receive every declared constant to emit.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "The value, a number: a whole number of either sign, or one written with a point.\n\nA literal only: an expression would put a parser and an evaluation order into a\ndescription format, and a constant cannot name another constant, so what cannot be\nwritten cannot cycle. How it is written settles what it is - ``2`` is a whole number,\nand anything carrying a point or an exponent is fractional, so ``2.0`` and ``1e3`` both\nare - because that is what the author is picking: the type, not the format. The\noutputs carry the number in its shortest spelling that reads back as the same number, a\nwhole number without a point and any other with a point or an exponent, so ``2.50``\nreaches the generated code as ``2.5`` and ``1e3`` as ``1000.0``.\nA whole number is bounded by what a 64 bit target can express, signed or unsigned, and\na fractional one must be finite: ``inf`` and ``nan`` name nothing a description can\nstate, and would reach a template as those words.\n\nNothing here requires the value to be a size. A constant that a shape names has to be\na whole number of at least 1, the same rule a dimension written as a literal obeys, but\nthat is checked where the shape names it - the declaration is not the place, because a\nconstant may be declared to be emitted and never dimension anything.", "title": "Value" }, "description": { "default": "", "description": "What the constant stands for, e.g. ``cells of the pressure manifold``.\n\nThis is where the meaning of a number is written down once, instead of being implied by\nevery object that happens to use it.", "title": "Description", "type": "string" } }, "required": [ "name", "value" ], "title": "ConstantDeclaration", "type": "object" } }, "additionalProperties": false, "required": [ "constants" ] }
- Fields:
constants (tuple[ddd.models.constants.ConstantDeclaration, ...])
- field constants: tuple[ConstantDeclaration, ...] [Required]
The constants this project names, in any order, and possibly none.
A file declaring none loads, and is reported as
empty-vocabulary.
- pydantic model ConstantDeclaration[source]
One named number, declared once and named wherever the project needs it.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.constants.ConstantDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>ConstantDeclaration</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>value</td><td port="value">Union[int, float]</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.constants.ConstantDeclaration

One named number, declared once and named wherever the project needs it.
"];
}](_images/graphviz-582139acbf5ecf78d097823fb425f5cb1c433800.png)
Show JSON schema
{ "title": "ConstantDeclaration", "description": "One named number, declared once and named wherever the project needs it.", "type": "object", "properties": { "name": { "description": "The name a shape writes where it would state a number: ``PRESSURE_CELLS``.\n\nAn identifier, because the name reaches the generated code as an identifier of its own;\nthe templates receive every declared constant to emit.", "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "title": "Name", "type": "string" }, "value": { "anyOf": [ { "maximum": 18446744073709551615, "minimum": -9223372036854775808, "type": "integer" }, { "type": "number" } ], "description": "The value, a number: a whole number of either sign, or one written with a point.\n\nA literal only: an expression would put a parser and an evaluation order into a\ndescription format, and a constant cannot name another constant, so what cannot be\nwritten cannot cycle. How it is written settles what it is - ``2`` is a whole number,\nand anything carrying a point or an exponent is fractional, so ``2.0`` and ``1e3`` both\nare - because that is what the author is picking: the type, not the format. The\noutputs carry the number in its shortest spelling that reads back as the same number, a\nwhole number without a point and any other with a point or an exponent, so ``2.50``\nreaches the generated code as ``2.5`` and ``1e3`` as ``1000.0``.\nA whole number is bounded by what a 64 bit target can express, signed or unsigned, and\na fractional one must be finite: ``inf`` and ``nan`` name nothing a description can\nstate, and would reach a template as those words.\n\nNothing here requires the value to be a size. A constant that a shape names has to be\na whole number of at least 1, the same rule a dimension written as a literal obeys, but\nthat is checked where the shape names it - the declaration is not the place, because a\nconstant may be declared to be emitted and never dimension anything.", "title": "Value" }, "description": { "default": "", "description": "What the constant stands for, e.g. ``cells of the pressure manifold``.\n\nThis is where the meaning of a number is written down once, instead of being implied by\nevery object that happens to use it.", "title": "Description", "type": "string" } }, "additionalProperties": false, "required": [ "name", "value" ] }
- Fields:
description (str)name (str)value (int | float)
- field name: Identifier [Required]
The name a shape writes where it would state a number:
PRESSURE_CELLS.An identifier, because the name reaches the generated code as an identifier of its own; the templates receive every declared constant to emit.
The name a shape writes where it would state a number:
PRESSURE_CELLS.An identifier, because the name reaches the generated code as an identifier of its own; the templates receive every declared constant to emit.
- field value: ConstantValue [Required]
The value, a number: a whole number of either sign, or one written with a point.
A literal only: an expression would put a parser and an evaluation order into a description format, and a constant cannot name another constant, so what cannot be written cannot cycle. How it is written settles what it is -
2is a whole number, and anything carrying a point or an exponent is fractional, so2.0and1e3both are - because that is what the author is picking: the type, not the format. The outputs carry the number in its shortest spelling that reads back as the same number, a whole number without a point and any other with a point or an exponent, so2.50reaches the generated code as2.5and1e3as1000.0. A whole number is bounded by what a 64 bit target can express, signed or unsigned, and a fractional one must be finite:infandnanname nothing a description can state, and would reach a template as those words.Nothing here requires the value to be a size. A constant that a shape names has to be a whole number of at least 1, the same rule a dimension written as a literal obeys, but that is checked where the shape names it - the declaration is not the place, because a constant may be declared to be emitted and never dimension anything.
The value, a number: a whole number of either sign, or one written with a point.
A literal only: an expression would put a parser and an evaluation order into a description format, and a constant cannot name another constant, so what cannot be written cannot cycle. How it is written settles what it is -
2is a whole number, and anything carrying a point or an exponent is fractional, so2.0and1e3both are - because that is what the author is picking: the type, not the format. The outputs carry the number in its shortest spelling that reads back as the same number, a whole number without a point and any other with a point or an exponent, so2.50reaches the generated code as2.5and1e3as1000.0. A whole number is bounded by what a 64 bit target can express, signed or unsigned, and a fractional one must be finite:infandnanname nothing a description can state, and would reach a template as those words.Nothing here requires the value to be a size. A constant that a shape names has to be a whole number of at least 1, the same rule a dimension written as a literal obeys, but that is checked where the shape names it - the declaration is not the place, because a constant may be declared to be emitted and never dimension anything.
- field description: str = ''
What the constant stands for, e.g.
cells of the pressure manifold.This is where the meaning of a number is written down once, instead of being implied by every object that happens to use it.
What the constant stands for, e.g.
cells of the pressure manifold.This is where the meaning of a number is written down once, instead of being implied by every object that happens to use it.
Measurement rasters
The rasters file. A raster is a DAQ event the target offers, named so that a definition can refer to it.
- pydantic model RastersFile[source]
Root object of a
*.ddd.jsonmeasurement raster description.rastersis the top level key that makes this a rasters file; DDD decides what a file is from that key alone. The file is listed in theincludesof a project like any other description.![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.rasters.RasterDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>RasterDeclaration</b></td></tr><tr><td>raster</td><td port="raster">str</td></tr><tr><td>event</td><td port="event">int</td></tr><tr><td>cycle</td><td port="cycle">str | None</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.rasters.RasterDeclaration

One DAQ event the target offers, named so that a definition can refer to it.
"];
"ddd.models.rasters.RastersFile" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>RastersFile</b></td></tr><tr><td>schema_reference</td><td port="schema_reference">str | None</td></tr><tr><td>rasters</td><td port="rasters">tuple[RasterDeclaration, ...]</td></tr></table>>,
tooltip="ddd.models.rasters.RastersFile

Root object of a ``*.ddd.json`` measurement raster description.

``rasters`` is \
the top level key that makes this a rasters file; DDD decides what a file
is from that key alone. The file is listed in the ``\
includes`` of a project like any
other description.
"];
"ddd.models.rasters.RastersFile":rasters:e -> "ddd.models.rasters.RasterDeclaration":_root:w [arrowhead=crownone,
arrowtail=nonenone];
}](_images/graphviz-717113510f46df50eb0a4fab4e95fa86a849dc3c.png)
Show JSON schema
{ "title": "DDD measurement rasters", "description": "Root object of a ``*.ddd.json`` measurement raster description.\n\n``rasters`` is the top level key that makes this a rasters file; DDD decides what a file\nis from that key alone. The file is listed in the ``includes`` of a project like any\nother description.", "type": "object", "properties": { "$schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Editor binding to a schema written by ``ddd schema -o``; not interpreted by DDD.", "title": "$Schema" }, "rasters": { "description": "The DAQ events the target offers, and possibly none.\n\nA file declaring none loads, and is reported as ``empty-vocabulary``.", "items": { "$ref": "#/$defs/RasterDeclaration" }, "title": "Rasters", "type": "array" } }, "$defs": { "RasterDeclaration": { "additionalProperties": false, "description": "One DAQ event the target offers, named so that a definition can refer to it.", "properties": { "raster": { "description": "The name a definition refers to, which is also the short name of the XCP event.\n\nThe a2l writes that short name into a field eight bytes wide, so a longer name is\nrefused rather than shortened: two names shortened to the same eight would collide in a\ncalibration tool rather than here, where the author could still do something about it.\nPrintable ASCII and no space, so that eight characters are eight bytes. A definition\nreferring to one is held to the same spelling.", "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "title": "Raster", "type": "string" }, "event": { "description": "The XCP event channel number, distinct across the project.\n\nThe one field of a declaration the generated a2l carries today; the rest wait for the\nmodule level ``DAQ`` block that defines the events themselves.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 65535, "minimum": 0, "title": "Event", "type": "integer" }, "cycle": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "The period, written as an integer and a unit: ``100us``, ``10ms``, ``1s``.\n\nNo space and no fractional part - write ``1500us`` rather than ``1.5ms``. The period is\none XCP can carry, that is a count of 1 to 255 times a decade from ``1ns`` to ``1s``, so\n``1500us`` is a period and ``1234ms`` is not. Left out, the\nevent is not cyclic: crank synchronous, on change, on demand. That is a real kind of\nraster rather than an omission, which is why the key has no derived default.", "title": "Cycle" }, "description": { "default": "", "description": "Free text saying what the event is, e.g. ``the 10 ms control task``.", "title": "Description", "type": "string" } }, "required": [ "raster", "event" ], "title": "RasterDeclaration", "type": "object" } }, "additionalProperties": false, "required": [ "rasters" ] }
- Fields:
rasters (tuple[ddd.models.rasters.RasterDeclaration, ...])
- field rasters: tuple[RasterDeclaration, ...] [Required]
The DAQ events the target offers, and possibly none.
A file declaring none loads, and is reported as
empty-vocabulary.
- pydantic model RasterDeclaration[source]
One DAQ event the target offers, named so that a definition can refer to it.
![digraph "Entity Relationship Diagram created by erdantic" {
graph [fontcolor=gray66,
fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=9,
nodesep=0.5,
rankdir=LR,
ranksep=1.5
];
node [fontname="Times New Roman,Times,Liberation Serif,serif",
fontsize=14,
label="\N",
shape=plain
];
edge [dir=both];
"ddd.models.rasters.RasterDeclaration" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>RasterDeclaration</b></td></tr><tr><td>raster</td><td port="raster">str</td></tr><tr><td>event</td><td port="event">int</td></tr><tr><td>cycle</td><td port="cycle">str | None</td></tr><tr><td>description</td><td port="description">str</td></tr></table>>,
tooltip="ddd.models.rasters.RasterDeclaration

One DAQ event the target offers, named so that a definition can refer to it.
"];
}](_images/graphviz-005d0b6a0616f4e41b5e141f17509f72d5707c8b.png)
Show JSON schema
{ "title": "RasterDeclaration", "description": "One DAQ event the target offers, named so that a definition can refer to it.", "type": "object", "properties": { "raster": { "description": "The name a definition refers to, which is also the short name of the XCP event.\n\nThe a2l writes that short name into a field eight bytes wide, so a longer name is\nrefused rather than shortened: two names shortened to the same eight would collide in a\ncalibration tool rather than here, where the author could still do something about it.\nPrintable ASCII and no space, so that eight characters are eight bytes. A definition\nreferring to one is held to the same spelling.", "maxLength": 8, "minLength": 1, "pattern": "^[\\x21-\\x7e]+$", "title": "Raster", "type": "string" }, "event": { "description": "The XCP event channel number, distinct across the project.\n\nThe one field of a declaration the generated a2l carries today; the rest wait for the\nmodule level ``DAQ`` block that defines the events themselves.\n\nA whole number written without a decimal point: ``4``, not ``4.0``, which the published\nschema accepts and the loader refuses.", "maximum": 65535, "minimum": 0, "title": "Event", "type": "integer" }, "cycle": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "The period, written as an integer and a unit: ``100us``, ``10ms``, ``1s``.\n\nNo space and no fractional part - write ``1500us`` rather than ``1.5ms``. The period is\none XCP can carry, that is a count of 1 to 255 times a decade from ``1ns`` to ``1s``, so\n``1500us`` is a period and ``1234ms`` is not. Left out, the\nevent is not cyclic: crank synchronous, on change, on demand. That is a real kind of\nraster rather than an omission, which is why the key has no derived default.", "title": "Cycle" }, "description": { "default": "", "description": "Free text saying what the event is, e.g. ``the 10 ms control task``.", "title": "Description", "type": "string" } }, "additionalProperties": false, "required": [ "raster", "event" ] }
- Fields:
cycle (str | None)description (str)event (int)raster (str)
- field raster: RasterName [Required]
The name a definition refers to, which is also the short name of the XCP event.
The a2l writes that short name into a field eight bytes wide, so a longer name is refused rather than shortened: two names shortened to the same eight would collide in a calibration tool rather than here, where the author could still do something about it. Printable ASCII and no space, so that eight characters are eight bytes. A definition referring to one is held to the same spelling.
The name a definition refers to, which is also the short name of the XCP event.
The a2l writes that short name into a field eight bytes wide, so a longer name is refused rather than shortened: two names shortened to the same eight would collide in a calibration tool rather than here, where the author could still do something about it. Printable ASCII and no space, so that eight characters are eight bytes. A definition referring to one is held to the same spelling.
- Constraints:
min_length = 1
max_length = 8
pattern = ^[x21-x7e]+$
- field event: int [Required]
The XCP event channel number, distinct across the project.
The one field of a declaration the generated a2l carries today; the rest wait for the module level
DAQblock that defines the events themselves.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.The XCP event channel number, distinct across the project.
The one field of a declaration the generated a2l carries today; the rest wait for the module level
DAQblock that defines the events themselves.A whole number written without a decimal point:
4, not4.0, which the published schema accepts and the loader refuses.- Constraints:
strict = True
ge = 0
le = 65535
- field cycle: str | None = None
The period, written as an integer and a unit:
100us,10ms,1s.No space and no fractional part - write
1500usrather than1.5ms. The period is one XCP can carry, that is a count of 1 to 255 times a decade from1nsto1s, so1500usis a period and1234msis not. Left out, the event is not cyclic: crank synchronous, on change, on demand. That is a real kind of raster rather than an omission, which is why the key has no derived default.The period, written as an integer and a unit:
100us,10ms,1s.No space and no fractional part - write
1500usrather than1.5ms. The period is one XCP can carry, that is a count of 1 to 255 times a decade from1nsto1s, so1500usis a period and1234msis not. Left out, the event is not cyclic: crank synchronous, on change, on demand. That is a real kind of raster rather than an omission, which is why the key has no derived default.
- field description: str = ''
Free text saying what the event is, e.g.
the 10 ms control task.