odxtools 7.1.1__py3-none-any.whl → 7.2.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/__init__.py +6 -4
- odxtools/additionalaudience.py +3 -5
- odxtools/admindata.py +5 -7
- odxtools/audience.py +3 -5
- odxtools/basecomparam.py +3 -5
- odxtools/basicstructure.py +10 -17
- odxtools/cli/_parser_utils.py +1 -1
- odxtools/cli/_print_utils.py +3 -2
- odxtools/cli/compare.py +1 -1
- odxtools/companydata.py +5 -7
- odxtools/companydocinfo.py +7 -8
- odxtools/companyrevisioninfo.py +3 -5
- odxtools/companyspecificinfo.py +8 -9
- odxtools/comparam.py +4 -6
- odxtools/comparaminstance.py +6 -8
- odxtools/comparamspec.py +14 -13
- odxtools/comparamsubset.py +17 -16
- odxtools/complexcomparam.py +5 -7
- odxtools/compumethods/compuconst.py +31 -0
- odxtools/compumethods/compudefaultvalue.py +27 -0
- odxtools/compumethods/compuinternaltophys.py +39 -0
- odxtools/compumethods/compuinversevalue.py +7 -0
- odxtools/compumethods/compumethod.py +67 -12
- odxtools/compumethods/compuphystointernal.py +39 -0
- odxtools/compumethods/compuscale.py +15 -26
- odxtools/compumethods/createanycompumethod.py +14 -160
- odxtools/compumethods/identicalcompumethod.py +31 -6
- odxtools/compumethods/linearcompumethod.py +69 -189
- odxtools/compumethods/linearsegment.py +193 -0
- odxtools/compumethods/scalelinearcompumethod.py +132 -26
- odxtools/compumethods/tabintpcompumethod.py +119 -99
- odxtools/compumethods/texttablecompumethod.py +107 -43
- odxtools/createanydiagcodedtype.py +10 -67
- odxtools/database.py +68 -62
- odxtools/dataobjectproperty.py +10 -19
- odxtools/description.py +47 -0
- odxtools/determinenumberofitems.py +4 -5
- odxtools/diagcodedtype.py +29 -12
- odxtools/diagcomm.py +10 -6
- odxtools/diagdatadictionaryspec.py +20 -21
- odxtools/diaglayer.py +34 -5
- odxtools/diaglayercontainer.py +17 -11
- odxtools/diaglayerraw.py +20 -21
- odxtools/diagnostictroublecode.py +7 -8
- odxtools/diagservice.py +9 -7
- odxtools/docrevision.py +5 -7
- odxtools/dopbase.py +7 -8
- odxtools/dtcdop.py +5 -8
- odxtools/dynamicendmarkerfield.py +22 -9
- odxtools/dynamiclengthfield.py +5 -11
- odxtools/element.py +4 -3
- odxtools/endofpdufield.py +0 -2
- odxtools/environmentdatadescription.py +4 -6
- odxtools/exceptions.py +1 -1
- odxtools/field.py +9 -9
- odxtools/functionalclass.py +3 -5
- odxtools/inputparam.py +3 -5
- odxtools/leadinglengthinfotype.py +15 -2
- odxtools/loadfile.py +64 -0
- odxtools/minmaxlengthtype.py +20 -2
- odxtools/modification.py +3 -5
- odxtools/multiplexer.py +7 -14
- odxtools/multiplexercase.py +4 -6
- odxtools/multiplexerdefaultcase.py +4 -6
- odxtools/multiplexerswitchkey.py +4 -5
- odxtools/negoutputparam.py +3 -5
- odxtools/outputparam.py +3 -5
- odxtools/parameterinfo.py +3 -3
- odxtools/parameters/codedconstparameter.py +2 -14
- odxtools/parameters/lengthkeyparameter.py +3 -17
- odxtools/parameters/nrcconstparameter.py +2 -14
- odxtools/parameters/parameter.py +22 -22
- odxtools/parameters/parameterwithdop.py +6 -8
- odxtools/parameters/physicalconstantparameter.py +5 -8
- odxtools/parameters/reservedparameter.py +4 -3
- odxtools/parameters/tablekeyparameter.py +6 -9
- odxtools/parameters/tablestructparameter.py +6 -8
- odxtools/parameters/valueparameter.py +5 -8
- odxtools/paramlengthinfotype.py +19 -6
- odxtools/parentref.py +15 -1
- odxtools/physicaldimension.py +3 -5
- odxtools/progcode.py +18 -7
- odxtools/protstack.py +3 -5
- odxtools/relateddoc.py +7 -9
- odxtools/request.py +8 -0
- odxtools/response.py +8 -0
- odxtools/scaleconstr.py +3 -3
- odxtools/singleecujob.py +12 -10
- odxtools/snrefcontext.py +29 -0
- odxtools/specialdata.py +3 -5
- odxtools/specialdatagroup.py +5 -7
- odxtools/specialdatagroupcaption.py +3 -6
- odxtools/standardlengthtype.py +27 -2
- odxtools/state.py +3 -5
- odxtools/statechart.py +9 -11
- odxtools/statetransition.py +4 -9
- odxtools/staticfield.py +4 -8
- odxtools/table.py +7 -8
- odxtools/tablerow.py +7 -6
- odxtools/teammember.py +3 -5
- odxtools/templates/comparam-spec.odx-c.xml.jinja2 +2 -5
- odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +2 -5
- odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -5
- odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
- odxtools/templates/macros/printCompuMethod.xml.jinja2 +153 -0
- odxtools/templates/macros/printDOP.xml.jinja2 +10 -132
- odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
- odxtools/templates/macros/printElementId.xml.jinja2 +3 -3
- odxtools/templates/macros/printMux.xml.jinja2 +3 -2
- odxtools/templates/macros/printTable.xml.jinja2 +2 -3
- odxtools/unit.py +3 -5
- odxtools/unitgroup.py +3 -5
- odxtools/unitspec.py +9 -10
- odxtools/utils.py +1 -26
- odxtools/version.py +2 -2
- odxtools/{write_pdx_file.py → writepdxfile.py} +19 -10
- odxtools/xdoc.py +3 -5
- {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/METADATA +1 -1
- odxtools-7.2.0.dist-info/RECORD +192 -0
- {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/WHEEL +1 -1
- odxtools/createcompanydatas.py +0 -17
- odxtools/createsdgs.py +0 -19
- odxtools/load_file.py +0 -13
- odxtools/load_odx_d_file.py +0 -6
- odxtools/load_pdx_file.py +0 -8
- odxtools-7.1.1.dist-info/RECORD +0 -186
- /odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +0 -0
- {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/LICENSE +0 -0
- {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/entry_points.txt +0 -0
- {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from ..odxtypes import AtomicOdxType, DataType
|
7
|
+
|
8
|
+
|
9
|
+
@dataclass
|
10
|
+
class CompuConst:
|
11
|
+
v: Optional[str]
|
12
|
+
vt: Optional[str]
|
13
|
+
|
14
|
+
data_type: DataType
|
15
|
+
|
16
|
+
@staticmethod
|
17
|
+
def compuvalue_from_et(et_element: ElementTree.Element, *, data_type: DataType) -> "CompuConst":
|
18
|
+
|
19
|
+
v = et_element.findtext("V")
|
20
|
+
vt = et_element.findtext("VT")
|
21
|
+
|
22
|
+
return CompuConst(v=v, vt=vt, data_type=data_type)
|
23
|
+
|
24
|
+
def __post_init__(self) -> None:
|
25
|
+
self._value: Optional[AtomicOdxType] = self.vt
|
26
|
+
if self.v is not None:
|
27
|
+
self._value = self.data_type.from_string(self.v)
|
28
|
+
|
29
|
+
@property
|
30
|
+
def value(self) -> Optional[AtomicOdxType]:
|
31
|
+
return self._value
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from ..odxtypes import DataType
|
7
|
+
from ..utils import dataclass_fields_asdict
|
8
|
+
from .compuconst import CompuConst
|
9
|
+
from .compuinversevalue import CompuInverseValue
|
10
|
+
|
11
|
+
|
12
|
+
@dataclass
|
13
|
+
class CompuDefaultValue(CompuConst):
|
14
|
+
compu_inverse_value: Optional[CompuInverseValue]
|
15
|
+
|
16
|
+
@staticmethod
|
17
|
+
def compuvalue_from_et(et_element: ElementTree.Element, *,
|
18
|
+
data_type: DataType) -> "CompuDefaultValue":
|
19
|
+
kwargs = dataclass_fields_asdict(
|
20
|
+
CompuConst.compuvalue_from_et(et_element, data_type=data_type))
|
21
|
+
|
22
|
+
compu_inverse_value = None
|
23
|
+
if (civ_elem := et_element.find("COMPU-INVERSE-VALUE")) is not None:
|
24
|
+
compu_inverse_value = CompuInverseValue.compuvalue_from_et(
|
25
|
+
civ_elem, data_type=data_type)
|
26
|
+
|
27
|
+
return CompuDefaultValue(**kwargs, compu_inverse_value=compu_inverse_value)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import List, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from ..odxlink import OdxDocFragment
|
7
|
+
from ..odxtypes import DataType
|
8
|
+
from ..progcode import ProgCode
|
9
|
+
from .compudefaultvalue import CompuDefaultValue
|
10
|
+
from .compuscale import CompuScale
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass
|
14
|
+
class CompuInternalToPhys:
|
15
|
+
compu_scales: List[CompuScale]
|
16
|
+
prog_code: Optional[ProgCode]
|
17
|
+
compu_default_value: Optional[CompuDefaultValue]
|
18
|
+
|
19
|
+
@staticmethod
|
20
|
+
def compu_internal_to_phys_from_et(et_element: ElementTree.Element,
|
21
|
+
doc_frags: List[OdxDocFragment], *, internal_type: DataType,
|
22
|
+
physical_type: DataType) -> "CompuInternalToPhys":
|
23
|
+
compu_scales = [
|
24
|
+
CompuScale.compuscale_from_et(
|
25
|
+
cse, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
26
|
+
for cse in et_element.iterfind("COMPU-SCALES/COMPU-SCALE")
|
27
|
+
]
|
28
|
+
|
29
|
+
prog_code = None
|
30
|
+
if (pce := et_element.find("PROG-CODE")) is not None:
|
31
|
+
prog_code = ProgCode.from_et(pce, doc_frags)
|
32
|
+
|
33
|
+
compu_default_value = None
|
34
|
+
if (cdve := et_element.find("COMPU-DEFAULT-VALUE")) is not None:
|
35
|
+
compu_default_value = CompuDefaultValue.compuvalue_from_et(
|
36
|
+
cdve, data_type=physical_type)
|
37
|
+
|
38
|
+
return CompuInternalToPhys(
|
39
|
+
compu_scales=compu_scales, prog_code=prog_code, compu_default_value=compu_default_value)
|
@@ -1,26 +1,81 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from
|
3
|
+
from enum import Enum
|
4
|
+
from typing import List, Optional
|
5
|
+
from xml.etree import ElementTree
|
4
6
|
|
7
|
+
from ..exceptions import odxraise
|
8
|
+
from ..odxlink import OdxDocFragment
|
5
9
|
from ..odxtypes import AtomicOdxType, DataType
|
10
|
+
from .compuinternaltophys import CompuInternalToPhys
|
11
|
+
from .compuphystointernal import CompuPhysToInternal
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
"
|
10
|
-
"
|
11
|
-
"
|
12
|
-
"TEXTTABLE"
|
13
|
-
|
13
|
+
|
14
|
+
class CompuCategory(Enum):
|
15
|
+
IDENTICAL = "IDENTICAL"
|
16
|
+
LINEAR = "LINEAR"
|
17
|
+
SCALE_LINEAR = "SCALE-LINEAR"
|
18
|
+
TEXTTABLE = "TEXTTABLE"
|
19
|
+
COMPUCODE = "COMPUCODE"
|
20
|
+
TAB_INTP = "TAB-INTP"
|
21
|
+
RAT_FUNC = "RAT-FUNC"
|
22
|
+
SCALE_RAT_FUNC = "SCALE-RAT-FUNC"
|
14
23
|
|
15
24
|
|
16
25
|
@dataclass
|
17
26
|
class CompuMethod:
|
18
|
-
|
27
|
+
"""A compu method translates between the internal representation
|
28
|
+
of a value and their physical representation.
|
29
|
+
|
30
|
+
There are many compu methods, but all of them are specified using
|
31
|
+
the same mechanism: The conversion from internal to physical
|
32
|
+
quantities is specified using the COMPU-INTERNAL-TO-PHYS subtag,
|
33
|
+
and the inverse is covered by
|
34
|
+
COMPU-PHYS-TO-INTERNAL. Alternatively to directly specifying the
|
35
|
+
parameters needed for conversion, it is also possible to specify a
|
36
|
+
Java program which does the conversion (doing this excludes using
|
37
|
+
ODX in non-Java contexts, though).
|
38
|
+
|
39
|
+
For details, refer to ASAM specification MCD-2 D (ODX), section 7.3.6.6.
|
40
|
+
|
41
|
+
"""
|
42
|
+
|
43
|
+
category: CompuCategory
|
44
|
+
compu_internal_to_phys: Optional[CompuInternalToPhys]
|
45
|
+
compu_phys_to_internal: Optional[CompuPhysToInternal]
|
46
|
+
|
19
47
|
physical_type: DataType
|
48
|
+
internal_type: DataType
|
20
49
|
|
21
|
-
@
|
22
|
-
def
|
23
|
-
|
50
|
+
@staticmethod
|
51
|
+
def compu_method_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
|
52
|
+
internal_type: DataType, physical_type: DataType) -> "CompuMethod":
|
53
|
+
cat_text = et_element.findtext("CATEGORY")
|
54
|
+
if cat_text is None:
|
55
|
+
odxraise("No category specified for compu method")
|
56
|
+
cat_text = "IDENTICAL"
|
57
|
+
|
58
|
+
try:
|
59
|
+
category = CompuCategory(cat_text)
|
60
|
+
except ValueError:
|
61
|
+
odxraise(f"Encountered compu method of unknown category '{cat_text}'")
|
62
|
+
category = CompuCategory.IDENTICAL
|
63
|
+
|
64
|
+
compu_internal_to_phys = None
|
65
|
+
if (citp_elem := et_element.find("COMPU-INTERNAL-TO-PHYS")) is not None:
|
66
|
+
compu_internal_to_phys = CompuInternalToPhys.compu_internal_to_phys_from_et(
|
67
|
+
citp_elem, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
68
|
+
compu_phys_to_internal = None
|
69
|
+
if (cpti_elem := et_element.find("COMPU-PHYS-TO-INTERNAL")) is not None:
|
70
|
+
compu_phys_to_internal = CompuPhysToInternal.compu_phys_to_internal_from_et(
|
71
|
+
cpti_elem, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
72
|
+
|
73
|
+
return CompuMethod(
|
74
|
+
category=category,
|
75
|
+
compu_internal_to_phys=compu_internal_to_phys,
|
76
|
+
compu_phys_to_internal=compu_phys_to_internal,
|
77
|
+
physical_type=physical_type,
|
78
|
+
internal_type=internal_type)
|
24
79
|
|
25
80
|
def convert_physical_to_internal(self, physical_value: AtomicOdxType) -> AtomicOdxType:
|
26
81
|
raise NotImplementedError()
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import List, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from ..odxlink import OdxDocFragment
|
7
|
+
from ..odxtypes import DataType
|
8
|
+
from ..progcode import ProgCode
|
9
|
+
from .compudefaultvalue import CompuDefaultValue
|
10
|
+
from .compuscale import CompuScale
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass
|
14
|
+
class CompuPhysToInternal:
|
15
|
+
compu_scales: List[CompuScale]
|
16
|
+
prog_code: Optional[ProgCode]
|
17
|
+
compu_default_value: Optional[CompuDefaultValue]
|
18
|
+
|
19
|
+
@staticmethod
|
20
|
+
def compu_phys_to_internal_from_et(et_element: ElementTree.Element,
|
21
|
+
doc_frags: List[OdxDocFragment], *, internal_type: DataType,
|
22
|
+
physical_type: DataType) -> "CompuPhysToInternal":
|
23
|
+
compu_scales = [
|
24
|
+
CompuScale.compuscale_from_et(
|
25
|
+
cse, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
26
|
+
for cse in et_element.iterfind("COMPU-SCALES/COMPU-SCALE")
|
27
|
+
]
|
28
|
+
|
29
|
+
prog_code = None
|
30
|
+
if (pce := et_element.find("PROG-CODE")) is not None:
|
31
|
+
prog_code = ProgCode.from_et(pce, doc_frags)
|
32
|
+
|
33
|
+
compu_default_value = None
|
34
|
+
if (cdve := et_element.find("COMPU-DEFAULT-VALUE")) is not None:
|
35
|
+
compu_default_value = CompuDefaultValue.compuvalue_from_et(
|
36
|
+
cdve, data_type=internal_type)
|
37
|
+
|
38
|
+
return CompuPhysToInternal(
|
39
|
+
compu_scales=compu_scales, prog_code=prog_code, compu_default_value=compu_default_value)
|
@@ -3,9 +3,11 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
+
from ..description import Description
|
6
7
|
from ..odxlink import OdxDocFragment
|
7
8
|
from ..odxtypes import AtomicOdxType, DataType
|
8
|
-
from
|
9
|
+
from .compuconst import CompuConst
|
10
|
+
from .compuinversevalue import CompuInverseValue
|
9
11
|
from .compurationalcoeffs import CompuRationalCoeffs
|
10
12
|
from .limit import Limit
|
11
13
|
|
@@ -13,33 +15,14 @@ from .limit import Limit
|
|
13
15
|
@dataclass
|
14
16
|
class CompuScale:
|
15
17
|
"""A COMPU-SCALE represents one value range of a COMPU-METHOD.
|
16
|
-
|
17
|
-
Example:
|
18
|
-
|
19
|
-
For a TEXTTABLE compu method a compu scale within COMPU-INTERNAL-TO-PHYS
|
20
|
-
can be defined with
|
21
|
-
```
|
22
|
-
scale = CompuScale(
|
23
|
-
short_label="example_label", # optional: provide a label
|
24
|
-
description="<p>fancy description</p>", # optional: provide a description
|
25
|
-
lower_limit=Limit(0), # required: lower limit
|
26
|
-
upper_limit=Limit(3), # required: upper limit
|
27
|
-
compu_inverse_value=2, # required if lower_limit != upper_limit
|
28
|
-
compu_const="true", # required: physical value to be shown to the user
|
29
|
-
)
|
30
|
-
```
|
31
|
-
|
32
|
-
Almost all attributes are optional but there are compu-method-specific restrictions.
|
33
|
-
E.g., lower_limit must always be defined unless the COMPU-METHOD is of CATEGORY LINEAR or RAT-FUNC.
|
34
|
-
Either `compu_const` or `compu_rational_coeffs` must be defined but never both.
|
35
18
|
"""
|
36
19
|
|
37
20
|
short_label: Optional[str]
|
38
|
-
description: Optional[
|
21
|
+
description: Optional[Description]
|
39
22
|
lower_limit: Optional[Limit]
|
40
23
|
upper_limit: Optional[Limit]
|
41
|
-
compu_inverse_value: Optional[
|
42
|
-
compu_const: Optional[
|
24
|
+
compu_inverse_value: Optional[CompuInverseValue]
|
25
|
+
compu_const: Optional[CompuConst]
|
43
26
|
compu_rational_coeffs: Optional[CompuRationalCoeffs]
|
44
27
|
|
45
28
|
# the following two attributes are not specified for COMPU-SCALE
|
@@ -52,15 +35,21 @@ class CompuScale:
|
|
52
35
|
def compuscale_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
|
53
36
|
internal_type: DataType, physical_type: DataType) -> "CompuScale":
|
54
37
|
short_label = et_element.findtext("SHORT-LABEL")
|
55
|
-
description =
|
38
|
+
description = Description.from_et(et_element.find("DESC"), doc_frags)
|
56
39
|
|
57
40
|
lower_limit = Limit.limit_from_et(
|
58
41
|
et_element.find("LOWER-LIMIT"), doc_frags, value_type=internal_type)
|
59
42
|
upper_limit = Limit.limit_from_et(
|
60
43
|
et_element.find("UPPER-LIMIT"), doc_frags, value_type=internal_type)
|
61
44
|
|
62
|
-
compu_inverse_value =
|
63
|
-
|
45
|
+
compu_inverse_value = None
|
46
|
+
if (cive := et_element.find("COMPU-INVERSE-VALUE")) is not None:
|
47
|
+
compu_inverse_value = CompuInverseValue.compuvalue_from_et(
|
48
|
+
cive, data_type=internal_type)
|
49
|
+
|
50
|
+
compu_const = None
|
51
|
+
if (cce := et_element.find("COMPU-CONST")) is not None:
|
52
|
+
compu_const = CompuConst.compuvalue_from_et(cce, data_type=physical_type)
|
64
53
|
|
65
54
|
compu_rational_coeffs: Optional[CompuRationalCoeffs] = None
|
66
55
|
if (crc_elem := et_element.find("COMPU-RATIONAL-COEFFS")) is not None:
|
@@ -1,184 +1,38 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
from typing import
|
2
|
+
from typing import List
|
3
3
|
from xml.etree import ElementTree
|
4
4
|
|
5
|
-
from ..exceptions import
|
5
|
+
from ..exceptions import odxraise, odxrequire
|
6
6
|
from ..odxlink import OdxDocFragment
|
7
7
|
from ..odxtypes import DataType
|
8
8
|
from .compumethod import CompuMethod
|
9
|
-
from .compuscale import CompuScale
|
10
9
|
from .identicalcompumethod import IdenticalCompuMethod
|
11
|
-
from .limit import Limit
|
12
10
|
from .linearcompumethod import LinearCompuMethod
|
13
11
|
from .scalelinearcompumethod import ScaleLinearCompuMethod
|
14
12
|
from .tabintpcompumethod import TabIntpCompuMethod
|
15
13
|
from .texttablecompumethod import TexttableCompuMethod
|
16
14
|
|
17
15
|
|
18
|
-
def _parse_compu_scale_to_linear_compu_method(
|
19
|
-
et_element: ElementTree.Element,
|
20
|
-
doc_frags: List[OdxDocFragment],
|
21
|
-
*,
|
22
|
-
internal_type: DataType,
|
23
|
-
physical_type: DataType,
|
24
|
-
is_scale_linear: bool = False,
|
25
|
-
**kwargs: Any,
|
26
|
-
) -> LinearCompuMethod:
|
27
|
-
odxassert(physical_type in [
|
28
|
-
DataType.A_FLOAT32,
|
29
|
-
DataType.A_FLOAT64,
|
30
|
-
DataType.A_INT32,
|
31
|
-
DataType.A_UINT32,
|
32
|
-
])
|
33
|
-
odxassert(internal_type in [
|
34
|
-
DataType.A_FLOAT32,
|
35
|
-
DataType.A_FLOAT64,
|
36
|
-
DataType.A_INT32,
|
37
|
-
DataType.A_UINT32,
|
38
|
-
])
|
39
|
-
|
40
|
-
if physical_type.python_type == float:
|
41
|
-
computation_python_type = physical_type.from_string
|
42
|
-
else:
|
43
|
-
computation_python_type = internal_type.from_string
|
44
|
-
|
45
|
-
kwargs = kwargs.copy()
|
46
|
-
kwargs["internal_type"] = internal_type
|
47
|
-
kwargs["physical_type"] = physical_type
|
48
|
-
|
49
|
-
coeffs = odxrequire(et_element.find("COMPU-RATIONAL-COEFFS"))
|
50
|
-
nums = coeffs.iterfind("COMPU-NUMERATOR/V")
|
51
|
-
|
52
|
-
offset = computation_python_type(odxrequire(next(nums).text))
|
53
|
-
factor_el = next(nums, None)
|
54
|
-
factor = computation_python_type(odxrequire(factor_el.text) if factor_el is not None else "0")
|
55
|
-
denominator = 1.0
|
56
|
-
if (string := coeffs.findtext("COMPU-DENOMINATOR/V")) is not None:
|
57
|
-
denominator = float(string)
|
58
|
-
if denominator == 0:
|
59
|
-
odxraise("CompuMethod: A denominator of zero will lead to divisions by zero.")
|
60
|
-
|
61
|
-
# Read lower limit
|
62
|
-
internal_lower_limit = Limit.limit_from_et(
|
63
|
-
et_element.find("LOWER-LIMIT"),
|
64
|
-
doc_frags,
|
65
|
-
value_type=internal_type,
|
66
|
-
)
|
67
|
-
|
68
|
-
kwargs["internal_lower_limit"] = internal_lower_limit
|
69
|
-
|
70
|
-
# Read upper limit
|
71
|
-
internal_upper_limit = Limit.limit_from_et(
|
72
|
-
et_element.find("UPPER-LIMIT"),
|
73
|
-
doc_frags,
|
74
|
-
value_type=internal_type,
|
75
|
-
)
|
76
|
-
|
77
|
-
kwargs["internal_upper_limit"] = internal_upper_limit
|
78
|
-
kwargs["denominator"] = denominator
|
79
|
-
kwargs["factor"] = factor
|
80
|
-
kwargs["offset"] = offset
|
81
|
-
|
82
|
-
return LinearCompuMethod(**kwargs)
|
83
|
-
|
84
|
-
|
85
|
-
def create_compu_default_value(et_element: Optional[ElementTree.Element],
|
86
|
-
doc_frags: List[OdxDocFragment], internal_type: DataType, *,
|
87
|
-
physical_type: DataType) -> Optional[CompuScale]:
|
88
|
-
if et_element is None:
|
89
|
-
return None
|
90
|
-
compu_const = physical_type.create_from_et(et_element)
|
91
|
-
scale = CompuScale.compuscale_from_et(
|
92
|
-
et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
93
|
-
scale.compu_const = compu_const
|
94
|
-
return scale
|
95
|
-
|
96
|
-
|
97
16
|
def create_any_compu_method_from_et(et_element: ElementTree.Element,
|
98
17
|
doc_frags: List[OdxDocFragment], *, internal_type: DataType,
|
99
18
|
physical_type: DataType) -> CompuMethod:
|
100
|
-
compu_category = et_element.findtext("CATEGORY")
|
101
|
-
odxassert(compu_category in [
|
102
|
-
"IDENTICAL",
|
103
|
-
"LINEAR",
|
104
|
-
"SCALE-LINEAR",
|
105
|
-
"TEXTTABLE",
|
106
|
-
"COMPUCODE",
|
107
|
-
"TAB-INTP",
|
108
|
-
"RAT-FUNC",
|
109
|
-
"SCALE-RAT-FUNC",
|
110
|
-
])
|
111
|
-
|
112
|
-
if et_element.find("COMPU-PHYS-TO-INTERNAL") is not None: # TODO: Is this never used?
|
113
|
-
raise NotImplementedError(f"Found COMPU-PHYS-TO-INTERNAL for category {compu_category}")
|
114
|
-
|
115
|
-
kwargs: Dict[str, Any] = {
|
116
|
-
"physical_type": physical_type,
|
117
|
-
"internal_type": internal_type,
|
118
|
-
}
|
19
|
+
compu_category = odxrequire(et_element.findtext("CATEGORY"))
|
119
20
|
|
120
21
|
if compu_category == "IDENTICAL":
|
121
|
-
|
122
|
-
internal_type
|
123
|
-
(internal_type in [DataType.A_ASCIISTRING, DataType.A_UTF8STRING] and
|
124
|
-
physical_type == DataType.A_UNICODE2STRING),
|
125
|
-
f"Internal type '{internal_type}' and physical type '{physical_type}'"
|
126
|
-
f" must be the same for compu methods of category '{compu_category}'")
|
127
|
-
return IdenticalCompuMethod(internal_type=internal_type, physical_type=physical_type)
|
128
|
-
|
129
|
-
if compu_category == "TEXTTABLE":
|
130
|
-
odxassert(physical_type == DataType.A_UNICODE2STRING)
|
131
|
-
compu_internal_to_phys = odxrequire(et_element.find("COMPU-INTERNAL-TO-PHYS"))
|
132
|
-
|
133
|
-
internal_to_phys: List[CompuScale] = []
|
134
|
-
for scale_elem in compu_internal_to_phys.iterfind("COMPU-SCALES/COMPU-SCALE"):
|
135
|
-
internal_to_phys.append(
|
136
|
-
CompuScale.compuscale_from_et(
|
137
|
-
scale_elem, doc_frags, internal_type=internal_type,
|
138
|
-
physical_type=physical_type))
|
139
|
-
compu_default_value = create_compu_default_value(
|
140
|
-
et_element.find("COMPU-INTERNAL-TO-PHYS/COMPU-DEFAULT-VALUE"), doc_frags, **kwargs)
|
141
|
-
|
142
|
-
return TexttableCompuMethod(
|
143
|
-
internal_to_phys=internal_to_phys,
|
144
|
-
compu_default_value=compu_default_value,
|
145
|
-
**kwargs,
|
146
|
-
)
|
147
|
-
|
22
|
+
return IdenticalCompuMethod.compu_method_from_et(
|
23
|
+
et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
148
24
|
elif compu_category == "LINEAR":
|
149
|
-
|
150
|
-
|
151
|
-
scale_elem = odxrequire(et_element.find("COMPU-INTERNAL-TO-PHYS/COMPU-SCALES/COMPU-SCALE"))
|
152
|
-
return _parse_compu_scale_to_linear_compu_method(scale_elem, doc_frags, **kwargs)
|
153
|
-
|
25
|
+
return LinearCompuMethod.compu_method_from_et(
|
26
|
+
et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
154
27
|
elif compu_category == "SCALE-LINEAR":
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
]
|
161
|
-
return ScaleLinearCompuMethod(linear_methods=linear_methods, **kwargs)
|
162
|
-
|
28
|
+
return ScaleLinearCompuMethod.compu_method_from_et(
|
29
|
+
et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
30
|
+
elif compu_category == "TEXTTABLE":
|
31
|
+
return TexttableCompuMethod.compu_method_from_et(
|
32
|
+
et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
163
33
|
elif compu_category == "TAB-INTP":
|
164
|
-
|
165
|
-
|
166
|
-
for scale_elem in et_element.iterfind("COMPU-INTERNAL-TO-PHYS/COMPU-SCALES/COMPU-SCALE"):
|
167
|
-
internal_point = internal_type.from_string(
|
168
|
-
odxrequire(scale_elem.findtext("LOWER-LIMIT")))
|
169
|
-
physical_point = physical_type.create_from_et(
|
170
|
-
odxrequire(scale_elem.find("COMPU-CONST")))
|
171
|
-
|
172
|
-
if not isinstance(internal_point, (float, int)):
|
173
|
-
odxraise()
|
174
|
-
if not isinstance(physical_point, (float, int)):
|
175
|
-
odxraise()
|
176
|
-
|
177
|
-
internal_points.append(internal_point)
|
178
|
-
physical_points.append(physical_point)
|
179
|
-
|
180
|
-
return TabIntpCompuMethod(
|
181
|
-
internal_points=internal_points, physical_points=physical_points, **kwargs)
|
34
|
+
return TabIntpCompuMethod.compu_method_from_et(
|
35
|
+
et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
182
36
|
|
183
37
|
# TODO: Implement all categories (never instantiate the CompuMethod base class!)
|
184
38
|
odxraise(f"Warning: Computation category {compu_category} is not implemented!")
|
@@ -1,16 +1,41 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
+
from typing import List
|
4
|
+
from xml.etree import ElementTree
|
3
5
|
|
4
|
-
from ..
|
5
|
-
from
|
6
|
+
from ..exceptions import odxassert
|
7
|
+
from ..odxlink import OdxDocFragment
|
8
|
+
from ..odxtypes import AtomicOdxType, DataType
|
9
|
+
from ..utils import dataclass_fields_asdict
|
10
|
+
from .compumethod import CompuMethod
|
6
11
|
|
7
12
|
|
8
13
|
@dataclass
|
9
14
|
class IdenticalCompuMethod(CompuMethod):
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
"""Identical compu methods just pass through the internal value.
|
16
|
+
|
17
|
+
For details, refer to ASAM specification MCD-2 D (ODX), section 7.3.6.6.2.
|
18
|
+
"""
|
19
|
+
|
20
|
+
@staticmethod
|
21
|
+
def compu_method_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
|
22
|
+
internal_type: DataType,
|
23
|
+
physical_type: DataType) -> "IdenticalCompuMethod":
|
24
|
+
cm = CompuMethod.compu_method_from_et(
|
25
|
+
et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
|
26
|
+
kwargs = dataclass_fields_asdict(cm)
|
27
|
+
|
28
|
+
odxassert(
|
29
|
+
internal_type == physical_type or
|
30
|
+
(internal_type
|
31
|
+
in [DataType.A_ASCIISTRING, DataType.A_UTF8STRING, DataType.A_UNICODE2STRING] and
|
32
|
+
physical_type
|
33
|
+
in [DataType.A_ASCIISTRING, DataType.A_UTF8STRING, DataType.A_UNICODE2STRING]),
|
34
|
+
f"Internal type and physical type must be the same for compu methods of category "
|
35
|
+
f"'{cm.category}' (internal type: '{internal_type.value}', physical type: "
|
36
|
+
f"'{physical_type.value}')")
|
37
|
+
|
38
|
+
return IdenticalCompuMethod(**kwargs)
|
14
39
|
|
15
40
|
def convert_physical_to_internal(self, physical_value: AtomicOdxType) -> AtomicOdxType:
|
16
41
|
return physical_value
|