@anik-2/autosar 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,146 @@
1
+ """Typed value checks and ECUC-JSON value rendering, driven by the param def."""
2
+ from __future__ import annotations
3
+
4
+ import math
5
+ import re
6
+ from typing import Optional
7
+
8
+ from .defs import DefNode
9
+
10
+ C_IDENT = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
11
+ BOOL_TRUE = {"true", "1"}
12
+ BOOL_FALSE = {"false", "0"}
13
+ JS_SAFE = 2 ** 53 - 1
14
+
15
+
16
+ def parse_int(s: str) -> Optional[int]:
17
+ s = s.strip()
18
+ try:
19
+ return int(s, 0)
20
+ except ValueError:
21
+ try:
22
+ return int(s) # leading zeros, e.g. "007"
23
+ except ValueError:
24
+ return None
25
+
26
+
27
+ def parse_float(s: str) -> Optional[float]:
28
+ t = s.strip()
29
+ if t.upper() in ("INF", "+INF"):
30
+ return math.inf
31
+ if t.upper() == "-INF":
32
+ return -math.inf
33
+ try:
34
+ return float(t)
35
+ except ValueError:
36
+ iv = parse_int(t)
37
+ return float(iv) if iv is not None else None
38
+
39
+
40
+ def _bound(s: Optional[str], f):
41
+ if s is None or s == "":
42
+ return None
43
+ return f(s)
44
+
45
+
46
+ def check_value(d: DefNode, raw: Optional[str]) -> list:
47
+ """Return [(rule, message)] problems with ``raw`` against ``d``. Empty list = OK."""
48
+ if raw is None or raw == "":
49
+ return [("ECUC-EMPTY-VALUE", f"{d.name}: empty value")]
50
+ k = d.kind
51
+ out = []
52
+ if k == "INTEGER":
53
+ v = parse_int(raw)
54
+ if v is None:
55
+ return [("ECUC-TYPE", f"{d.name}: '{raw}' is not an integer")]
56
+ lo, hi = _bound(d.min, parse_int), _bound(d.max, parse_int)
57
+ if (lo is not None and v < lo) or (hi is not None and v > hi):
58
+ out.append(("ECUC-RANGE", f"{d.name}={raw} outside [{d.min}..{d.max}]"))
59
+ elif k == "FLOAT":
60
+ v = parse_float(raw)
61
+ if v is None or math.isnan(v):
62
+ return [("ECUC-TYPE", f"{d.name}: '{raw}' is not a float")]
63
+ lo, hi = _bound(d.min, parse_float), _bound(d.max, parse_float)
64
+ bad = (lo is not None and (v < lo or (d.min_open and v == lo))) or \
65
+ (hi is not None and (v > hi or (d.max_open and v == hi)))
66
+ if bad:
67
+ out.append(("ECUC-RANGE", f"{d.name}={raw} outside {'(' if d.min_open else '['}{d.min}..{d.max}{')' if d.max_open else ']'}"))
68
+ elif k == "BOOLEAN":
69
+ if raw.strip().lower() not in BOOL_TRUE | BOOL_FALSE:
70
+ out.append(("ECUC-TYPE", f"{d.name}: '{raw}' is not a boolean (true/false/1/0)"))
71
+ elif k == "ENUMERATION":
72
+ if d.literals and raw.strip() not in d.literals:
73
+ lits = ", ".join(d.literals[:20]) + (" …" if len(d.literals) > 20 else "")
74
+ out.append(("ECUC-ENUM", f"{d.name}: '{raw}' is not a literal of the def ({lits})"))
75
+ elif k in ("STRING", "FUNCTION-NAME", "LINKER-SYMBOL", "MULTILINE-STRING"):
76
+ if d.min_len is not None and len(raw) < d.min_len:
77
+ out.append(("ECUC-STRING", f"{d.name}: length {len(raw)} < min {d.min_len}"))
78
+ if d.max_len is not None and len(raw) > d.max_len:
79
+ out.append(("ECUC-STRING", f"{d.name}: length {len(raw)} > max {d.max_len}"))
80
+ if k in ("FUNCTION-NAME", "LINKER-SYMBOL") and not C_IDENT.match(raw.strip()):
81
+ out.append(("ECUC-STRING", f"{d.name}: '{raw}' is not a valid C identifier"))
82
+ if d.regex:
83
+ try:
84
+ if not re.fullmatch(d.regex, raw):
85
+ out.append(("ECUC-STRING", f"{d.name}: '{raw}' does not match /{d.regex}/"))
86
+ except re.error:
87
+ pass
88
+ return out
89
+
90
+
91
+ def expected_value_tag(d: DefNode) -> Optional[str]:
92
+ k = d.kind or ""
93
+ if k in ("INTEGER", "FLOAT", "BOOLEAN"):
94
+ return "ECUC-NUMERICAL-PARAM-VALUE"
95
+ if k in ("ENUMERATION", "STRING", "FUNCTION-NAME", "LINKER-SYMBOL", "MULTILINE-STRING"):
96
+ return "ECUC-TEXTUAL-PARAM-VALUE"
97
+ if k == "ADD-INFO":
98
+ return "ECUC-ADD-INFO-PARAM-VALUE"
99
+ if k == "INSTANCE-REFERENCE":
100
+ return "ECUC-INSTANCE-REFERENCE-VALUE"
101
+ if k.endswith("REFERENCE"):
102
+ return "ECUC-REFERENCE-VALUE"
103
+ return None
104
+
105
+
106
+ def to_json(d: Optional[DefNode], raw: Optional[str], is_ref: bool, numerical: bool):
107
+ """Raw ARXML text -> compact JSON value (int/float/bool/str, refs as '->/path')."""
108
+ if raw is None:
109
+ return None
110
+ if is_ref:
111
+ return "->" + raw if raw.startswith("/") else raw
112
+ k = d.kind if d is not None else ("NUMBER" if numerical else None)
113
+ t = raw.strip()
114
+ if k == "BOOLEAN" or (k == "NUMBER" and t.lower() in ("true", "false")):
115
+ lo = t.lower()
116
+ return True if lo in BOOL_TRUE else False if lo in BOOL_FALSE else raw
117
+ if k in ("INTEGER", "NUMBER"):
118
+ v = parse_int(t)
119
+ if v is not None:
120
+ return v if abs(v) <= JS_SAFE and t == str(v) else t # keep hex / huge as text
121
+ if k == "INTEGER":
122
+ return raw
123
+ if k in ("FLOAT", "NUMBER"):
124
+ v = parse_float(t)
125
+ if v is not None and math.isfinite(v):
126
+ return v
127
+ return raw
128
+ return raw
129
+
130
+
131
+ def from_json(d: Optional[DefNode], v) -> str:
132
+ """JSON value from an edit op -> ARXML text."""
133
+ if isinstance(v, bool):
134
+ return "true" if v else "false"
135
+ if isinstance(v, (int, float)):
136
+ if isinstance(v, float) and v.is_integer() and d is not None and d.kind == "FLOAT":
137
+ return repr(v)
138
+ return str(v)
139
+ if v is None:
140
+ raise ValueError("null is not a value; use op 'remove' to delete a parameter")
141
+ s = str(v)
142
+ if s.startswith("->"):
143
+ s = s[2:]
144
+ if d is not None and d.kind == "BOOLEAN" and s.lower() in ("true", "false"):
145
+ s = s.lower()
146
+ return s
@@ -0,0 +1,141 @@
1
+ """Byte-offset-preserving XML tree for ARXML.
2
+
3
+ The engine never re-serialises a whole file. It parses with expat, records the byte span of every
4
+ element (start tag, content, end tag) and the line it starts on, and later patches only the spans
5
+ an edit touches. Comments, whitespace, attribute order, UUIDs and everything else outside the
6
+ patched spans stay byte-identical.
7
+
8
+ Namespace-agnostic: a prefixed tag (``ar:ECUC-CONTAINER-VALUE``) is stored without its prefix, so
9
+ any AUTOSAR schema namespace (r4.0 or a later one) parses the same way.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import xml.parsers.expat as expat
14
+ from typing import Iterator, Optional
15
+
16
+
17
+ class Node:
18
+ __slots__ = ("tag", "attrs", "start", "stag_end", "end", "cstart", "cend", "line", "children", "parent", "_text")
19
+
20
+ def __init__(self, tag: str, attrs: dict, start: int, stag_end: int, line: int, parent: "Optional[Node]"):
21
+ self.tag = tag
22
+ self.attrs = attrs
23
+ self.start = start # byte offset of '<'
24
+ self.stag_end = stag_end # byte offset just after the start tag's '>'
25
+ self.end = stag_end # byte offset just after the element (set on close)
26
+ self.cstart: Optional[int] = None # content span (None for <X/>)
27
+ self.cend: Optional[int] = None
28
+ self.line = line
29
+ self.children: list[Node] = []
30
+ self.parent = parent
31
+ self._text: list[str] = []
32
+
33
+ @property
34
+ def text(self) -> str:
35
+ return "".join(self._text)
36
+
37
+ def child(self, tag: str) -> "Optional[Node]":
38
+ for c in self.children:
39
+ if c.tag == tag:
40
+ return c
41
+ return None
42
+
43
+ def child_text(self, tag: str) -> Optional[str]:
44
+ c = self.child(tag)
45
+ return c.text.strip() if c is not None else None
46
+
47
+ def iter(self) -> Iterator["Node"]:
48
+ stack = [self]
49
+ while stack:
50
+ n = stack.pop()
51
+ yield n
52
+ stack.extend(reversed(n.children))
53
+
54
+ @property
55
+ def short_name(self) -> Optional[str]:
56
+ return self.child_text("SHORT-NAME")
57
+
58
+ def __repr__(self) -> str: # pragma: no cover
59
+ return f"<Node {self.tag} {self.short_name or ''} @{self.line}>"
60
+
61
+
62
+ def _local(name: str) -> str:
63
+ return name.rsplit(":", 1)[-1]
64
+
65
+
66
+ def _stag_end(data: bytes, start: int) -> int:
67
+ """Index just past the '>' closing the start tag at ``start`` (quote-aware)."""
68
+ i = start + 1
69
+ n = len(data)
70
+ quote = 0
71
+ while i < n:
72
+ b = data[i]
73
+ if quote:
74
+ if b == quote:
75
+ quote = 0
76
+ elif b in (0x22, 0x27): # " '
77
+ quote = b
78
+ elif b == 0x3E: # >
79
+ return i + 1
80
+ i += 1
81
+ raise ValueError(f"unterminated start tag at byte {start}")
82
+
83
+
84
+ def parse(data: bytes) -> Node:
85
+ """Parse ``data`` and return the document element with byte spans filled in."""
86
+ p = expat.ParserCreate()
87
+ p.buffer_text = True
88
+ stack: list[Node] = []
89
+ root: list[Node] = []
90
+
91
+ def start(name, attrs):
92
+ s = p.CurrentByteIndex
93
+ se = _stag_end(data, s)
94
+ node = Node(_local(name), {_local(k): v for k, v in attrs.items()}, s, se, p.CurrentLineNumber,
95
+ stack[-1] if stack else None)
96
+ if stack:
97
+ stack[-1].children.append(node)
98
+ else:
99
+ root.append(node)
100
+ stack.append(node)
101
+
102
+ def end(name):
103
+ node = stack.pop()
104
+ if data[node.stag_end - 2] == 0x2F: # '/' of '/>'
105
+ node.end = node.stag_end
106
+ else:
107
+ idx = p.CurrentByteIndex
108
+ node.cstart = node.stag_end
109
+ node.cend = idx
110
+ node.end = data.index(b">", idx) + 1
111
+
112
+ def chars(t):
113
+ if stack:
114
+ stack[-1]._text.append(t)
115
+
116
+ p.StartElementHandler = start
117
+ p.EndElementHandler = end
118
+ p.CharacterDataHandler = chars
119
+ p.Parse(data, True)
120
+ if not root:
121
+ raise ValueError("no root element")
122
+ return root[0]
123
+
124
+
125
+ def escape(s: str) -> str:
126
+ return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
127
+
128
+
129
+ def escape_attr(s: str) -> str:
130
+ return escape(s).replace('"', "&quot;")
131
+
132
+
133
+ def line_indent(data: bytes, pos: int) -> Optional[bytes]:
134
+ """Whitespace between the previous newline and ``pos`` if it is all whitespace, else None."""
135
+ nl = data.rfind(b"\n", 0, pos)
136
+ seg = data[nl + 1:pos]
137
+ return seg if seg.strip() == b"" else None
138
+
139
+
140
+ def line_of(data: bytes, pos: int) -> int:
141
+ return data.count(b"\n", 0, pos) + 1
@@ -0,0 +1,13 @@
1
+ [project]
2
+ name = "ecuc-engine"
3
+ version = "0.1.0"
4
+ description = "Load, read, edit in place, validate and diff AUTOSAR ECUC ARXML (Hydron AUTOSAR pack)"
5
+ requires-python = ">=3.10"
6
+ # The core is stdlib-only; autosar-data adds a strict schema check of every edited file.
7
+ dependencies = ["autosar-data==0.17.0"]
8
+
9
+ [project.optional-dependencies]
10
+ test = ["pytest>=8"]
11
+
12
+ [tool.pytest.ini_options]
13
+ testpaths = ["tests"]
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: autosar
3
+ description: >-
4
+ AUTOSAR Classic integration expertise — ECUC configuration (ARXML), param defs, BSW module
5
+ config, code generation and build, and config-to-code tracing. Load it at the START of any task
6
+ that touches .arxml files, ECUC values/param defs, DEFINITION-REFs, a BSW module's configuration
7
+ (Com, PduR, CanIf, EcuC, Os, Rte, NvM, Dem, Dcm, …), generated Output/ code, or the vendor
8
+ configurator / SIP. It carries the tool map (ecuc_read/ecuc_edit/ecuc_validate/arxml_diff,
9
+ autosar_trace/autosar_config_lookup, autosar_generate/autosar_build), the edit → validate →
10
+ generate → build → trace loop, and the ECUC model rules needed to edit correctly.
11
+ ---
12
+ # AUTOSAR skill — Classic Platform integration layer
13
+
14
+ You are working on an AUTOSAR Classic ECU project. The configuration is ECUC ARXML; generated C
15
+ in `Output/` is derived from it; in-house code in `Source/` calls the generated symbols.
16
+
17
+ ## Hard rules
18
+ 1. **Never hand-write or hand-edit ARXML** (no `write`/`edit`/`sed` on `.arxml`). Every change goes
19
+ through `ecuc_edit`, which picks the value element, DEFINITION-REF/DEST and VALUE-REF DEST from
20
+ the param defs and patches only the changed bytes. Reading raw ARXML for context is fine; prefer `ecuc_read`.
21
+ 2. **Validate after every edit**: `ecuc_validate` (scoped with `files`/`module` if large). Fix
22
+ every error you introduced before moving on; report pre-existing ones separately.
23
+ 3. **Cite** the AUTOSAR path, the DEFINITION-REF and file:line for every element you discuss or change.
24
+ 4. **Generated code is an output.** Never edit `Output/` (or other generated files) to fix a
25
+ problem — change the configuration and regenerate.
26
+ 5. Values come from the param defs (ranges, literals, multiplicity) and the SWS; when the defs do
27
+ not settle a question (cross-module consistency, handle IDs, timing), say so and cite the SWS
28
+ requirement rather than guessing.
29
+
30
+ ## Tool map
31
+ | Need | Tool |
32
+ |---|---|
33
+ | What modules/files/defs exist | `ecuc_read` (no path) |
34
+ | Values of a module/container | `ecuc_read path=… depth=…` |
35
+ | What may be set/added here (types, ranges, literals, multiplicity) | `ecuc_read path=… schema=true`, or a def path `/AUTOSAR/EcucDefs/<Mod>/…` |
36
+ | Change config | `ecuc_edit ops=[…]` (`dry_run` first for large edits) |
37
+ | Check config | `ecuc_validate` |
38
+ | Review a change / PR / two versions | `arxml_diff a b` |
39
+ | Which C symbols does this config produce, who calls them / where does this symbol come from | `autosar_trace query=…` |
40
+ | Refs in/out, children of an element in the ingested repo | `autosar_config_lookup path=…` |
41
+ | Regenerate code | `autosar_generate` (configured command, asks permission) |
42
+ | Compile/link | `autosar_build` |
43
+ | Spec questions (SWS/TPS requirement text) | the project's ingested docs search tools |
44
+
45
+ ## The loop
46
+ `ecuc_read (schema) → ecuc_edit → ecuc_validate → autosar_generate → arxml_diff / inspect Output → autosar_build → autosar_trace (impact on Source/)`.
47
+ Details and failure handling: `references/workflow.md`.
48
+
49
+ ## References (load when relevant)
50
+ - `references/ecuc-model.md` — module/container/param/ref values vs defs, DEFINITION-REF, ECUC JSON, multiplicity, choice containers, refs vs foreign refs.
51
+ - `references/symbolic-names.md` — the symbolic-name rule (TPS_ECUC_02108) that links config to generated `#define`s, handle IDs.
52
+ - `references/config-classes.md` — pre-compile / link-time / post-build config classes, variants, post-build loadable/selectable.
53
+ - `references/project-layout.md` — Config / Input / Output / Source / Build / SIP and `.hydron/autosar.json`.
54
+ - `references/workflow.md` — the edit → validate → generate → build → trace loop, diagnostics rules, and what to do when a step fails.
55
+
56
+ ## Reading diagnostics
57
+ `file:line SEVERITY RULE path — message [def DEFINITION-REF]`. Rules: ECUC-MISSING-PARAM,
58
+ ECUC-MULT-CONTAINER/-PARAM, ECUC-CHOICE, ECUC-RANGE, ECUC-ENUM, ECUC-TYPE, ECUC-STRING,
59
+ ECUC-REF-DANGLING, ECUC-REF-DEST, ECUC-REF-UNRESOLVED (foreign target not loaded: add System/SWC
60
+ ARXML to `input`), ECUC-UNKNOWN-DEF (often a release mismatch between config and param defs),
61
+ ECUC-DUP-NAME, ECUC-NO-DEF (module defs not loaded → module not validated), ECUC-VALUE-TYPE,
62
+ ECUC-DEST-MISMATCH, ECUC-OBSOLETE. These are mechanical checks from the defs; they do not cover
63
+ SWS cross-module rules — reason about those explicitly.
@@ -0,0 +1,23 @@
1
+ # Configuration classes and post-build
2
+
3
+ Every param/ref def lists, per implementation variant, when its value is fixed
4
+ (`VALUE-CONFIG-CLASSES` in recent releases):
5
+
6
+ | Class | Fixed at | Generated as | Changing it needs |
7
+ |---|---|---|---|
8
+ | PRE-COMPILE | compile time | `#define`s in `<Mod>_Cfg.h` | regenerate + full rebuild |
9
+ | LINK | link time | `const` data in `<Mod>_Lcfg.c` | regenerate + relink of that object |
10
+ | POST-BUILD | after build (flash/load) | `const` tables in `<Mod>_PBcfg.c`, passed to `<Mod>_Init(ConfigPtr)` | regenerate post-build data only (if the project uses post-build loadable) |
11
+
12
+ The module's `IMPLEMENTATION-CONFIG-VARIANT` (VARIANT-PRE-COMPILE / VARIANT-LINK-TIME /
13
+ VARIANT-POST-BUILD) selects which class applies; it must be one of the module def's
14
+ `SUPPORTED-CONFIG-VARIANTS`.
15
+
16
+ **Post-build selectable** (several configuration sets in one image, chosen at init via
17
+ `EcuM`/`<Mod>_Init` config pointer) and **post-build loadable** (configuration flashed separately)
18
+ only allow changing values whose class is POST-BUILD for the selected variant, and multiplicity
19
+ only where `MULTIPLICITY-CONFIG-CLASSES` allows it. `POST-BUILD-VARIANT-VALUE=true` means the value
20
+ may differ between post-build variants (predefined variants / variation points).
21
+
22
+ When proposing a change, state its class: a pre-compile change forces a full rebuild and a new
23
+ software version; a post-build change may ship as a data update.
@@ -0,0 +1,42 @@
1
+ # ECUC model basics
2
+
3
+ **Definitions vs values.** Param defs (`ECUC-MODULE-DEF` trees: the AUTOSAR StMD
4
+ `/AUTOSAR/EcucDefs/<Mod>` and vendor VSMD/BSWMD refinements) describe what may be configured.
5
+ Values (`ECUC-MODULE-CONFIGURATION-VALUES`) are the configuration. Every value element points to
6
+ its def through `DEFINITION-REF` (an AUTOSAR path); the `DEST` attribute names the def's metaclass.
7
+
8
+ **Hierarchy.**
9
+ - Module configuration → `CONTAINERS` → `ECUC-CONTAINER-VALUE` → `SUB-CONTAINERS` …
10
+ - A container holds `PARAMETER-VALUES` (`ECUC-NUMERICAL-PARAM-VALUE` for integer/float/boolean,
11
+ `ECUC-TEXTUAL-PARAM-VALUE` for enum/string/function-name/linker-symbol) and `REFERENCE-VALUES`
12
+ (`ECUC-REFERENCE-VALUE` with `VALUE-REF DEST=…`, `ECUC-INSTANCE-REFERENCE-VALUE`).
13
+ - A value's AUTOSAR path is the chain of SHORT-NAMEs: `/<Pkg>/<Module>/<Container>/…`. The def
14
+ path follows the *def* names: `/AUTOSAR/EcucDefs/Com/ComConfig/ComSignal`.
15
+
16
+ **ECUC JSON** (what `ecuc_read` returns and `ecuc_edit add` accepts): containers keyed
17
+ `"<DefName>:<ShortName>"` (just `"<Name>"` when equal), params by def short-name, multi-valued
18
+ params as arrays, refs as `"->/path"`, `@path`/`@def`/`@at` metadata.
19
+
20
+ **Multiplicity.** `LOWER/UPPER-MULTIPLICITY` (or `UPPER-MULTIPLICITY-INFINITE`) on every container,
21
+ param and ref def. Lower ≥ 1 = mandatory. A **choice container** (`ECUC-CHOICE-CONTAINER-DEF`)
22
+ must hold exactly one of its `CHOICES`.
23
+
24
+ **Parameter kinds.** INTEGER (uint64-safe, MIN/MAX), FLOAT (MIN/MAX with OPEN/CLOSED interval,
25
+ INF), BOOLEAN (`true`/`false`/`1`/`0`), ENUMERATION (literals), STRING / FUNCTION-NAME /
26
+ LINKER-SYMBOL (length, regex, C identifiers), ADD-INFO, MULTILINE-STRING.
27
+
28
+ **References.**
29
+ - ECUC reference (`ECUC-REFERENCE-DEF`, choice/symbolic-name refs): target is another container
30
+ value whose DEFINITION-REF matches a `DESTINATION-REF` (e.g. `ComPduIdRef → EcuC/…/Pdu`).
31
+ - Foreign reference (`ECUC-FOREIGN-REFERENCE-DEF`): target is a System/SWC element of the metaclass
32
+ in `DESTINATION-TYPE` (e.g. `I-SIGNAL-TO-I-PDU-MAPPING`); `VALUE-REF DEST` names the target's
33
+ concrete metaclass. Resolving it needs the System extract in `input`.
34
+ - Instance references point into a component instance context; the engine reads but does not edit them.
35
+
36
+ **Split files.** One module's configuration may be split across several files with the same
37
+ module path; tools merge them for reading and edit each element in the file it lives in.
38
+
39
+ **Releases.** The def metamodel drifts across releases (e.g. `VALUE-CONFIG-CLASSES` vs older
40
+ `ECUC-IMPLEMENTATION-CONFIGURATION-CLASS`; params added/removed). Always validate against the
41
+ param defs of the release the project's SIP targets; an ECUC-UNKNOWN-DEF burst usually means
42
+ mismatched defs, not broken config.
@@ -0,0 +1,29 @@
1
+ # Project layout (typical OEM / Tier-1 integration repo)
2
+
3
+ | Folder | Holds | Who edits |
4
+ |---|---|---|
5
+ | `Config/` | ECUC values ARXML (one or more files per module), configurator project file | integrator, via the configurator or `ecuc_edit` |
6
+ | `Input/` | System description / ECU extract, DBC/LDF/FIBEX, SWC descriptions, diagnostic data | comes from the OEM network/system team |
7
+ | `Output/` | generated BSW/RTE/OS/MCAL configuration code and reports | generator only — never by hand |
8
+ | `Source/` | in-house application and integration code (callouts, CDDs, SWC runnables) | developers |
9
+ | `Build/` | makefiles/CMake, linker scripts, compiler options | build owner |
10
+ | `SIP/` (or `BSW/`, `ThirdParty/`) | the vendor's Software Integration Package: static BSW code, BSWMD with vendor param defs (VSMD), generators | vendor; read-only |
11
+
12
+ Names vary; the tools classify `.arxml` files by content, not by folder.
13
+
14
+ ## `.hydron/autosar.json`
15
+ Optional; pins what the tools load and how to generate/build:
16
+
17
+ ```json
18
+ {
19
+ "paramDefs": ["SIP/**/bswmd/*.arxml", "~/autosar/R22-11/AUTOSAR_MOD_ECUConfigurationParameters.arxml"],
20
+ "config": ["Config/**/*.arxml"],
21
+ "input": ["Input/**/*.arxml"],
22
+ "generate": {"command": "<vendor-cli> -p Config/Ecu.dpa --generate {module}", "cwd": ".", "timeoutSec": 3600},
23
+ "build": {"command": "make -C Build -j8 all", "timeoutSec": 3600}
24
+ }
25
+ ```
26
+ Without it: param defs = every `.arxml` holding `ECUC-MODULE-DEF` (else `$AUTOSAR_PARAMDEFS`, a
27
+ path list), config = every file holding `ECUC-MODULE-CONFIGURATION-VALUES`, input = all other
28
+ `.arxml`. Use the param defs of the release and vendor the project actually targets; the vendor
29
+ BSWMD defs take precedence for vendor-specific parameters.
@@ -0,0 +1,25 @@
1
+ # Symbolic names: how config becomes C symbols
2
+
3
+ **TPS_ECUC_02108 (symbolic name rule).** For a container whose def has a parameter with
4
+ `SYMBOLIC-NAME-VALUE=true` (typically the handle ID, e.g. `ComHandleId`, `PduRDestPduHandleId`,
5
+ `CanIfTxPduId`), the generator emits a `#define` named
6
+
7
+ <Module>Conf_<ContainerDefName>_<ContainerShortName> value = that parameter
8
+
9
+ e.g. `ComConf_ComSignal_DoorLatch`, `PduRConf_PduRDestPdu_Tx_Msg1`. In-house code and other BSW
10
+ modules must use these symbols, never literal IDs. A `*-REF` with `SYMBOLIC-NAME-REFERENCE` uses
11
+ the target's symbolic name.
12
+
13
+ **Consequences for edits.**
14
+ - Renaming a container (SHORT-NAME) renames its symbol: every caller in `Source/` breaks. Run
15
+ `autosar_trace` on the element first to list callers.
16
+ - Handle IDs: often zero-based and dense per module; shared IDs must agree across modules
17
+ (TPS_ECUC_02106). When adding a container with a handle ID, read the siblings and pick the next
18
+ free value per the module's convention; say which convention you assumed.
19
+ - Vendor generators may add prefixes or use different names for vendor-specific containers;
20
+ `autosar_trace` reports links by `method` (`symbolic_name` = rule match, score 1.0;
21
+ `token_match`/`value_match` = heuristic, check the score).
22
+
23
+ **Other generated artefacts.** Const configuration tables (`<Mod>_PBcfg.c`, `<Mod>_Lcfg.c`),
24
+ `<Mod>_Cfg.h` macros (feature switches from booleans such as `…DevErrorDetect`), and callout
25
+ prototypes from FUNCTION-NAME params (the in-house code must define those functions).
@@ -0,0 +1,29 @@
1
+ # The integration loop
2
+
3
+ 1. **Orient.** `ecuc_read` (no path) → modules, files, whether param defs loaded. If it warns that
4
+ no defs were found, stop and ask for the param-def location (or set `paramDefs`); without defs
5
+ nothing is validated and new elements cannot be added.
6
+ 2. **Understand the target.** `ecuc_read path=<container> schema=true` for the allowed params,
7
+ ranges, literals, multiplicity. For cross-module work also read the referenced containers
8
+ (e.g. ComIPdu → EcuC Pdu → PduR routing path → CanIf Tx PDU). `autosar_trace` shows which C
9
+ symbols and callers depend on the element.
10
+ 3. **Edit.** One `ecuc_edit` call with all related ops (it is all-or-nothing). Use `dry_run` to
11
+ show a non-trivial change first. Never write ARXML yourself.
12
+ 4. **Validate.** `ecuc_validate` (scope with `module`/`files` on big projects). Separate findings you
13
+ introduced from pre-existing ones (`arxml_diff` against the committed version helps). Fix yours.
14
+ 5. **Generate.** `autosar_generate` (only with no new errors). If it fails, read its error output,
15
+ map each message to the AUTOSAR path / parameter, fix via `ecuc_edit`, re-validate.
16
+ 6. **Review output.** `arxml_diff` for ARXML outputs; for C, check the expected symbols changed
17
+ (e.g. a new `ComConf_ComSignal_<Name>`).
18
+ 7. **Build.** `autosar_build`; compile/link errors usually mean a renamed/removed symbolic name or a
19
+ callout (FUNCTION-NAME) not implemented in `Source/`. `autosar_trace` the symbol to its config.
20
+ 8. **Report.** List each change as `path` (DEFINITION-REF) old → new, its config class, the
21
+ validation result, generator/build status, and impacted callers.
22
+
23
+ ## Failure handling
24
+ - ECUC-UNKNOWN-DEF everywhere → wrong release/vendor defs loaded; check `paramDefs`.
25
+ - ECUC-REF-UNRESOLVED → the System/SWC ARXML is not in `input`; add it rather than ignoring.
26
+ - `ecuc_edit` rejected a value → it violates the def; do not `force` unless the user confirms the
27
+ def is wrong for their vendor release, and say so.
28
+ - Backend tools (`autosar_trace`, `autosar_config_lookup`) report NOTES such as "data source
29
+ predates the feature, re-ingest it": relay them; the graph needs a re-ingest of the code data source.