odxtools 6.4.2__py3-none-any.whl → 6.5.0__py3-none-any.whl

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.
@@ -460,7 +460,10 @@ class BasicStructure(ComplexDop):
460
460
  else:
461
461
  return []
462
462
 
463
- def print_message_format(self, indent: int = 5, allow_unknown_lengths: bool = False) -> None:
463
+ def print_message_format(self,
464
+ indent: int = 5,
465
+ allow_unknown_lengths: bool = False,
466
+ plumbing_output: bool = True) -> None:
464
467
  """
465
468
  Print a description of the message format to `stdout`.
466
469
  """
@@ -470,5 +473,6 @@ class BasicStructure(ComplexDop):
470
473
  print(f"{indent * ' '}" + f"\n{indent * ' '}".join(message_as_lines))
471
474
  else:
472
475
  print("Sorry, couldn't pretty print message layout. :(")
473
- for p in self.parameters:
474
- print(indent * " " + str(p).replace("\n", f"\n{indent * ' '}"))
476
+ if plumbing_output:
477
+ for p in self.parameters:
478
+ print(indent * " " + str(p).replace("\n", f"\n{indent * ' '}"))
@@ -1,9 +1,22 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import re
3
+ from typing import Any, Dict, List, Optional, Union
3
4
 
4
5
  import markdownify
6
+ from rich import console, print
7
+ from tabulate import tabulate # TODO: switch to rich tables
5
8
 
9
+ from ..diaglayer import DiagLayer
6
10
  from ..diagservice import DiagService
11
+ from ..parameters.codedconstparameter import CodedConstParameter
12
+ from ..parameters.nrcconstparameter import NrcConstParameter
13
+ from ..parameters.parameter import Parameter
14
+ from ..parameters.physicalconstantparameter import PhysicalConstantParameter
15
+ from ..parameters.systemparameter import SystemParameter
16
+ from ..parameters.valueparameter import ValueParameter
17
+ from ..singleecujob import SingleEcuJob
18
+
19
+ terminal = console.Console()
7
20
 
8
21
 
9
22
  def format_desc(desc: str, ident: int = 0) -> str:
@@ -19,15 +32,14 @@ def format_desc(desc: str, ident: int = 0) -> str:
19
32
  return desc
20
33
 
21
34
 
22
- def print_diagnostic_service(
23
- service: DiagService,
24
- print_params: bool = False,
25
- print_pre_condition_states: bool = False,
26
- print_state_transitions: bool = False,
27
- print_audiences: bool = False,
28
- allow_unknown_bit_lengths: bool = False,
29
- ) -> None:
30
- print(f" {service.short_name} <ID: {service.odx_id}>")
35
+ def print_diagnostic_service(service: DiagService,
36
+ print_params: bool = False,
37
+ print_pre_condition_states: bool = False,
38
+ print_state_transitions: bool = False,
39
+ print_audiences: bool = False,
40
+ allow_unknown_bit_lengths: bool = False,
41
+ plumbing_output: bool = False) -> None:
42
+ print(f" [cyan]{service.short_name}[/cyan] <ID: {service.odx_id}>")
31
43
 
32
44
  if service.description:
33
45
  desc = format_desc(service.description, ident=3)
@@ -53,27 +65,71 @@ def print_diagnostic_service(
53
65
  print(f" Enabled-Audiences: {', '.join(enabled_audiences_short_names)}")
54
66
 
55
67
  if print_params:
56
- assert service.request is not None
57
- assert service.positive_responses is not None
58
- assert service.negative_responses is not None
68
+ print_service_parameters(
69
+ service,
70
+ allow_unknown_bit_lengths=allow_unknown_bit_lengths,
71
+ plumbing_output=plumbing_output)
72
+
73
+
74
+ def print_service_parameters(service: DiagService,
75
+ allow_unknown_bit_lengths: bool = False,
76
+ plumbing_output: bool = False) -> None:
77
+ # prints parameter details of request, posivite response and negative response of diagnostic service
78
+
79
+ assert service.request is not None
80
+ assert service.positive_responses is not None
81
+ assert service.negative_responses is not None
82
+
83
+ # Request
84
+ print(f"\n [yellow]Request Properties[/yellow]:")
85
+ print(f" Request Name: {service.request.short_name}")
59
86
 
60
- print(f" Message format of a request:")
61
- service.request.print_message_format(
62
- indent=3, allow_unknown_lengths=allow_unknown_bit_lengths)
87
+ if service.request and not service.request.required_parameters:
88
+ ba = f" Byte-Array: {service()!r}"
89
+ hs = f" Hex-String: 0x{str(service().hex().upper())}"
90
+ terminal.print(ba, overflow="ellipsis", soft_wrap=True)
91
+ terminal.print(hs, overflow="ellipsis", soft_wrap=True)
92
+ else:
93
+ print(f" Byte-Array: ---\n Hex-String: ---")
63
94
 
64
- print(f" Number of positive responses: {len(service.positive_responses)}")
65
- if len(service.positive_responses) == 1:
66
- resp = service.positive_responses[0]
95
+ print(f" Service Parameters: {service.request.parameters}\n")
96
+ table = extract_parameter_tabulation_data(list(service.request.parameters))
97
+ print(tabulate(table, headers='keys', tablefmt='presto'))
98
+ print(f"\n Message format of the request:")
99
+ service.request.print_message_format(
100
+ indent=0, allow_unknown_lengths=allow_unknown_bit_lengths, plumbing_output=plumbing_output)
67
101
 
68
- print(f" Message format of a positive response:")
69
- resp.print_message_format(indent=3, allow_unknown_lengths=allow_unknown_bit_lengths)
102
+ # Positive Response
103
+ print(f"\n [yellow]Positive Response Properties[/yellow]:")
104
+ print(f" Number of Positive Responses: {len(service.positive_responses)}")
105
+ print(f" Positive Responses: {service.positive_responses}")
106
+ if len(service.positive_responses) == 1:
107
+ resp = service.positive_responses[0]
108
+ print(f" Service Parameters: {resp.parameters}\n")
109
+ table = extract_parameter_tabulation_data(list(resp.parameters))
110
+ print(tabulate(table, headers='keys', tablefmt='presto'))
111
+ print(f"\n Message format of the positive response:")
112
+ resp.print_message_format(
113
+ indent=0,
114
+ allow_unknown_lengths=allow_unknown_bit_lengths,
115
+ plumbing_output=plumbing_output)
70
116
 
71
- print(f" Number of negative responses: {len(service.negative_responses)}")
72
- if len(service.negative_responses) == 1:
73
- resp = service.negative_responses[0]
117
+ # Negative Response
118
+ print(f"\n [yellow]Negative Response Properties[/yellow]:")
119
+ print(f" Number of Negative Responses: {len(service.negative_responses)}")
120
+ print(f" Negative Responses: {service.negative_responses}")
121
+ if len(service.negative_responses) == 1:
122
+ resp = service.negative_responses[0]
123
+ print(f" Service Parameters: {resp.parameters}\n")
124
+ table = extract_parameter_tabulation_data(list(resp.parameters))
125
+ print(tabulate(table, headers='keys', tablefmt='presto'))
126
+ print(f"\n Message format of a negative response:")
127
+ resp.print_message_format(
128
+ indent=0,
129
+ allow_unknown_lengths=allow_unknown_bit_lengths,
130
+ plumbing_output=plumbing_output)
74
131
 
75
- print(f" Message format of a negative response:")
76
- resp.print_message_format(indent=3, allow_unknown_lengths=allow_unknown_bit_lengths)
132
+ print("\n")
77
133
 
78
134
  if (service.positive_responses and
79
135
  len(service.positive_responses) > 1) or (service.negative_responses and
@@ -81,3 +137,132 @@ def print_diagnostic_service(
81
137
  # Does this ever happen?
82
138
  raise NotImplementedError(
83
139
  f"The diagnostic service {service.odx_id} offers more than one response!")
140
+
141
+
142
+ def extract_service_tabulation_data(services: List[DiagService]) -> Dict[str, Any]:
143
+ # extracts data of diagnostic services into Dictionary which can be printed by tabulate module
144
+ # TODO: consider indentation
145
+
146
+ name = []
147
+ semantic = []
148
+ request: List[Optional[str]] = []
149
+
150
+ for service in services:
151
+ name.append(service.short_name)
152
+ semantic.append(service.semantic)
153
+
154
+ if service.request and not service.request.required_parameters:
155
+ request.append(f"0x{str(s.hex().upper())[:32]}...") if len(
156
+ s := service()) > 32 else request.append(f"0x{str(s.hex().upper())}")
157
+ else:
158
+ request.append(None)
159
+
160
+ return {'Name': name, 'Semantic': semantic, 'Hex-Request': request}
161
+
162
+
163
+ def extract_parameter_tabulation_data(parameters: List[Parameter]) -> Dict[str, Any]:
164
+ # extracts data of parameters of diagnostic services into Dictionary which can be printed by tabulate module
165
+ # TODO: consider indentation
166
+
167
+ name = []
168
+ byte = []
169
+ bit_length: List[Optional[int]] = []
170
+ semantic = []
171
+ param_type = []
172
+ value: List[Optional[str]] = []
173
+ value_type: List[Optional[str]] = []
174
+ data_type: List[Optional[str]] = []
175
+ dop: List[Optional[str]] = []
176
+
177
+ for param in parameters:
178
+ name.append(param.short_name)
179
+ byte.append(param.byte_position)
180
+ semantic.append(param.semantic)
181
+ param_type.append(param.parameter_type)
182
+ if param.get_static_bit_length() is not None:
183
+ bit_length.append(param.get_static_bit_length())
184
+ length = (param.get_static_bit_length() or 0) // 4
185
+ else:
186
+ bit_length.append(None)
187
+ if isinstance(param, CodedConstParameter):
188
+ if isinstance(param.coded_value, int):
189
+ value.append(f"0x{param.coded_value:0{length}X}")
190
+ elif isinstance(param.coded_value, bytes) or isinstance(param.coded_value, bytearray):
191
+ value.append(f"0x{param.coded_value.hex().upper()}")
192
+ else:
193
+ value.append(f"{param.coded_value!r}")
194
+ data_type.append(param.diag_coded_type.base_data_type.name)
195
+ value_type.append('coded value')
196
+ dop.append(None)
197
+ elif isinstance(param, NrcConstParameter):
198
+ data_type.append(param.diag_coded_type.base_data_type.name)
199
+ value.append(str(param.coded_values))
200
+ value_type.append('coded values')
201
+ dop.append(None)
202
+ elif isinstance(param, (PhysicalConstantParameter, SystemParameter, ValueParameter)):
203
+ dop.append(param.dop.short_name)
204
+ if (tmp := getattr(param, "physical_type", None)) is not None:
205
+ data_type.append(tmp.base_data_type.name)
206
+ else:
207
+ data_type.append(None)
208
+ if isinstance(param, PhysicalConstantParameter):
209
+ if isinstance(param.physical_constant_value, bytes) or isinstance(
210
+ param.physical_constant_value, bytearray):
211
+ value.append(f"0x{param.physical_constant_value.hex().upper()}")
212
+ else:
213
+ value.append(f"{param.physical_constant_value!r}")
214
+ value_type.append('constant value')
215
+ elif isinstance(param, ValueParameter) and param.physical_default_value is not None:
216
+ if isinstance(param.physical_default_value, bytes) or isinstance(
217
+ param.physical_default_value, bytearray):
218
+ value.append(f"0x{param.physical_default_value.hex().upper()}")
219
+ else:
220
+ value.append(f"{param.physical_default_value!r}")
221
+ value_type.append('default value')
222
+ else:
223
+ value.append(None)
224
+ value_type.append(None)
225
+ else:
226
+ value.append(None)
227
+ data_type.append(None)
228
+ value_type.append(None)
229
+ dop.append(None)
230
+
231
+ return {
232
+ 'Name': name,
233
+ 'Byte Position': byte,
234
+ 'Bit Length': bit_length,
235
+ 'Semantic': semantic,
236
+ 'Parameter Type': param_type,
237
+ 'Data Type': data_type,
238
+ 'Value': value,
239
+ 'Value Description': value_type,
240
+ 'Linked DOP': dop
241
+ }
242
+
243
+
244
+ def print_dl_metrics(variants: List[DiagLayer]) -> None:
245
+
246
+ name = []
247
+ type = []
248
+ num_services = []
249
+ num_dops = []
250
+ num_comparams = []
251
+ for variant in variants:
252
+ assert isinstance(variant, DiagLayer)
253
+ all_services: List[Union[DiagService, SingleEcuJob]] = sorted(
254
+ variant.services, key=lambda x: x.short_name)
255
+ name.append(variant.short_name)
256
+ type.append(variant.variant_type.value)
257
+ num_services.append(len(all_services))
258
+ num_dops.append(len(variant.diag_data_dictionary_spec.data_object_props))
259
+ num_comparams.append(len(variant.comparams))
260
+
261
+ table = {
262
+ 'Name': name,
263
+ 'Variant Type': type,
264
+ 'Number of Services': num_services,
265
+ 'Number of DOPs': num_dops,
266
+ 'Number of communication parameters': num_comparams
267
+ }
268
+ print(tabulate(table, headers='keys', tablefmt='presto'))