hardbyte / python-can

The can package provides controller area network support for Python developers
https://python-can.readthedocs.io
GNU Lesser General Public License v3.0
1.26k stars 599 forks source link

Re-connect with PCANBasic fails after failed connection attempt #729

Open stefanhoelzl opened 4 years ago

stefanhoelzl commented 4 years ago

I am using python-can with an PEAK-Dongle. Sometimes I get an exception during Bus creation than I would like try another connection attempt, but this Fails, because python-can has intitialized the PCAN-DLL but did not uninitialize it. And since multiple Connections are not allowed with PCANBasic the second connection attempt also Fails (and all other in the same process)

The issue can be Show with the following script

import can
try:
    bus = can.interface.Bus(bustype="pcan", channel="PCAN_USBBUS1", bitrate=5000000)
    bus.shutdown()
except:
    print("exception")
# the following attempt ALWAYS fails if the first attempt has also failed
bus = can.interface.Bus(bustype="pcan", channel="PCAN_USBBUS1", bitrate=5000000)
bus.shutdown()

The problematic code is here. Before this line the PCAN-Dll get initialized but if afterwards a exception is raised, it does not get uninitilized.

A simple solution can be the following:


class PcanBus(BusABC):
  def __init__(…):
    # ...
    try:
        if result != PCAN_ERROR_OK:
            raise PcanError(self._get_formatted_error(result))

        result = self.m_objPCANBasic.SetValue(
            self.m_PcanHandle, PCAN_ALLOW_ERROR_FRAMES, PCAN_PARAMETER_ON
        )

        if result != PCAN_ERROR_OK:
            raise PcanError(self._get_formatted_error(result))

        if HAS_EVENTS:
            self._recv_event = CreateEvent(None, 0, 0, None)
            result = self.m_objPCANBasic.SetValue(
                self.m_PcanHandle, PCAN_RECEIVE_EVENT, self._recv_event
            )
            if result != PCAN_ERROR_OK:
                raise PcanError(self._get_formatted_error(result))

        super().__init__(channel=channel, state=state, bitrate=bitrate, *args, **kwargs)
    except:
        self.m_objPCANBasic.Uninitialize(self.m_PcanHandle)
        raise
felixdivo commented 3 years ago

This sounds like a good addition. Would you prepare a small PR?