Diagnostics over CAN

This part of the documentation explains the implementation of the Diagnostics over CAN (DoCAN) protocol.

DoCAN implementation is located in the uds.can sub-package and divided into smaller modules each handling one of the following features:

Note

You may use the Diagnostics over CAN (DoCAN) protocol independently from UDS.

Addressing

CAN Addressing may use multiple formats. The CAN addressing implementation is divided into multiple sub-modules and located in uds.can.addressing.

CanAddressingFormat

CanAddressingFormat is an Enum containing all possible CAN Addressing Formats.

Methods:

Example code:

import uds

# check if provided value is CanAddressingFormat member
uds.can.CanAddressingFormat.is_member(uds.can.CanAddressingFormat.NORMAL_ADDRESSING)  # True

# convert a valid string to enum member
uds.can.CanAddressingFormat.validate_member("Extended Addressing")  # uds.can.CanAddressingFormat.EXTENDED_ADDRESSING

# check invalid values
uds.can.CanAddressingFormat.is_member("not a CAN Addressing Format")  # False
uds.can.CanAddressingFormat.validate_member("not a CAN Addressing Format")  # raises ValueError

AbstractCanAddressingInformation

AbstractCanAddressingInformation class defines common API and contains common code for CAN related addressing information storages. It is located in uds.can.addressing.abstract_addressing_information.

Warning

A user shall not use AbstractCanAddressingInformation directly as this is an abstract class.

NormalCanAddressingInformation

NormalCanAddressingInformation class is a storage for Addressing Information in Normal CAN Addressing Format.

From the user perspective, objects creation and passing them correctly are the only interactions. This is why we only explain how to properly initialize objects of this class.

In case of Normal CAN Addressing Format, each address is fully carried in CAN Identifier field of CAN Frame. That is why only “can_id” parameters shall be passed upon NormalCanAddressingInformation object creation.

Example code:

import uds

# create storage for CAN Addressing Information that use Normal Addressing Format
ecu_ai = uds.can.addressing.NormalCanAddressingInformation(
    rx_physical_params={"can_id": 0x7E8},
    tx_physical_params={"can_id": 0x7E0},
    rx_functional_params={"can_id": 0x7E8},
    tx_functional_params={"can_id": 0x7DF})

NormalFixedCanAddressingInformation

NormalFixedCanAddressingInformation class is a storage for Addressing Information in Normal Fixed CAN Addressing Format.

From the user perspective, objects creation and passing them correctly are the only interactions. This is why we only explain how to properly initialize objects of this class.

In case of Normal Fixed CAN Addressing Format each address is fully carried in CAN Identifier field of CAN Frame, but CAN Identifier value contains Source Address, Target Address and priority parameters. Upon NormalFixedCanAddressingInformation object creation, each address might be defined using either “can_id” parameter, combination of “target_address” and “source_address” parameters or by providing all these parameters (compatibility cross-check would be performed then).

Example code:

import uds

# create storage for CAN Addressing Information that use Normal Fixed Addressing Format
ecu_ai_1 = uds.can.addressing.NormalFixedCanAddressingInformation(
    rx_physical_params={"can_id": 0x18DAF101},
    tx_physical_params={"can_id": 0x18DA01F1},
    rx_functional_params={"can_id": 0x18DBF101},
    tx_functional_params={"can_id": 0x18DB33F1})
# define object with the same addresses, but provide parameters differently
ecu_ai_2 = uds.can.addressing.NormalFixedCanAddressingInformation(
    rx_physical_params={"target_address": 0xF1, "source_address": 0x01},
    tx_physical_params={"target_address": 0x01, "source_address": 0xF1},
    rx_functional_params={"can_id": 0x18DBF101, "target_address": 0xF1, "source_address": 0x01},
    tx_functional_params={"can_id": 0x18DB33F1, "target_address": 0x33, "source_address": 0xF1})
ecu_ai_1 == ecu_ai_2  # True
# define object with similar addresses, but using non-default priority value
ecu_ai_3 = uds.can.addressing.NormalFixedCanAddressingInformation(
    rx_physical_params={"can_id": 0xDAF101},
    tx_physical_params={"can_id": 0xDA01F1, "target_address": 0x01, "source_address": 0xF1},
    rx_functional_params={"can_id": 0x1CDBF101},
    tx_functional_params={"can_id": 0x1CDB33F1, "target_address": 0x33, "source_address": 0xF1})
ecu_ai_1 == ecu_ai_3  # False

Warning

To set CAN Identifier value with priority parameter other than default value (6 - 0b110), “can_id” parameter has to be provided.

ExtendedCanAddressingInformation

ExtendedCanAddressingInformation class is a storage for Addressing Information in Extended CAN Addressing Format.

From the user perspective, objects creation and passing them correctly are the only interactions. This is why we only explain how to properly initialize objects of this class.

In case of Extended CAN Addressing Format, each address is carried by CAN Identifier and first data byte of CAN Frame (called Target Address). Exactly two parameters “can_id” and “target_address” shall be passed to each address upon ExtendedCanAddressingInformation object creation.

Example code:

import uds

# create storage for CAN Addressing Information that use Extended Addressing Format
ecu_ai = uds.can.addressing.ExtendedCanAddressingInformation(
    rx_physical_params={"can_id": 0x701, "target_address": 0x01},
    tx_physical_params={"can_id": 0x702, "target_address": 0xF1},
    rx_functional_params={"can_id": 0x701, "target_address": 0xFF},
    tx_functional_params={"can_id": 0x702, "target_address": 0xF1})

Mixed11BitCanAddressingInformation

Mixed11BitCanAddressingInformation class is a storage for Addressing Information in Mixed CAN Addressing Format which use Standard CAN ID.

From the user perspective, objects creation and passing them correctly are the only interactions. This is why we only explain how to properly initialize objects of this class.

In the Mixed CAN Addressing Format, each address is carried by the CAN Identifier and the first data byte of the CAN Frame (Address Extension). Exactly two parameters “can_id” and “address_extension” shall be passed to each address upon Mixed11BitCanAddressingInformation object creation.

Note

Value of “address_extension” parameter must be the same for transmitting (Tx) and receiving (Rx) addresses. It applies to both addresses pairs (for physical and functional communication).

Example code:

import uds

# create storage for CAN Addressing Information that use Mixed Addressing Format using standard CAN Identifiers
ecu_ai = uds.can.addressing.Mixed11BitCanAddressingInformation(
    rx_physical_params={"can_id": 0x701, "address_extension": 0x01},
    tx_physical_params={"can_id": 0x702, "address_extension": 0x01},
    rx_functional_params={"can_id": 0x701, "address_extension": 0xFF},
    tx_functional_params={"can_id": 0x702, "address_extension": 0xFF})

Mixed29BitCanAddressingInformation

Mixed29BitCanAddressingInformation class is a storage for Addressing Information in Mixed CAN Addressing Format which use Extended CAN ID.

From the user perspective, objects creation and passing them correctly are the only interactions. This is why we only explain how to properly initialize objects of this class.

In case of Mixed CAN Addressing Format

Each address in case of Mixed CAN Addressing Format, each address is carried by CAN Identifier and first data byte of CAN Frame (called Address Extension). On top of that, CAN Identifier value contains Source Address, Target Address and priority parameters. Upon Mixed29BitCanAddressingInformation object creation, each address must contain “address_extension”, and “can_id”, combination of “target_address” and “source_address” parameters, or all these parameters (compatibility cross-check would be performed then).

Note

Value of “address_extension” parameter must be the same for transmitting (Tx) and receiving (Rx) addresses. It applies to both addresses pairs (for physical and functional communication).

Example code:

import uds

# create storage for CAN Addressing Information that use Normal Fixed Addressing Format
ecu_ai_1 = uds.can.addressing.Mixed29BitCanAddressingInformation(
    rx_physical_params={"can_id": 0x18CEF101,
                        "address_extension": 0x2D},
    tx_physical_params={"can_id": 0x18CE01F1,
                        "address_extension": 0x2D},
    rx_functional_params={"can_id": 0x18CDF101,
                          "address_extension": 0x8C},
    tx_functional_params={"can_id": 0x18CD33F1,
                          "address_extension": 0x8C})
# define object with the same addresses, but provide parameters differently
ecu_ai_2 = uds.can.addressing.Mixed29BitCanAddressingInformation(
    rx_physical_params={"target_address": 0xF1, "source_address": 0x01,
                        "address_extension": 0x2D},
    tx_physical_params={"target_address": 0x01, "source_address": 0xF1,
                        "address_extension": 0x2D},
    rx_functional_params={"can_id": 0x18CDF101, "target_address": 0xF1, "source_address": 0x01,
                          "address_extension": 0x8C},
    tx_functional_params={"can_id": 0x18CD33F1, "target_address": 0x33, "source_address": 0xF1,
                          "address_extension": 0x8C})
ecu_ai_1 == ecu_ai_2  # True
# define object with similar addresses, but using non-default priority value
ecu_ai_3 = uds.can.addressing.Mixed29BitCanAddressingInformation(
    rx_physical_params={"can_id": 0xCEF101,
                        "address_extension": 0x2D},
    tx_physical_params={"can_id": 0xCE01F1, "target_address": 0x01, "source_address": 0xF1,
                        "address_extension": 0x2D},
    rx_functional_params={"can_id": 0x1CCDF101,
                          "address_extension": 0x8C},
    tx_functional_params={"can_id": 0x1CCD33F1, "target_address": 0x33, "source_address": 0xF1,
                          "address_extension": 0x8C})
ecu_ai_1 == ecu_ai_3  # False

Warning

To set CAN Identifier value with priority parameter other than default value (6 - 0b110), “can_id” parameter has to be provided.

CanAddressingInformation

CanAddressingInformation is factory for AbstractCanAddressingInformation subclasses. You might use it to create Addressing Information object using addressing_format argument as CAN Addressing Format selector.

Example code:

import uds

# create examples storages for CAN Addressing Information
ecu_ai = uds.can.addressing.CanAddressingInformation(
    addressing_format=uds.can.CanAddressingFormat.NORMAL_ADDRESSING,
    rx_physical_params={"can_id": 0x7E8},
    tx_physical_params={"can_id": 0x7E0},
    rx_functional_params={"can_id": 0x7E8},
    tx_functional_params={"can_id": 0x7DF})
ecu_ai_2 = uds.can.CanAddressingInformation(
    addressing_format=uds.can.CanAddressingFormat.EXTENDED_ADDRESSING,
    rx_physical_params={"can_id": 0x701, "target_address": 0x01},
    tx_physical_params={"can_id": 0x702, "target_address": 0xF1},
    rx_functional_params={"can_id": 0x701, "target_address": 0xFF},
    tx_functional_params={"can_id": 0x702, "target_address": 0xF1})
ecu_ai_3 = uds.can.CanAddressingInformation(
    addressing_format=uds.can.CanAddressingFormat.MIXED_29BIT_ADDRESSING,
    rx_physical_params={"can_id": 0x18CEF101, "address_extension": 0x2D},
    tx_physical_params={"can_id": 0x18CE01F1, "address_extension": 0x2D},
    rx_functional_params={"can_id": 0x18CDF101, "address_extension": 0x8C},
    tx_functional_params={"can_id": 0x18CD33F1, "address_extension": 0x8C})

Frame

There are a few aspects of CAN Frames management that had to be implemented, including CAN Identifiers, DLC value and data field length. The whole implementation can be found in uds.can.frame module.

CanIdHandler

CanIdHandler class was defined as a collection of various helper functions for CAN ID management. There is no need to create an object, as each contained method is in fact class method.

As a user, you would normally never use CanIdHandler class directly, therefore we are happy to just inform you about its existence.

CanDlcHandler

CanDlcHandler class was defined as collection of various helper functions for DLC field and data bytes management for CAN bus. There is no need to create an object, as each contained method is in fact class method.

As a user, you would normally never use CanDlcHandler class directly, therefore we are happy to just inform you about its existence.

Packet

Packet implementation for CAN is located in uds.can.packet sub-package. It is divided into the following parts:

CanPacketType

CanPacketType is an enum with all Network Protocol Control Information (N_PCI) values for Diagnostics over CAN defined.

Methods:

AbstractCanPacketContainer

AbstractCanPacketContainer class defines attributes of container for all parameters used by CAN Packets. It also contains implementation for multiple parameters extractions. It is a move to avoid repeating similar code in both CanPacket and - CanPacketRecord classes.

Warning

A user shall not use ~uds.can.packet.abstract_container.AbstractCanPacketContainer directly as this is an abstract class.

CanPacket

CanPacket class defines a structure for CAN Packets information. It is located in uds.can.packet.can_packet.

Attributes:

Methods:

Example code:

import uds

# create examples CAN Packet objects
sf = uds.can.CanPacket(addressing_format=uds.can.CanAddressingFormat.NORMAL_ADDRESSING,
                       packet_type=uds.can.CanPacketType.SINGLE_FRAME,
                       addressing_type=uds.addressing.AddressingType.FUNCTIONAL,
                       can_id=0x742,
                       payload=[0x3E, 0x00])
ff = uds.can.CanPacket(addressing_format=uds.can.CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
                       packet_type=uds.can.CanPacketType.FIRST_FRAME,
                       addressing_type=uds.addressing.AddressingType.PHYSICAL,
                       target_address=0xF1,
                       source_address=0x12,
                       dlc=8,
                       payload=[0x62, 0x12, 0x34, 0x56, 0x78, 0x9A],
                       data_length=123)
fc = uds.can.CanPacket(addressing_format=uds.can.CanAddressingFormat.EXTENDED_ADDRESSING,
                       packet_type=uds.can.CanPacketType.FLOW_CONTROL,
                       addressing_type=uds.addressing.AddressingType.PHYSICAL,
                       can_id=0x615,
                       target_address=0xA2,
                       flow_status=uds.can.CanFlowStatus.Overflow)
cf = uds.can.CanPacket(addressing_format=uds.can.CanAddressingFormat.MIXED_29BIT_ADDRESSING,
                       packet_type=uds.can.CanPacketType.CONSECUTIVE_FRAME,
                       addressing_type=uds.addressing.AddressingType.PHYSICAL,
                       target_address=0xF1,
                       source_address=0x3B,
                       address_extension=0x10,
                       payload=b"\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F",
                       sequence_number=1)
# show content of created packets
print(sf)
print(ff)
print(fc)
print(cf)

Note

Methods set_addressing_information() and set_packet_data() are providing tools to changing multiple connected attributes at the same time, but it is recommended to always create new CanPacket objects instead.

CanPacketRecord

CanPacketRecord class define a structure for CAN Packet records (storage for information about CAN Packets that were either transmitted or received). It is located in uds.can.packet.can_packet_record.

Attributes:

Methods:

Note

A user would not create objects of CanPacketRecord class in typical situations, but one would probably use them quite often as they are returned by communication layers (e.g. uds.transport_interface) of uds package.

Warning

All CanPacketRecord attributes are read-only (they are set only once upon an object creation) as they store historic data and history cannot be changed (can’t it, right?).

Single Frame

CAN Single Frame implementation is located in uds.can.packet.single_frame. This code does not have to be called directly by users, as higher layers of this package (e.g. AbstractCanPacketContainer, CanPacket) are already integrated with it.

Some user might find these functions useful (e.g. for testing proper error handling of Diagnostics over CAN (DoCAN) protocol):

First Frame

CAN First Frame implementation is located in uds.can.packet.first_frame. This code does not have to be called directly by users, as higher layers of this package (e.g. AbstractCanPacketContainer, CanPacket) are already integrated with it.

Some user might find these functions useful (e.g. for testing proper error handling of Diagnostics over CAN (DoCAN) protocol):

Consecutive Frame

CAN Consecutive Frame implementation is located in uds.can.packet.consecutive_frame. This code does not have to be called directly by users, as higher layers of this package (e.g. AbstractCanPacketContainer, CanPacket) are already integrated with it.

Some user might find these functions useful (e.g. for testing proper error handling of Diagnostics over CAN (DoCAN) protocol):

Flow Control

CAN Flow Control implementation is located in uds.can.packet.flow_control.

The key Flow Control related implementation:

Some user might find these functions useful (e.g. for testing proper error handling of Diagnostics over CAN (DoCAN) protocol):

CanFlowStatus

CanFlowStatus class is an Enum with all possible CAN Flow Status values defined.

Methods:

Example code:

import uds

# check if there is member defined for the value
uds.can.CanFlowStatus.is_member(uds.can.CanFlowStatus.ContinueToSend)  # True
uds.can.CanFlowStatus.validate_member(3)  # uds.can.CanFlowStatus.Overflow
uds.can.CanFlowStatus.is_member("Not a CAN Flow Status")  # False
uds.can.CanFlowStatus.validate_member(0xF)  # raises ValueError

CanSTminTranslator

CanSTminTranslator class was defined as a collection of various helper functions for Separation Time Minimum (STmin) management. There is no need to create an object, as each contained method is in fact class method.

Methods:

Example code:

import uds

# check if provided time value [ms] can be encoded as STmin
uds.can.CanSTminTranslator.is_time_value(0.1)  # True
uds.can.CanSTminTranslator.is_time_value(127)  # True

# encode time value [ms] into raw STmin value
uds.can.CanSTminTranslator.encode(0.1)  # 241
uds.can.CanSTminTranslator.encode(127)  # 127

# decode raw STmin value into time value [ms]
uds.can.CanSTminTranslator.decode(241)  # 0.1 [ms]
uds.can.CanSTminTranslator.decode(127)  # 127 [ms]

AbstractFlowControlParametersGenerator

AbstractFlowControlParametersGenerator defines abstract API for Flow Control Generators that are used by CAN Transport Interface (attribute flow_control_parameters_generator of AbstractCanTransportInterface has to be an object of AbstractFlowControlParametersGenerator class)

Warning

A user shall not use AbstractFlowControlParametersGenerator directly as this is an abstract class.

DefaultFlowControlParametersGenerator

DefaultFlowControlParametersGenerator provides typical concrete implementation for AbstractFlowControlParametersGenerator. It cover all typical use cases.

Normally users would just create DefaultFlowControlParametersGenerator objects and pass them to CAN Transport Interface, where all interactions are executed. The examples below are provided to visualize how DefaultFlowControlParametersGenerator objects are used.

Example code:

import uds

# create example flow control parameters generators
fc_gen_1 = uds.can.DefaultFlowControlParametersGenerator(block_size=2,
                                                         st_min=5,
                                                         wait_count=2,
                                                         repeat_wait=False)
# create iterators for flow control parameters
fc_iter_1 = iter(fc_gen_1)
# generate following flow control parameters (Flow Status, Block Size, STmin)
next(fc_iter_1)  # (<CanFlowStatus.Wait: 1>, None, None)
next(fc_iter_1)  # (<CanFlowStatus.Wait: 1>, None, None)
next(fc_iter_1)  # (<CanFlowStatus.ContinueToSend: 0>, 2, 5)
next(fc_iter_1)  # (<CanFlowStatus.ContinueToSend: 0>, 2, 5)

# example 2
fc_gen_2 = uds.can.DefaultFlowControlParametersGenerator(block_size=13,
                                                         st_min=241,
                                                         wait_count=1,
                                                         repeat_wait=True)
fc_iter_2 = iter(fc_gen_2)
next(fc_iter_2)  # (<CanFlowStatus.Wait: 1>, None, None)
next(fc_iter_2)  # (<CanFlowStatus.ContinueToSend: 0>, 13, 241)
next(fc_iter_2)  # (<CanFlowStatus.Wait: 1>, None, None)
next(fc_iter_2)  # (<CanFlowStatus.ContinueToSend: 0>, 13, 241)

Segmentation

Segmentation on CAN bus is fully implemented by CanSegmenter.

CanSegmenter

CanSegmenter handles segmentation process specific for CAN bus.

Following functionalities are provided by CanSegmenter:

  • Configuration of the segmenter:

    As a user, you are able to configure CanSegmenter parameters which determines the addressing and other attributes of CAN packets.

    Example code:

    import uds
    
    # let's assume that CAN Addressing Information object is already created
    can_node_addressing_information: uds.can.CanAddressingInformation
    
    # configure example CAN Segmenter for this CAN Node
    can_segmenter = uds.can.CanSegmenter(addressing_information=can_node_addressing_information,
                                         dlc=8,
                                         min_dlc=None,
                                         use_data_optimization=False,
                                         filler_byte=0xFF)
    
    # change CAN Segmenter configuration
    can_segmenter.dlc=0xF
    can_segmenter.min_dlc=0x8
    can_segmenter.use_data_optimization = True
    can_segmenter.filler_byte = 0xAA
    
  • Diagnostic message segmentation:

    As a user, you are able to segment diagnostic messages into CAN packets.

    Example code:

    import uds
    
    # let's assume that we have `can_segmenter` already configured
    can_segmenter: uds.can.CanSegmenter
    
    # define diagnostic message to segment
    uds_message_1 = uds.message.UdsMessage(payload=[0x3E, 0x00],
                                           addressing_type=uds.addressing.AddressingType.FUNCTIONAL)
    uds_message_2 = uds.message.UdsMessage(payload=[0x62, 0x10, 0x00] + [0x20]*100,
                                           addressing_type=uds.addressing.AddressingType.PHYSICAL)
    
    # use segmenter to segment defined UDS Messages
    can_packets_1 = can_segmenter.segmentation(uds_message_1)  # output: Single Frame
    can_packets_2 = can_segmenter.segmentation(uds_message_2)  # output: First Frame with Consecutive Frame(s)
    

    Note

    It is impossible to segment functionally addressed diagnostic message into First Frame and Consecutive Frame(s) as such operation is considered incorrect according to Diagnostics over CAN.

  • CAN packets desegmentation:

    As a user, you are able to desegment CAN packets into diagnostic messages.

    Example code:

    import uds
    
    # let's assume that we have `can_segmenter` already configured
    can_segmenter: uds.can.CanSegmenter
    
    # define CAN packets to desegment
    can_packets_1 = [
        uds.can.CanPacket(packet_type=uds.can.CanPacketType.SINGLE_FRAME,
                          addressing_format=uds.can.CanAddressingFormat.EXTENDED_ADDRESSING,
                          addressing_type=uds.addressing.AddressingType.FUNCTIONAL,
                          can_id=0x6A5,
                          target_address=0x0C,
                          payload=[0x3E, 0x80])
    ]
    can_packets_2 = [
        uds.can.CanPacket(packet_type=uds.can.CanPacketType.FIRST_FRAME,
                          addressing_format=uds.can.CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
                          addressing_type=uds.addressing.AddressingType.PHYSICAL,
                          target_address=0x12,
                          source_address=0xE0,
                          dlc=8,
                          data_length=15,
                          payload=[0x62, 0x10, 0x00] + 3*[0x20]),
        uds.can.CanPacket(packet_type=uds.can.CanPacketType.CONSECUTIVE_FRAME,
                          addressing_format=uds.can.CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
                          addressing_type=uds.addressing.AddressingType.PHYSICAL,
                          target_address=0x12,
                          source_address=0xE0,
                          dlc=8,
                          sequence_number=1,
                          payload=7*[0x20]),
        uds.can.CanPacket(packet_type=uds.can.CanPacketType.CONSECUTIVE_FRAME,
                          addressing_format=uds.can.CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
                          addressing_type=uds.addressing.AddressingType.PHYSICAL,
                          target_address=0x12,
                          source_address=0xE0,
                          sequence_number=2,
                          payload=2 * [0x20],
                          filler_byte=0x99)
    ]
    
    # use CAN Segmenter to desegment defined CAN packets
    uds_message_1 = can_segmenter.desegmentation(can_packets_1)
    uds_message_2 = can_segmenter.desegmentation(can_packets_2)
    
    # show content of desegmented messages
    print(uds_message_1)  # UdsMessage(payload=[0x3E, 0x80], addressing_type=Functional)
    print(uds_message_2)  # UdsMessage(payload=[0x62, 0x10, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20], addressing_type=Physical)
    

    Warning

    Desegmentation performs only sanity check of CAN packets content, therefore some inconsistencies with Diagnostic on CAN standard might be silently accepted as long as a diagnostic message can be unambiguously decoded out of provided CAN packets.

    Note

    Desegmentation can be performed for any CAN packets (not only those targeting this CAN Node) using any valid CAN Addressing Format.

Transport

Diagnostic Messages and CAN Packets are sent and received by so called Transport Interfaces. For CAN bus, currently there are following Transport Interfaces defined:

AbstractCanTransportInterface

AbstractCanTransportInterface class defines common part for all CAN related Transport Interfaces, including all Diagnostic over CAN <knowledge-base-docan> related parameters.

Attributes:

Methods:

Warning

A user shall not use AbstractCanTransportInterface directly as this is an abstract class.

PythonCanTransportInterface

PythonCanTransportInterface class is concrete Transport Interface implementation that uses python-can package for CAN bus communication (sending and receiving CAN frames). Implementation is located in uds.can.transport_interface.python_can.

Following functionalities are provided by PythonCanTransportInterface:

  • Configuration of the transport interface:

    The configuration takes place during uds.can.transport_interface.python_can.PythonCanTransportInterface.__init__() call.

    User can provide notifier and async_notifier objects on top of other arguments defined in uds.can.transport_interface.common.AbstractCanTransportInterface.__init__().

    Warning

    There shall be exactly one notifier active at any time. Either for synchronous (with BufferedReader listeners) or asynchronous (with AsyncBufferedReader listeners and loop attribute set).

    Example code:

    import uds
    from can import BusABC
    
    # let's assume we have python-can bus interface defined
    # More info: https://python-can.readthedocs.io/en/stable/bus.html#bus-api
    python_can_interface: BusABC
    
    # let's assume that CAN Addressing Information object is already created
    can_node_addressing_information: uds.can.CanAddressingInformation
    
    # configure example CAN Transport Interface
    can_transport_interface = uds.can.PythonCanTransportInterface(
        network_manager=python_can_interface,
        addressing_information=can_node_addressing_information,
        n_as_timeout=50,
        n_ar_timeout=900,
        n_bs_timeout=50,
        n_br=10,
        n_cs=0,
        n_cr_timeout = 900,
        dlc=0xF,
        min_dlc=0x8,
        use_data_optimization=True,
        filler_byte=0x55,
        flow_control_parameters_generator=uds.can.DefaultFlowControlParametersGenerator(st_min=0,
                                                                                        block_size=5,
                                                                                        wait_count=0,
                                                                                        repeat_wait=False),
        can_version=uds.can.CanVersion.CAN_FD,
        bitrate_switch=True)
    
    # change CAN Transport Interface configuration
    can_transport_interface.n_as_timeout = uds.can.PythonCanTransportInterface.N_AS_TIMEOUT
    can_transport_interface.n_ar_timeout = uds.can.PythonCanTransportInterface.N_AR_TIMEOUT
    can_transport_interface.n_bs_timeout = uds.can.PythonCanTransportInterface.N_BS_TIMEOUT
    can_transport_interface.n_br = uds.can.PythonCanTransportInterface.DEFAULT_N_BR
    can_transport_interface.n_cs = uds.can.PythonCanTransportInterface.DEFAULT_N_CS
    can_transport_interface.n_cr_timeout = uds.can.PythonCanTransportInterface.N_CR_TIMEOUT
    can_transport_interface.dlc = 8
    can_transport_interface.use_data_optimization = False
    can_transport_interface.filler_byte = 0xAA
    can_transport_interface.flow_control_parameters_generator = uds.can.DefaultFlowControlParametersGenerator(
        st_min=100,
        block_size=15,
        wait_count=1,
        repeat_wait=True)
    can_transport_interface.can_version = uds.can.CanVersion.CLASSIC_CAN
    can_transport_interface.bitrate_switch = False
    
  • Synchronous communication

    PythonCanTransportInterface defines following methods for synchronous CAN communication:

  • Asynchronous communication

    PythonCanTransportInterface defines following methods for synchronous CAN communication:

Warning

Synchronous and asynchronous implementation shall not be mixed.

Note

Currently only half-duplex communication is implemented.

The matter is further explained in handling unexpected CAN packets arrivals chapter.