-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from KLBa/feature/internalize-param-nrc-const
- Loading branch information
Showing
13 changed files
with
239 additions
and
24 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# SPDX-License-Identifier: MIT | ||
# Copyright (c) 2022 MBition GmbH | ||
|
||
from typing import List | ||
from ..decodestate import DecodeState | ||
from ..encodestate import EncodeState | ||
from ..diagcodedtypes import DiagCodedType | ||
from ..odxtypes import DataType | ||
from ..exceptions import DecodeError, EncodeError | ||
|
||
from .parameterbase import Parameter | ||
|
||
|
||
class NrcConstParameter(Parameter): | ||
"""A param of type NRC-CONST defines a set of values to be matched. | ||
An NRC-CONST can only be used in a negative response. | ||
Its encoding behaviour is similar to a VALUE parameter with a TEXTTABLE. | ||
However, an NRC-CONST is used for matching a response (similar to a CODED-CONST). | ||
See ASAM MCD-2 D (ODX), p. 77-79. | ||
""" | ||
|
||
def __init__(self, short_name, diag_coded_type: DiagCodedType, coded_values: List[int], **kwargs): | ||
super().__init__(short_name, | ||
parameter_type="NRC-CONST", **kwargs) | ||
|
||
self._diag_coded_type = diag_coded_type | ||
# TODO: Does it have to be an integer or is that just common practice? | ||
assert all(isinstance(coded_value, int) | ||
for coded_value in coded_values) | ||
self.coded_values = coded_values | ||
|
||
@property | ||
def diag_coded_type(self): | ||
return self._diag_coded_type | ||
|
||
@property | ||
def bit_length(self): | ||
return self.diag_coded_type.bit_length | ||
|
||
@property | ||
def internal_data_type(self) -> DataType: | ||
return self.diag_coded_type.base_data_type | ||
|
||
def is_required(self): | ||
return False | ||
|
||
def is_optional(self): | ||
return False | ||
|
||
def get_coded_value(self): | ||
return self.coded_value | ||
|
||
def get_coded_value_as_bytes(self, encode_state: EncodeState): | ||
if self.short_name in encode_state.parameter_values: | ||
if encode_state.parameter_values[self.short_name] not in self.coded_values: | ||
raise EncodeError(f"The parameter '{self.short_name}' must have" | ||
f" one of the constant values {self.coded_values}") | ||
else: | ||
coded_value = encode_state.parameter_values[self.short_name] | ||
else: | ||
# If the user does not select one, just select any. | ||
# I think it does not matter ... | ||
coded_value = self.coded_values[0] | ||
return self.diag_coded_type.convert_internal_to_bytes(coded_value, encode_state, bit_position=self.bit_position) | ||
|
||
def decode_from_pdu(self, decode_state: DecodeState): | ||
if self.byte_position is not None and self.byte_position != decode_state.next_byte_position: | ||
# Update byte position | ||
decode_state = decode_state._replace( | ||
next_byte_position=self.byte_position) | ||
|
||
# Extract coded values | ||
coded_value, next_byte_position = self.diag_coded_type.convert_bytes_to_internal(decode_state, | ||
bit_position=self.bit_position) | ||
|
||
# Check if the coded value in the message is correct. | ||
if coded_value not in self.coded_values: | ||
raise DecodeError( | ||
f"Coded constant parameter does not match! " | ||
f"The parameter {self.short_name} expected a coded value in {self.coded_values} but got {coded_value} " | ||
f"at byte position {decode_state.next_byte_position} " | ||
f"in coded message {decode_state.coded_message.hex()}." | ||
) | ||
|
||
return coded_value, next_byte_position | ||
|
||
def _as_dict(self): | ||
d = super()._as_dict() | ||
if self.bit_length is not None: | ||
d["bit_length"] = self.bit_length | ||
d["coded_values"] = self.coded_values | ||
return d | ||
|
||
def __repr__(self): | ||
repr_str = f"CodedConstParameter(short_name='{self.short_name}', coded_values={self.coded_values}" | ||
if self.long_name is not None: | ||
repr_str += f", long_name='{self.long_name}'" | ||
if self.byte_position is not None: | ||
repr_str += f", byte_position='{self.byte_position}'" | ||
if self.bit_position: | ||
repr_str += f", bit_position='{self.bit_position}'" | ||
if self.semantic is not None: | ||
repr_str += f", semantic='{self.semantic}'" | ||
repr_str += f", diag_coded_type={repr(self.diag_coded_type)}" | ||
if self.description is not None: | ||
repr_str += f", description='{' '.join(self.description.split())}'" | ||
return repr_str + ")" | ||
|
||
def __str__(self): | ||
lines = [ | ||
super().__str__(), | ||
] | ||
return "\n".join(lines) | ||
|
||
def get_description_of_valid_values(self) -> str: | ||
"""return a human-understandable description of valid physical values""" | ||
return f"One of the constant internal values: {self.coded_values}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
# SPDX-License-Identifier: MIT | ||
# Copyright (c) 2022 MBition GmbH | ||
|
||
__version__ = '1.1.0' | ||
__version__ = '1.2.0' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# SPDX-License-Identifier: MIT | ||
# Copyright (c) 2022 MBition GmbH | ||
|
||
import unittest | ||
from xml.etree import ElementTree | ||
|
||
from odxtools.odxtypes import DataType | ||
from odxtools.parameters import NrcConstParameter, read_parameter_from_odx | ||
|
||
|
||
class TestReadNrcParam(unittest.TestCase): | ||
def test_read_nrcconst_from_odx(self): | ||
ODX = """ | ||
<PARAM SEMANTIC="SUBFUNCTION-ID" xsi:type="NRC-CONST" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
<SHORT-NAME>NR_identifier</SHORT-NAME> | ||
<LONG-NAME>Identifier for the negative response</LONG-NAME> | ||
<BYTE-POSITION>0</BYTE-POSITION> | ||
<CODED-VALUES> | ||
<CODED-VALUE>16</CODED-VALUE> | ||
<CODED-VALUE>10</CODED-VALUE> | ||
</CODED-VALUES> | ||
<DIAG-CODED-TYPE BASE-DATA-TYPE="A_UINT32" xsi:type="STANDARD-LENGTH-TYPE"> | ||
<BIT-LENGTH>8</BIT-LENGTH> | ||
</DIAG-CODED-TYPE> | ||
</PARAM> | ||
""" | ||
root = ElementTree.fromstring(ODX) | ||
param = read_parameter_from_odx(root) | ||
|
||
self.assertIsInstance(param, NrcConstParameter) | ||
self.assertEqual("SUBFUNCTION-ID", param.semantic) | ||
self.assertEqual("NR_identifier", param.short_name) | ||
self.assertEqual("Identifier for the negative response", | ||
param.long_name) | ||
self.assertEqual([16, 10], param.coded_values) | ||
self.assertEqual(DataType.A_UINT32, | ||
param.diag_coded_type.base_data_type) | ||
self.assertEqual(8, param.diag_coded_type.bit_length) |
Oops, something went wrong.