def _make_can( registers: MutableMapping[str, ValueProxy], node_id: Optional[int]) -> Iterator[pyuavcan.transport.Transport]: def init(name: str, default: RelaxedValue) -> ValueProxy: return registers.setdefault("uavcan.can." + name, ValueProxy(default)) iface_list = str(init("iface", "")).split() mtu = int(init("mtu", Natural16([64]))) br_arb, br_data = init("bitrate", Natural32([1_000_000, 4_000_000])).ints if iface_list: from pyuavcan.transport.can import CANTransport for iface in iface_list: media: pyuavcan.transport.can.media.Media if iface.lower().startswith("socketcan:"): from pyuavcan.transport.can.media.socketcan import SocketCANMedia media = SocketCANMedia(iface.split(":")[-1], mtu=mtu) else: from pyuavcan.transport.can.media.pythoncan import PythonCANMedia media = PythonCANMedia( iface, br_arb if br_arb == br_data else (br_arb, br_data), mtu) yield CANTransport(media, node_id)
async def _unittest_can_pythoncan() -> None: asyncio.get_running_loop().slow_callback_duration = 5.0 media_a = PythonCANMedia("virtual:0", 500000) media_b = PythonCANMedia("virtual:0", 500000) assert media_a.mtu == 8 assert media_b.mtu == 8 assert media_a.interface_name == "virtual:0" assert media_b.interface_name == "virtual:0" assert media_a.number_of_acceptance_filters == media_b.number_of_acceptance_filters assert media_a._maybe_thread is None assert media_b._maybe_thread is None rx_a: typing.List[typing.Tuple[Timestamp, Envelope]] = [] rx_b: typing.List[typing.Tuple[Timestamp, Envelope]] = [] def on_rx_a(frames: typing.Iterable[typing.Tuple[Timestamp, Envelope]]) -> None: nonlocal rx_a frames = list(frames) print("RX A:", frames) rx_a += frames def on_rx_b(frames: typing.Iterable[typing.Tuple[Timestamp, Envelope]]) -> None: nonlocal rx_b frames = list(frames) print("RX B:", frames) rx_b += frames media_a.start(on_rx_a, False) media_b.start(on_rx_b, False) assert media_a._maybe_thread is not None assert media_b._maybe_thread is not None await asyncio.sleep(2.0) # This wait is needed to ensure that the RX thread handles read timeout properly ts_begin = Timestamp.now() await media_b.send( [ Envelope(DataFrame(FrameFormat.EXTENDED, 0xBADC0FE, bytearray(range(8))), loopback=True), Envelope(DataFrame(FrameFormat.EXTENDED, 0x12345678, bytearray(range(0))), loopback=False), Envelope(DataFrame(FrameFormat.BASE, 0x123, bytearray(range(6))), loopback=True), ], asyncio.get_event_loop().time() + 1.0, ) await asyncio.sleep(0.1) ts_end = Timestamp.now() print("rx_a:", rx_a) # Three received from another part assert len(rx_a) == 3 for ts, _f in rx_a: assert ts_begin.monotonic_ns <= ts.monotonic_ns <= ts_end.monotonic_ns assert ts_begin.system_ns <= ts.system_ns <= ts_end.system_ns rx_external = list(filter(lambda x: True, rx_a)) assert rx_external[0][1].frame.identifier == 0xBADC0FE assert rx_external[0][1].frame.data == bytearray(range(8)) assert rx_external[0][1].frame.format == FrameFormat.EXTENDED assert rx_external[1][1].frame.identifier == 0x12345678 assert rx_external[1][1].frame.data == bytearray(range(0)) assert rx_external[1][1].frame.format == FrameFormat.EXTENDED assert rx_external[2][1].frame.identifier == 0x123 assert rx_external[2][1].frame.data == bytearray(range(6)) assert rx_external[2][1].frame.format == FrameFormat.BASE print("rx_b:", rx_b) # Two messages are loopback and were copied assert len(rx_b) == 2 rx_loopback = list(filter(lambda x: True, rx_b)) assert rx_loopback[0][1].frame.identifier == 0xBADC0FE assert rx_loopback[0][1].frame.data == bytearray(range(8)) assert rx_loopback[0][1].frame.format == FrameFormat.EXTENDED assert rx_loopback[1][1].frame.identifier == 0x123 assert rx_loopback[1][1].frame.data == bytearray(range(6)) assert rx_loopback[1][1].frame.format == FrameFormat.BASE media_a.close() media_b.close()
async def _unittest_can_pythoncan_socketcan() -> None: asyncio.get_running_loop().slow_callback_duration = 5.0 media_a = PythonCANMedia("socketcan:vcan2", 0, 8) media_b = PythonCANMedia("socketcan:vcan2", 0, 64) rx_a: typing.List[typing.Tuple[Timestamp, Envelope]] = [] rx_b: typing.List[typing.Tuple[Timestamp, Envelope]] = [] def on_rx_a(frames: typing.Iterable[typing.Tuple[Timestamp, Envelope]]) -> None: nonlocal rx_a rx_a += list(frames) def on_rx_b(frames: typing.Iterable[typing.Tuple[Timestamp, Envelope]]) -> None: nonlocal rx_b rx_b += list(frames) media_a.start(on_rx_a, no_automatic_retransmission=False) media_b.start(on_rx_b, no_automatic_retransmission=False) ts_begin = Timestamp.now() await media_a.send( [ Envelope(DataFrame(FrameFormat.EXTENDED, 0xBADC0FE, bytearray(b"123")), loopback=True), Envelope(DataFrame(FrameFormat.EXTENDED, 0x12345678, bytearray(b"456")), loopback=False), ], asyncio.get_event_loop().time() + 1.0, ) await asyncio.sleep(1.0) ts_end = Timestamp.now() assert len(rx_b) == 2 assert ts_begin.monotonic_ns <= rx_b[0][0].monotonic_ns <= ts_end.monotonic_ns assert ts_begin.monotonic_ns <= rx_b[1][0].monotonic_ns <= ts_end.monotonic_ns assert ts_begin.system_ns <= rx_b[0][0].system_ns <= ts_end.system_ns assert ts_begin.system_ns <= rx_b[1][0].system_ns <= ts_end.system_ns assert not rx_b[0][1].loopback assert not rx_b[1][1].loopback assert rx_b[0][1].frame.identifier == 0xBADC0FE assert rx_b[1][1].frame.identifier == 0x12345678 assert rx_b[0][1].frame.data == b"123" assert rx_b[1][1].frame.data == b"456" assert len(rx_a) == 1 assert ts_begin.monotonic_ns <= rx_a[0][0].monotonic_ns <= ts_end.monotonic_ns assert ts_begin.system_ns <= rx_a[0][0].system_ns <= ts_end.system_ns assert rx_a[0][1].loopback assert rx_a[0][1].frame.identifier == 0xBADC0FE assert rx_a[0][1].frame.data == b"123" media_a.close() media_b.close() media_a.close() # Ensure idempotency. media_b.close()