예제 #1
0
파일: conftest.py 프로젝트: alkasm/pyuavcan
 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
예제 #2
0
        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
예제 #3
0
파일: conftest.py 프로젝트: alkasm/pyuavcan
        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,
            )
예제 #4
0
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)
예제 #5
0
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,
        )
예제 #6
0
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.
예제 #7
0
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.