Giter Site home page Giter Site logo

pylessard / python-can-isotp Goto Github PK

View Code? Open in Web Editor NEW
252.0 16.0 78.0 386 KB

A Python package that provides support for ISO-TP (ISO-15765) protocol

License: MIT License

Python 98.11% Shell 1.19% Dockerfile 0.71%
isotp 15765 iso15765 iso-15765 iso-tp obd canbus can automotive uds

python-can-isotp's Introduction

python-can-isotp

https://app.travis-ci.com/pylessard/python-can-isotp.svg?branch=master

This project is a Python package meant to provide support for IsoTP (ISO-15765) protocol written in Python 3. The code is published under MIT license on GitHub (pylessard/python-can-isotp).

This package contains a Python implementation of the protocol that works in the user space that may or may not be coupled with python-can. It also contains a wrapper for a simplified usage of the Linux SocketCAN IsoTP kernel module

Documentation

The documentation is available here : https://can-isotp.readthedocs.io

Requirements

  • Python 3.7+

Installation

using pip:

pip install can-isotp

python-can-isotp's People

Contributors

giovanni-superpedestrian avatar johanbrus avatar karlding avatar mikisama avatar ppistorius avatar pylessard avatar strupppi avatar tpierson-voxx avatar wanam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-can-isotp's Issues

Tx Frames sent at STmin = 0 while setting Tx STmin to a value > 0

I'm trying to set Tx STmin , but with no success. Below is my code:

# Refer to isotp documentation for full details about parameters
isotp_params = {
   'stmin' : 0xF3,                          # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
   'blocksize' : 8,                       # Request the sender to send 8 consecutives frames before sending a new flow control message
   'wftmax' : 2048,                          # Number of wait frame allowed before triggering an error
   'll_data_length' : 8,                  # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
   'tx_padding' : 0,                      # Will pad all transmitted CAN messages with byte 0x00. None means no padding
   'rx_flowcontrol_timeout' : 1000,        # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
   'rx_consecutive_frame_timeout' : 1000, # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds
   'squash_stmin_requirement' : False     # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
}

bus = KvaserBus(channel=0, bitrate=500000)                                          # Link Layer (CAN protocol)
tp_addr = isotp.Address(isotp.AddressingMode.Normal_11bits, txid=0x620, rxid=0x621) # Network layer addressing scheme
stack = isotp.CanStack(bus=bus, address=tp_addr, params=isotp_params)               # Network/Transport layer (IsoTP protocol)
conn = PythonIsoTpConnection(stack)   

Then in protocol.py I find this:

self.timer_tx_stmin = self.Timer(timeout = 0)
self.timer_rx_fc = self.Timer(timeout = float(self.params.rx_flowcontrol_timeout) / 1000)
self.timer_rx_cf = self.Timer(timeout = float(self.params.rx_consecutive_frame_timeout) / 1000)

STmin param seems doesn't take effect and always set to 0?

How can I send long CAN message greater than 8 bytes in python-can-isotp ?

Hi, I am new to python. I am working on a project using CANtact toolkit I am using two toolkits one to send the CAN message and others to receive the CAN message. I created a socket between the two devices and it worked fine for sending and receiving the standard CAN message of 8 Byte. Now I want to send more than 8 bytes of the message and I came across can-isotp protocol. I have used python-can for implementation of my project so far so I would like to continue with python-can-isotp. What is the simple code to send and receive CAN message using python-can-isotp? Also, should I create a new socket to receive more than 8 bytes of data? I have used the following code to create a socket between two CANtact devices. What change has to be made to the code to make it accept more than 8 bytes of data?I want to send and receive a CAN message like this [127, 51, 17, 124, 242, 102, 165, 37, 160, 41, 165, 149, 65, 179, 232, 15, 63, 76, 4, 0, 90, 72, 203, 250, 155, 188, 169, 58, 114, 16, 85, 107]

#!/bin/env python
import socket
import struct

canformat = '<IB3x8s'

class CanBridge():
    def __init__(self, interface_from, interface_to):
        self.interface_from = interface_from
        self.interface_to = interface_to
        self.canSocket_to = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
        self.canSocket_from = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
        try: 
            self.canSocket_to.bind((self.interface_to,))
            self.canSocket_from.bind((self.interface_from,))
        except OSError: 
            print("Could not bind to interfaces")
        #put the sockets in blocking mode.
        self.canSocket_to.settimeout(None)
        self.canSocket_from.settimeout(None)

    def run(self):
        while True:
            raw_bytes = self.canSocket_from.recv(4096)#512
            try:
                self.canSocket_to.send(raw_bytes)
            except OSError: #Buffer overflow usually from lack of connection.
                pass

            rawID,DLC,candata = struct.unpack(canformat,raw_bytes)
            canID = rawID & 0x1FFFFFFF
            candata_string = " ".join(["{:02X}".format(b) for b in candata])
            print("{:08X} {}".format(canID, candata_string))

if __name__ == '__main__':
    bridge = CanBridge('slcan1','slcan0')
    bridge.run()

min_frame_length for iso_tp_frames

some OEMs are defining their ISO-TP CAN-Frames with some kind of a "minimum length". That means If you are on a CAN-FD Bus and you are sending data which is <=6 bytes, the CAN-FD-Frame will always be of a length of 8 bytes. Even if you are just sending a simple 2 byte data, the can-stack will pad the missing bytes up to 8. If you want to send data on the same connections with data >=8 it will t use the appropriate frame length on an CAN-FD-Frame up to 64.

I can´t find such an setting inside that lib. I´m not even sure if this has to be inside ISO-TP or rather inside python-can.

I could only found 2 options which do not lead to the descibed behavior

  1. tx_padding not None & tx_data_length = 64 --> This will always pad up to 64
  2. tx_padding is None & tx_data_length = 64 --> This will send frames < 8 DLC in case of small data

If anyone has an idea how to solve that issues it would be great, otherwise I could help to integrate such a feature if wanted.

Thanks

UDS client gets a timeout when receiving segmented frames while the blocksize within isotp_params is set to zero

Hi,

I am using the udsoncan along with python-can-isotp and python-can for communication with my server. I have set the blocksize for isotp to be zero which should indicate an infinitely large block size.

But when I try using read_data_by_identifier to get data from the server, the reply for which will be send in more than two segmented frames , an "integer division or modulo by zero" error is also printed out and a TimeoutException is triggered. But I have verified that the server is responding to the request properly.

The log during the same is a provided below

2019-06-27 13:41:42 [ERROR] Connection: integer division or modulo by zero
2019-06-27 13:41:43 [DEBUG] Connection: No data received: [TimeoutException] - Did not receive frame from user queue in time (timeout=1 sec)
2019-06-27 13:41:43 [ERROR] UdsClient: [TimeoutException] : Did not receive response in time. P2 timeout time has expired (timeout=1.000 sec)

If I increase the blocksize more than zero, the data is properly received.

Isn't the above mentioned behaviour a bug ?

send flow control frame timeout

I use PythonIsoTpConnection in udsoncan.connections to send and recive can msg,but when use it to test uds service 2E to write data, it will timeout sometimes when send flow control frame, please Look at the picture below
image

Hardware:vector cancasexl
Python 3.7.9

here is code
class UdsLib:

def set_can_config(self, tx_id=0x703, rx_id=0x70B):

    try:
        self.bus = can.interface.Bus(bustype='vector', channel='0,1', app_name='Python Can', bitrate=500000,
                                     receive_own_messages=True)
        self.tp_addr = isotp.Address(addressing_mode=isotp.AddressingMode.Normal_11bits, txid=tx_id, rxid=rx_id)
        tp_stack = isotp.CanStack(bus=self.bus, address=self.tp_addr, params=iso_tp_params)
        self.conn = PythonIsoTpConnection(tp_stack)
    except:
        AssertionError(sys.exc_info()[0])
    else:
        logger.info("Set Can config is ok!")

def diagnostic_request(self, request_dat):
    request_pdu = binascii.a2b_hex(request_dat)
    if not self.conn.is_open():
        self.conn.open()
    try:
        self.conn.send(request_pdu)
    except can.CanError:
        AssertionError("Send request data fail")
    else:
        logger.info('Sending %d bytes : <%s>' % (len(request_pdu), binascii.hexlify(request_pdu)))

def diagnostic_respond(self, respond_dat):
    expect_respond_pdu = binascii.a2b_hex(respond_dat)
    try:
        resp_pdu = self.conn.wait_frame(timeout=2)

        if resp_pdu is not None:
            while resp_pdu[0] == 0x7F and resp_pdu[2] == 0x78:
                logger.info('Received %d bytes : <%s>' % (len(resp_pdu), binascii.hexlify(resp_pdu)))
                resp_pdu = self.conn.wait_frame(timeout=3)
    except Exception as err:
        raise err

    if resp_pdu is not None:
        logger.info('ECU: Received %d bytes : <%s>' % (len(resp_pdu), binascii.hexlify(resp_pdu)))
        if resp_pdu.find(expect_respond_pdu) == 0:
            return True
        else:
            return binascii.b2a_hex(resp_pdu)
    return resp_pdu

def close_can(self):
    self.conn.close()
    self.bus.stop_all_periodic_tasks()
    self.bus.shutdown()
    logger.info("close the device")

UDS client cannot receive segmented frames over CAN-FD when ll_data_length does not match UDS server configuration

In the current implementation, CAN frame are conveyed on a CAN-FD bus instead of CAN-FD frames. The following pull request proposes a fix for this: #12. It is necessary to include this fix to reproduce the below issue.

Using the above pull request, a UDS client is able to send segmented CAN-FD frames to a UDS server. However, a UDS client is not always able to properly receive segmented CAN-FD frames. It depends on the ll_data_length configuration parameter.

The behaviour of the python-can-isotp layer has been compared with kernel module implementation: https://github.com/hartkopp/can-isotp. The kernel module works fine with different configuration (note the ll_data_length parameter is named tx_dl in this module - the name explicitly specifies that it applies to Tx only).

Below is a table listing the results for some testing: KS = Kernel Space (hartkopp's module), US = User Space (python-can-isotp).

Test # UDS server isotp layer UDS server ll_data_length UDS client isotp layer UDS client ll_data_length Reception of CAN-FD segmented frame
1 US 64 US 64 OK
2 US 8 US 8 OK
3 US 8 US 64 NOK: Received invalid CAN frame
4 US 64 US 8 NOK: Reception of CONSECUTIVE FRAME timed out
5 KS 64 KS 64 OK
6 KS 8 KS 8 OK
7 KS 8 KS 64 OK
8 KS 64 KS 8 OK
9 KS 8 US 64 NOK: Received invalid CAN frame
10 KS 64 US 8 NOK: Reception of CONSECUTIVE FRAME timed out

From these tests, we can observe the following:

  1. If UDS client's ll_data_length parameter matches UDS server's ll_data_length, the segmented CAN-FD frames are properly received.

  2. If UDS client's ll_data_length parameter is less than UDS server's ll_data_length, python-can-isotp layer raises a "Reception of CONSECUTIVE FRAME timed out" exception:

    self.trigger_error(isotp.errors.ConsecutiveFrameTimeoutError("Reception of CONSECUTIVE_FRAME timed out."))

  3. If UDS client's ll_data_length parameter is larger than UDS server's ll_data_length, python-can-isotp layer raises a "Received invalid CAN frame: First frame specifies a length that is inconsistent with underlying CAN message DLC" exception:

    raise ValueError('First frame specifies a length that is inconsistent with underlying CAN message DLC')

It seems that the implementation makes the assumption that UDS server shall send segmented frames according to UDS client's ll_data_length configuration - which is likely wrong. My understanding is that there is no negociation regarding this parameter. UDS client ll_data_length parameter shall only apply to transmitted messages. UDS client shall be able to process different data lengths and not rely on its own configuration.

To reproduce:

  • Make sure to use a CAN-FD bus + the above fix to convey CAN-FD frames
  • Send a UDS request expecting a long frame as an answer (i.e. requiring segmentation) to an ECU
  • Play with ll_data_length on UDS client / server sides and try the above use case.

RD performance?

Hello @pylessard,

I implemented the software download using this lib (Vector interface, windows 10) but it looks like the Multi-message mechanism isn't terribly perfomant. Any insights here? I'm on a 500kbps bus and the download of 700kB of data takes ~ 40s? That's at least 3 times too slow.

Why is it that slow? Was anyone able to achieve faster transfer speeds? I'm pretty much just sending the multi message one after another with minimal downtime inbetween to grab new data from the bytearray.

Not sure I'm doing something wrong or is Windows impacting us so hard due to a ton of smaller timeouts in the transport layer...

Thanks in advance!

MK

Isotp Transport layer can't recieve can in time

Hi,
the server is response the request timely,but the IsoTP Transport layer didn’t recieve the can msg in time.
the code is same as issue #50

INFO Connection:connections.py:449 Connection opened
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'1001']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0210010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.389645 <701> (8) b'0210010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.391792 <781> (8) b'065001003201f400'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'5001003201f4']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'1003']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.523789 <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.526788 <781> (8) b'065003003201f400'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'5003003201f4']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'2701']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.649799 <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.651773 <781> (8) b'066701cca8f3b600'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'6701cca8f3b6']
DEBUG Connection:connections.py:51 Sending 6 bytes : [b'270200000000']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0627020000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.796657 <701> (8) b'0627020000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.801785 <781> (8) b'037f273500000000'
DEBUG Connection:connections.py:78 Received 3 bytes : [b'7f2735']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'1003']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.988792 <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892866.991774 <781> (8) b'065003003201f400'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'5003003201f4']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'2701']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892867.383900 <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892867.386743 <781> (8) b'06670119694e7900'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'670119694e79']
DEBUG Connection:connections.py:51 Sending 6 bytes : [b'270200000000']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0627020000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892868.215265 <701> (8) b'0627020000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892868.216732 <781> (8) b'037f273500000000'
DEBUG Connection:connections.py:78 Received 3 bytes : [b'7f2735']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'1003']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892869.103942 <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892869.106686 <781> (8) b'065003003201f400'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'5003003201f4']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'2701']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892869.493930 <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892869.496674 <781> (8) b'066701b67e020900'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'6701b67e0209']
DEBUG Connection:connections.py:51 Sending 6 bytes : [b'270200000000']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0627020000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892870.024165 <701> (8) b'0627020000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892870.026656 <781> (8) b'037f273600000000'
DEBUG Connection:connections.py:78 Received 3 bytes : [b'7f2736']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'1003']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892870.319511 <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892870.321641 <781> (8) b'065003003201f400'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'5003003201f4']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'2701']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892870.787709 <701> (8) b'0227010000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892870.791616 <781> (8) b'037f273700000000'
DEBUG Connection:connections.py:78 Received 3 bytes : [b'7f2737']
DEBUG Connection:connections.py:51 Sending 2 bytes : [b'1003']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892871.372225 <701> (8) b'0210030000000000'
DEBUG isotp:protocol.py:471 Receiving : 1627892871.376599 <781> (8) b'065003003201f400'
DEBUG Connection:connections.py:78 Received 6 bytes : [b'5003003201f4']
DEBUG Connection:connections.py:51 Sending 6 bytes : [b'270200000000']
DEBUG isotp:protocol.py:478 Sending : <701> (8) b'0627020000000000'
DEBUG Connection:connections.py:70 No data received: [TimeoutException] - Did not receive frame IsoTP Transport layer in time (timeout=2 sec)

image

Use CAN Extended Adresses

Hi,
Thanks for your work.
Can you share an example using extended addressing?
When I use 8 char addresses, it send only the 3 last. I've tried to find the good options but I probably miss something.

Regards

Add type hints

Issue

Type hints are needed for downstream projects to use mypy and other automated tooling

Solution

Merge my pull request which includes a decent set of mypy stubs for the package.

Alternatives

Add type hints throughout the package

Context

These stubs satisfied mypy when I installed them into a local /stubs directory for a project that relies on can-isotp.

Extended address modes don't receive anything

Hi,
i tried to use stack with extended addressing modes (11 bits, 29 bits) - send works,
but it doesn't receive anything.

I think there is a bug in Address._is_for_me_extended():
line 228: return msg.arbitration_id == self.rxid and int(msg.data[0]) == self.source_address

May be it should be self.target_address instead of self.source_address?

Receiving from multiple addresses in NormalFixed addressing

My goal is to use the OBD-2 protocol on top of can-isotp.
In OBD-2, the target/source addresses are encoded in the arbitration ID, therefore I use AddressingMode.NormalFixed_29bits

I want to receive both messages that are "broadcasted", i.e. messages with an arbitration id of 0x18DB33F1, as well as messages that are directed to one specific receiver, e.g. 0x18DA01FF.

I tried using two separate CanStacks in order to receive both types of messages, like so:

addr1 = isotp.Address(isotp.AddressingMode.NormalFixed_29bits, target_address=0xF1, source_address=0x33)
stack1 = isotp.CanStack(self.bus, address=addr1, error_handler=self.my_error_handler)

addr2 = isotp.Address(isotp.AddressingMode.NormalFixed_29bits, target_address=0xF1, source_address=0x01)
stack2 = isotp.CanStack(self.bus, address=addr2, error_handler=self.my_error_handler)

For each stack I have a separate thread that calls its process() method.
With this, I do not receive any messages. If I only use the first two lines, I am receiving the broadcast messages correctly.

Is there a better way to do that?

Python script stucks at bind step.

Hi,
I've got some issues binding the sockets and using the socket example as described in the docs.
My code looks like the following:

import isotp

s = isotp.socket()
s2 = isotp.socket()
# Configuring the sockets.
s.set_fc_opts(stmin=5, bs=10)
#s.set_general_opts(...)
#s.set_ll_opts(...)

print("socket parameters set")

s.bind("vcan0", isotp.Address(rxid=0x123 ,txid=0x456))

print("bound first socket")
s2.bind("vcan0", isotp.Address(rxid=0x456, txid=0x123))
print("bound second socket")

s2.send(b"Hello, this is a long payload sent in small chunks of 8 bytes.")
print(s.recv())

If I run this, I get the following output:
image

At this point, the terminal is kind of stuck and not working/responding anymore. To re run the script, i have to restart the kernel.
I'm using Python 3.7.9 and Spyder 4 (tried it with Python 3.8 before and downgraded the version after it wasn't working).

Did you face that problem before and have any suggestions on how to solve it? Best regards!

Overflow flow status is ignored

I think your library should call error_handler in such a case. My setup : using your library I'm sending a message like this :

#!/usr/bin/env python3

import isotp
import logging
import time
import can
import msgpack


def my_error_handler(error):
    logging.warning('IsoTp error happened : %s - %s' %
                    (error.__class__.__name__, str(error)))


bus = can.interface.Bus(bustype='socketcan', channel='slcan0', bitrate=500000)

addr = isotp.Address(isotp.AddressingMode.NormalFixed_29bits,
                     source_address=0x11, target_address=0x22)

stack = isotp.CanStack(bus, address=addr, error_handler=my_error_handler)

# Just some data, not relevant
stack.send(msgpack.packb({"sensor": "accel", "time": 1,
                          "data": [1.2, 3.4]}, use_bin_type=True))

while stack.transmitting():
    stack.process()
    time.sleep(stack.sleep_time())

print("Payload transmission done.")

bus.shutdown()

Now another library running on a microcontroller (https://github.com/iwasz/cpp-can-isotp) is listening and it responds with a flow frame, and everything works if the message is short enough. Below I attach the candump any output :

  slcan0  18DA2211   [8]  10 2C 83 A6 73 65 6E 73
  slcan0  18DA1122   [3]  30 00 0A <- 3 == flow frame, 0 == CONTINUE TO SEND
  slcan0  18DA2211   [8]  21 6F 72 A5 61 63 63 65
  slcan0  18DA2211   [8]  22 6C A4 74 69 6D 65 01
  slcan0  18DA2211   [8]  23 A4 64 61 74 61 92 CB
  slcan0  18DA2211   [8]  24 3F F3 33 33 33 33 33
  slcan0  18DA2211   [8]  25 33 CB 40 0B 33 33 33
  slcan0  18DA2211   [4]  26 33 33 33

But if I try to send too much data (where too much means more than 128, because listening peer is constrained to this number), and the listening peer responds with overflow status, your library (the sender) does not raise an error. This is a dump :

  slcan0  18DA2211   [8]  10 85 84 A6 73 65 6E 73
  slcan0  18DA1122   [3]  32 00 0A <- 3 == flow frame, 2 == OVERFLOW

And the python outputs just:

Payload transmission done.

Relevant paragraph in the 2004 ISO is 6.5.3.3. Let me know what you think, I might misinterpret the ISO as well (but the fact is that I send a message and even though it didn't pass through, I am not being informed abut that). Thanks.

Listener/Notifier and UDS command

Hello, when i have a logger and a notifier on the can layer, it seems like uds command (e.g. ecu reset) times out and never returns response. My code is below. Is there a way to have a logger constantly logging CAN messages while sparingly sending UDS commands? Uncomment initialization of logger1 and notifier1 on line 17 and 18.

my setup is Peak's pcan usb dongle with an ecu with uds server.

[TimeoutException] : Did not receive response in time. Global request timeout time has expired (timeout=2.000 sec)

import can
from can.interfaces.pcan.pcan import PcanBus
import udsoncan
import isotp
from udsoncan.connections import IsoTPSocketConnection, PythonIsoTpConnection
from udsoncan.client import Client
from udsoncan.exceptions import *
from udsoncan.services import *

import time
import os

if __name__ == "__main__":
    can_bus = PcanBus("PCAN_USBBUS7", bitrate=500000)
    #logger1 = can.Logger("test.asc")
    #notifier1 = can.Notifier(bus=can_bus, listeners=[logger1])

     
    
    isotp_params = {
   'stmin' : 32,                          # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
   'blocksize' : 8,                       # Request the sender to send 8 consecutives frames before sending a new flow control message
   'wftmax' : 0,                          # Number of wait frame allowed before triggering an error
   'tx_data_length' : 8,                  # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
   'tx_data_min_length' : None,           # Minimum length of CAN messages. When different from None, messages are padded to meet this length. Works with CAN 2.0 and CAN FD.
   'tx_padding' : 0,                      # Will pad all transmitted CAN messages with byte 0x00.
   'rx_flowcontrol_timeout' : 1000,       # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
   'rx_consecutive_frame_timeout' : 1000, # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds
   'squash_stmin_requirement' : False,    # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
   'max_frame_size' : 4095                # Limit the size of receive frame.
    }
    config={
    "standard_version": 2006,
    "use_server_timing": False,
    "ignore_all_zero_dtc": True,
    "tolerate_zero_padding": True,
    "p2_timeout": 10,
    }
    tp_addr = isotp.Address(isotp.AddressingMode.Normal_11bits, txid=0x604, rxid=0x614) # Network layer addressing scheme
    stack = isotp.CanStack(bus=can_bus, address=tp_addr, params=isotp_params)               # Network/Transport layer (IsoTP protocol)
    conn = PythonIsoTpConnection(stack)  
    client = Client(conn, request_timeout=2, config=config)


    with Client(conn, request_timeout=2, config=config) as client:                                     # Application layer (UDS protocol)
        client.ecu_reset(ECUReset.ResetType.hardReset)

    #notifier1.stop()
    #logger1.stop()

    can_bus.shutdown()

WrongSequenceNumberError

I realize this error condition is intentional. But, by nature CAN may not send messages orderly.
I was able to trigger this with a simple message:

data = b'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
data = data + data

WARNING:root:IsoTp error happened : WrongSequenceNumberError - Received a ConsecutiveFrame with wrong SequenceNumber. Expecting 0x3, Received 0x8
WARNING:isotp:Received a ConsecutiveFrame with wrong SequenceNumber. Expecting 0x3, Received 0x8

candump shows:

  can0  100   [8]  10 48 30 31 32 33 34 35
  can0  456   [3]  30 08 00
  can0  100   [8]  21 36 37 38 39 41 42 43
  can0  100   [8]  22 44 45 46 47 48 49 4A
  can0  100   [8]  28 4A 4B 4C 4D 4E 4F 50

CAN FD long message support

CAN-FD allows messages longer than 8 bytes. When setting ll_data_length to a value larger than 8 and then sending data longer than 8 bytes, python-can-isotp is encoding the length paramter incorrectly. In some cases, the length is even overflowing in the high bits of the first byte and thus changing the frame type. Receiving long messages is probably affected as well.

Reproduction

def show_msg(msg):
    print("can msg:", msg.data.hex())
    print()

address = isotp.Address(rxid=0x123, txid=0x456)
tl = isotp.TransportLayer(rxfn=lambda: None, txfn=show_msg, address=address, params={
    'll_data_length': 32, 
    'tx_padding': 0x00
})

for l in (5, 10, 20):
    data = bytearray(list(range(0xA1, 0xA1+l)))
    print("len:", l, "data:", data.hex())
    tl.send(data)
    tl.process()

Current Output

len: 5 data: a1a2a3a4a5
can msg: 05a1a2a3a4a50000000000000000000000000000000000000000000000000000

len: 10 data: a1a2a3a4a5a6a7a8a9aa
can msg: 0aa1a2a3a4a5a6a7a8a9aa000000000000000000000000000000000000000000

len: 20 data: a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4
can msg: 14a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b40000000000000000000000

Expected Output

According to ISO 15765-2 Section 9.6, SF_DL should be stored in the 2nd Byte if CAN_DL exceeds 8 bytes. Bits 0-3 of the first byte should be set to zero:

len: 5 data: a1a2a3a4a5
can msg: 05a1a2a3a4a50000000000000000000000000000000000000000000000000000

len: 10 data: a1a2a3a4a5a6a7a8a9aa
can msg: 000aa1a2a3a4a5a6a7a8a9aa0000000000000000000000000000000000000000

len: 20 data: a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4
can msg: 0014a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b400000000000000000000


send flow control(FC)

.This is not a issue.I need to send FC to ECU,but i don't know how to do it with the library.
my code is :


import can
import time
from udsoncan.connections import PythonIsoTpConnection
from udsoncan.client import Client
import isotp
import udsoncan.configs

# Refer to isotp documentation for full details about parameters
isotp_params = {
'stmin' : 32,                          # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
'blocksize' : 8,                       # Request the sender to send 8 consecutives frames before sending a new flow control message
'wftmax' : 0,                          # Number of wait frame allowed before triggering an error
'tx_data_length' : 8,                 # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
'tx_data_min_length' : None,         # Minimum length of CAN messages. When different from None, messages are padded to meet this length. Works with CAN 2.0 and CAN FD.
'tx_padding' : 0,                      # Will pad all transmitted CAN messages with byte 0x00.
'rx_flowcontrol_timeout' : 1000,       # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
'rx_consecutive_frame_timeout' : 1000, # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds
'squash_stmin_requirement' : False,    # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
'max_frame_size' : 4095               # Limit the size of receive frame.
}

mybus = can.Bus(bustype='canalystii', channel=0, bitrate=500000)
##mylog=can.Logger('test1.blf')
##mynotifier = can.Notifier(mybus,[mylog,can.Printer()])
###print(mybus)

config = dict(udsoncan.configs.default_client_config)
config['data_identifiers'] = {
##   0x1234 : MyCustomCodecThatShiftBy4,    # Uses own custom defined codec. Giving the class is ok
##   0x1235 : MyCustomCodecThatShiftBy4(),  # Same as 0x1234, giving an instance is good also
0xF180 : udsoncan.AsciiCodec(15)       # Codec that read ASCII string. We must tell the length of the string
}


tp_addr = isotp.Address(isotp.AddressingMode.Normal_11bits, txid=0x731, rxid=0x739) # Network layer addressing scheme
stack = isotp.CanStack(bus=mybus, address=tp_addr, params=isotp_params)               # Network/Transport layer (IsoTP protocol)
conn = PythonIsoTpConnection(stack)                                                 # interface between Application and Transport layer
with Client(conn,request_timeout=1,config=config) as client:                                     # Application layer (UDS protocol)
response = client.read_data_by_identifier(0xF180)
print(response.service_data.values[0xF180])

isotp.socket() behavior deviates from python sockets on timeouts

A standard python socket would encounter a socket.timeout Exception on recv() if no data came in. The can-isotp package, on the other hand, catches the exception and converts it into a return None.

I think this is wrong for several reasons:

  1. It deviates from the programmer's expectations that a can-isotp socket behaves like a regular python socket.
  2. The can-isotp package may not know if a timeout is an error or normal behavior. It is up to application code to determine.
  3. It obscures that the application may be waiting for IO before reaching a timeout.
  4. Code that expects to catch a timeout exception may end up generating a TypeError as it works with the None object.

Proposal:

When istop.socket.recv() times out, the socket.timeout error should either be passed down, or converted and re-raised explicitly as a TimeoutError().

Example

sock = isotp.socket()
sock.set_opts(txpad=0xcc)
sock.bind("can0", isotp.Address(txid=0x7e0, rxid=0x7e8))

bogus_msg = bytes([0xde, 0xad, 0xc0, 0xff, 0xee])
answer sock.send(bogus_msg)
try:
	answer = sock.recv()
except socket.error as err:
	# EXPECTATION: we hit this handler
	return

# REALITY: We get a None object when we expect actual data
# The line below will explode with an isotp socket
print(len(answer))

Linux kernel 5.4.x displays "OSError: [Errno 22] Invalid argument" when _socket.bind() called

After recently updating my Linux kernel to 5.4.x, it seems that there is some sort of interface change to binding sockets causing breakage. As a result I get the following traceback:

Traceback (most recent call last):
  File "./my-app", line 22, in <module>
    my_session.start()
  File "/home/rslindee/work/my_session.py", line 112, in start
    self.client.open()
  File "/home/rslindee/work/python-udsoncan/udsoncan/client.py", line 58, in open
    self.conn.open()
  File "/home/rslindee/work/python-udsoncan/udsoncan/connections.py", line 260, in open
    self.tpsock.bind(self.interface, rxid=self.rxid, txid=self.txid)
  File "/home/rslindee/work/python-can-isotp/isotp/tpsock/__init__.py", line 165, in bind
    self._socket.bind((interface, rxid, txid))
OSError: [Errno 22] Invalid argument

If I revert my kernel to 5.3.x, everything works fine (this is an existing application that utilized your python modules with great success up until now). Note: I am able to successfully build my isotp kernel module and run a tool like isotpdump just fine with kernel 5.4.x, it is primarily my python script leveraging python-can-isotp that I'm having trouble with.

Some more system info:

OS: Fedora 31
Kernel: 5.4.8
Python: 3.7.6
python-can-isotp commit: 6f7f4d1

Please let me know if there is any additional info I could provide that would be useful!

ConsecutiveFrameTimeoutError for first consecutive frame

I found that ConsecutiveFrameTimeoutError was not raised, although, the first consecutive frame was not received after first frame and flow control exchange:
S R
-----First Frame----->
<--- Flow Control----

Is that expected behaviour - that ConsecutiveFrameTimeoutError raises only if consecutive frame receieved with delay.
What if the first consecutive frame will not come at all?
I thought in this case ConsecutiveFrameTimeoutError should be raised.

can not enable data bitrate in CANFD mode

in my test, after the CAN FD mode enable(TransportLayer['can_fd'] = true,), the FDF bit in CAN bus can be set, but the BRS bit can NOT be set.
After my checking, there is no parameter bitrate_switch in the below can.Message() of protocol.py, but bitrate_switch is available parameter in the class Message of python-can.

_class CanStack(TransportLayer):  
  def _tx_canbus_3plus(self, msg):
        self.bus.send(can.Message(arbitration_id=msg.arbitration_id, data = msg.data, is_extended_id=msg.is_extended_id, is_fd=msg.is_fd))
    def _tx_canbus_3minus(self, msg):
        self.bus.send(can.Message(arbitration_id=msg.arbitration_id, data = msg.data, extended_id=msg.is_extended_id, is_fd=msg.is_fd))_

is there any other method to enable BRS? or need update the source code of can-isotp

OSError: [Errno 93] Protocol not supported

Hi, I use this project on RasberryPi3, I used the example code to test,and I got an error when I run s = isotp.socket() , It confused me, actually.
Error:
File "/usr/local/opt/python-3.7.0/lib/python3.7/socket.py", line 151, in __init__ _socket.socket.__init__(self, family, type, proto, fileno) OSError: [Errno 93] Protocol not supported

Python-can-isotp consume a asc file

Hi, i want to know if the Python-can-isotp can consume a CAN log file (.asc .txt ...) to extract the payload of the frame that are CAN TP data frames. If not any help on a possible solution ?

stmin is not consistent with multiframe messages

while using isotp.CanStack & stack.process and setting stmin in funtion set_fc_opts doesn't have a consistent stmin time gap between messages of flow control. if 10 ms is set then there are instances of 0.008 or 0.006 which occurs during runtime with a complimentary stmin of 0.011 or 0.013 .

File: 1--------

import isotp
import can
from can.interface import Bus
import time
while True:
    isotp_params = {
     'stmin': 255, # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
     'blocksize' : 0, # Request the sender to send 8 consecutives frames before sending a new flow control message
     'wftmax': 0, # Number of wait frame allowed before triggering an error
     'tx_data_length': 8, # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
     'tx_padding': 0, # Will pad all transmitted CAN messages with byte 0x00. None means no padding
     'rx_flowcontrol_timeout': 1000, # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
     'rx_consecutive_frame_timeout': 1000, # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds
     'squash_stmin_requirement': False # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
    }
    #lst = [40, 41, 42, 34, 48, 50, 63, 15, 66, 99, 12, 87, 59, 9, 78, 44]
    lst = []
    data = bytes(lst)
    bus = Bus(bustype='socketcan', channel='can1', bitrate=500000, receive_own_messages=True)
    rxid = 0x628
    txid = 0x6A8
    isExtId = False
    s = isotp.socket()
    tp_addr = isotp.Address(isExtId, rxid=rxid, txid=txid)
    stack = isotp.CanStack(bus, address = tp_addr, params = isotp_params)
    s.set_fc_opts(stmin=10, bs=0)
    s.bind("can1", tp_addr)
    
    stack.send(data)
    while stack.transmitting():
        stack.process()
        time.sleep(stack.sleep_time())
    time.sleep(3)

FIle 2 ---------

import isotp
import can
from can.interface import Bus
import time

isotp_params = {
     'stmin': 255, # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
     'blocksize' : 0, # Request the sender to send 8 consecutives frames before sending a new flow control message
     'wftmax': 0, # Number of wait frame allowed before triggering an error
     'll_data_length': 8, # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
     'tx_padding': 0, # Will pad all transmitted CAN messages with byte 0x00. None means no padding
     'rx_flowcontrol_timeout': 1000, # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
     'rx_consecutive_frame_timeout': 1000, # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds
     'squash_stmin_requirement': False # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
    }

rxid = 0x6A8
txid = 0x628
isExtId = False

bus = Bus(bustype='socketcan', channel='can0', bitrate=500000, receive_own_messages=True)

lst = [10, 21, 72, 33, 48, 50, 63, 15, 66, 99, 12, 87, 59, 9, 78, 44, 10, 21, 72, 33, 48, 50, 63, 15, 66, 99, 12, 87, 59, 9, 78, 44]
for x in range(190):
     lst.append(x)
data = bytes(lst)

def can_isotp_tx(bus, isExtId, rxid, txid, data, receiver = False): 
     s = isotp.socket()   
     tp_addr = isotp.Address(isExtId, rxid=rxid, txid=txid)
     s.bind("can0", tp_addr)
     stack = isotp.CanStack(bus = bus, address = tp_addr, params = isotp_params)
     s.send(data)
     time.sleep(2)
while True:
     can_isotp_tx(bus, isExtId, rxid, txid, data, receiver = False)

Also Can you clear that what is the difference between
s = isotp.socket() & s.set_fc_opts & s.send

and

s= isotp.CanStack(params) & s.process

which would be better in order to handle proper flow control

Unstable Connection

Hi, I have two problems with the library.

1- The first one is a bit weird. When my laptop is connected to the dock station and other devices I get a fellow control error. But when I disconnect the laptop it works properly and I can have communication through CAN. The docking station is connected to two monitors. I have tried several times but I always the same results. I am not sure, but I think STmin is set to 12ms in the embedded board. If it makes sense in this case I can ask for the embedded device specification. Is there any solution to this problem?

2- The second problem: I have a file that I want to write to the board. The payload of the file is 280 bytes. The defined Blocksize on the board is set to 10. The problem is that on the embedded board it is defined that in the first frame it should be defined that the length of this data is 280 bytes and after 10 frames the "CONSECUTIVE FRAME" will be called, until the last frame. If I set the Blocksize on the embedded device to ex. 200 the problem will be solved because it sends all the frames without calling "CONSECUTIVE FRAME" but in this case, the default is 10. And if I shrink the package, because the length of the data changes, the data is not valid to the board. Does anyone have a solution?

If there is a need for the sample code please let me know.
Thank you in advance :)

[CAN_FD] Padding disabled with tx_data_length set

Hi there,

I encountered the following behaviour:

The settings:

        self.bus = can.interface.Bus(bustype='vector', channel=0, bitrate=500000, app_name="CANoe", fd=True,
                                     data_bitrate=2000000, bitrate_switch = True)
        addr = isotp.Address(isotp.AddressingMode.Normal_11bits, rxid=0x604, txid=0x704, is_fd=True)
        self.stack = isotp.CanStack(self.bus, address=addr, error_handler=self.my_error_handler,

                                    params={'tx_padding': 0, 'can_fd': True,
                                            'bitrate_switch': True,
                                            'tx_data_length': 64})

If the tx_data_length is not there the CAN_FD fraems are padded to 8Bytes.

As soon as the 'tx_data_length': 64 is set the padding is no longer working and we're sending "real" frame lengths again.

Is this intended? Is it possible to setup the padding beaviour to always pad to 8 Bytes (or a configurable value?).

Am I missing something? Is this a feature or a bug? ;)

Thanks in advance!

/A

Tx Frames sent at STmin = 0 while setting Tx STmin to a value > 0

I'm trying to set Tx STmin to a value between 1ms and 10ms, but with no success.

_connection = IsoTPSocketConnection(self._can_channel, rxid=self._fota_uds_rxid, txid=self._fota_uds_txid, addressing_mode=addressing_mode)
_connection.tpsock.set_opts(optflag=optflag, txpad=0, frame_txtime=self._txdelay, tx_stmin=5)

Current behavior:
1- If we set Tx STmin to None, we respect the server Rx STmin value which is 10ms in my case, which is working fine.
2- But when I set STmin > 0ms, we ignore the server STmin value, but I see in the candump that the frames are sent at 0ms for what ever non null value I set for STmin.

Functional Message Support for Server

I need to receive a message as a functional request (0x7DF) however I need to response on a physical address (0x7E8) and also listen for Flow Control Frames on (0x7E0).

I would like to my isotp.Address(rxid=[0x7DF, 0x7E0]) so that I can catch any of these messages. I'm working on updating this now but am not sure if I'll have success.

Access underlying python-can bus

I am trying to use can-isotp with udsoncan.
The isotp layer should only need those messages with the specified receive message id.
In my use case I must be able to receive all other messages and process them independent of isotp and without interfering uds/isotp communication.

I couldnt find any documentation about this behaviour.
Is this possible with the current implementation of isotp?

I tried using a second thread which calls the receive method of the can bus. But then I will get a timeout exception when I use uds services.

I am posting in the isotp project because I think this would be a feature for the isotp layer.

Receive flow control frames from ECU when transmitting, rather than can-isotp receiver?

Thank you so much for making this module.

I am trying to use the isotp module to send data to an ECU on a Vector CAN interface, using the transmit example from the documentation. In the bus trace, I see the First Frame from can-isotp, and a response Flow Control from my ECU. However, can-isotp then reports that it timed out while waiting for a Flow Control frame.

I can get can-isotp to communicate with itself by running the transmit example and threaded receive example code side by side (using a separate bus instance in each with the same settings), but it still appears can-isotp is generating the flow control frame and the transmitter is using that (trace from CANalyzer, ECU FC in green and can-isotp FC in yellow):

image

Can can-isotp be configured to use Flow Control frames from an ECU rather than generating them in the can-isotp receiver side? Any tips on how to accomplish that?

stmin is wrong at least on windows.

So I got a lot slower transfer than I expected I did a quick hack to busy wait to get something much more like what the stmin time should be. Not sure what a proper solution really is. maybe the code as is works fine under linux.

$ git diff -w
diff --git a/isotp/protocol.py b/isotp/protocol.py
index 1acd21b..d2d041c 100755
--- a/isotp/protocol.py
+++ b/isotp/protocol.py
@@ -826,6 +826,10 @@ class TransportLayer:
             pass # Nothing to do. Flow control will make the FSM switch state by calling init_tx_consecutive_frame

         elif self.tx_state == self.TxState.TRANSMIT_CF:
+            while not self.timer_tx_stmin.is_timed_out() :
+                #print(f"timer_tx_stmin active elaspsed = {self.timer_tx_stmin.elapsed()}")
+                pass
+
             if self.timer_tx_stmin.is_timed_out() or self.params.squash_stmin_requirement:
                 data_length = self.params.tx_data_length-1-len(self.address.tx_payload_prefix)
                 msg_data = self.address.tx_payload_prefix + bytearray([0x20 | self.tx_seqnum]) + self.tx_buffer[:data_length]

How Sending with functional addressing in client

I am so sorry, I have been on a business trip before, so I have never time to reply

  • why does it need to be functional?
  1. I want to design a software download tool for vehicle flashing, So I need to turn off the communication($28) enable and DTC detection($85) enable of other ECUs through functional addressing, and then refresh the ECU through physical addressing.
  • do you expect an answer from your server?
  1. No
  • do you want to switch between functional and physical back and forth?
  1. yes

for example

client.change_session(DiagnosticSessionControl.Session.extendedDiagnosticSession) # use functional addr
client.control_dtc_setting(services.ControlDTCSetting.SettingType.off)  # use functional addr
client.communication_control(services.CommunicationControl.ControlType.disableRxAndTx,0x01)   # use functional addr
client.change_session(services.DiagnosticSessionControl.Session.programmingSession)  # use physical addr
client.unlock_security_access(0x11) # use physical addr
                     ....

Rate limit the sending of consecutive frames regardless of server request

I am on Windows using Vector HW. I use udsoncan to perform a transfer data operation in 4KB blocks with python-can-isotp as the TP layer.
The server, in its flow control, has stmin=0 so python-can-isotp sends as fast as possible. However, it seems the Vector driver sometimes can't handle the fast rate and throws a XL_ERR_QUEUE_IS_FULL error.

According to this page:

You have a program that writes messages very quickly to the buffer so that the data rate of the real bus is exceeded (e.g. while-/for-loops).

Suggesting that the bus data rate needs to be respected to avoid this error.

Therefore, I'd like to rate limit the transmit. Is there a way to have python-can-isotp set a minimum value for transmit stmin? i.e. if server gives stmin=0, we still limit it to some value (e.g. 1ms separation)? Perhaps based on the bus rate?

Receiving from multiple ECUs using single bus

I wanted to check if my understanding is correct in what I am trying to do.

I want to send and receive to multiple ECUs (addresses). I am using python-can and udsoncan.
I had assumed that I would instantiate one python-can bus and then just send up different stacks

bus = VectorBus(channel=0, bitrate=500000)
addr = isotp.Address(isotp.AddressingMode.Normal_11bits, rxid=0x123, txid=0x456)
stack = isotp.CanStack(bus, address=addr)

addr2 = isotp.Address(isotp.AddressingMode.Normal_11bits, rxid=0x567, txid=0x789)
stack2 = isotp.CanStack(bus, address=addr2)

However, I find that no messages are received. If I create a bus2 and use that in stack2, it works fine. But is it correct that I need to instantiate a new bus for each address (ECU) that I want to communicate with?

I understand python-can will notify as required (i.e. for the messages (arbitration IDs) you are interested in) so I thought it was possible for only one bus to be used. Or is python-can-isotp consuming all messages received on that bus?

Possibility to switch off Flow Control sending on Rx

I have some projects where it is not necessary to send a flow control after reception of first frame
In my case another ECU is taking care of that.

Proposal: Implement a parameter to switch off flow control on reception, e.g.
image

Non blocking python canbus usage

I want to use python-can-isotp (for python uds) with continuing to use the python canbus for other non iso-tp messages.

I have tested one of the solutions for this mentioned in #19 .

I have created a virtual canbus class inherited from BusABC which re-implements the 'recv' and 'send' methods. The virtual canbus class itself is taking a notifier and a canbus object. This bus is passed to 'isotp.CanStack'.

I can see on the canbus that the rested Id is correctly sent and that the response id is received (via the listener object).
The isotp is calling / pooling the 'recv' of the virtual canbus but it seems not to process the data because there is a timeout error for the isotp response.

If a pass a real python can bus object isotp and uds is works correctly.

Consecutive Messages occasionally too fast

Hi,

I'm using udsoncan to transfer a file over can-isotp. System is Windows.
During the transfer I occasionally get two consecutive messages, which have a very short sepeartion time, leading to my receiver dropping one of them. The receiver requests a separation time of 1 ms, while the messages are sent apart 300 microseconds. The following trace shows the sender (CAN-ID 0x10A) transfering a file using udsoncan to the receiver (CAN-ID 0x10B).
grafik

Increasing the separation time up to 5 ms decreases the occurence of the two messages sent shortly after, but it still occures from time to time. In the following trace the seperation time is set to 5 ms and again sender (CAN-ID 0x10A) sends via udsoncan to the receiver (CAN-ID 0x10B).
grafik

I use these isotp parameters:

isotp_params = {
        'stmin': 32,
        # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
        'blocksize': 8,  # Request the sender to send 8 consecutives frames before sending a new flow control message
        'wftmax': 0,  # Number of wait frame allowed before triggering an error
        'll_data_length': 8,  # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
        'tx_padding': 0xFF,  # Will pad all transmitted CAN messages with byte 0x00. None means no padding
        'rx_flowcontrol_timeout': 1000,
        # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
        'rx_consecutive_frame_timeout': 1000,
        # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds
        'squash_stmin_requirement': False
        # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
    }

From my understanding this should be prevented by ST in isotp. Is there anything I am missing?

stack.process() got stuck during milti frame Tx

Hi,

Observed some weird behavior in my Python code for transmitting Multi-frame CAN MESSAGE.

code:
While stack.transmitting():
Stack.process()
time.sleep(stack.sleep_time())

the execution hangs in stack.process() function call and eventually the while loop doesn’t break causing the whole code stuck.

please advise.

can.Message.__init__, is_extended_id vs extended_id

I'm having trouble using python-can-isotp with python-can. tx_canbus attempts to create a new can.Message using the extended_id keyword argument, but this has been changed to is_extended_id.

The issue is at

self.bus.send(can.Message(arbitration_id=msg.arbitration_id, data = msg.data, extended_id=msg.is_extended_id, is_fd=msg.is_fd))

It seems like a simple one line fix, but I'm not sure if I using the wrong version or doing something else to cause this error.

FlowControl are not read by the stack most of the times

I have can-isotp module running on RaspeberryPi4 and I am trying to send a multi-frame data from CAN using CAN HAT.
But whenever the module is sending the First frame it keeps on waiting for FC till it times out. Even though the Flow control frame was received on the Bus. I could verify that by printing the frame received also in candump command.

Module somehow doesnt recognize the FC frame and gives the timeout error.

Please guide me in this, my project execution has got stuck due to this issue.

Support for ISOTP extended adressing

Hi @pylessard,
great work!
I checked your code, since I'm always interested in different approaches for ISOTP implementations.

I missed one feature of your code. Some OEMs use extended ISOTP addressing for various purposes.
I don't talk about extended CAN identifiers. The ISOTP standard supports extended addresses in the first byte of the CAN data frame.
You can generate this extended addressing for example with isotpsend

echo "de ad be ef" | isotpsend -s 641 -d 251 -x 41:51 vcan0

Register callback per addressing; multi-threading

Hi,
I have to deal with a rather complex ecu, that sends different PDUs (on 15 different Rx/Tx addresses) at an arbitrary time and in random order.
I would like to handle them all with a single python script. Hence I am wondering if a mechanism that accepts a simple address-to-callback dictionary might do it. All the can stack handling and threading is hidden from my program. The callback methods are provided with the received message and voila.

However for today, my simple question is, is it safe to run 15 threads (as described here https://can-isotp.readthedocs.io/en/latest/isotp/examples.html#threaded-reception-with-python-can) each with different addressing.

If I misunderstood the whole concept, then please let me know, too :-).

Thanks
Lars

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.