Skip to content

Commit b22aed7

Browse files
Implement receive_own_messages option for more buses (hardbyte#166)
Don't use local echo for Kvaser by default unless single_handle is used (fixes hardbyte#160) Make logger and player use single_handle. Add receive_own_messages to socketcan_native, virtual and kvaser buses. Fix filtering of extended and standard IDs for socketcan.
1 parent c616fdc commit b22aed7

9 files changed

Lines changed: 43 additions & 13 deletions

File tree

can/interfaces/kvaser/canlib.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,11 @@ def __init__(self, channel, can_filters=None, **config):
309309
:param bool single_handle:
310310
Use one Kvaser CANLIB bus handle for both reading and writing.
311311
This can be set if reading and/or writing is done from one thread.
312+
:param bool receive_own_messages:
313+
If messages transmitted should also be received back.
314+
Only works if single_handle is also False.
315+
If you want to receive messages from other applications on the same
316+
computer, set this to True or set single_handle to True.
312317
"""
313318
log.info("CAN Filters: {}".format(can_filters))
314319
log.info("Got configuration of: {}".format(config))
@@ -319,6 +324,7 @@ def __init__(self, channel, can_filters=None, **config):
319324
no_samp = config.get('no_samp', 0)
320325
driver_mode = config.get('driver_mode', DRIVER_MODE_NORMAL)
321326
single_handle = config.get('single_handle', False)
327+
receive_own_messages = config.get('receive_own_messages', False)
322328

323329
try:
324330
channel = int(channel)
@@ -350,6 +356,15 @@ def __init__(self, channel, can_filters=None, **config):
350356
4)
351357
canSetBusParams(self._read_handle, bitrate, tseg1, tseg2, sjw, no_samp, 0)
352358

359+
# By default, use local echo if single handle is used (see #160)
360+
local_echo = single_handle or receive_own_messages
361+
if receive_own_messages and single_handle:
362+
log.warning("receive_own_messages only works if single_handle is False")
363+
canIoCtl(self._read_handle,
364+
canstat.canIOCTL_SET_LOCAL_TXECHO,
365+
ctypes.byref(ctypes.c_byte(local_echo)),
366+
1)
367+
353368
if self.single_handle:
354369
log.debug("We don't require separate handles to the bus")
355370
self._write_handle = self._read_handle

can/interfaces/kvaser/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ def CANSTATUS_SUCCESS(status):
183183
canIOCTL_SET_USB_THROTTLE = 28
184184
canIOCTL_GET_USB_THROTTLE = 29
185185
canIOCTL_SET_BUSON_TIME_AUTO_RESET = 30
186+
canIOCTL_SET_LOCAL_TXECHO = 32
186187
canIOCTL_PREFER_EXT = 1
187188
canIOCTL_PREFER_STD = 2
188189
canIOCTL_CLEAR_ERROR_COUNTERS = 5

can/interfaces/socketcan/socketcan_common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ def pack_filters(can_filters=None):
2323
if can_filter.get('extended'):
2424
can_id |= CAN_EFF_FLAG
2525
filter_data.append(can_id)
26-
filter_data.append(can_filter['can_mask'])
26+
filter_data.append(can_filter['can_mask'] | CAN_EFF_FLAG)
2727
return struct.pack(can_filter_fmt, *filter_data)

can/interfaces/socketcan/socketcan_native.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,13 @@ def capturePacket(sock):
370370
class SocketcanNative_Bus(BusABC):
371371
channel_info = "native socketcan channel"
372372

373-
def __init__(self, channel, **kwargs):
373+
def __init__(self, channel, receive_own_messages=False, **kwargs):
374374
"""
375375
:param str channel:
376376
The can interface name with which to create this bus. An example channel
377377
would be 'vcan0'.
378-
378+
:param bool receive_own_messages:
379+
If messages transmitted should also be received back.
379380
:param list can_filters:
380381
A list of dictionaries, each containing a "can_id" and a "can_mask".
381382
"""
@@ -386,6 +387,12 @@ def __init__(self, channel, **kwargs):
386387
if 'can_filters' in kwargs and len(kwargs['can_filters']) > 0:
387388
log.debug("Creating a filtered can bus")
388389
self.set_filters(kwargs['can_filters'])
390+
try:
391+
self.socket.setsockopt(socket.SOL_CAN_RAW,
392+
socket.CAN_RAW_RECV_OWN_MSGS,
393+
struct.pack('i', receive_own_messages))
394+
except Exception as e:
395+
log.error("Could not receive own messages (%s)", e)
389396

390397
bindSocket(self.socket, channel)
391398
super(SocketcanNative_Bus, self).__init__()

can/interfaces/virtual.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
virtual CAN interface for testing purposes.
66
77
Any VirtualBus instances connecting to the same channel
8-
will get the same messages. Sent messages will also be
9-
echoed back to the same bus.
8+
will get the same messages.
109
"""
1110

1211
import logging
@@ -29,8 +28,9 @@
2928
class VirtualBus(BusABC):
3029
"""Virtual CAN bus using an internal message queue for testing."""
3130

32-
def __init__(self, channel=None, **config):
31+
def __init__(self, channel=None, receive_own_messages=False, **config):
3332
self.channel_info = 'Virtual bus channel %s' % channel
33+
self.receive_own_messages = receive_own_messages
3434

3535
# Create a new channel if one does not exist
3636
if channel not in channels:
@@ -53,7 +53,8 @@ def send(self, msg, timeout=None):
5353
msg.timestamp = time.time()
5454
# Add message to all listening on this channel
5555
for bus_queue in self.channel:
56-
bus_queue.put(msg)
56+
if bus_queue != self.queue or self.receive_own_messages:
57+
bus_queue.put(msg)
5758
logger.log(9, 'Transmitted message:\n%s', msg)
5859

5960
def shutdown(self):

can/logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def main():
7171
can_mask = int(can_mask, base=16) & socket.CAN_ERR_FLAG
7272
can_filters.append({"can_id": can_id, "can_mask": can_mask})
7373

74-
config = {"can_filters": can_filters}
74+
config = {"can_filters": can_filters, "single_handle": True}
7575
if results.interface:
7676
config["bustype"] = results.interface
7777
if results.bitrate:

can/player.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def main():
5656
logging_level_name = ['critical', 'error', 'warning', 'info', 'debug', 'subdebug'][min(5, verbosity)]
5757
can.set_logging_level(logging_level_name)
5858

59-
config = {}
59+
config = {"single_handle": True}
6060
if results.interface:
6161
config["bustype"] = results.interface
6262
if results.bitrate:

examples/vcan_filtered.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import time
22
import can
33

4-
bus = can.interface.Bus(bustype='socketcan', channel='vcan0')
4+
bus = can.interface.Bus(bustype='socketcan',
5+
channel='vcan0',
6+
receive_own_messages=True)
57

6-
can_filters = [{"can_id": 1, "can_mask": 0xf}]
8+
can_filters = [{"can_id": 1, "can_mask": 0xf, "extended": True}]
79
bus.set_filters(can_filters)
810
notifier = can.Notifier(bus, [can.Printer()])
11+
bus.send(can.Message(arbitration_id=1, extended_id=True))
12+
bus.send(can.Message(arbitration_id=2, extended_id=True))
13+
bus.send(can.Message(arbitration_id=1, extended_id=False))
914
time.sleep(10)

test/simplecyclic_test.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ class SimpleCyclicSendTaskTest(unittest.TestCase):
1111
def test_cycle_time(self):
1212
msg = can.Message(extended_id=False, arbitration_id=0x100, data=[0,1,2,3,4,5,6,7])
1313
bus = can.interface.Bus(bustype='virtual')
14+
bus2 = can.interface.Bus(bustype='virtual')
1415
task = bus.send_periodic(msg, 0.01, 1)
1516
self.assertIsInstance(task, can.broadcastmanager.CyclicSendTaskABC)
1617
sleep(1.5)
17-
size = bus.queue.qsize()
18+
size = bus2.queue.qsize()
1819
print(size)
1920
# About 100 messages should have been transmitted. Some overhead will
2021
# make it less though
2122
self.assertTrue(90 < size < 110)
22-
last_msg = bus.recv()
23+
last_msg = bus2.recv()
2324
self.assertEqual(last_msg, msg)
2425

2526

0 commit comments

Comments
 (0)