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:
is_member()– check if a value is a valid enum membervalidate_member()– validate and convert a value to an enum member
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:
dlc
Methods:
__init__()
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
CanSegmenterparameters 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:
See also
AbstractCanTransportInterface
AbstractCanTransportInterface class defines common part for all CAN related
Transport Interfaces, including all Diagnostic over CAN <knowledge-base-docan> related parameters.
Attributes:
Methods:
__init__()
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
PythonCanTransportInterfacedefines following methods for synchronous CAN communication:Asynchronous communication
PythonCanTransportInterfacedefines 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.