Skip to content

Commit

Permalink
Merge pull request #350 from andlaus/implement_libraries
Browse files Browse the repository at this point in the history
implement libraries
  • Loading branch information
andlaus authored Oct 17, 2024
2 parents 769dae3 + 5d7cf47 commit b1e3d6c
Show file tree
Hide file tree
Showing 16 changed files with 170 additions and 31 deletions.
4 changes: 4 additions & 0 deletions examples/somersaultecu.py
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,7 @@ class SomersaultSID(IntEnum):
comparam_spec_ref=OdxLinkRef("CPS_ISO_15765_3_on_ISO_15765_2",
[OdxDocFragment("ISO_15765_3_on_ISO_15765_2", "COMPARAM-SPEC")]),
comparam_refs=somersault_comparam_refs,
libraries=NamedItemList(),
prot_stack_snref=None,
)
somersault_protocol = Protocol(diag_layer_raw=somersault_protocol_raw)
Expand Down Expand Up @@ -2180,6 +2181,7 @@ class SomersaultSID(IntEnum):
comparam_refs=[],
diag_variables_raw=[],
variable_groups=NamedItemList(),
libraries=NamedItemList(),
dyn_defined_spec=None)
somersault_base_variant = BaseVariant(diag_layer_raw=somersault_base_variant_raw)

Expand Down Expand Up @@ -2227,6 +2229,7 @@ class SomersaultSID(IntEnum):
ecu_variant_patterns=[],
diag_variables_raw=[],
variable_groups=NamedItemList(),
libraries=NamedItemList(),
dyn_defined_spec=None,
)
somersault_lazy_ecu = EcuVariant(diag_layer_raw=somersault_lazy_ecu_raw)
Expand Down Expand Up @@ -2464,6 +2467,7 @@ class SomersaultSID(IntEnum):
ecu_variant_patterns=[],
diag_variables_raw=[],
variable_groups=NamedItemList(),
libraries=NamedItemList(),
dyn_defined_spec=None,
)
somersault_assiduous_ecu = EcuVariant(diag_layer_raw=somersault_assiduous_ecu_raw)
Expand Down
5 changes: 5 additions & 0 deletions odxtools/diaglayers/diaglayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ..diagdatadictionaryspec import DiagDataDictionarySpec
from ..diagservice import DiagService
from ..exceptions import DecodeError, odxassert, odxraise
from ..library import Library
from ..message import Message
from ..nameditemlist import NamedItemList, TNamed
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
Expand Down Expand Up @@ -259,6 +260,10 @@ def global_negative_responses(self) -> NamedItemList[Response]:
def import_refs(self) -> List[OdxLinkRef]:
return self.diag_layer_raw.import_refs

@property
def libraries(self) -> List[Library]:
return self.diag_layer_raw.libraries

@property
def sdgs(self) -> List[SpecialDataGroup]:
return self.diag_layer_raw.sdgs
Expand Down
14 changes: 13 additions & 1 deletion odxtools/diaglayers/diaglayerraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ..element import IdentifiableElement
from ..exceptions import odxassert, odxraise, odxrequire
from ..functionalclass import FunctionalClass
from ..library import Library
from ..nameditemlist import NamedItemList
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
from ..request import Request
Expand Down Expand Up @@ -47,7 +48,7 @@ class DiagLayerRaw(IdentifiableElement):
state_charts: NamedItemList[StateChart]
additional_audiences: NamedItemList[AdditionalAudience]
# sub_components: List[DiagLayer] # TODO
# libraries: List[DiagLayer] # TODO
libraries: NamedItemList[Library]
sdgs: List[SpecialDataGroup]

@property
Expand Down Expand Up @@ -149,6 +150,10 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
for el in et_element.iterfind("ADDITIONAL-AUDIENCES/ADDITIONAL-AUDIENCE")
]

libraries = [
Library.from_et(el, doc_frags) for el in et_element.iterfind("LIBRARYS/LIBRARY")
]

sdgs = [
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
]
Expand All @@ -168,6 +173,7 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
import_refs=import_refs,
state_charts=NamedItemList(state_charts),
additional_audiences=NamedItemList(additional_audiences),
libraries=NamedItemList(libraries),
sdgs=sdgs,
**kwargs)

Expand Down Expand Up @@ -200,6 +206,8 @@ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
odxlinks.update(state_chart._build_odxlinks())
for additional_audience in self.additional_audiences:
odxlinks.update(additional_audience._build_odxlinks())
for library in self.libraries:
odxlinks.update(library._build_odxlinks())
for sdg in self.sdgs:
odxlinks.update(sdg._build_odxlinks())

Expand Down Expand Up @@ -252,6 +260,8 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
state_chart._resolve_odxlinks(odxlinks)
for additional_audience in self.additional_audiences:
additional_audience._resolve_odxlinks(odxlinks)
for library in self.libraries:
library._resolve_odxlinks(odxlinks)
for sdg in self.sdgs:
sdg._resolve_odxlinks(odxlinks)

Expand Down Expand Up @@ -282,5 +292,7 @@ def _resolve_snrefs(self, context: SnRefContext) -> None:
state_chart._resolve_snrefs(context)
for additional_audience in self.additional_audiences:
additional_audience._resolve_snrefs(context)
for library in self.libraries:
library._resolve_snrefs(context)
for sdg in self.sdgs:
sdg._resolve_snrefs(context)
4 changes: 3 additions & 1 deletion odxtools/diagservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class DiagService(DiagComm):
pos_response_refs: List[OdxLinkRef]
neg_response_refs: List[OdxLinkRef]

# TODO: pos_response_suppressable: Optional[PosResponseSuppressable] # (sic!)
# note that the spec has a typo here: it calls the corresponding
# XML tag POS-RESPONSE-SUPPRESSABLE...
# TODO: pos_response_suppressible: Optional[PosResponseSuppressible]

is_cyclic_raw: Optional[bool]
is_multiple_raw: Optional[bool]
Expand Down
66 changes: 66 additions & 0 deletions odxtools/library.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# SPDX-License-Identifier: MIT
from dataclasses import dataclass
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 .utils import dataclass_fields_asdict


@dataclass
class Library(IdentifiableElement):
"""
A library defines a shared library used for single ECU jobs etc.
It this is basically equivalent to ProgCode.
"""

code_file: str
encryption: Optional[str]
syntax: str
revision: str
entrypoint: Optional[str]

@property
def code(self) -> bytes:
return self._code

@staticmethod
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Library":

kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))

code_file = odxrequire(et_element.findtext("CODE-FILE"))
encryption = et_element.findtext("ENCRYPTION")
syntax = odxrequire(et_element.findtext("SYNTAX"))
revision = odxrequire(et_element.findtext("REVISION"))
entrypoint = et_element.findtext("ENTRYPOINT")

return Library(
code_file=code_file,
encryption=encryption,
syntax=syntax,
revision=revision,
entrypoint=entrypoint,
**kwargs)

def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
return {self.odx_id: self}

def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
pass

def _resolve_snrefs(self, context: SnRefContext) -> None:
aux_file = odxrequire(context.database).auxiliary_files.get(self.code_file)

if aux_file is None:
odxraise(f"Reference to auxiliary file '{self.code_file}' "
f"could not be resolved")
self._code: bytes = cast(bytes, None)
return

self._code = aux_file.read()
aux_file.seek(0)
12 changes: 8 additions & 4 deletions odxtools/progcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from xml.etree import ElementTree

from .exceptions import odxraise, odxrequire
from .library import Library
from .nameditemlist import NamedItemList
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
from .snrefcontext import SnRefContext

Expand All @@ -12,16 +14,20 @@
class ProgCode:
"""A reference to code that is executed by a single ECU job"""
code_file: str
encryption: Optional[str]
syntax: str
revision: str
encryption: Optional[str]
entrypoint: Optional[str]
library_refs: List[OdxLinkRef]

@property
def code(self) -> bytes:
return self._code

@property
def libraries(self) -> NamedItemList[Library]:
return self._libraries

@staticmethod
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ProgCode":
code_file = odxrequire(et_element.findtext("CODE-FILE"))
Expand Down Expand Up @@ -49,9 +55,7 @@ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
return {}

def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
# TODO: Libraries are currently not internalized.
# Once they are internalized, resolve the `library_refs` references here.
pass
self._libraries = NamedItemList([odxlinks.resolve(x, Library) for x in self.library_refs])

def _resolve_snrefs(self, context: SnRefContext) -> None:
aux_file = odxrequire(context.database).auxiliary_files.get(self.code_file)
Expand Down
5 changes: 3 additions & 2 deletions odxtools/templates/macros/printCompuMethod.xml.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,13 @@
{%- macro printProgCode(pc) -%}
<PROG-CODE>
<CODE-FILE>{{pc.code_file}}</CODE-FILE>
<SYNTAX>{{pc.syntax}}</SYNTAX>
{%- if pc.encryption is not none %}
<ENCRYPTION>{{pc.encryption}}</ENCRYPTION>
{%- endif %}
<SYNTAX>{{pc.syntax}}</SYNTAX>
<REVISION>{{pc.revision}}</REVISION>
{%- if pc.entry_point is not none %}
<ENTRY-POINT>{{pc.entry_point}}</ENTRY-POINT>
<ENTRYPOINT>{{pc.entrypoint}}</ENTRYPOINT>
{%- endif %}
{%- if pc.library_refs %}
<LIBRARY-REFS>
Expand Down
8 changes: 8 additions & 0 deletions odxtools/templates/macros/printDiagLayer.xml.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
{%- import('macros/printResponse.xml.jinja2') as presp %}
{%- import('macros/printStateChart.xml.jinja2') as psc %}
{%- import('macros/printAudience.xml.jinja2') as paud %}
{%- import('macros/printLibrary.xml.jinja2') as plib %}
{%- import('macros/printSpecialData.xml.jinja2') as psd %}
{%- import('macros/printEcuVariantPattern.xml.jinja2') as pvpat %}
{%- import('macros/printAdminData.xml.jinja2') as pad %}
Expand Down Expand Up @@ -202,5 +203,12 @@
{%- endfor %}
</ADDITIONAL-AUDIENCES>
{%- endif %}
{%- if dlr.libraries %}
<LIBRARYS>
{%- for lib in dlr.libraries %}
{{ plib.printLibrary(lib)|indent(2) }}
{%- endfor %}
</LIBRARYS>
{%- endif %}
{{- psd.printSpecialDataGroups(dlr.sdgs)|indent(0, first=True) }}
{%- endmacro -%}
21 changes: 21 additions & 0 deletions odxtools/templates/macros/printLibrary.xml.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{#- -*- mode: sgml; tab-width: 1; indent-tabs-mode: nil -*-
#
# SPDX-License-Identifier: MIT
-#}

{%- import('macros/printElementId.xml.jinja2') as peid %}

{%- macro printLibrary(library) %}
<LIBRARY{#- #} {{-peid.printElementIdAttribs(library)}}{# -#}>
{{ peid.printElementIdSubtags(library)|indent(1) }}
<CODE-FILE>{{library.code_file}}</CODE-FILE>
{%- if library.encryption is not none %}
<ENCRYPTION>{{library.encryption}}</ENCRYPTION>
{%- endif %}
<SYNTAX>{{library.syntax}}</SYNTAX>
<REVISION>{{library.revision}}</REVISION>
{%- if library.entrypoint is not none %}
<ENTRYPOINT>{{library.entrypoint}}</ENTRYPOINT>
{%- endif %}
</LIBRARY>
{%- endmacro %}
25 changes: 2 additions & 23 deletions odxtools/templates/macros/printSingleEcuJob.xml.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

{%- import('macros/printElementId.xml.jinja2') as peid %}
{%- import('macros/printDiagComm.xml.jinja2') as pdc %}
{%- import('macros/printCompuMethod.xml.jinja2') as pcm %}

{%- macro printSingleEcuJob(job) -%}
<SINGLE-ECU-JOB {{pdc.printDiagCommAttribs(job)|indent(1) }}>
{{pdc.printDiagCommSubtags(job) | indent(2, first=True) }}
<PROG-CODES>
{%- for prog in job.prog_codes %}
{{ printProgCode(prog)|indent(4) }}
{{ pcm.printProgCode(prog)|indent(4) }}
{%- endfor %}
</PROG-CODES>
{%- if job.input_params %}
Expand Down Expand Up @@ -39,28 +40,6 @@
{%- endmacro -%}


{%- macro printProgCode(prog) -%}
<PROG-CODE>
<CODE-FILE>{{prog.code_file}}</CODE-FILE>
{%- if prog.encryption %}
<ENCRYPTION>{{prog.encryption}}</ENCRYPTION>
{%- endif %}
<SYNTAX>{{prog.syntax}}</SYNTAX>
<REVISION>{{prog.revision}}</REVISION>
{%- if prog.entrypoint %}
<ENTRYPOINT>{{prog.entrypoint}}</ENTRYPOINT>
{%- endif %}
{%- if prog.library_refs %}
<LIBRARY-REFS>
{%- for ref in prog.library_refs %}
<LIBRARY-REF ID-REF="{{ref.ref_id}}" />
{%- endfor %}
</LIBRARY-REFS>
{%- endif %}
</PROG-CODE>
{%- endmacro -%}


{%- macro printInputParam(param) -%}
<INPUT-PARAM {{-make_xml_attrib("OID", param.oid)}}
{{-make_xml_attrib("SEMANTIC", param.semantic)}}>
Expand Down
Loading

0 comments on commit b1e3d6c

Please sign in to comment.