Skip to content

Commit 215673c

Browse files
christiansandberghardbyte
authored andcommitted
Avoid using polling for PCAN. Closes hardbyte#53
* Use events to wait for PCAN messages * Log warning on some bus errors and return None * Fix verbosity of PCAN debug output * Code cleanup * Update PCAN installation instructions
1 parent e975bf9 commit 215673c

2 files changed

Lines changed: 38 additions & 22 deletions

File tree

can/interfaces/pcan/pcan.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
except:
2020
boottimeEpoch = 0
2121

22+
try:
23+
import win32event
24+
except ImportError:
25+
win32event = None
26+
2227
if sys.version_info >= (3, 3):
2328
# new in 3.3
2429
timeout_clock = time.perf_counter
@@ -27,7 +32,6 @@
2732
timeout_clock = time.clock
2833

2934
# Set up logging
30-
logging.basicConfig(level=logging.WARNING)
3135
log = logging.getLogger('can.pcan')
3236

3337

@@ -83,6 +87,13 @@ def __init__(self, channel, *args, **kwargs):
8387
if result != PCAN_ERROR_OK:
8488
raise PcanError(self._get_formatted_error(result))
8589

90+
if win32event is not None:
91+
self._recv_event = win32event.CreateEvent(None, 0, 0, None)
92+
result = self.m_objPCANBasic.SetValue(
93+
self.m_PcanHandle, PCAN_RECEIVE_EVENT, self._recv_event)
94+
if result != PCAN_ERROR_OK:
95+
raise PcanError(self._get_formatted_error(result))
96+
8697
super(PcanBus, self).__init__(*args, **kwargs)
8798

8899
def _get_formatted_error(self, error):
@@ -142,24 +153,35 @@ def reset(self):
142153
return status == PCAN_ERROR_OK
143154

144155
def recv(self, timeout=None):
145-
start_time = timeout_clock()
146-
147-
if timeout is None:
148-
timeout = 0
149-
150-
rx_msg = Message()
156+
if win32event is not None:
157+
# We will utilize events for the timeout handling
158+
timeout_ms = int(timeout * 1000) if timeout is not None else win32event.INFINITE
159+
elif timeout is not None:
160+
# Calculate max time
161+
end_time = timeout_clock() + timeout
162+
else:
163+
# Skip timeout handling
164+
end_time = 0
151165

152166
log.debug("Trying to read a msg")
153167

154168
result = None
155169
while result is None:
156170
result = self.m_objPCANBasic.Read(self.m_PcanHandle)
157-
if result[0] == PCAN_ERROR_QRCVEMPTY or result[0] == PCAN_ERROR_BUSLIGHT or result[0] == PCAN_ERROR_BUSHEAVY:
158-
if timeout_clock() - start_time >= timeout:
171+
if result[0] == PCAN_ERROR_QRCVEMPTY:
172+
if win32event is not None:
173+
result = None
174+
val = win32event.WaitForSingleObject(self._recv_event, timeout_ms)
175+
if val != win32event.WAIT_OBJECT_0:
176+
return None
177+
elif timeout_clock() >= end_time:
159178
return None
160179
else:
161180
result = None
162181
time.sleep(0.001)
182+
elif result[0] & (PCAN_ERROR_BUSLIGHT | PCAN_ERROR_BUSHEAVY):
183+
log.warning(self._get_formatted_error(result[0]))
184+
return None
163185
elif result[0] != PCAN_ERROR_OK:
164186
raise PcanError(self._get_formatted_error(result[0]))
165187

doc/installation.rst

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,19 @@ To install ``python-can`` using the Kvaser CANLib SDK as the backend:
4141
PCAN
4242
~~~~
4343

44-
To use the PCAN-Basic API as the backend (which has only been tested
45-
with Python 2.7):
46-
47-
1. Download the latest version of the `PCAN-Basic
48-
API <http://www.peak-system.com/Downloads.76.0.html?>`__.
49-
50-
2. Extract ``PCANBasic.dll`` from the Win32 subfolder of the archive or
51-
the x64 subfolder depending on whether you have a 32-bit or 64-bit
52-
installation of Python.
53-
54-
3. Copy ``PCANBasic.dll`` into the working directory where you will be
55-
running your python script. There is probably a way to install the
56-
dll properly, but I'm not certain how to do that.
44+
Download and install the latest driver for your interface from
45+
`PEAK-System's download page <http://www.peak-system.com/Support.55.0.html?&L=1>`__.
5746

5847
Note that PCANBasic API timestamps count seconds from system startup. To
5948
convert these to epoch times, the uptime library is used. If it is not
6049
available, the times are returned as number of seconds from system
6150
startup. To install the uptime library, run ``pip install uptime``.
6251

52+
This library can take advantage of the `Python for Windows Extensions
53+
<https://sourceforge.net/projects/pywin32>`__ library if installed.
54+
It will be used to get notified of new messages instead of
55+
the CPU intensive polling that will otherwise have be used.
56+
6357
IXXAT
6458
~~~~~
6559

0 commit comments

Comments
 (0)