Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IXXAT and isCAN dongle can't handle unit not responding #1743

Open
Svalann opened this issue Feb 15, 2024 · 0 comments
Open

IXXAT and isCAN dongle can't handle unit not responding #1743

Svalann opened this issue Feb 15, 2024 · 0 comments
Labels

Comments

@Svalann
Copy link

Svalann commented Feb 15, 2024

Describe the bug

First of all, I think this issue might be related to Graceful exception handling in Notifier thread. I have a similar issue where I need to catch startup messages during boot before application is launched. I have a small timeframe where I can intercept this and need to be on the bus to catch it. This works fine with Kvaser and PCAN. This catching might be performed with a separate listener but normally we test units regularly with the power switching on and off to evaluate vehicle startup, there are important messages sent out the first milliseconds, like NMTs and heartbeats. Also it is annoying to manually re-connect every time even when not handling startup.

But to summarize, IXXAT and isCAN fail to re-establish connection once a unit has lost power, or cable disconnected etc.

Not sure this is related to the issue but network.bus.flush_tx_buffer() is sometimes needed with a Kvaser dongle for example but this does not fix it with IXXAT and isCAN at least.

To Reproduce

A simple test case

"""Testing Dongle not responsive, test connection every 20 ms"""
import time
import canopen

class DongleTester(object):
    """Test Dongle not responsive"""
    def __init__(self):
        self.dongle = "ixxat"
        # self.dongle = "iscan"
        self.bitrate = 500000
        self.channel = 0
        self.node_id = 5
        self.network = canopen.Network()
        self.node = canopen.Node(self.node_id, None)
        self.node.associate_network(self.network)

    def connect(self):
        """Connect to network"""
        try:
            self.network.connect(
                bustype=self.dongle,
                channel=self.channel,
                bitrate=self.bitrate,
                extended=True,
                receive_own_messages=True,
                driver_mode=False)
        except Exception as ex:
            print(ex)

    def real_run(self):
        """Main loop"""
        while True:
            try:
                time.sleep(0.02)
                response = self.node.sdo.upload(0x1000, 0)
                print(response)
            except canopen.network.CanError as ex:
                self.network.bus.flush_tx_buffer()
                time.sleep(0.1)
                print(f"{ex}")
            except Exception as ex:
                print(f"Exc: {ex}")

test = DongleTester()
test.connect()
test.real_run()

Expected behavior

On a sdo request to a non responsive unit should return (or similar): SdoError: No SDO response received
Bus should not be locked/terminated.

Additional context

OS and version: Win 11
Python version: 3.11.5 (Also 3.7.9 with same result)
python-can version: 4.3.1 (Also 4.2.2 with same result)
python-can interface/s (if applicable): IXXAT and isCAN

I tried finding the core issue but unsuccessful. With some small changes I can achieve what I'm looking for but it is probably way to dangerous and is not fixing the actual problem but rather ignores errors. I wish I could provide with a solution suggestion. (See Trace)

But what I have tested is in isCAN to change in _recv_internal the line
if e.error_code != 8:
to
if e.error_code not in (8, 18, 20, 31):

and in IXXAT change in _recv_internal the line

elif error_byte_1 & constants.CAN_STATUS_ERRLIM:
      raise VCIError("Error warning limit exceeded")

to just pass instead of raise that VCIError.

Traceback and logs

isCAN trace

-- sprint of succesfull response --
b'\x00\x00\x00\x05'
b'\x00\x00\x00\x05'

-- Breaks power to unit --

Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]

-- Until here it can recover if unit is powered on (seems to be about 10 messages) --

Exception in thread can.notifier for bus "IS-CAN: c_ubyte(0)":
Traceback (most recent call last):
File "C:\Program Files\Python311\Lib\threading.py", line 1038, in _bootstrap_inner
self.run()
File "C:\Program Files\Python311\Lib\threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "python\Lib\site-packages\can\notifier.py", line 124, in _rx_thread
if msg := bus.recv(self.timeout):
^^^^^^^^^^^^^^^^^^^^^^
File "python\Lib\site-packages\can\bus.py", line 121, in recv
msg, already_filtered = self._recv_internal(timeout=time_left)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "python\Lib\site-packages\can\interfaces\iscan.py", line 125, in _recv_internal
iscan.isCAN_ReceiveMessageEx(self.channel, ctypes.byref(raw_msg))
File "python\Lib\site-packages\can\interfaces\iscan.py", line 43, in check_status
raise IscanOperationError(function, result, arguments)
can.interfaces.iscan.IscanOperationError: Function isCAN_ReceiveMessageEx failed: Error warning [Error Code 20]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]
Function isCAN_TransmitMessageEx failed: Transmission not acknowledged on bus [Error Code 31]

IXXAT trace:

-- print of succesfull response --
b'\x00\x00\x00\x05'
b'\x00\x00\x00\x05'

-- Breaks power to unit --

CAN acknowledgment error
CAN message flags bAddFlags/bFlags2 0x00 bflags 0x05
Exception in thread can.notifier for bus "unknown":
Traceback (most recent call last):
File "C:\Program Files\Python311\Lib\threading.py", line 1038, in _bootstrap_inner
self.run()
File "C:\Program Files\Python311\Lib\threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "python\Lib\site-packages\can\notifier.py", line 124, in _rx_thread
if msg := bus.recv(self.timeout):
^^^^^^^^^^^^^^^^^^^^^^
File "python\Lib\site-packages\can\bus.py", line 121, in recv
msg, already_filtered = self._recv_internal(timeout=time_left)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "python\Lib\site-packages\can\interfaces\ixxat\canlib.py", line 148, in _recv_internal
return self.bus._recv_internal(timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "python\Lib\site-packages\can\interfaces\ixxat\canlib_vcinpl.py", line 733, in _recv_internal
raise VCIError("Error warning limit exceeded")
can.interfaces.ixxat.exceptions.VCIError: Error warning limit exceeded
An error has caused receiving of messages to stop
Error warning limit exceeded
An error has caused receiving of messages to stop
Error warning limit exceeded

@Svalann Svalann added the bug label Feb 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant