Skip to content

Add node id number to comm control #217

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 2 commits into from
Mar 4, 2024
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
31 changes: 31 additions & 0 deletions test/client/test_communication_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from udsoncan.exceptions import *

from test.ClientServerTest import ClientServerTest
from udsoncan import latest_standard


class TestCommunicationControl(ClientServerTest):
Expand Down Expand Up @@ -29,6 +30,18 @@ def _test_comcontrol_enable_node(self):
self.assertTrue(response.positive)
self.assertEqual(response.service_data.control_type_echo, control_type)

def test_comcontrol_enable_node_with_enhanced_addr_info(self):
request = self.conn.touserqueue.get(timeout=0.2)
self.assertEqual(request, b"\x28\x05\x01\x12\x34")
self.conn.fromuserqueue.put(b"\x68\x05") # Positive response

def _test_comcontrol_enable_node_with_enhanced_addr_info(self):
control_type = services.CommunicationControl.ControlType.enableRxAndTxWithEnhancedAddressInformation
com_type = CommunicationType(subnet=CommunicationType.Subnet.node, normal_msg=True)
response = self.udsclient.communication_control(control_type=control_type, communication_type=com_type, node_id=0x1234)
self.assertTrue(response.positive)
self.assertEqual(response.service_data.control_type_echo, control_type)

def test_comcontrol_enable_node_spr(self):
request = self.conn.touserqueue.get(timeout=0.2)
self.assertEqual(request, b"\x28\x80\x01")
Expand Down Expand Up @@ -148,3 +161,21 @@ def _test_bad_param(self):

with self.assertRaises(ValueError):
self.udsclient.communication_control(control_type=0, communication_type='x')

with self.assertRaises(ValueError):
self.udsclient.communication_control(
control_type=services.CommunicationControl.ControlType.enableRxAndDisableTxWithEnhancedAddressInformation,
communication_type=CommunicationType(subnet=CommunicationType.Subnet.node, normal_msg=True)) # Missing node_id

with self.assertRaises(ValueError):
self.udsclient.communication_control(
control_type=services.CommunicationControl.ControlType.enableRxAndTxWithEnhancedAddressInformation,
communication_type=CommunicationType(subnet=CommunicationType.Subnet.node, normal_msg=True)) # Missing node_id

with self.assertRaises(ValueError):
self.udsclient.config['standard_version'] = 2006
self.udsclient.communication_control(
control_type=services.CommunicationControl.ControlType.enableRxAndTxWithEnhancedAddressInformation,
communication_type=CommunicationType(subnet=CommunicationType.Subnet.node, normal_msg=True),
node_id=0x1234) # node_id not allowed
self.udsclient.config['standard_version'] = latest_standard
23 changes: 19 additions & 4 deletions udsoncan/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,8 @@ def access_timing_parameter(self,
@standard_error_management
def communication_control(self,
control_type: int,
communication_type: Union[int, bytes, CommunicationType]
communication_type: Union[int, bytes, CommunicationType],
node_id: Optional[int] = None,
) -> Optional[services.CommunicationControl.InterpretedResponse]:
"""
Switches the transmission or reception of certain messages on/off with :ref:`CommunicationControl<CommunicationControl>` service.
Expand All @@ -826,15 +827,29 @@ def communication_control(self,
:param communication_type: Indicates what section of the network and the type of message that should be affected by the command. Refer to :ref:`CommunicationType<CommunicationType>` for more details. If an `integer` or a `bytes` is given, the value will be decoded to create the required :ref:`CommunicationType<CommunicationType>` object
:type communication_type: :ref:`CommunicationType<CommunicationType>`, bytes, int

:param node_id: DTC memory identifier (nodeIdentificationNumber). This value is user defined and introduced in 2013 version of ISO-14229-1.
Possible only when control type is ``enableRxAndDisableTxWithEnhancedAddressInformation`` or ``enableRxAndTxWithEnhancedAddressInformation``
Only added to the request payload when different from None. Default : None
:type node_id: int

:return: The server response parsed by :meth:`CommunicationControl.interpret_response<udsoncan.services.CommunicationControl.interpret_response>`
:rtype: :ref:`Response<Response>`
"""

communication_type = services.CommunicationControl.normalize_communication_type(communication_type)

request = services.CommunicationControl.make_request(control_type, communication_type)
self.logger.info('%s - ControlType=0x%02x (%s) - Sending request with a CommunicationType byte of 0x%02x (%s)' % (self.service_log_prefix(services.CommunicationControl),
control_type, services.CommunicationControl.ControlType.get_name(control_type), communication_type.get_byte_as_int(), str(communication_type)))
request = services.CommunicationControl.make_request(
control_type, communication_type, node_id, standard_version=self.config['standard_version'])

self.logger.info('%s - ControlType=0x%02x (%s) - Sending request with a CommunicationType byte of 0x%02x (%s). nodeIdentificationNumber=%s ' % (
self.service_log_prefix(services.CommunicationControl),
control_type,
services.CommunicationControl.ControlType.get_name(control_type),
communication_type.get_byte_as_int(),
str(communication_type),
str(node_id)
)
)

response = self.send_request(request)
if response is None:
Expand Down
7 changes: 7 additions & 0 deletions udsoncan/services/ClearDiagnosticInformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ def make_request(cls, group: int = 0xFFFFFF, memory_selection: Optional[int] = N
:param group: DTC mask ranging from 0 to 0xFFFFFF. 0xFFFFFF means all DTCs
:type group: int

:param memory_selection: Number identifying the respective DTC memory. This value is user defined and introduced in 2013 version of ISO-14229-1.
Only added to the request payload when different from None. Default : None
:type memory_selection: int

:param standard_version: The version of the ISO-14229 (the year). eg. 2006, 2013, 2020
:type standard_version: int

:raises ValueError: If parameters are out of range, missing or wrong type
"""
tools.validate_int(group, min=0, max=0xFFFFFF, name='Group of DTC')
Expand Down
35 changes: 32 additions & 3 deletions udsoncan/services/CommunicationControl.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
from udsoncan.BaseService import BaseService, BaseSubfunction, BaseResponseData
from udsoncan.ResponseCode import ResponseCode
import udsoncan.tools as tools
from udsoncan import latest_standard
import struct

from typing import cast, Union
from typing import cast, Union, Optional


class CommunicationControl(BaseService):
Expand All @@ -22,6 +24,8 @@ class ControlType(BaseSubfunction):
enableRxAndDisableTx = 1
disableRxAndEnableTx = 2
disableRxAndTx = 3
enableRxAndDisableTxWithEnhancedAddressInformation = 4
enableRxAndTxWithEnhancedAddressInformation = 5

supported_negative_response = [ResponseCode.SubFunctionNotSupported,
ResponseCode.IncorrectMessageLengthOrInvalidFormat,
Expand Down Expand Up @@ -55,7 +59,7 @@ def normalize_communication_type(self, communication_type: Union[int, bytes, Com
return communication_type

@classmethod
def make_request(cls, control_type: int, communication_type: CommunicationType) -> Request:
def make_request(cls, control_type: int, communication_type: CommunicationType, node_id: Optional[int] = None, standard_version=latest_standard) -> Request:
"""
Generates a request for CommunicationControl

Expand All @@ -65,14 +69,39 @@ def make_request(cls, control_type: int, communication_type: CommunicationType)
:param communication_type: The communication type requested.
:type communication_type: :ref:`CommunicationType <CommunicationType>`, int, bytes

:param node_id: DTC memory identifier. This value is user defined and introduced in 2013 version of ISO-14229-1.
Possible and required only when ``control_type`` is ``enableRxAndDisableTxWithEnhancedAddressInformation`` or ``enableRxAndTxWithEnhancedAddressInformation``
Default : ``None``
:type node_id: int

:param standard_version: The version of the ISO-14229 (the year). eg. 2006, 2013, 2020
:type standard_version: int

:raises ValueError: If parameters are out of range, missing or wrong type
"""
tools.validate_int(control_type, min=0, max=0x7F, name='Control type')

require_node_id = standard_version >= 2013 and control_type in (
CommunicationControl.ControlType.enableRxAndDisableTxWithEnhancedAddressInformation,
CommunicationControl.ControlType.enableRxAndTxWithEnhancedAddressInformation
)

if require_node_id and node_id is None:
raise ValueError(
"node_id is required when the standard version is 2013 (or more recent) and when control_type is enableRxAndDisableTxWithEnhancedAddressInformation or enableRxAndTxWithEnhancedAddressInformation ")
elif not require_node_id and node_id is not None:
raise ValueError(
"node_id is only possible when the standard version is 2013 (or more recent) and when control_type is enableRxAndDisableTxWithEnhancedAddressInformation or enableRxAndTxWithEnhancedAddressInformation ")

communication_type = cls.normalize_communication_type(communication_type)
request = Request(service=cls, subfunction=control_type)
request.data = communication_type.get_byte()
payload = communication_type.get_byte()

if node_id is not None:
tools.validate_int(node_id, min=0, max=0xFFFF, name='nodeIdentificationNumber')
payload += struct.pack('>H', node_id)

request.data = payload
return request

@classmethod
Expand Down
3 changes: 3 additions & 0 deletions udsoncan/services/DiagnosticSessionControl.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ def interpret_response(cls, response: Response, standard_version: int = latest_s
:param response: The received response to interpret
:type response: :ref:`Response<Response>`

:param standard_version: The version of the ISO-14229 (the year). eg. 2006, 2013, 2020
:type standard_version: int

:raises InvalidResponseException: If length of ``response.data`` is too short
"""
if response.data is None:
Expand Down