@@ -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.
@@ -441,6 +489,8 @@ def recv(self, timeout=None):
441489
442490 if status == canstat .canOK :
443491 log .debug ('read complete -> status OK' )
492+ if not self ._is_filter_match (arb_id .value ):
493+ return None
444494 data_array = data .raw
445495 flags = flags .value
446496 is_extended = bool (flags & canstat .canMSG_EXT )
0 commit comments