|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +""" |
| 4 | +This module implements an OS and hardware independent |
| 5 | +virtual CAN interface for testing purposes. |
| 6 | +
|
| 7 | +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. |
| 10 | +""" |
| 11 | + |
| 12 | +import logging |
| 13 | +import time |
| 14 | +try: |
| 15 | + import queue as queue |
| 16 | +except ImportError: |
| 17 | + import Queue as queue |
| 18 | +from can.bus import BusABC |
| 19 | + |
| 20 | + |
| 21 | +logger = logging.getLogger(__name__) |
| 22 | +logger.setLevel(logging.DEBUG) |
| 23 | + |
| 24 | + |
| 25 | +# Channels are lists of queues, one for each connection |
| 26 | +channels = {} |
| 27 | + |
| 28 | +class VirtualBus(BusABC): |
| 29 | + """Virtual CAN bus using an internal message queue for testing.""" |
| 30 | + |
| 31 | + def __init__(self, channel=None, **config): |
| 32 | + self.channel_info = 'Virtual bus channel %s' % channel |
| 33 | + |
| 34 | + # Create a new channel if one does not exist |
| 35 | + if channel not in channels: |
| 36 | + channels[channel] = [] |
| 37 | + |
| 38 | + self.queue = queue.Queue() |
| 39 | + self.channel = channels[channel] |
| 40 | + self.channel.append(self.queue) |
| 41 | + |
| 42 | + def recv(self, timeout=None): |
| 43 | + try: |
| 44 | + msg = self.queue.get(block=bool(timeout), timeout=timeout) |
| 45 | + except queue.Empty: |
| 46 | + return None |
| 47 | + |
| 48 | + logger.log(9, 'Received message:\n%s', msg) |
| 49 | + return msg |
| 50 | + |
| 51 | + def send(self, msg): |
| 52 | + msg.timestamp = time.time() |
| 53 | + # Add message to all listening on this channel |
| 54 | + for bus_queue in self.channel: |
| 55 | + bus_queue.put(msg) |
| 56 | + logger.log(9, 'Transmitted message:\n%s', msg) |
| 57 | + |
| 58 | + def shutdown(self): |
| 59 | + self.channel.remove(self.queue) |
0 commit comments