返回教程正文

配套源码

fake_backend.py

app/tests/fake_backend.py
generic_can Brick:在 VENTUNO Q 上自定义 CAN 报文app/tests/fake_backend.py
Python107 行
"""不依赖真实硬件和python-can的内存CAN后端。"""

import queue
import threading

from generic_can.backends import CanBackend
from generic_can.errors import CANBackendError
from generic_can.frame import CanFrame


class FakeBackend(CanBackend):
    """用线程安全队列模拟最小CanBackend契约。"""

    def __init__(self):
        """
        @description         : 创建一个尚未打开的内存测试后端
        @param self          : 当前FakeBackend对象
        @return              : 无
        """
        self.open_count = 0
        self.close_count = 0
        self.sent_frames = []
        self._receive_queue = queue.Queue()
        self._lock = threading.Lock()
        self._is_open = False
        self.send_entered = threading.Event()
        self.release_send = threading.Event()
        self.release_send.set()
        self.close_called = threading.Event()
        self.operation_log = []

    def open(self):
        """
        @description         : 标记后端已打开并记录调用次数
        @param self          : 当前FakeBackend对象
        @return              : 无
        """
        with self._lock:
            self.open_count += 1
            self._is_open = True

    def send(self, frame):
        """
        @description         : 保存一帧发送记录但不访问真实CAN设备
        @param self          : 当前FakeBackend对象
        @param frame         : 需要记录的CanFrame
        @return              : 无
        """
        with self._lock:
            is_open = self._is_open
        if not is_open:
            raise CANBackendError("fake backend is not open")

        self.send_entered.set()
        if not self.release_send.wait(timeout=2.0):
            raise CANBackendError("fake send release timed out")

        with self._lock:
            self.sent_frames.append(frame)
            self.operation_log.append("send_finished")

    def receive(self, timeout_s):
        """
        @description         : 从测试注入队列等待一帧或异常
        @param self          : 当前FakeBackend对象
        @param timeout_s     : 最长等待秒数
        @return              : CanFrame或超时None
        """
        if not self._is_open:
            raise CANBackendError("fake backend is not open")
        try:
            value = self._receive_queue.get(timeout=timeout_s)
        except queue.Empty:
            return None
        if isinstance(value, BaseException):
            raise value
        return value

    def close(self):
        """
        @description         : 标记后端关闭并记录调用次数
        @param self          : 当前FakeBackend对象
        @return              : 无
        """
        self.close_called.set()
        with self._lock:
            self.operation_log.append("close_called")
            self.close_count += 1
            self._is_open = False

    def inject(self, frame):
        """
        @description         : 向接收线程注入一帧CanFrame
        @param self          : 当前FakeBackend对象
        @param frame         : 待注入的CanFrame
        @return              : 无
        """
        self._receive_queue.put(frame)

    def inject_error(self, error):
        """
        @description         : 向接收线程注入一个待抛出的异常
        @param self          : 当前FakeBackend对象
        @param error         : 待抛出的异常对象
        @return              : 无
        """
        self._receive_queue.put(error)