Reputation:
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 (i.e. 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.
Upvotes: 1
Views: 2895
Reputation:
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.
Upvotes: 3