odxtools 9.4.0__py3-none-any.whl → 9.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.
- odxtools/basevariantpattern.py +38 -0
- odxtools/comparamsubset.py +7 -3
- odxtools/dataobjectproperty.py +2 -2
- odxtools/diaglayers/basevariant.py +5 -0
- odxtools/diaglayers/basevariantraw.py +7 -1
- odxtools/diaglayers/ecuvariant.py +16 -0
- odxtools/ecuvariantpattern.py +20 -9
- odxtools/encodestate.py +3 -2
- odxtools/matchingbasevariantparameter.py +38 -0
- odxtools/matchingparameter.py +108 -27
- odxtools/minmaxlengthtype.py +3 -3
- odxtools/odxtypes.py +4 -3
- odxtools/standardlengthtype.py +10 -10
- odxtools/subcomponent.py +6 -3
- odxtools/templates/macros/printBaseVariant.xml.jinja2 +4 -9
- odxtools/templates/macros/printBaseVariantPattern.xml.jinja2 +32 -0
- odxtools/templates/macros/printEcuVariantPattern.xml.jinja2 +7 -6
- odxtools/utils.py +4 -0
- odxtools/variantmatcher.py +209 -0
- odxtools/variantpattern.py +38 -0
- odxtools/version.py +9 -4
- {odxtools-9.4.0.dist-info → odxtools-9.5.0.dist-info}/METADATA +1 -1
- {odxtools-9.4.0.dist-info → odxtools-9.5.0.dist-info}/RECORD +27 -24
- {odxtools-9.4.0.dist-info → odxtools-9.5.0.dist-info}/WHEEL +1 -1
- odxtools/createecuvariantpatterns.py +0 -18
- odxtools/ecuvariantmatcher.py +0 -171
- {odxtools-9.4.0.dist-info → odxtools-9.5.0.dist-info}/LICENSE +0 -0
- {odxtools-9.4.0.dist-info → odxtools-9.5.0.dist-info}/entry_points.txt +0 -0
- {odxtools-9.4.0.dist-info → odxtools-9.5.0.dist-info}/top_level.txt +0 -0
odxtools/ecuvariantmatcher.py
DELETED
@@ -1,171 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: MIT
|
2
|
-
from enum import Enum
|
3
|
-
from typing import Dict, Generator, List, Optional
|
4
|
-
|
5
|
-
from .diaglayers.diaglayer import DiagLayer
|
6
|
-
from .diaglayers.diaglayertype import DiagLayerType
|
7
|
-
from .diaglayers.ecuvariant import EcuVariant
|
8
|
-
from .diagservice import DiagService
|
9
|
-
from .exceptions import OdxError, odxassert, odxrequire
|
10
|
-
from .matchingparameter import MatchingParameter
|
11
|
-
from .odxtypes import ParameterValue
|
12
|
-
from .response import Response
|
13
|
-
|
14
|
-
|
15
|
-
class EcuVariantMatcher:
|
16
|
-
"""EcuVariantMatcher implements the matching algorithm of ecu variants according to their
|
17
|
-
ECU-VARIANT-PATTERN according to ISO 22901-1.
|
18
|
-
|
19
|
-
Usage (example):
|
20
|
-
|
21
|
-
```python
|
22
|
-
|
23
|
-
# initialize the matcher with a list of ecu variants,
|
24
|
-
# i.e., DiagLayer instances of variant_type == DiagLayerType.ECU-VARIANT
|
25
|
-
matcher = EcuVariantMatcher(ecu_variant_candidates=[...], use_cache=use_cache)
|
26
|
-
|
27
|
-
# run the request loop to obtain responses for every request
|
28
|
-
for req in matcher.request_loop():
|
29
|
-
resp = ... # make a UDS request
|
30
|
-
matcher.evaluate(resp)
|
31
|
-
|
32
|
-
# result
|
33
|
-
if matcher.has_match()
|
34
|
-
match = matcher.get_active_ecu_variant()
|
35
|
-
```
|
36
|
-
"""
|
37
|
-
|
38
|
-
class State(Enum):
|
39
|
-
PENDING = 0
|
40
|
-
NO_MATCH = 1
|
41
|
-
MATCH = 2
|
42
|
-
|
43
|
-
@staticmethod
|
44
|
-
def get_ident_service(diag_layer: DiagLayer, matching_param: MatchingParameter) -> DiagService:
|
45
|
-
service_name = matching_param.diag_comm_snref
|
46
|
-
service = odxrequire(diag_layer.services.get(service_name))
|
47
|
-
return service
|
48
|
-
|
49
|
-
@staticmethod
|
50
|
-
def encode_ident_request(diag_layer: DiagLayer, matching_param: MatchingParameter) -> bytes:
|
51
|
-
service = EcuVariantMatcher.get_ident_service(diag_layer, matching_param)
|
52
|
-
return bytes(service.encode_request())
|
53
|
-
|
54
|
-
@staticmethod
|
55
|
-
def decode_ident_response(
|
56
|
-
diag_layer: DiagLayer,
|
57
|
-
matching_param: MatchingParameter,
|
58
|
-
response_bytes: bytes,
|
59
|
-
) -> str:
|
60
|
-
"""Decode a binary response and extract the identification string according
|
61
|
-
to the snref or snpathref of the matching_param.
|
62
|
-
"""
|
63
|
-
service = EcuVariantMatcher.get_ident_service(diag_layer, matching_param)
|
64
|
-
|
65
|
-
# ISO 22901 requires that snref or snpathref is resolvable in at least one
|
66
|
-
# POS-RESPONSE or NEG-RESPONSE
|
67
|
-
pos_neg_responses: List[Response] = []
|
68
|
-
if service.positive_responses is not None:
|
69
|
-
pos_neg_responses.extend(service.positive_responses)
|
70
|
-
if service.negative_responses is not None:
|
71
|
-
pos_neg_responses.extend(service.negative_responses)
|
72
|
-
|
73
|
-
for any_response in pos_neg_responses:
|
74
|
-
decoded_val: Optional[ParameterValue] = any_response.decode(response_bytes)
|
75
|
-
# disassemble snref / snpathref
|
76
|
-
path_ref = matching_param.out_param_if.split(".")
|
77
|
-
for ref in path_ref:
|
78
|
-
if isinstance(decoded_val, dict) and ref in decoded_val:
|
79
|
-
decoded_val = decoded_val[ref]
|
80
|
-
else:
|
81
|
-
decoded_val = None
|
82
|
-
break
|
83
|
-
|
84
|
-
if decoded_val is not None:
|
85
|
-
if isinstance(decoded_val, str) or isinstance(decoded_val, int):
|
86
|
-
return str(decoded_val)
|
87
|
-
|
88
|
-
raise OdxError(f"The snref or snpathref '{matching_param.out_param_if}' is cannot be \
|
89
|
-
resolved for any positive or negative response.")
|
90
|
-
|
91
|
-
def __init__(self, ecu_variant_candidates: List[EcuVariant], use_cache: bool = True):
|
92
|
-
|
93
|
-
self.ecus = ecu_variant_candidates
|
94
|
-
for ecu in self.ecus:
|
95
|
-
odxassert(ecu.variant_type == DiagLayerType.ECU_VARIANT)
|
96
|
-
|
97
|
-
self.use_cache = use_cache
|
98
|
-
self.req_resp_cache: Dict[bytes, bytes] = {}
|
99
|
-
self._recent_ident_response: Optional[bytes] = None
|
100
|
-
|
101
|
-
self._state = EcuVariantMatcher.State.PENDING
|
102
|
-
|
103
|
-
def request_loop(self) -> Generator[bytes, None, None]:
|
104
|
-
"""The request loop yields byte sequences of requests, which shall be executed within the
|
105
|
-
loop body. It is required to pass the response back to the matcher using the evaluate method.
|
106
|
-
"""
|
107
|
-
if not self.is_pending():
|
108
|
-
return
|
109
|
-
|
110
|
-
for ecu in self.ecus:
|
111
|
-
any_match = False
|
112
|
-
for pattern in ecu.ecu_variant_patterns:
|
113
|
-
all_match = True
|
114
|
-
for matching_param in pattern.matching_parameters:
|
115
|
-
req_bytes = bytes(EcuVariantMatcher.encode_ident_request(ecu, matching_param))
|
116
|
-
if self.use_cache and req_bytes in self.req_resp_cache:
|
117
|
-
resp_bytes = self.req_resp_cache[req_bytes]
|
118
|
-
else:
|
119
|
-
yield req_bytes
|
120
|
-
resp_bytes = self._get_ident_response()
|
121
|
-
self._update_cache(req_bytes, resp_bytes)
|
122
|
-
ident_val = EcuVariantMatcher.decode_ident_response(
|
123
|
-
ecu, matching_param, resp_bytes)
|
124
|
-
all_match &= matching_param.is_match(ident_val)
|
125
|
-
if all_match:
|
126
|
-
any_match = True
|
127
|
-
break
|
128
|
-
if any_match:
|
129
|
-
self._state = EcuVariantMatcher.State.MATCH
|
130
|
-
self._match = ecu
|
131
|
-
break
|
132
|
-
if self.is_pending():
|
133
|
-
# no pattern has matched for any ecu variant
|
134
|
-
self._state = EcuVariantMatcher.State.NO_MATCH
|
135
|
-
|
136
|
-
def evaluate(self, resp_bytes: bytes) -> None:
|
137
|
-
"""Update the matcher with the response to a requst.
|
138
|
-
|
139
|
-
Warning: Use this method EXACTLY once within the loop body of the request loop.
|
140
|
-
"""
|
141
|
-
self._recent_ident_response = bytes(resp_bytes)
|
142
|
-
|
143
|
-
def is_pending(self) -> bool:
|
144
|
-
"""True iff request loop has not yet been run."""
|
145
|
-
return self._state == EcuVariantMatcher.State.PENDING
|
146
|
-
|
147
|
-
def has_match(self) -> bool:
|
148
|
-
"""Returns true iff the non-pending matcher found a matching ecu variant.
|
149
|
-
|
150
|
-
Raises a runtime error if the matcher is pending.
|
151
|
-
"""
|
152
|
-
if self.is_pending():
|
153
|
-
raise RuntimeError(
|
154
|
-
"EcuVariantMatcher is pending. Run the request_loop to determine the active ecu variant."
|
155
|
-
)
|
156
|
-
return self._state == EcuVariantMatcher.State.MATCH
|
157
|
-
|
158
|
-
def get_active_ecu_variant(self) -> DiagLayer:
|
159
|
-
"""Returns the matched, i.e., active ecu variant if such a variant has been found."""
|
160
|
-
odxassert(self.has_match())
|
161
|
-
return self._match
|
162
|
-
|
163
|
-
def _update_cache(self, req_bytes: bytes, resp_bytes: bytes) -> None:
|
164
|
-
if self.use_cache:
|
165
|
-
self.req_resp_cache[req_bytes] = resp_bytes
|
166
|
-
|
167
|
-
def _get_ident_response(self) -> bytes:
|
168
|
-
if not self._recent_ident_response:
|
169
|
-
raise RuntimeError(
|
170
|
-
"No response available. Did you forget to call 'evaluate()' in a loop?")
|
171
|
-
return self._recent_ident_response
|
File without changes
|
File without changes
|
File without changes
|