Using UDS protocol

UdsAuxiliary class (pykiso.lib.auxiliaries.udsaux.uds_auxiliary.UdsAuxiliary) contained in uds_auxiliary.py is the main interface between user and all the behind implemented logic. This class defines usable keywords(methods) for scripters in order to send uds requests to the device under test (raw or configurable)…

Configuration

To configure the UDS auxiliary 3 parameters are mandatory :

  • odx_file_path: path to the odx formatted ecu diagnostic definition file.

Note

More information about yaml test configuration creation are available under Test Integration Framework project documentation.

Find below a complete configuration example :

auxiliaries:
  uds_aux:
    connectors:
        com: can_channel
    config:
      # you can specify your odx file by using odx_file_path parameter
      # and instead of using send_uds_raw method use the send_uds_config
      # for a more human readable command
      odx_file_path: null
      request_id : 0x123
      response_id : 0x321
      # uds_layer parameter is not mandatory and by default the following
      # values will be applied:
      # transport_protocol -> CAN
      # p2_can_client -> 5
      # p2_can_server -> 1
      uds_layer:
        transport_protocol: 'CAN'
        p2_can_client: 5
        p2_can_server: 1
      # tp_layer parameter is not mandatory and by default the following
      # values will be applied:
      # addressing_type -> NORMAL
      # n_sa -> 0xFF
      # n_ta -> 0xFF
      # n_ae -> 0xFF
      # m_type -> DIAGNOSTICS
      # discard_neg_resp -> False
      tp_layer:
        addressing_type: 'NORMAL'
        n_sa: 0xFF
        n_ta: 0xFF
        n_ae: 0xFF
        m_type: 'DIAGNOSTICS'
        discard_neg_resp: False
    type: pykiso.lib.auxiliaries.udsaux.uds_auxiliary:UdsAuxiliary
connectors:
  can_channel:
    config:
      interface : 'pcan'
      channel: 'PCAN_USBBUS1'
      state: 'ACTIVE'
    type: pykiso.lib.connectors.cc_pcan_can:CCPCanCan
test_suite_list:
- suite_dir: test_uds
  test_filter_pattern: 'test_raw_uds*.py'
  test_suite_id: 1

Send UDS Raw Request

Send UDS request as list of raw bytes.

The method send_uds_raw(pykiso.lib.auxiliaries.udsaux.UdsAuxiliary.send_uds_raw()) takes one mandatory parameter msg_to_send and one optional : timeout_in_s The parameter msg_to_send is simply the UDS request payload which is a list of bytes.

The optional parameter timeout_in_s (by default fixed to 5 seconds) simply represent the maximum amount of time in second to wait for a response from the device under test. If this timeout is reached, the uds-auxiliary stop to acquire and log an error.

The method send_uds_raw method returns a UdsResponse object, which is a subclass of UserList. UserList allow to keep property of the list, meanwhile attributes can be set, for UdsResponse, defined attributes refer to the positivity of the response, and its NRC if negative.

class UdsResponse(UserList):
    NEGATIVE_RESPONSE_SID = 0x7F

    def __init__(self, response_data) -> None:
        super().__init__(response_data)
        self.is_negative = False
        self.nrc = None
        if self.data and self.data[0] == self.NEGATIVE_RESPONSE_SID:
            self.is_negative = True
            self.nrc = NegativeResponseCode(self.data[2])

Here is an example:

import pykiso
from pykiso.auxiliaries import uds_aux
from collections import UserList

@pykiso.define_test_parameters(suite_id=1, case_id=1, aux_list=[uds_aux])
class ExampleUdsTest(pykiso.BasicTest):
    def setUp(self):
        """Hook method from unittest in order to execute code before test case run.
        """
        pass

    def test_run(self):
        # Set extended session
        diag_session_response = uds_aux.send_uds_raw([0x10, 0x03])
        self.assertEqual(diag_session_response[:2], [0x50, 0x03])
        self.assertEqual(type(diag_session_response), UserList)
        self.assertFalse(diag_session_response.is_negative)

    def tearDown(self):
        """Hook method from unittest in order to execute code after test case run.
        """
        pass

Send UDS Config Request

Send UDS request as a configurable data dictionary. This method can be more practical for UDS requests with long payloads and a multitude of parameters. The method send_uds_config(pykiso.lib.auxiliaries.udsaux.uds_auxiliary.UdsAuxiliary.send_uds_config()) takes one mandatory parameter msg_to_send and an optional one timeout_in_s. The parameter msg_to_send is the UDS request defined as a configurable dictionary that always respects the below defined template:

Note

this feature is only available if a valid ODX file is given at auxiliary configuration level

req = {
    'service': %SERVICE_ID%,
    'data': %DATA%
}

SERVICE_ID -> SID (Service Identifier) of the UDS request either defined as a byte or the corresponding enum label:

class IsoServices(IntEnum):
    DiagnosticSessionControl = 0x10
    EcuReset = 0x11
    SecurityAccess = 0x27
    CommunicationControl = 0x28
    TesterPresent = 0x3E
    AccessTimingParameter = 0x83
    SecuredDataTransmission = 0x84
    ControlDTCSetting = 0x85
    ResponseOnEvent = 0x86
    LinkControl = 0x87
    ReadDataByIdentifier = 0x22
    ReadMemoryByAddress = 0x23
    ReadScalingDataByIdentifier = 0x24
    ReadDataByPeriodicIdentifier = 0x2A
    DynamicallyDefineDataIdentifier = 0x2C
    WriteDataByIdentifier = 0x2E
    WriteMemoryByAddress = 0x3D
    ClearDiagnosticInformation = 0x14
    ReadDTCInformation = 0x19
    InputOutputControlByIdentifier = 0x2F
    RoutineControl = 0x31
    RequestDownload = 0x34
    RequestUpload = 0x35
    TransferData = 0x36
    RequestTransferExit = 0x37
DATA -> dictionary that contains the following keys:
  • ‘parameter’: DID (Data Identifier) of the UDS request. (In most UDS services with DID)

  • %param_n%: one or many keys that represent the parameters related to the service, those depend on ODX definition that is tested.

See some examples of UDS requests below:

import pykiso
from pykiso.auxiliaries import uds_aux
from uds import IsoServices

@pykiso.define_test_parameters(suite_id=1, case_id=1, aux_list=[uds_aux])
class ExampleUdsTest(pykiso.BasicTest):
    def setUp(self):
        """Hook method from unittest in order to execute code before test case run.
        """
        pass

    def test_run(self):
            extendedSession_req = {
                "service": IsoServices.DiagnosticSessionControl,
                "data": {"parameter": "Extended Diagnostic Session"},
            }
            diag_session_response = uds_aux.send_uds_config(extendedSession_req)

    def tearDown(self):
        """Hook method from unittest in order to execute code after test case run.
        """
        pass

The optional parameter timeout_in_s (by default fixed to 6 seconds) simply represents the maximum amount of time in second to wait for a response from the device under test. If this timeout is reached, the uds-auxiliary stops to acquire and log an error.

If the corresponding response is received from entity under test, send_uds_config method returns it also as a preconfigured dictionary. In case of a UDS positive response and no data to be returned, None is returned by the send_uds_config method. In case of a UDS negative response, a dictionary with the key ‘NRC’ is returned and the NRC value. Optionally, ‘NRC_Label’ may be returned if it is defined in ODX for the called service, containing the uds negative response description.

UDS Reset functions

Reset might be integrated in different tests.

The methods:

do not take any argument, and regarding the config (with our without odx file) will send either raw message, or uds config (except for the key_off_on methods, but can remain acceptable for odx uds config)

Soft reset
uds_aux.soft_reset()

UDS check functions

Check functions might be integrated in different tests.

The methods:

The methods take as only mandatory argument the received response. The parameter rest is the response as a userlist object.

UDS read & write data

Read data(udsaux.uds_auxiliary.UdsAuxiliary.read_data()) and write(udsaux.uds_auxiliary.UdsAuxiliary.write_data()) are two helper API that use send_uds_config with specific ISO services (udsaux.uds_utils.UdsAuxiliary.read_data())

ReadDataByIdentifier = 0x22

WriteDataByIdentifier = 0x2E

Using write_data takes two arguments : parameter, and value. Parameter is simply a string that refer to the name of the data you want to modify, and value is simply the value you want to assign to the chosen parameters API must return None in case of positive response, and dictionary with NRC in it (for further information, check in send_uds_config documentation). Using this API is similar to do this :

req = {
    'service': IsoServices.WriteDataByIdentifier,
    'data': {'parameter': 'MyProduct', 'dataRecord': [('SuperProduct', '12345')]}
}

resp = uds_aux.send_uds_config(writeProductCode_req)
return resp

In the same way, read_data takes one argument : parameter.

Parameter is a string that contain the name of the data that is to be read. API must return dictionary with either data associated to the read parameter, or NRC.

UDS tester present sender

In order for any diagnostic session to be kept open, a tester presence frame has to be sent every 5 seconds. For this purpose, the tester present sender context manager can be used, it will send the tester present frame at the period given, allowing you to keep the session open for more than 5 seconds.

# start sending tester present messages every 3 seconds until the context manager is exited
with uds_aux.tester_present_sender(period=3):
    # Perform uds commands here

It is also possible to start and stop the tester present sender manually with the methods start_tester_present_sender and stop_tester_present_sender.

# start sending tester present messages every 1 seconds until the context manager is exited
uds_aux.start_tester_present_sender(period=1)
# Perform uds commands here
uds_aux.stop_tester_present_sender()

It is then possible to check if the tester present is active with the attribute is_tester_present

if uds_aux.is_tester_present:
    # Perform commands here