简体   繁体   中英

How can I trap CAN bus exceptions such as 'Network down' from within python-can interfaces?

I have a small python project to simulate CAN-enabled electronics that I have built. The project has a shell interpreter to interact with the simulated electronics devices. I'm at a point I'd like to trap exceptions thrown from within python-can running instances and print friendly error messages in the main shell UI instead of getting a full stack trace garbling the display.

For instance, if I run my script while the can0 interface is not configured (ie before executing ip link set can0 up type can bitrate 250000 ) I get a stack trace such as this:

Failed to send: Timestamp:        0.000000        ID: 0541    000    DLC: 8    01 1a c4 13 00 00 e2 04
> Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/lib/python3.6/site-packages/can/notifier.py", line 39, in rx_thread
    msg = self.bus.recv(self.timeout)
  File "/usr/lib/python3.6/site-packages/can/interfaces/socketcan_native.py", line 341, in recv
    packet = capturePacket(self.socket)
  File "/usr/lib/python3.6/site-packages/can/interfaces/socketcan_native.py", line 274, in capturePacket
    cf, addr = sock.recvfrom(can_frame_size)
OSError: [Errno 100] Network is down

Note that the '>' sign above is my mini-shell prompt. That looks ugly, right.

I first tried to derive SocketcanNative_Bus and override the recv() method but then my new class is rejected as there's a check in /usr/lib/python3.6/site-packages/can/interfaces/interface.py that validates an interface class name against a list of well-known modules. So this might be not-quite-the-way-to-go.

Before I try anything else stupid, does python-can provide some means to intercept OS errors that occur in Notifier threads during transmission of data packets or when the CAN interface goes down, for instance?

Note that since I'm using a USB CAN adapter, it's pointless to check the network state only when the script starts because the CAN adapter could as well be unplugged while the script runs. So the only relevant way is to catch exceptions thrown by python-can modules and show a friendly message in the main thread.

I still don't know if that's what python-can developers intended but here's my latest working attempt. I'm overriding the recv() method of a class SocketcanNative_Bus instance, aka bus :

can.rc['interface'] = 'socketcan_native'
can.rc['channel'] = args[1]

from can.interfaces.socketcan_native import SocketcanNative_Bus
def recv(self, timeout=None):
    try:
        return SocketcanNative_Bus.recv(self, timeout)
    except OSError as e:
        print(str(e))
        return None

try:
    import types
    bus = can.interface.Bus()
    bus.recv = types.MethodType(recv, bus)

except OSError as e:
    print('Error {0}: {1}'.format(e.errno, e.strerror), file=sys.stderr)

I dynamically overrode the bus instance's method recv() using Python's types.MethodType() . It's called patching as explained elsewhere on Stackoverflow .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM