Skip to content

Commit

Permalink
ISO17987 support (#114)
Browse files Browse the repository at this point in the history
* ISO17987 support
* Grammar supports file rev., endianness and ISO versions.
  • Loading branch information
c4deszes authored Mar 12, 2023
1 parent f72956a commit 839eb96
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 19 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- ISO17987 version support
- Grammar support for the following ISO17987 fields:
- `LDF_file_revision`
- Endianness

### Fixes

- `LinSlave` protocol version property is now the correct type

## [0.18.0] - 2022-12-13

### Changed
Expand Down
2 changes: 1 addition & 1 deletion ldfparser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from .frame import LinEventTriggeredFrame, LinFrame, LinUnconditionalFrame
from .ldf import LDF
from .lin import (LIN_VERSION_1_3, LIN_VERSION_2_0, LIN_VERSION_2_1,
LIN_VERSION_2_2, LinVersion)
LIN_VERSION_2_2, LinVersion, ISO17987_2015, Iso17987Version)
from .node import (LinMaster, LinProductId, LinSlave,
LinNodeCompositionConfiguration, LinNodeComposition)
from .parser import parse_ldf, parse_ldf_to_dict, parseLDF, parseLDFtoDict
Expand Down
9 changes: 9 additions & 0 deletions ldfparser/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ def header_speed(self, tree):
def header_channel(self, tree):
return ("channel_name", tree[0])

def header_file_revision(self, tree):
return ("file_revision", tree[0])

def header_sig_byte_order_big_endian(self, tree):
return ("endianness", "big")

def header_sig_byte_order_little_endian(self, tree):
return ("endianness", "little")

def nodes(self, tree):
if len(tree) == 0:
return ("nodes", {})
Expand Down
12 changes: 9 additions & 3 deletions ldfparser/grammars/ldf.lark
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
start: ldf

ldf: (header_lin_description_file | header_protocol_version | header_language_version | header_speed | header_channel | nodes | node_compositions | signals | diagnostic_signals | diagnostic_addresses | frames | sporadic_frames | event_triggered_frames | diagnostic_frames | node_attributes | schedule_tables | signal_groups | signal_encoding_types | signal_representations)*
ldf: (header_lin_description_file | header_protocol_version | header_language_version | header_speed | header_channel | header_file_revision | header_sig_byte_order_big_endian | header_sig_byte_order_little_endian | nodes | node_compositions | signals | diagnostic_signals | diagnostic_addresses | frames | sporadic_frames | event_triggered_frames | diagnostic_frames | node_attributes | schedule_tables | signal_groups | signal_encoding_types | signal_representations)*

ldf_identifier: CNAME
ldf_version: C_VERSION
ldf_version: LIN_VERSION | ISO_VERSION
ldf_integer: C_INT
ldf_float: C_FLOAT
ldf_channel_name: ESCAPED_STRING
Expand All @@ -15,6 +15,11 @@ header_language_version: "LIN_language_version" "=" "\"" ldf_version "\"" ";"
header_speed: "LIN_speed" "=" ldf_float "kbps" ";"
header_channel: "Channel_name" "=" ldf_channel_name ";"

// ISO1798 Specification
header_file_revision: "LDF_file_revision" "=" ESCAPED_STRING ";"
header_sig_byte_order_big_endian: "LIN_sig_byte_order_big_endian" ";"
header_sig_byte_order_little_endian: "LIN_sig_byte_order_little_endian" ";"

// LIN 2.1 Specification, section 9.2.2
nodes: "Nodes" "{" nodes_master? nodes_slaves? "}"
nodes_master: "Master" ":" ldf_identifier "," ldf_float "ms" "," ldf_float "ms" ";"
Expand Down Expand Up @@ -113,7 +118,8 @@ signal_representation_node: ldf_identifier ":" ldf_identifier ("," ldf_identifie

C_INT: ("0x"HEXDIGIT+) | ("-"? INT)
C_FLOAT: ("-"? INT ("." INT)?) ("e" ("+" | "-")? INT)?
C_VERSION: INT "." INT
LIN_VERSION: INT "." INT
ISO_VERSION: "ISO17987" ":" INT

ANY_SEMICOLON_TERMINATED_LINE: /.*;/

Expand Down
10 changes: 5 additions & 5 deletions ldfparser/ldf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
from typing import Union, Dict, List

from .lin import LinVersion
from .lin import LinVersion, Iso17987Version
from .frame import LinFrame, LinSporadicFrame, LinUnconditionalFrame, LinEventTriggeredFrame
from .diagnostics import LinDiagnosticFrame, LinDiagnosticRequest, LinDiagnosticResponse
from .signal import LinSignal
Expand All @@ -19,8 +19,8 @@ class LDF():

def __init__(self):
self._source: Dict = None
self._protocol_version: LinVersion = None
self._language_version: LinVersion = None
self._protocol_version: Union[LinVersion, Iso17987Version] = None
self._language_version: Union[LinVersion, Iso17987Version] = None
self._baudrate: int = None
self._channel: str = None
self._master: LinMaster = None
Expand All @@ -38,11 +38,11 @@ def __init__(self):
self._schedule_tables: Dict[str, ScheduleTable] = {}
self._comments: List[str] = []

def get_protocol_version(self) -> LinVersion:
def get_protocol_version(self) -> Union[LinVersion, Iso17987Version]:
"""Returns the protocol version of the LIN network"""
return self._protocol_version

def get_language_version(self) -> LinVersion:
def get_language_version(self) -> Union[LinVersion, Iso17987Version]:
"""Returns the LDF language version"""
return self._language_version

Expand Down
54 changes: 54 additions & 0 deletions ldfparser/lin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Utility classes for LIN objects
"""
from typing import Union

class LinVersion:
"""
Expand Down Expand Up @@ -72,3 +73,56 @@ def __ne__(self, o: object) -> bool:
LIN_VERSION_2_0 = LinVersion(2, 0)
LIN_VERSION_2_1 = LinVersion(2, 1)
LIN_VERSION_2_2 = LinVersion(2, 2)

class Iso17987Version:

def __init__(self, revision: int) -> None:
self.revision = revision

@staticmethod
def from_string(version: str) -> 'Iso17987Version':
(standard, revision) = version.split(':')

return Iso17987Version(int(revision))

def __str__(self) -> str:
return f"ISO17987:{self.revision}"

def __eq__(self, o: object) -> bool:
if isinstance(o, Iso17987Version):
return self.revision == o.revision
return False

def __gt__(self, o) -> bool:
if isinstance(o, Iso17987Version):
return (self.revision > o.revision)
if isinstance(o, LinVersion):
return True
raise TypeError()

def __lt__(self, o) -> bool:
if isinstance(o, Iso17987Version):
return (self.revision < o.revision)
if isinstance(o, LinVersion):
return False
raise TypeError()

def __ge__(self, o) -> bool:
return not self.__lt__(o)

def __le__(self, o) -> bool:
return not self.__gt__(o)

def __ne__(self, o: object) -> bool:
return not self.__eq__(o)

ISO17987_2015 = Iso17987Version(2015)

def parse_lin_version(version: str) -> Union[LinVersion, Iso17987Version]:
try:
return LinVersion.from_string(version)
except ValueError:
try:
return Iso17987Version.from_string(version)
except ValueError:
raise ValueError(f'{version} is not a valid LIN version.')
6 changes: 3 additions & 3 deletions ldfparser/node.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""
LIN Node utilities
"""
from typing import List, TYPE_CHECKING
from typing import List, TYPE_CHECKING, Union

if TYPE_CHECKING:
from .frame import LinFrame
from .signal import LinSignal
from .lin import LinVersion
from .lin import LinVersion, Iso17987Version

LIN_SUPPLIER_ID_WILDCARD = 0x7FFF
LIN_FUNCTION_ID_WILDCARD = 0xFFFF
Expand Down Expand Up @@ -113,7 +113,7 @@ class LinSlave(LinNode):

def __init__(self, name: str) -> None:
super().__init__(name)
self.lin_protocol: 'LinVersion' = None
self.lin_protocol: Union[LinVersion, Iso17987Version] = None
self.configured_nad: int = None
self.initial_nad: int = None
self.product_id: LinProductId = None
Expand Down
8 changes: 4 additions & 4 deletions ldfparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .frame import LinEventTriggeredFrame, LinSporadicFrame, LinUnconditionalFrame
from .signal import LinSignal
from .encoding import ASCIIValue, BCDValue, LinSignalEncodingType, LogicalValue, PhysicalValue, ValueConverter
from .lin import LIN_VERSION_2_0, LIN_VERSION_2_1, LinVersion
from .lin import LIN_VERSION_2_0, LIN_VERSION_2_1, parse_lin_version
from .node import LinMaster, LinProductId, LinSlave
from .ldf import LDF
from .grammar import LdfTransformer
Expand Down Expand Up @@ -92,8 +92,8 @@ def parseLDF(path: str, captureComments: bool = False, encoding: str = None) ->
return parse_ldf(path, captureComments, encoding)

def _populate_ldf_header(json: dict, ldf: LDF):
ldf._protocol_version = LinVersion.from_string(_require_key(json, 'protocol_version', 'LDF missing protocol version.'))
ldf._language_version = LinVersion.from_string(_require_key(json, 'language_version', 'LDF missing language version.'))
ldf._protocol_version = parse_lin_version(_require_key(json, 'protocol_version', 'LDF missing protocol version.'))
ldf._language_version = parse_lin_version(_require_key(json, 'language_version', 'LDF missing language version.'))
ldf._baudrate = _require_key(json, 'speed', 'LDF missing speed definition.')
ldf._channel = json.get('channel_name')

Expand Down Expand Up @@ -171,7 +171,7 @@ def _create_ldf2x_node(node: dict, language_version: float):
name = node['name']
lin_protocol = _require_key(node, 'lin_protocol', f"Node {name} has no LIN protocol version specified.")
slave = LinSlave(name)
slave.lin_protocol = lin_protocol
slave.lin_protocol = parse_lin_version(lin_protocol)
slave.configured_nad = _require_key(node, 'configured_nad', f"Node {name} has no configured NAD.")
slave.initial_nad = slave.configured_nad if node.get('initial_nad') is None else node.get('initial_nad')

Expand Down
2 changes: 1 addition & 1 deletion ldfparser/templates/ldf.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Nodes {
{%- endif %}
}

{%- if ldf.get_language_version().major == 2 %}
{%- if ldf.get_language_version().major == 2 or "Iso17987Version" in ldf.get_language_version().__class__.__name__ %}
Node_attributes {
{%- for slave in ldf.get_slaves() %}
{{slave.name}} {
Expand Down
Loading

0 comments on commit 839eb96

Please sign in to comment.