Skip to content

Commit

Permalink
More fixes for NrcConstParameter
Browse files Browse the repository at this point in the history
Since these parameters usually overlap with a value parameter (the
specification gives the impression that they always do), let's pretend
that NRC-CONST parameters are not required to be specified and are
also not settable.

Signed-off-by: Andreas Lauser <[email protected]>
Signed-off-by: Katja Köhler <[email protected]>
  • Loading branch information
andlaus committed Apr 25, 2024
1 parent 9626268 commit 5a4d8b8
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 17 deletions.
38 changes: 26 additions & 12 deletions odxtools/parameters/nrcconstparameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@

@dataclass
class NrcConstParameter(Parameter):
"""A param of type NRC-CONST defines a set of values to be matched.
"""A param of type NRC-CONST defines a set of values to be matched for a negative response to apply.
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).
The behaviour of NRC-CONST parameters is similar to CODED-CONST
parameters in that they allow to specify which coding objects
apply to a binary string, but in contrast to CODED-CONST
parameters they allow to specify multiple values. Thus, the value
of a CODED-CONST parameter is usually set using an overlapping
VALUE parameter. Since NRC-CONST parameters can only be specified
for negative responses, they can thus be regarded as a multiplexer
mechanism that is specific to negative responses.
See ASAM MCD-2 D (ODX), p. 77-79.
"""

diag_coded_type: DiagCodedType
Expand Down Expand Up @@ -83,12 +89,12 @@ def internal_data_type(self) -> DataType:
@property
@override
def is_required(self) -> bool:
return len(self.coded_values) > 1
return False

@property
@override
def is_settable(self) -> bool:
return True
return False

@override
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
Expand All @@ -103,12 +109,20 @@ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
else:
coded_value = physical_value
else:
# If the user does not select a value, just select
# any. (This branch should only be taken if there is only
# one possible coded value because if there are more,
# specifying a parameter value is mandatory,
# cf. the `.is_required` property.)
coded_value = self.coded_values[0]
# If the user did not select a value, the value of the
# this parameter is set by another parameter which
# overlaps with it. We thus just move the cursor.
bit_pos = encode_state.cursor_bit_position
bit_len = self.diag_coded_type.get_static_bit_length()

if bit_len is None:
odxraise("The diag coded type of NRC-CONST parameters must "
"exhibit a static size")
return

encode_state.cursor_byte_position += (bit_pos + bit_len + 7) // 8
encode_state.cursor_bit_position = 0
return

self.diag_coded_type.encode_into_pdu(cast(AtomicOdxType, coded_value), encode_state)

Expand Down
36 changes: 33 additions & 3 deletions tests/test_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,23 @@ def test_encode_nrc_const(self) -> None:
is_highlow_byte_order_raw=None,
is_condensed_raw=None,
)
dop = DataObjectProperty(
odx_id=OdxLinkId("dop.id", doc_frags),
short_name="dop_sn",
long_name="example dop",
description=None,
admin_data=None,
diag_coded_type=diag_coded_type,
physical_type=PhysicalType(DataType.A_UINT32, display_radix=None, precision=None),
compu_method=IdenticalCompuMethod(
internal_type=DataType.A_UINT32, physical_type=DataType.A_UINT32),
unit_ref=None,
sdgs=[],
internal_constr=None,
physical_constr=None,
)
odxlinks = OdxLinkDatabase()
odxlinks.update(dop._build_odxlinks())
param1 = CodedConstParameter(
short_name="param1",
long_name=None,
Expand All @@ -212,6 +229,19 @@ def test_encode_nrc_const(self) -> None:
bit_position=None,
sdgs=[],
)
param3 = ValueParameter(
short_name="param3",
long_name=None,
description=None,
semantic=None,
dop_ref=OdxLinkRef.from_id(dop.odx_id),
dop_snref=None,
physical_default_value_raw=None,
byte_position=1,
bit_position=None,
sdgs=[],
)
param3._resolve_odxlinks(odxlinks)
resp = Response(
odx_id=OdxLinkId("response_id", doc_frags),
short_name="response_sn",
Expand All @@ -220,13 +250,13 @@ def test_encode_nrc_const(self) -> None:
admin_data=None,
sdgs=[],
response_type=ResponseType.POSITIVE,
parameters=NamedItemList([param1, param2]),
parameters=NamedItemList([param1, param2, param3]),
byte_size=None,
)

with self.assertRaises(EncodeError):
resp.encode() # "No value for required parameter param2 specified"
self.assertEqual(resp.encode(param2=0xAB), bytearray([0x12, 0xAB]))
resp.encode() # "No value for required parameter param3 specified"
self.assertEqual(resp.encode(param3=0xAB), bytearray([0x12, 0xAB]))
self.assertRaises(EncodeError, resp.encode, param2=0xEF)

def test_encode_overlapping(self) -> None:
Expand Down
3 changes: 1 addition & 2 deletions tests/test_somersault.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,9 @@ def test_free_param_info(self) -> None:
expected_output = ("forward_soberness_check: uint\n"
"num_flips: uint\n"
"sault_time: uint\n"
"reason: NRC_const; choices = [0, 1, 2]\n"
"flips_successfully_done: uint\n")
actual_output = stdout.getvalue()
self.assertEqual(actual_output, expected_output)
self.assertEqual(expected_output, actual_output)

def test_decode_response(self) -> None:
ecu = odxdb.ecus.somersault_lazy
Expand Down

0 comments on commit 5a4d8b8

Please sign in to comment.