def one(nid: typing.Optional[int]) -> RedundantTransport: red = RedundantTransport() red.attach_inferior( CANTransport(SocketCANMedia("vcan0", 64), nid)) red.attach_inferior( CANTransport(SocketCANMedia("vcan1", 32), nid)) return red
def make_tmr_can(nid: typing.Optional[int]) -> pyuavcan.transport.Transport: from pyuavcan.transport.redundant import RedundantTransport tr = RedundantTransport() tr.attach_inferior(CANTransport(SocketCANMedia("vcan0", 8), local_node_id=nid)) tr.attach_inferior(CANTransport(SocketCANMedia("vcan1", 32), local_node_id=nid)) tr.attach_inferior(CANTransport(SocketCANMedia("vcan2", 64), local_node_id=nid)) return tr
def can_socketcan_vcan0() -> typing.Iterator[TransportFactory]: from pyuavcan.transport.can import CANTransport from pyuavcan.transport.can.media.socketcan import SocketCANMedia yield lambda nid_a, nid_b: ( CANTransport(SocketCANMedia("vcan0", 16), nid_a), CANTransport(SocketCANMedia("vcan0", 64), nid_b), True, )
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)
def _get_run_configs() -> typing.Iterable[RunConfig]: """ Provides interface options to test the demo against. When adding new transports, add them to the demo and update this factory accordingly. Don't forget about redundant configurations, too. """ from pyuavcan.transport.redundant import RedundantTransport from pyuavcan.transport.serial import SerialTransport from pyuavcan.transport.udp import UDPTransport # UDP yield RunConfig( demo_env_vars={"DEMO_INTERFACE_KIND": "udp"}, local_transport_factory=lambda nid: UDPTransport(f"127.0.0.{1 if nid is None else nid}", anonymous=nid is None), ) # Serial yield RunConfig( demo_env_vars={"DEMO_INTERFACE_KIND": "serial"}, local_transport_factory=lambda nid: SerialTransport("socket://localhost:50905", local_node_id=nid), ) # DMR UDP+Serial def make_udp_serial(nid: typing.Optional[int]) -> pyuavcan.transport.Transport: tr = RedundantTransport() if nid is not None: tr.attach_inferior(UDPTransport(f"127.0.0.{nid}")) else: tr.attach_inferior(UDPTransport(f"127.0.0.1", anonymous=True)) tr.attach_inferior(SerialTransport("socket://localhost:50905", local_node_id=nid)) return tr yield RunConfig( demo_env_vars={"DEMO_INTERFACE_KIND": "udp_serial"}, local_transport_factory=make_udp_serial, ) if sys.platform.startswith("linux"): from pyuavcan.transport.can.media.socketcan import SocketCANMedia from pyuavcan.transport.can import CANTransport # CAN yield RunConfig( demo_env_vars={"DEMO_INTERFACE_KIND": "can"}, # The demo uses Classic CAN! SocketCAN does not support nonuniform MTU well. local_transport_factory=lambda nid: CANTransport(SocketCANMedia("vcan0", 8), local_node_id=nid), ) # TMR CAN def make_tmr_can(nid: typing.Optional[int]) -> pyuavcan.transport.Transport: from pyuavcan.transport.redundant import RedundantTransport tr = RedundantTransport() tr.attach_inferior(CANTransport(SocketCANMedia("vcan0", 8), local_node_id=nid)) tr.attach_inferior(CANTransport(SocketCANMedia("vcan1", 32), local_node_id=nid)) tr.attach_inferior(CANTransport(SocketCANMedia("vcan2", 64), local_node_id=nid)) return tr yield RunConfig( demo_env_vars={"DEMO_INTERFACE_KIND": "can_can_can"}, local_transport_factory=make_tmr_can, )
async def _unittest_can_socketcan() -> None: from pyuavcan.transport import Timestamp from pyuavcan.transport.can.media import TimestampedDataFrame, DataFrame, FrameFormat, FilterConfiguration if sys.platform != 'linux': # pragma: no cover pytest.skip( 'SocketCAN test skipped because we do not seem to be on a GNU/Linux-based system' ) from pyuavcan.transport.can.media.socketcan import SocketCANMedia available = SocketCANMedia.list_available_interface_names() print('Available SocketCAN ifaces:', available) assert 'vcan0' in available, \ 'Either the interface listing method is not working or the environment is not configured correctly. ' \ 'Please ensure that the virtual SocketCAN interface "vcan0" is available, and its MTU is set to 64+8.' media_a = SocketCANMedia('vcan0', 12) media_b = SocketCANMedia('vcan0', 64) assert media_a.mtu == 12 assert media_b.mtu == 64 assert media_a.interface_name == 'vcan0' assert media_b.interface_name == 'vcan0' 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 media_a.configure_acceptance_filters( [FilterConfiguration.new_promiscuous()]) media_b.configure_acceptance_filters( [FilterConfiguration.new_promiscuous()]) rx_a: typing.List[TimestampedDataFrame] = [] def on_rx_a(frames: typing.Iterable[TimestampedDataFrame]) -> None: nonlocal rx_a frames = list(frames) print('RX A:', frames) rx_a += frames def on_rx_b(frames: typing.Iterable[TimestampedDataFrame]) -> None: frames = list(frames) print('RX B:', frames) asyncio.ensure_future( media_b.send_until(frames, asyncio.get_event_loop().time() + 1.0)) media_a.start(on_rx_a, False) media_b.start(on_rx_b, True) 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 select() timeout properly ts_begin = Timestamp.now() await media_a.send_until([ DataFrame(identifier=0xbadc0fe, data=bytearray(range(8)), format=FrameFormat.EXTENDED, loopback=True), DataFrame(identifier=0x12345678, data=bytearray(range(0)), format=FrameFormat.EXTENDED, loopback=False), DataFrame(identifier=0x123, data=bytearray(range(6)), format=FrameFormat.BASE, loopback=True), ], asyncio.get_event_loop().time() + 1.0) await asyncio.sleep(0.1) ts_end = Timestamp.now() print('rx_a:', rx_a) # Three sent back from the other end, two loopback assert len(rx_a) == 5 for f in rx_a: assert ts_begin.monotonic_ns <= f.timestamp.monotonic_ns <= ts_end.monotonic_ns assert ts_begin.system_ns <= f.timestamp.system_ns <= ts_end.system_ns rx_loopback = list(filter(lambda x: x.loopback, rx_a)) rx_external = list(filter(lambda x: not x.loopback, rx_a)) assert len(rx_loopback) == 2 and len(rx_external) == 3 assert rx_loopback[0].identifier == 0xbadc0fe assert rx_loopback[0].data == bytearray(range(8)) assert rx_loopback[0].format == FrameFormat.EXTENDED assert rx_loopback[1].identifier == 0x123 assert rx_loopback[1].data == bytearray(range(6)) assert rx_loopback[1].format == FrameFormat.BASE assert rx_external[0].identifier == 0xbadc0fe assert rx_external[0].data == bytearray(range(8)) assert rx_external[0].format == FrameFormat.EXTENDED assert rx_external[1].identifier == 0x12345678 assert rx_external[1].data == bytearray(range(0)) assert rx_external[1].format == FrameFormat.EXTENDED assert rx_external[2].identifier == 0x123 assert rx_external[2].data == bytearray(range(6)) assert rx_external[2].format == FrameFormat.BASE media_a.close() media_b.close() await asyncio.sleep( 1 ) # Let all pending tasks finalize properly to avoid stack traces in the output.
async def _unittest_can_socketcan() -> None: from pyuavcan.transport import Timestamp from pyuavcan.transport.can.media import Envelope, DataFrame, FrameFormat, FilterConfiguration from pyuavcan.transport.can.media.socketcan import SocketCANMedia available = SocketCANMedia.list_available_interface_names() print("Available SocketCAN ifaces:", available) assert "vcan0" in available, ( "Either the interface listing method is not working or the environment is not configured correctly. " 'Please ensure that the virtual SocketCAN interface "vcan0" is available, and its MTU is set to 64+8.' ) media_a = SocketCANMedia("vcan0", 12) media_b = SocketCANMedia("vcan0", 64) assert media_a.mtu == 12 assert media_b.mtu == 64 assert media_a.interface_name == "vcan0" assert media_b.interface_name == "vcan0" assert media_a.number_of_acceptance_filters == media_b.number_of_acceptance_filters assert media_a._maybe_thread is None # pylint: disable=protected-access assert media_b._maybe_thread is None # pylint: disable=protected-access media_a.configure_acceptance_filters( [FilterConfiguration.new_promiscuous()]) media_b.configure_acceptance_filters( [FilterConfiguration.new_promiscuous()]) rx_a: 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: frames = list(frames) print("RX B:", frames) asyncio.ensure_future( media_b.send((e for _, e in frames), asyncio.get_event_loop().time() + 1.0)) media_a.start(on_rx_a, False) media_b.start(on_rx_b, True) assert media_a._maybe_thread is not None # pylint: disable=protected-access assert media_b._maybe_thread is not None # pylint: disable=protected-access await asyncio.sleep( 2.0 ) # This wait is needed to ensure that the RX thread handles select() timeout properly ts_begin = Timestamp.now() await media_a.send( [ Envelope(DataFrame(FrameFormat.BASE, 0x123, bytearray(range(6))), loopback=True), Envelope(DataFrame(FrameFormat.EXTENDED, 0x1BADC0FE, bytearray(range(8))), loopback=True), ], asyncio.get_event_loop().time() + 1.0, ) await media_a.send( [ Envelope(DataFrame(FrameFormat.EXTENDED, 0x1FF45678, bytearray(range(0))), loopback=False), ], asyncio.get_event_loop().time() + 1.0, ) await asyncio.sleep(1.0) ts_end = Timestamp.now() print("rx_a:", rx_a) # Three sent back from the other end, two loopback assert len(rx_a) == 5 for t, _ in rx_a: assert ts_begin.monotonic_ns <= t.monotonic_ns <= ts_end.monotonic_ns assert ts_begin.system_ns <= t.system_ns <= ts_end.system_ns rx_loopback = [e.frame for t, e in rx_a if e.loopback] rx_external = [e.frame for t, e in rx_a if not e.loopback] assert len(rx_loopback) == 2 and len(rx_external) == 3 assert rx_loopback[0].identifier == 0x123 assert rx_loopback[0].data == bytearray(range(6)) assert rx_loopback[0].format == FrameFormat.BASE assert rx_loopback[1].identifier == 0x1BADC0FE assert rx_loopback[1].data == bytearray(range(8)) assert rx_loopback[1].format == FrameFormat.EXTENDED assert rx_external[0].identifier == 0x123 assert rx_external[0].data == bytearray(range(6)) assert rx_external[0].format == FrameFormat.BASE assert rx_external[1].identifier == 0x1BADC0FE assert rx_external[1].data == bytearray(range(8)) assert rx_external[1].format == FrameFormat.EXTENDED assert rx_external[2].identifier == 0x1FF45678 assert rx_external[2].data == bytearray(range(0)) assert rx_external[2].format == FrameFormat.EXTENDED media_a.close() media_b.close() await asyncio.sleep( 1 ) # Let all pending tasks finalize properly to avoid stack traces in the output.