Skip to content

Commit fd91477

Browse files
committed
Merge development branch into default.
Adds consistent support for filtering messages received on a Bus.
2 parents ccb73ff + e276670 commit fd91477

33 files changed

+445
-296
lines changed

CONTRIBUTORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ Bruno Pennati
1616
Jack Jester-Weinstein
1717
Joshua Villyard
1818
Giuseppe Corbelli <[email protected]>
19+
Christian Sandberg

README

Lines changed: 17 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -19,169 +19,30 @@ python-can
1919
The **C**\ ontroller **A**\ rea **N**\ etwork is a bus standard designed
2020
to allow microcontrollers and devices to communicate with each other. It
2121
has priority based bus arbitration, reliable deterministic
22-
communication. It is used in cars, trucks, wheelchairs and more. See
23-
`wikipedia <http://en.wikipedia.org/wiki/CAN_bus>`__ for more info.
22+
communication. It is used in cars, trucks, boats, wheelchairs and more.
2423

25-
This module provides controller area network support for
26-
`Python <http://python.org/download/>`__.
24+
The ``can`` package provides controller area network support for
25+
Python developers; providing `common abstractions to
26+
different hardware devices`, and a suite of utilities for sending and receiving
27+
messages on a can bus.
2728

28-
Configuration File
29-
------------------
29+
The library supports Python 2.7, Python 3.3+ and runs on Mac, Linux and Windows.
3030

31-
In order to use this library a CAN interface needs to be specified. A
32-
method to do this is to create a configuration file.
33-
On Linux systems the config file is searched in the following paths:
31+
You can find more information in the documentation, online at
32+
`python-can.readthedocs.org <https://python-can.readthedocs.org/en/stable/>`__.
3433

35-
1. ``/etc/can.conf``
36-
2. ``$HOME/.can``
37-
3. ``$HOME/.canrc``
3834

39-
On Windows systems the config file is searched in the following paths:
40-
1. ``can.ini`` (current working directory)
41-
2. ``$APPDATA/can.ini``
42-
43-
The configuration file sets the default interface and channel:
44-
45-
::
46-
47-
[default]
48-
interface = <the name of the interface to use>
49-
channel = <the channel to use by default>
50-
51-
Interfaces
35+
Discussion
5236
----------
5337

54-
The interface available are:
55-
56-
kvaser
57-
~~~~~~
58-
59-
`Kvaser <http://www.kvaser.com>`__'s CANLib SDK for Windows (also
60-
available on Linux)
61-
62-
socketcan
63-
~~~~~~~~~
64-
65-
On linux the socketcan interface is exposed via either:
66-
67-
- socketcan\_ctypes
68-
- socketcan\_native
69-
70-
serial
71-
~~~~~~
72-
73-
A text based interface. For example use over bluetooth with
74-
``/dev/rfcomm0``
75-
76-
pcan
77-
~~~~
78-
79-
`Peak-System <http://www.peak-system.com/>`__'s PCAN-Basic API.
80-
81-
IXXAT
82-
~~~~~
83-
84-
`IXXAT <http://www.ixxat.com/>`__'s Virtual CAN Interface V3 SDK ONLY on Windows.
85-
The Linux ECI SDK is currently unsupported.
86-
On Linux some devices are supported with socketcan.
87-
88-
virtual
89-
~~~~~~~
90-
91-
A virtual CAN bus that can be used for automatic tests. Any Bus instances
92-
connecting to the same channel (in the same python program) will get each
93-
others messages.
94-
95-
Installation
96-
------------
97-
98-
GNU/Linux dependencies
99-
----------------------
100-
101-
Reasonably modern Linux Kernels (2.6.25 or newer) have an implementation
102-
of ``socketcan``. This version of python-can will directly use socketcan
103-
if called with Python 3.3 or greater, otherwise that interface is used
104-
via ctypes.
105-
106-
Windows dependencies
107-
--------------------
108-
109-
Kvaser
110-
~~~~~~
111-
112-
To install ``python-can`` using the Kvaser CANLib SDK as the backend:
113-
114-
1. Install the `latest stable release of
115-
Python <http://python.org/download/>`__.
116-
117-
2. Install `Kvaser's latest Windows CANLib
118-
drivers <http://www.kvaser.com/en/downloads.html>`__.
119-
120-
3. Test that Kvaser's own tools work to ensure the driver is properly
121-
installed and that the hardware is working.
122-
123-
PCAN
124-
~~~~
125-
126-
To use the PCAN-Basic API as the backend (which has only been tested
127-
with Python 2.7):
128-
129-
1. Download the latest version of the `PCAN-Basic
130-
API <http://www.peak-system.com/Downloads.76.0.html?>`__.
131-
132-
2. Extract ``PCANBasic.dll`` from the Win32 subfolder of the archive or
133-
the x64 subfolder depending on whether you have a 32-bit or 64-bit
134-
installation of Python.
135-
136-
3. Copy ``PCANBasic.dll`` into the working directory where you will be
137-
running your python script. There is probably a way to install the
138-
dll properly, but I'm not certain how to do that.
139-
140-
Note that PCANBasic API timestamps count seconds from system startup. To
141-
convert these to epoch times, the uptime library is used. If it is not
142-
available, the times are returned as number of seconds from system
143-
startup. To install the uptime library, run ``pip install uptime``.
144-
145-
IXXAT
146-
~~~~~
147-
148-
To install ``python-can`` using the IXXAT VCI V3 SDK as the backend:
149-
150-
1. Install the `latest stable release of
151-
Python <http://python.org/download/>`__.
152-
153-
2. Install `IXXAT's latest Windows VCI V3 SDK
154-
drivers <http://www.ixxat.com/support/file-and-documents-download/drivers/vci-v3-driver-download>`__.
155-
156-
3. Test that IXXAT's own tools (i.e. MiniMon) work to ensure the driver
157-
is properly installed and that the hardware is working.
158-
159-
Install python-can
160-
------------------
161-
162-
You may need to install
163-
`pip <http://www.pip-installer.org/en/latest/installing.html>`__ and
164-
`setuptools <https://pypi.python.org/pypi/setuptools>`__ first.
165-
166-
Two options, install normally with:
167-
168-
::
169-
170-
python setup.py install
171-
172-
Or to do a "development" install of this package to your machine (this
173-
allows you to make changes locally or pull updates from the Mercurial
174-
repository and use them without having to reinstall):
175-
176-
::
177-
178-
python setup.py develop
38+
If you run into bugs, you can file them in our
39+
`issue tracker <https://bitbucket.org/hardbyte/python-can/issues>`__.
17940

180-
On linux you will need ``sudo`` rights.
41+
There is also a `python-can <https://groups.google.com/forum/#!forum/python-can>`__
42+
mailing list for development discussion.
18143

182-
Documentation and Help
183-
----------------------
44+
`Stackoverflow <https://stackoverflow.com/questions/tagged/can+python>`__ has several
45+
questions and answers tagged with ``python+can``.
18446

185-
- The Sphinx documentation for python-can can be viewed online at `python-can.readthedocs.org <https://python-can.readthedocs.org/en/latest/>`__
186-
- Questions can be found on `StackOverflow <https://stackoverflow.com/questions/tagged/can+python>`__ (tagged with python+can)
187-
- `Google groups mailing list <https://groups.google.com/forum/#!forum/python-can>`__
47+
Wherever we interact, we strive to follow the
48+
`Python Community Code of Conduct <https://www.python.org/psf/codeofconduct/>`__.

can/__init__.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
"""
22
can is an object-orient Controller Area Network interface module.
3-
4-
Modules include:
5-
6-
:mod:`can.message`
7-
defines the :class:`~can.Message` class which is the
8-
lowest level of OO access to the library.
9-
103
"""
114
import logging
125
log = logging.getLogger('can')
136

147
rc = dict(channel=0)
158

9+
1610
class CanError(IOError):
1711
pass
1812

can/broadcastmanager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ def modify_data(self, message):
4747
"""Update the contents of this periodically sent message without altering
4848
the timing.
4949
50-
:param message: The :class:`~can.Message` with new :attr:`Message.data`. Note it must have the same
51-
:attr:`Message.arbitration_id`.
50+
:param message: The :class:`~can.Message` with new :attr:`Message.data`.
51+
Note it must have the same :attr:`~can.Message.arbitration_id`.
5252
"""
5353

5454

can/bus.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def __init__(self, channel=None, can_filters=None, **config):
4343
def recv(self, timeout=None):
4444
"""Block waiting for a message from the Bus.
4545
46+
:param float timeout: Seconds to wait for a message.
47+
4648
:return:
4749
None on timeout or a :class:`can.Message` object.
4850
"""
@@ -91,7 +93,7 @@ def set_filters(self, can_filters=None):
9193
raise NotImplementedError("Trying to set_filters on unsupported bus")
9294

9395
def flush_tx_buffer(self):
94-
"""Used for CAN backends which need to flush their transmit buffer.
96+
"""Used for CAN interfaces which need to flush their transmit buffer.
9597
9698
"""
9799
pass

can/interfaces/interface.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ class Bus(object):
1111
"""
1212
Instantiates a CAN Bus of the given `bustype`, falls back to reading a
1313
configuration file from default locations.
14-
15-
:raises: NotImplementedError if the bustype isn't recognized
16-
1714
"""
1815

1916
@classmethod
2017
def __new__(cls, other, channel=None, *args, **kwargs):
18+
"""
19+
Takes the same arguments as :class:`can.BusABC` with the addition of:
20+
21+
:param kwargs:
22+
Should contain a bustype key with a valid interface name.
2123
24+
:raises: NotImplementedError if the bustype isn't recognized
25+
"""
2226
if 'bustype' in kwargs:
2327
can.rc['interface'] = kwargs['bustype']
2428
del kwargs['bustype']

can/interfaces/kvaser/canlib.py

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -349,16 +349,6 @@ def __init__(self, channel, can_filters=None, **config):
349349
4)
350350
canSetBusParams(self._read_handle, bitrate, tseg1, tseg2, sjw, no_samp, 0)
351351

352-
if can_filters is not None and len(can_filters):
353-
log.info("The kvaser canlib backend is filtering messages")
354-
code, mask = 0, 0
355-
for can_filter in can_filters:
356-
code |= can_filter['can_id']
357-
mask |= can_filter['can_mask']
358-
log.info("Filtering on: {} {}".format(code, mask))
359-
canSetAcceptanceFilter(self._read_handle, code, mask, 0)
360-
canSetAcceptanceFilter(self._read_handle, code, mask, 1)
361-
362352
if self.single_handle:
363353
log.debug("We don't require separate handles to the bus")
364354
self._write_handle = self._read_handle
@@ -367,6 +357,9 @@ def __init__(self, channel, can_filters=None, **config):
367357
self._write_handle = canOpenChannel(channel, canstat.canOPEN_ACCEPT_VIRTUAL)
368358
canBusOn(self._read_handle)
369359

360+
self.sw_filters = []
361+
self.set_filters(can_filters)
362+
370363
can_driver_mode = canstat.canDRIVER_SILENT if driver_mode == DRIVER_MODE_SILENT else canstat.canDRIVER_NORMAL
371364
canSetBusOutputControl(self._write_handle, can_driver_mode)
372365
log.debug('Going bus on TX handle')
@@ -384,6 +377,41 @@ def __init__(self, channel, can_filters=None, **config):
384377

385378
super(KvaserBus, self).__init__()
386379

380+
def set_filters(self, can_filters=None):
381+
"""Apply filtering to all messages received by this Bus.
382+
383+
Calling without passing any filters will reset the applied filters.
384+
385+
Since Kvaser only supports setting one filter per handle, the filtering
386+
will be done in the :meth:`recv` if more than one filter is requested.
387+
388+
:param list can_filters:
389+
A list of dictionaries each containing a "can_id" and a "can_mask".
390+
391+
>>> [{"can_id": 0x11, "can_mask": 0x21}]
392+
393+
A filter matches, when ``<received_can_id> & can_mask == can_id & can_mask``
394+
"""
395+
can_id = 0
396+
can_mask = 0
397+
398+
if not can_filters:
399+
log.info('Filtering has been disabled')
400+
self.sw_filters = []
401+
elif len(can_filters) == 1:
402+
can_id = can_filters[0]['can_id']
403+
can_mask = can_filters[0]['can_mask']
404+
log.info('canlib is filtering on ID 0x%X, mask 0x%X', can_id, can_mask)
405+
self.sw_filters = []
406+
elif len(can_filters) > 1:
407+
log.info('Filtering is handled in Python')
408+
self.sw_filters = can_filters
409+
410+
# Set same filter for both handles as well as standard and extended IDs
411+
for handle in (self._read_handle, self._write_handle):
412+
for ext in (0, 1):
413+
canSetAcceptanceFilter(handle, can_id, can_mask, ext)
414+
387415
def flush_tx_buffer(self):
388416
"""
389417
Flushes the transmit buffer on the Kvaser
@@ -417,6 +445,26 @@ def __convert_timestamp(self, value):
417445
self.pc_time_offset += lag
418446
return timestamp
419447

448+
def _is_filter_match(self, arb_id):
449+
"""
450+
If SW filtering is used, checks if the `arb_id` matches any of
451+
the filters setup.
452+
453+
:param int arb_id:
454+
CAN ID to check against.
455+
456+
:return:
457+
True if `arb_id` matches any filters
458+
(or if SW filtering is not used).
459+
"""
460+
if not self.sw_filters:
461+
# Filtering done on HW or driver level or no filtering
462+
return True
463+
for can_filter in self.sw_filters:
464+
if not (arb_id ^ can_filter['can_id']) & can_filter['can_mask']:
465+
return True
466+
return False
467+
420468
def recv(self, timeout=None):
421469
"""
422470
Read a message from kvaser device.
@@ -447,6 +495,8 @@ def recv(self, timeout=None):
447495

448496
if status == canstat.canOK:
449497
log.debug('read complete -> status OK')
498+
if not self._is_filter_match(arb_id.value):
499+
return None
450500
data_array = data.raw
451501
flags = flags.value
452502
is_extended = bool(flags & canstat.canMSG_EXT)

can/interfaces/pcan.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ def __init__(self, channel, *args, **kwargs):
6060
:param str channel:
6161
The can interface name. An example would be PCAN_USBBUS1
6262
63-
Backend Configuration
64-
---------------------
65-
6663
:param int bitrate:
6764
Bitrate of channel in bit/s.
6865
Default is 500 Kbs

0 commit comments

Comments
 (0)