udsxml2tex 0.1.0__tar.gz

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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 udsxml2tex contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.4
2
+ Name: udsxml2tex
3
+ Version: 0.1.0
4
+ Summary: Convert AUTOSAR DCM arxml to LaTeX UDS specification documents
5
+ Author: udsxml2tex contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/udsxml2tex/udsxml2tex
8
+ Project-URL: Repository, https://github.com/udsxml2tex/udsxml2tex
9
+ Keywords: autosar,arxml,uds,dcm,latex,tex,diagnostics
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Documentation
20
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: lxml>=4.9.0
25
+ Requires-Dist: Jinja2>=3.1.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # udsxml2tex
32
+
33
+ **Convert AUTOSAR DCM arxml to LaTeX UDS specification documents**
34
+
35
+ A Python library that parses AUTOSAR DCM (Diagnostic Communication Manager) arxml configuration files and automatically generates ISO 14229 (UDS: Unified Diagnostic Services) specification documents in LaTeX format.
36
+
37
+ ## Features
38
+
39
+ - Automatically extracts UDS specification data from DCM arxml files
40
+ - Diagnostic sessions
41
+ - Security access levels
42
+ - UDS service list (SID, supported sessions, NRCs, etc.)
43
+ - DID (Data Identifier) definitions
44
+ - Routine Control definitions
45
+ - Generates professional LaTeX specification documents
46
+ - Customizable via Jinja2 templates
47
+ - Available as both a CLI command and a Python API
48
+ - Supports merging multiple arxml files
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install udsxml2tex
54
+ ```
55
+
56
+ From source (for development):
57
+
58
+ ```bash
59
+ git clone https://github.com/udsxml2tex/udsxml2tex.git
60
+ cd udsxml2tex
61
+ pip install -e ".[dev]"
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ### CLI
67
+
68
+ ```bash
69
+ # Basic conversion
70
+ udsxml2tex input.arxml
71
+
72
+ # Specify output file
73
+ udsxml2tex input.arxml -o output.tex
74
+
75
+ # Override ECU name
76
+ udsxml2tex input.arxml --ecu-name "MyECU"
77
+
78
+ # Merge and convert multiple files
79
+ udsxml2tex dcm_config.arxml dcm_dids.arxml -o merged_spec.tex
80
+
81
+ # Verbose logging
82
+ udsxml2tex input.arxml -v
83
+ ```
84
+
85
+ ### Python API
86
+
87
+ ```python
88
+ from udsxml2tex import ArxmlParser, TexGenerator
89
+
90
+ # Parse ARXML
91
+ parser = ArxmlParser()
92
+ spec = parser.parse("path/to/dcm_config.arxml")
93
+
94
+ # Generate LaTeX
95
+ generator = TexGenerator()
96
+ generator.generate(spec, "output/uds_spec.tex")
97
+
98
+ # Get as string
99
+ tex_content = generator.generate_string(spec)
100
+ ```
101
+
102
+ ### Custom Templates
103
+
104
+ You can use your own LaTeX templates:
105
+
106
+ ```python
107
+ generator = TexGenerator(template_dir="my_templates/")
108
+ generator.generate(spec, "output.tex", template_name="custom.tex.j2")
109
+ ```
110
+
111
+ ```bash
112
+ udsxml2tex input.arxml --template-dir my_templates/ --template custom.tex.j2
113
+ ```
114
+
115
+ ## Generated Document Structure
116
+
117
+ 1. **Title Page** — ECU name, date
118
+ 2. **Table of Contents**
119
+ 3. **Document Overview** — Protocol information, CAN IDs
120
+ 4. **Diagnostic Sessions** — Session list (ID, P2/P2* timers)
121
+ 5. **Security Access** — Security level list
122
+ 6. **UDS Services** — Service overview + detailed per-service info (including NRCs)
123
+ 7. **DID Definitions** — DID overview + data element details
124
+ 8. **Routine Control** — Routine overview + parameter details
125
+
126
+ ## Supported arxml Structure
127
+
128
+ The following AUTOSAR DCM configuration elements are parsed:
129
+
130
+ | Element | Description |
131
+ |---------|-------------|
132
+ | `DcmDsl` | Diagnostic Session Layer (protocol, timing) |
133
+ | `DcmDsp` | Diagnostic Service Processing (sessions, security, DIDs, routines) |
134
+ | `DcmDsd` | Diagnostic Service Dispatcher (service table) |
135
+
136
+ Supports AUTOSAR R4.x arxml format.
137
+
138
+ ## Requirements
139
+
140
+ - Python >= 3.9
141
+ - lxml >= 4.9.0
142
+ - Jinja2 >= 3.1.0
143
+ - LaTeX distribution (for compiling the generated .tex files)
144
+
145
+ ## License
146
+
147
+ MIT License
@@ -0,0 +1,117 @@
1
+ # udsxml2tex
2
+
3
+ **Convert AUTOSAR DCM arxml to LaTeX UDS specification documents**
4
+
5
+ A Python library that parses AUTOSAR DCM (Diagnostic Communication Manager) arxml configuration files and automatically generates ISO 14229 (UDS: Unified Diagnostic Services) specification documents in LaTeX format.
6
+
7
+ ## Features
8
+
9
+ - Automatically extracts UDS specification data from DCM arxml files
10
+ - Diagnostic sessions
11
+ - Security access levels
12
+ - UDS service list (SID, supported sessions, NRCs, etc.)
13
+ - DID (Data Identifier) definitions
14
+ - Routine Control definitions
15
+ - Generates professional LaTeX specification documents
16
+ - Customizable via Jinja2 templates
17
+ - Available as both a CLI command and a Python API
18
+ - Supports merging multiple arxml files
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install udsxml2tex
24
+ ```
25
+
26
+ From source (for development):
27
+
28
+ ```bash
29
+ git clone https://github.com/udsxml2tex/udsxml2tex.git
30
+ cd udsxml2tex
31
+ pip install -e ".[dev]"
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ### CLI
37
+
38
+ ```bash
39
+ # Basic conversion
40
+ udsxml2tex input.arxml
41
+
42
+ # Specify output file
43
+ udsxml2tex input.arxml -o output.tex
44
+
45
+ # Override ECU name
46
+ udsxml2tex input.arxml --ecu-name "MyECU"
47
+
48
+ # Merge and convert multiple files
49
+ udsxml2tex dcm_config.arxml dcm_dids.arxml -o merged_spec.tex
50
+
51
+ # Verbose logging
52
+ udsxml2tex input.arxml -v
53
+ ```
54
+
55
+ ### Python API
56
+
57
+ ```python
58
+ from udsxml2tex import ArxmlParser, TexGenerator
59
+
60
+ # Parse ARXML
61
+ parser = ArxmlParser()
62
+ spec = parser.parse("path/to/dcm_config.arxml")
63
+
64
+ # Generate LaTeX
65
+ generator = TexGenerator()
66
+ generator.generate(spec, "output/uds_spec.tex")
67
+
68
+ # Get as string
69
+ tex_content = generator.generate_string(spec)
70
+ ```
71
+
72
+ ### Custom Templates
73
+
74
+ You can use your own LaTeX templates:
75
+
76
+ ```python
77
+ generator = TexGenerator(template_dir="my_templates/")
78
+ generator.generate(spec, "output.tex", template_name="custom.tex.j2")
79
+ ```
80
+
81
+ ```bash
82
+ udsxml2tex input.arxml --template-dir my_templates/ --template custom.tex.j2
83
+ ```
84
+
85
+ ## Generated Document Structure
86
+
87
+ 1. **Title Page** — ECU name, date
88
+ 2. **Table of Contents**
89
+ 3. **Document Overview** — Protocol information, CAN IDs
90
+ 4. **Diagnostic Sessions** — Session list (ID, P2/P2* timers)
91
+ 5. **Security Access** — Security level list
92
+ 6. **UDS Services** — Service overview + detailed per-service info (including NRCs)
93
+ 7. **DID Definitions** — DID overview + data element details
94
+ 8. **Routine Control** — Routine overview + parameter details
95
+
96
+ ## Supported arxml Structure
97
+
98
+ The following AUTOSAR DCM configuration elements are parsed:
99
+
100
+ | Element | Description |
101
+ |---------|-------------|
102
+ | `DcmDsl` | Diagnostic Session Layer (protocol, timing) |
103
+ | `DcmDsp` | Diagnostic Service Processing (sessions, security, DIDs, routines) |
104
+ | `DcmDsd` | Diagnostic Service Dispatcher (service table) |
105
+
106
+ Supports AUTOSAR R4.x arxml format.
107
+
108
+ ## Requirements
109
+
110
+ - Python >= 3.9
111
+ - lxml >= 4.9.0
112
+ - Jinja2 >= 3.1.0
113
+ - LaTeX distribution (for compiling the generated .tex files)
114
+
115
+ ## License
116
+
117
+ MIT License
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "udsxml2tex"
7
+ version = "0.1.0"
8
+ description = "Convert AUTOSAR DCM arxml to LaTeX UDS specification documents"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ {name = "udsxml2tex contributors"},
14
+ ]
15
+ keywords = ["autosar", "arxml", "uds", "dcm", "latex", "tex", "diagnostics"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Documentation",
27
+ "Topic :: Text Processing :: Markup :: LaTeX",
28
+ ]
29
+ dependencies = [
30
+ "lxml>=4.9.0",
31
+ "Jinja2>=3.1.0",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest>=7.0",
37
+ "pytest-cov>=4.0",
38
+ ]
39
+
40
+ [project.scripts]
41
+ udsxml2tex = "udsxml2tex.cli:main"
42
+
43
+ [project.urls]
44
+ Homepage = "https://github.com/udsxml2tex/udsxml2tex"
45
+ Repository = "https://github.com/udsxml2tex/udsxml2tex"
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["src"]
49
+
50
+ [tool.setuptools.package-data]
51
+ udsxml2tex = ["templates/*.tex.j2"]
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,33 @@
1
+ """udsxml2tex - Convert AUTOSAR DCM arxml to LaTeX UDS specification documents."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from udsxml2tex.generator import TexGenerator
6
+ from udsxml2tex.models import (
7
+ DataElement,
8
+ DiagSession,
9
+ Did,
10
+ NrcEntry,
11
+ Routine,
12
+ RoutineParameter,
13
+ SecurityLevel,
14
+ SubFunction,
15
+ UdsService,
16
+ UdsSpecification,
17
+ )
18
+ from udsxml2tex.parser import ArxmlParser
19
+
20
+ __all__ = [
21
+ "ArxmlParser",
22
+ "TexGenerator",
23
+ "UdsSpecification",
24
+ "UdsService",
25
+ "DiagSession",
26
+ "SecurityLevel",
27
+ "Did",
28
+ "DataElement",
29
+ "Routine",
30
+ "RoutineParameter",
31
+ "SubFunction",
32
+ "NrcEntry",
33
+ ]
@@ -0,0 +1,7 @@
1
+ """Allow running udsxml2tex as ``python -m udsxml2tex``."""
2
+
3
+ import sys
4
+
5
+ from udsxml2tex.cli import main
6
+
7
+ sys.exit(main())
@@ -0,0 +1,126 @@
1
+ """Command-line interface for udsxml2tex."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import logging
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ from udsxml2tex.generator import TexGenerator
11
+ from udsxml2tex.parser import ArxmlParser
12
+
13
+
14
+ def _build_parser() -> argparse.ArgumentParser:
15
+ parser = argparse.ArgumentParser(
16
+ prog="udsxml2tex",
17
+ description="Convert AUTOSAR DCM arxml to LaTeX UDS specification documents.",
18
+ )
19
+ parser.add_argument(
20
+ "input",
21
+ nargs="+",
22
+ help="Input ARXML file(s). Multiple files will be merged.",
23
+ )
24
+ parser.add_argument(
25
+ "-o",
26
+ "--output",
27
+ default=None,
28
+ help="Output .tex file path. Default: <input_stem>_uds_spec.tex",
29
+ )
30
+ parser.add_argument(
31
+ "--ecu-name",
32
+ default=None,
33
+ help="Override ECU name in the generated document.",
34
+ )
35
+ parser.add_argument(
36
+ "--template-dir",
37
+ default=None,
38
+ help="Directory containing custom Jinja2 LaTeX templates.",
39
+ )
40
+ parser.add_argument(
41
+ "--template",
42
+ default="uds_spec.tex.j2",
43
+ help="Template file name (default: uds_spec.tex.j2).",
44
+ )
45
+ parser.add_argument(
46
+ "-v",
47
+ "--verbose",
48
+ action="store_true",
49
+ help="Enable verbose logging output.",
50
+ )
51
+ parser.add_argument(
52
+ "--version",
53
+ action="version",
54
+ version="%(prog)s 0.1.0",
55
+ )
56
+ return parser
57
+
58
+
59
+ def main(argv: list[str] | None = None) -> int:
60
+ """Main entry point for the CLI.
61
+
62
+ Args:
63
+ argv: Command-line arguments. Defaults to sys.argv[1:].
64
+
65
+ Returns:
66
+ Exit code (0 for success).
67
+ """
68
+ parser = _build_parser()
69
+ args = parser.parse_args(argv)
70
+
71
+ # Configure logging
72
+ level = logging.DEBUG if args.verbose else logging.INFO
73
+ logging.basicConfig(
74
+ level=level,
75
+ format="%(levelname)s: %(message)s",
76
+ )
77
+
78
+ # Validate input files
79
+ input_paths = [Path(p) for p in args.input]
80
+ for p in input_paths:
81
+ if not p.exists():
82
+ logging.error("Input file not found: %s", p)
83
+ return 1
84
+ if not p.suffix.lower() == ".arxml":
85
+ logging.warning(
86
+ "File does not have .arxml extension: %s", p
87
+ )
88
+
89
+ # Determine output path
90
+ if args.output:
91
+ output_path = Path(args.output)
92
+ else:
93
+ stem = input_paths[0].stem
94
+ output_path = input_paths[0].parent / f"{stem}_uds_spec.tex"
95
+
96
+ # Parse ARXML
97
+ arxml_parser = ArxmlParser()
98
+ try:
99
+ if len(input_paths) == 1:
100
+ spec = arxml_parser.parse(input_paths[0])
101
+ else:
102
+ spec = arxml_parser.parse_multi(input_paths)
103
+ except Exception as e:
104
+ logging.error("Failed to parse ARXML: %s", e)
105
+ return 1
106
+
107
+ # Override ECU name if specified
108
+ if args.ecu_name:
109
+ spec.ecu_name = args.ecu_name
110
+
111
+ # Generate LaTeX
112
+ try:
113
+ tex_gen = TexGenerator(template_dir=args.template_dir)
114
+ result = tex_gen.generate(
115
+ spec, output_path, template_name=args.template
116
+ )
117
+ logging.info("Output written to: %s", result)
118
+ except Exception as e:
119
+ logging.error("Failed to generate LaTeX: %s", e)
120
+ return 1
121
+
122
+ return 0
123
+
124
+
125
+ if __name__ == "__main__":
126
+ sys.exit(main())
@@ -0,0 +1,165 @@
1
+ """LaTeX generator for UDS specification documents."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ from jinja2 import Environment, FileSystemLoader, select_autoescape
10
+
11
+ from udsxml2tex.models import UdsSpecification
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ # Characters that need escaping in LaTeX
16
+ _LATEX_ESCAPE_MAP = {
17
+ "&": r"\&",
18
+ "%": r"\%",
19
+ "$": r"\$",
20
+ "#": r"\#",
21
+ "_": r"\_",
22
+ "{": r"\{",
23
+ "}": r"\}",
24
+ "~": r"\textasciitilde{}",
25
+ "^": r"\textasciicircum{}",
26
+ }
27
+
28
+
29
+ def _latex_escape(text: str) -> str:
30
+ """Escape special LaTeX characters in text."""
31
+ if not text:
32
+ return ""
33
+ # Don't escape backslashes that are already LaTeX commands
34
+ result = []
35
+ i = 0
36
+ while i < len(text):
37
+ ch = text[i]
38
+ if ch == "\\" and i + 1 < len(text) and text[i + 1].isalpha():
39
+ # Likely a LaTeX command, don't escape
40
+ result.append(ch)
41
+ elif ch in _LATEX_ESCAPE_MAP:
42
+ result.append(_LATEX_ESCAPE_MAP[ch])
43
+ else:
44
+ result.append(ch)
45
+ i += 1
46
+ return "".join(result)
47
+
48
+
49
+ class TexGenerator:
50
+ """Generate LaTeX documents from UDS specification data."""
51
+
52
+ def __init__(self, template_dir: Optional[str | Path] = None) -> None:
53
+ """Initialize the TeX generator.
54
+
55
+ Args:
56
+ template_dir: Directory containing Jinja2 templates.
57
+ Defaults to the built-in templates directory.
58
+ """
59
+ if template_dir is None:
60
+ template_dir = Path(__file__).parent / "templates"
61
+ else:
62
+ template_dir = Path(template_dir)
63
+
64
+ self.template_dir = template_dir
65
+ self.env = Environment(
66
+ loader=FileSystemLoader(str(template_dir)),
67
+ block_start_string=r"\BLOCK{",
68
+ block_end_string="}",
69
+ variable_start_string=r"\VAR{",
70
+ variable_end_string="}",
71
+ comment_start_string=r"\#{",
72
+ comment_end_string="}",
73
+ autoescape=False,
74
+ trim_blocks=True,
75
+ lstrip_blocks=True,
76
+ )
77
+ # Register custom filters
78
+ self.env.filters["latex_escape"] = _latex_escape
79
+
80
+ def generate(
81
+ self,
82
+ spec: UdsSpecification,
83
+ output_path: str | Path,
84
+ template_name: str = "uds_spec.tex.j2",
85
+ ) -> Path:
86
+ """Generate a LaTeX document from the UDS specification.
87
+
88
+ Args:
89
+ spec: The UDS specification data.
90
+ output_path: Path for the output .tex file.
91
+ template_name: Name of the Jinja2 template to use.
92
+
93
+ Returns:
94
+ Path to the generated .tex file.
95
+ """
96
+ output_path = Path(output_path)
97
+ output_path.parent.mkdir(parents=True, exist_ok=True)
98
+
99
+ template = self.env.get_template(template_name)
100
+
101
+ # Sort data for consistent output
102
+ services = sorted(spec.services, key=lambda s: s.service_id)
103
+ dids = sorted(spec.dids, key=lambda d: d.did_id)
104
+ routines = sorted(spec.routines, key=lambda r: r.routine_id)
105
+ sessions = sorted(spec.sessions, key=lambda s: s.session_id)
106
+ security_levels = sorted(spec.security_levels, key=lambda s: s.security_level)
107
+
108
+ context = {
109
+ "ecu_name": spec.ecu_name,
110
+ "description": spec.description,
111
+ "protocol_name": spec.protocol_name,
112
+ "can_rx_id": spec.can_rx_id,
113
+ "can_tx_id": spec.can_tx_id,
114
+ "can_functional_id": spec.can_functional_id,
115
+ "sessions": sessions,
116
+ "security_levels": security_levels,
117
+ "services": services,
118
+ "dids": dids,
119
+ "routines": routines,
120
+ }
121
+
122
+ rendered = template.render(**context)
123
+
124
+ output_path.write_text(rendered, encoding="utf-8")
125
+ logger.info("Generated LaTeX document: %s", output_path)
126
+
127
+ return output_path
128
+
129
+ def generate_string(
130
+ self,
131
+ spec: UdsSpecification,
132
+ template_name: str = "uds_spec.tex.j2",
133
+ ) -> str:
134
+ """Generate LaTeX content as a string.
135
+
136
+ Args:
137
+ spec: The UDS specification data.
138
+ template_name: Name of the Jinja2 template to use.
139
+
140
+ Returns:
141
+ Rendered LaTeX content.
142
+ """
143
+ template = self.env.get_template(template_name)
144
+
145
+ services = sorted(spec.services, key=lambda s: s.service_id)
146
+ dids = sorted(spec.dids, key=lambda d: d.did_id)
147
+ routines = sorted(spec.routines, key=lambda r: r.routine_id)
148
+ sessions = sorted(spec.sessions, key=lambda s: s.session_id)
149
+ security_levels = sorted(spec.security_levels, key=lambda s: s.security_level)
150
+
151
+ context = {
152
+ "ecu_name": spec.ecu_name,
153
+ "description": spec.description,
154
+ "protocol_name": spec.protocol_name,
155
+ "can_rx_id": spec.can_rx_id,
156
+ "can_tx_id": spec.can_tx_id,
157
+ "can_functional_id": spec.can_functional_id,
158
+ "sessions": sessions,
159
+ "security_levels": security_levels,
160
+ "services": services,
161
+ "dids": dids,
162
+ "routines": routines,
163
+ }
164
+
165
+ return template.render(**context)