8000 Put classes representing XML tag types into separate files by andlaus · Pull Request #403 · mercedes-benz/odxtools · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Put classes representing XML tag types into separate files #403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions examples/somersaultecu.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
from odxtools.comparaminstance import ComparamInstance
from odxtools.comparamspec import ComparamSpec
from odxtools.comparamsubset import ComparamSubset
from odxtools.compumethods.compucategory import CompuCategory
from odxtools.compumethods.compuconst import CompuConst
from odxtools.compumethods.compuinternaltophys import CompuInternalToPhys
from odxtools.compumethods.compumethod import CompuCategory, CompuMethod
from odxtools.compumethods.compumethod import CompuMethod
from odxtools.compumethods.compuscale import CompuScale
from odxtools.compumethods.identicalcompumethod import IdenticalCompuMethod
from odxtools.compumethods.limit import Limit
Expand Down Expand Up @@ -70,7 +71,8 @@
from odxtools.tablerow import TableRow
from odxtools.teammember import TeamMember
from odxtools.unit import Unit
from odxtools.unitgroup import UnitGroup, UnitGroupCategory
from odxtools.unitgroup import UnitGroup
from odxtools.unitgroupcategory import UnitGroupCategory
from odxtools.unitspec import UnitSpec
from odxtools.xdoc import XDoc

Expand Down
8 changes: 8 additions & 0 deletions odxtools/addressing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: MIT
from enum import Enum


class Addressing(Enum):
FUNCTIONAL = "FUNCTIONAL"
PHYSICAL = "PHYSICAL"
FUNCTIONAL_OR_PHYSICAL = "FUNCTIONAL-OR-PHYSICAL"
17 changes: 2 additions & 15 deletions odxtools/basecomparam.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,17 @@
# SPDX-License-Identifier: MIT
from dataclasses import dataclass
from enum import Enum
from typing import Any, Dict, List, Optional, cast
from xml.etree import ElementTree

from .element import IdentifiableElement
from .exceptions import odxraise, odxrequire
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
from .snrefcontext import SnRefContext
from .standardizationlevel import StandardizationLevel
from .usage import Usage
from .utils import dataclass_fields_asdict


class StandardizationLevel(Enum):
STANDARD = "STANDARD"
OEM_SPECIFIC = "OEM-SPECIFIC"
OPTIONAL = "OPTIONAL"
OEM_OPTIONAL = "OEM-OPTIONAL"


class Usage(Enum):
ECU_SOFTWARE = "ECU-SOFTWARE"
ECU_COMM = "ECU-COMM"
APPLICATION = "APPLICATION"
TESTER = "TESTER"


@dataclass
class BaseComparam(IdentifiableElement):
param_class: str
Expand Down
7 changes: 4 additions & 3 deletions odxtools/basicstructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

from typing_extensions import override

from .codec import (composite_codec_decode_from_pdu, composite_codec_encode_into_pdu,
composite_codec_get_free_parameters, composite_codec_get_required_parameters,
composite_codec_get_static_bit_length)
from .complexdop import ComplexDop
from .compositecodec import (composite_codec_decode_from_pdu, composite_codec_encode_into_pdu,
composite_codec_get_free_parameters,
composite_codec_get_required_parameters,
composite_codec_get_static_bit_length)
from .decodestate import DecodeState
from .encodestate import EncodeState
from .exceptions import DecodeError, odxraise
Expand Down
185 changes: 1 addition & 184 deletions odxtools/codec.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
# SPDX-License-Identifier: MIT
import typing
from typing import List, Optional, runtime_checkable
from typing import Optional, runtime_checkable

from .decodestate import DecodeState
from .encodestate import EncodeState
from .exceptions import EncodeError, odxraise
from .odxtypes import ParameterValue
from .parameters.codedconstparameter import CodedConstParameter
from .parameters.matchingrequestparameter import MatchingRequestParameter
from .parameters.parameter import Parameter
from .parameters.physicalconstantparameter import PhysicalConstantParameter


@runtime_checkable
Expand All @@ -31,181 +26,3 @@ def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:

def get_static_bit_length(self) -> Optional[int]:
...


@runtime_checkable
class CompositeCodec(Codec, typing.Protocol):
"""Any object which can be en- or decoded to be transferred over
the wire which is composed of multiple parameter implements this
API.

"""

@property
def parameters(self) -> List[Parameter]:
return []

@property
def required_parameters(self) -> List[Parameter]:
return []

@property
def free_parameters(self) -> List[Parameter]:
return []


# some helper functions useful for composite codec objects
def composite_codec_get_static_bit_length(codec: CompositeCodec) -> Optional[int]:
"""Compute the length of a composite codec object in bits

This is basically the sum of the lengths of all parameters. If the
length of any parameter can only determined at runtime, `None` is
returned.
"""

cursor = 0
byte_length = 0
for param in codec.parameters:
param_bit_length = param.get_static_bit_length()
if param_bit_length is None:
# We were not able to calculate a static bit length
return None
elif param.byte_position is not None:
cursor = param.byte_position

cursor += ((param.bit_position or 0) + param_bit_length + 7) // 8
byte_length = max(byte_length, cursor)

return byte_length * 8


def composite_codec_get_required_parameters(codec: CompositeCodec) -> List[Parameter]:
"""Return the list of parameters which are required to be
specified for encoding the composite codec object

I.e., all free parameters that do not exhibit a default value.
"""
return [p for p in codec.parameters if p.is_required]


def composite_codec_get_free_parameters(codec: CompositeCodec) -> List[Parameter]:
"""Return the list of parameters which can be freely specified by
the user when encoding the composite codec object

This means all required parameters plus parameters that can be
omitted because they specify a default.
"""
return [p for p in codec.parameters if p.is_settable]


def composite_codec_get_coded_const_prefix(codec: CompositeCodec,
request_prefix: bytes = b'') -> bytes:
encode_state = EncodeState(coded_message=bytearray(), triggering_request=request_prefix)

for param in codec.parameters:
if (isinstance(param, MatchingRequestParameter) and param.request_byte_position < len(request_prefix)) or \
isinstance(param, (CodedConstParameter, PhysicalConstantParameter)):
param.encode_into_pdu(physical_value=None, encode_state=encode_state)
else:
break

return encode_state.coded_message


def composite_codec_encode_into_pdu(codec: CompositeCodec, physical_value: Optional[ParameterValue],
encode_state: EncodeState) -> None:
from .parameters.lengthkeyparameter import LengthKeyParameter
from .parameters.tablekeyparameter import TableKeyParameter

if not isinstance(physical_value, dict):
odxraise(
f"Expected a dictionary for the values of {codec.short_name}, "
f"got {type(physical_value).__name__}", EncodeError)
elif encode_state.cursor_bit_position != 0:
odxraise(
f"Compositional codec objecs must be byte aligned, but "
f"{codec.short_name} requested to be at bit position "
f"{encode_state.cursor_bit_position}", EncodeError)
encode_state.bit_position = 0

orig_origin = encode_state.origin_byte_position
encode_state.origin_byte_position = encode_state.cursor_byte_position

orig_is_end_of_pdu = encode_state.is_end_of_pdu
encode_state.is_end_of_pdu = False

# ensure that no values for unknown parameters are specified.
if not encode_state.allow_unknown_parameters:
param_names = {param.short_name for param in codec.parameters}
for param_value_name in physical_value:
if param_value_name not in param_names:
odxraise(f"Value for unknown parameter '{param_value_name}' specified "
f"for composite codec object {codec.short_name}")

for param in codec.parameters:
if id(param) == id(codec.parameters[-1]):
# The last parameter of the composite codec object is at
# the end of the PDU if the codec object itself is at the
# end of the PDU.
#
# TODO: This assumes that the last parameter specified in
# the ODX is located last in the PDU...
encode_state.is_end_of_pdu = orig_is_end_of_pdu

if isinstance(param, (LengthKeyParameter, TableKeyParameter)):
# At this point, we encode a placeholder value for length-
# and table keys, since these can be specified
# implicitly (i.e., by means of parameters that use
# these keys). To avoid getting an "overlapping
# parameter" warning, we must encode a value of zero
# into the PDU here and add the real value of the
# parameter in a post-processing step.
param.encode_placeholder_into_pdu(
physical_value=physical_value.get(param.short_name), encode_state=encode_state)

continue

if param.is_required and param.short_name not in physical_value:
odxraise(f"No value for required parameter {param.short_name} specified", EncodeError)

param_phys_value = physical_value.get(param.short_name)
param.encode_into_pdu(physical_value=param_phys_value, encode_state=encode_state)

encode_state.journal.append((param, param_phys_value))

encode_state.is_end_of_pdu = False

# encode the length- and table keys. This cannot be done above
# because we allow these to be defined implicitly (i.e. they
# are defined by their respective users)
for param in codec.parameters:
if not isinstance(param, (LengthKeyParameter, TableKeyParameter)):
# the current parameter is neither a length- nor a table key
continue

# Encode the value of the key parameter into the message
param.encode_value_into_pdu(encode_state=encode_state)

encode_state.origin_byte_position = orig_origin


def composite_codec_decode_from_pdu(codec: CompositeCodec,
decode_state: DecodeState) -> ParameterValue:
# move the origin since positions specified by sub-parameters of
# composite codec objects are relative to the beginning of the
# object.
orig_origin = decode_state.origin_byte_position
decode_state.origin_byte_position = decode_state.cursor_byte_position

result = {}
for param in codec.parameters:
value = param.decode_from_pdu(decode_state)

decode_state.journal.append((param, value))
result[param.short_name] = value

# decoding of the composite codec object finished. go back the
# original origin.
decode_state.origin_byte_position = orig_origin

return result
9 changes: 1 addition & 8 deletions odxtools/commrelation.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: MIT
import warnings
from dataclasses import dataclass
from enum import Enum
from typing import Any, Dict, List, Optional
from xml.etree import ElementTree

from .commrelationvaluetype import CommRelationValueType
from .description import Description
from .diagcomm import DiagComm
from .diagservice import DiagService
Expand All @@ -14,13 +14,6 @@
from .snrefcontext import SnRefContext


class CommRelationValueType(Enum):
CURRENT = "CURRENT"
STORED = "STORED"
STATIC = "STATIC"
SUBSTITUTED = "SUBSTITUTED"


@dataclass
class CommRelation:
description: Optional[Description]
Expand Down
9 changes: 9 additions & 0 deletions odxtools/commrelationvaluetype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: MIT
from enum import Enum


class CommRelationValueType(Enum):
CURRENT = "CURRENT"
STORED = "STORED"
STATIC = "STATIC"
SUBSTITUTED = "SUBSTITUTED"
Loading
0