@@ -349,15 +349,8 @@ 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 )
352+ self .sw_filters = []
353+ self .set_filters (can_filters )
361354
362355 if self .single_handle :
363356 log .debug ("We don't require separate handles to the bus" )
@@ -384,6 +377,44 @@ 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+ if not can_filters :
396+ # Disable all filters
397+ self .sw_filters = []
398+ canSetAcceptanceFilter (self ._read_handle , 0 , 0 , 0 )
399+ canSetAcceptanceFilter (self ._read_handle , 0 , 0 , 1 )
400+ elif len (can_filters ) == 1 :
401+ # Standard messages
402+ canSetAcceptanceFilter (self ._read_handle ,
403+ can_filters [0 ]['can_id' ],
404+ can_filters [0 ]['can_mask' ],
405+ 0 )
406+ # Extended messages
407+ canSetAcceptanceFilter (self ._read_handle ,
408+ can_filters [0 ]['can_id' ],
409+ can_filters [0 ]['can_mask' ],
410+ 1 )
411+ self .sw_filters = []
412+ elif len (can_filters ) > 1 :
413+ self .sw_filters = can_filters
414+ # Disable HW filtering
415+ canSetAcceptanceFilter (self ._read_handle , 0 , 0 , 0 )
416+ canSetAcceptanceFilter (self ._read_handle , 0 , 0 , 1 )
417+
387418 def flush_tx_buffer (self ):
388419 """
389420 Flushes the transmit buffer on the Kvaser
@@ -417,6 +448,26 @@ def __convert_timestamp(self, value):
417448 self .pc_time_offset += lag
418449 return timestamp
419450
451+ def _is_filter_match (self , arb_id ):
452+ """
453+ If SW filtering is used, checks if the `arb_id` matches any of
454+ the filters setup.
455+
456+ :param int arb_id:
457+ CAN ID to check against.
458+
459+ :return:
460+ True if `arb_id` matches any filters
461+ (or if SW filtering is not used).
462+ """
463+ if not self .sw_filters :
464+ # Filtering done on HW or driver level
465+ return True
466+ for can_filter in self .sw_filters :
467+ if not (arb_id ^ can_filter ['can_id' ]) & can_filter ['can_mask' ]:
468+ return True
469+ return False
470+
420471 def recv (self , timeout = None ):
421472 """
422473 Read a message from kvaser device.
@@ -441,6 +492,8 @@ def recv(self, timeout=None):
441492
442493 if status == canstat .canOK :
443494 log .debug ('read complete -> status OK' )
495+ if not self ._is_filter_match (arb_id .value ):
496+ return None
444497 data_array = data .raw
445498 flags = flags .value
446499 is_extended = bool (flags & canstat .canMSG_EXT )
0 commit comments