Exemple #1
0
class VehicleTest(asynctest.TestCase):

    """
    Class to test Vehicle
    """

    def setUp(self):
        """Set up some data that is reused in many tests"""
        self.dialect = 'ardupilotmega'
        self.mavversion = 2.0
        self.source_system = 255
        self.source_component = 0
        self.target_system = 1
        self.target_component = 0

        # This is the "vehicle" to respond to messages
        self.mod = getpymavlinkpackage(self.dialect, self.mavversion)
        self.mavVehicle = self.mod.MAVLink(self, srcSystem=self.target_system,
                                           srcComponent=self.target_component,
                                           use_native=False)
        self.mavVehicle.robust_parsing = True

        self.veh = None

        self.txpackets = []

        self.onNewPackets = []

    def onNewEvent(self, vehName, pkt):
        """Callback for new packet"""
        self.onNewPackets.append(pkt)

    async def tearDown(self):
        """Close down the test"""
        if self.veh:
            await self.veh.stopheartbeat()
            await self.veh.stoprxtimeout()

    def newpacketcallback(self, buf: bytes, vehname: str):
        """Callback when a vehicle sends a packet"""
        self.txpackets.append(buf)

    def paramcallback(self, buf: bytes, vehname: str):
        """Callback when a vehicle sends a packet - for param testing"""
        # if param request, start sending some params
        pkt = self.mavVehicle.parse_char(buf)
        if isinstance(pkt, self.mod.MAVLink_param_request_list_message):
            # send all params (3 of them)
            pkt = self.mod.MAVLink_param_value_message(
                'RC8_MIN', 1100, self.mod.MAV_PARAM_TYPE_REAL32, 3, 0)
            self.veh.newPacketCallback(pkt)
            pkt = self.mod.MAVLink_param_value_message(
                'RC8_TRIM', 1500, self.mod.MAV_PARAM_TYPE_REAL32, 3, 1)
            self.veh.newPacketCallback(pkt)
            pkt = self.mod.MAVLink_param_value_message(
                'RC8_MAX', 1900, self.mod.MAV_PARAM_TYPE_REAL32, 3, 2)
            self.veh.newPacketCallback(pkt)
        # callback for setting a param
        elif isinstance(pkt, self.mod.MAVLink_param_set_message):
            # send back confirmation
            pkt = self.mod.MAVLink_param_value_message(
                pkt.param_id, pkt.param_value, pkt.param_type, 1, 1)
            self.veh.newPacketCallback(pkt)

    def paramcallbackpartial(self, buf: bytes, vehname: str):
        """Callback when a vehicle sends a packet - for param testing"""
        # if param request, start sending some params
        pkt = self.mavVehicle.parse_char(buf)
        if isinstance(pkt, self.mod.MAVLink_param_request_list_message):
            # send all params (3 of them)
            pkt = self.mod.MAVLink_param_value_message(
                'RC8_MIN', 1100, self.mod.MAV_PARAM_TYPE_REAL32, 3, 0)
            self.veh.newPacketCallback(pkt)
            pkt = self.mod.MAVLink_param_value_message(
                'RC8_MAX', 1900, self.mod.MAV_PARAM_TYPE_REAL32, 3, 2)
            self.veh.newPacketCallback(pkt)
        if isinstance(pkt, self.mod.MAVLink_param_request_read_message):
            # get the missing param
            if pkt.param_index == 1:
                pkt = self.mod.MAVLink_param_value_message(
                    'RC8_TRIM', 1500, self.mod.MAV_PARAM_TYPE_REAL32, 3, 1)
                self.veh.newPacketCallback(pkt)

    async def test_vehicle(self):
        """Test vehicle initialises OK"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)

        assert self.veh is not None

    # async def test_onPacketCallback(self):
    #    """Test the onPacketCallback works"""
    #    self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
    #                       self.target_system, self.target_component, self.dialect, self.mavversion)
    #    self.veh.onPacketRxAttach(self.onNewEvent)
    #
    #    pkt = self.mod.MAVLink_heartbeat_message(
    #        self.mod.MAV_TYPE_QUADROTOR, self.mod.MAV_AUTOPILOT_ARDUPILOTMEGA, 0, 0, 0, int(self.mavversion))
    #    self.veh.newPacketCallback(pkt)
    #
    #    await asyncio.sleep(0.01)
    #
    #    assert len(self.onNewPackets) == 1
    #    assert self.onNewPackets[0] == pkt

    async def test_getPacket(self):
        """Test getting a packet"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        pkt = self.mod.MAVLink_heartbeat_message(
            self.mod.MAV_TYPE_QUADROTOR, self.mod.MAV_AUTOPILOT_ARDUPILOTMEGA, 0, 0, 0, int(self.mavversion))
        self.veh.newPacketCallback(pkt)

        await asyncio.sleep(0.01)

        assert len(self.veh.latestPacketDict) == 1
        assert self.veh.getPacket(self.mod.MAVLINK_MSG_ID_HEARTBEAT) == pkt
        assert self.veh.getPacket(
            self.mod.MAVLINK_MSG_ID_ESC_TELEMETRY_9_TO_12) is None

    async def test_heartbeat(self):
        """Test heatbeat rate and stopping hb task"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.newpacketcallback

        await self.veh.setHearbeatRate(0.001)
        await asyncio.sleep(0.15)

        # stop for a while - no extra hb emitted
        await self.veh.setHearbeatRate(0)
        await asyncio.sleep(0.01)

        # due to timer jitter, can only test for approx rate
        # Expecting between 4 and 120 hb packets
        assert len(self.txpackets) > 4
        assert len(self.txpackets) < 120

    async def test_noheartbeat(self):
        """Test no hb task ever"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.newpacketcallback

        await self.veh.setHearbeatRate(0)
        await asyncio.sleep(0.01)

        assert len(self.txpackets) == 0

    async def test_rxheartbeat(self):
        """Test correct rx of hb from vehicle - time of last packet"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.newpacketcallback
        await self.veh.setTimeout(0.05)

        pkt = self.mod.MAVLink_heartbeat_message(
            self.mod.MAV_TYPE_QUADROTOR, self.mod.MAV_AUTOPILOT_ARDUPILOTMEGA, 0, 0, 0, int(self.mavversion))
        self.veh.newPacketCallback(pkt)

        await asyncio.sleep(0.02)
        assert self.veh.isConnected is True

        await asyncio.sleep(0.10)
        assert self.veh.isConnected is False

    async def test_norxheartbeat(self):
        """Test no rx hb task ever"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)

        await self.veh.setTimeout(0)
        await asyncio.sleep(0.01)

        assert self.veh.isConnected is False

    async def test_vehtypename(self):
        """Test correct veh type and gf name from vehicle"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.newpacketcallback

        pkt = self.mod.MAVLink_heartbeat_message(
            self.mod.MAV_TYPE_QUADROTOR, self.mod.MAV_AUTOPILOT_ARDUPILOTMEGA, 0, 0, 0, int(self.mavversion))
        self.veh.newPacketCallback(pkt)

        assert self.veh.fcName == "MAV_AUTOPILOT_ARDUPILOTMEGA"
        assert self.veh.vehType == "MAV_TYPE_QUADROTOR"

    async def test_armmodestatus(self):
        """Test getting of the arming status and mode from heartbeat"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)

        assert self.veh.isArmed is None
        assert self.veh.flightMode is None

        pkt = self.mod.MAVLink_heartbeat_message(
            self.mod.MAV_TYPE_QUADROTOR, self.mod.MAV_AUTOPILOT_ARDUPILOTMEGA, self.mod.MAV_MODE_AUTO_DISARMED, 0, 0, int(self.mavversion))
        self.veh.newPacketCallback(pkt)

        assert self.veh.isArmed is False
        assert self.veh.flightMode == "0"

        pkt = self.mod.MAVLink_heartbeat_message(
            self.mod.MAV_TYPE_QUADROTOR, self.mod.MAV_AUTOPILOT_ARDUPILOTMEGA, self.mod.MAV_MODE_MANUAL_ARMED, 1, 0, int(self.mavversion))
        self.veh.newPacketCallback(pkt)

        assert self.veh.isArmed is True
        assert self.veh.flightMode == "1"

        pkt = self.mod.MAVLink_heartbeat_message(
            self.mod.MAV_TYPE_QUADROTOR, self.mod.MAV_AUTOPILOT_ARDUPILOTMEGA, self.mod.MAV_MODE_MANUAL_DISARMED, 15, 0, int(self.mavversion))
        self.veh.newPacketCallback(pkt)

        assert self.veh.isArmed is False
        assert self.veh.flightMode == '15'

    async def test_params_before(self):
        """Test getting of the parameters before downloaded"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)

        assert self.veh.getParams('RC8_MAX') is None
        assert self.veh.getParams() is None

    async def test_params_noresponse(self):
        """Test getting of the parameters, no response from vehicle"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        await self.veh.downloadParams(timeout=0.1)

        assert self.veh.getParams('RC8_MAX') is None
        assert self.veh.getParams() is None

    async def test_get_params(self):
        """Test getting of the parameters, got all. Plus typo"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.paramcallback
        await self.veh.downloadParams(timeout=0.25)

        assert self.veh.getParams('RC8_MAX') == 1900
        assert self.veh.getParams('RC8_MAXXX') is None

    async def test_get_params_retry(self):
        """Test getting of the parameters, need to retry some"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.paramcallbackpartial
        await self.veh.downloadParams(timeout=0.25)

        assert self.veh.getParams('RC8_MAX') == 1900
        assert self.veh.getParams('RC8_TRIM') == 1500

    async def test_set_param_no_params(self):
        """Test setting of params if params not downloaded yet"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.paramcallback

        assert await self.veh.setParam('RC8_MAX', 1800) is False

    async def test_set_param(self):
        """Test setting of param"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.paramcallback
        await self.veh.downloadParams(timeout=0.25)

        assert await self.veh.setParam('RC8_MAX', 1730) is True
        assert self.veh.getParams('RC8_MAX') == 1730

    def test_sendPacket(self):
        """Assembling a packet"""
        self.veh = Vehicle(self.loop, "VehA", self.source_system, self.source_component,
                           self.target_system, self.target_component, self.dialect, self.mavversion)
        self.veh.txcallback = self.newpacketcallback

        self.veh.sendPacket(self.mod.MAVLINK_MSG_ID_HEARTBEAT,
                            type=self.mod.MAV_TYPE_GCS,
                            autopilot=self.mod.MAV_AUTOPILOT_INVALID,
                            base_mode=0,
                            custom_mode=0,
                            system_status=0,
                            mavlink_version=int(self.mavversion))

        assert len(self.txpackets) == 1
class ConnectionMatrixTest(asynctest.TestCase):

    """
    Class to test The connection matrix
    """

    def setUp(self):
        """Set up some data that is reused in many tests"""
        self.dialect = 'ardupilotmega'
        self.version = 2.0
        self.ip = "127.0.0.1"

        # The links
        self.linkA = 'tcpclient:127.0.0.1:15001'
        self.linkB = 'tcpserver:127.0.0.1:15020'
        self.linkC = 'udpclient:127.0.0.1:15002'
        self.linkD = 'udpserver:127.0.0.1:15021'

        # The vehicles. Note the vehicles A and C have the same sysid
        # Source s/c then target s/c
        self.VehA = Vehicle(self.loop, "VehA", 255, 0, 4,
                            0, self.dialect, self.version)
        self.VehB = Vehicle(self.loop, "VehB", 254, 0, 3,
                            0, self.dialect, self.version)
        self.VehC = Vehicle(self.loop, "VehC", 255, 0, 4,
                            0, self.dialect, self.version)

        # Dict of data rx'd by each link
        self.rxdata = {}

        # Dict of data rx'd by each vehicle
        self.vehpkts = {}

        self.mod = getpymavlinkpackage(self.dialect, self.version)
        # From the vehicle
        self.mavUAS = self.mod.MAVLink(
            self, srcSystem=4, srcComponent=0, use_native=False)
        self.mavoneUAS = self.mod.MAVLink(
            self, srcSystem=3, srcComponent=0, use_native=False)
        self.mavGCS = self.mod.MAVLink(
            self, srcSystem=255, srcComponent=0, use_native=False)
        self.mavoneGCS = self.mod.MAVLink(
            self, srcSystem=254, srcComponent=0, use_native=False)

    async def tearDown(self):
        """Called at the end of each test"""
        await self.VehA.stopheartbeat()
        await self.VehB.stopheartbeat()
        await self.VehC.stopheartbeat()
        await self.VehA.stoprxtimeout()
        await self.VehB.stoprxtimeout()
        await self.VehC.stoprxtimeout()

    def newpacketcallbackVeh(self, vehname, pkt, strconnection):
        """Callback when a vehicle has a new packet"""
        try:
            self.vehpkts[vehname].append(pkt)
        except KeyError:
            self.vehpkts[vehname] = [pkt]

    def newpacketcallbackLnk(self, pkt, strconnection):
        """Callback when a test link has a new packet"""
        try:
            self.rxdata[strconnection].append(pkt)
        except KeyError:
            self.rxdata[strconnection] = [pkt]

    async def test_matrixstartup(self):
        """Test a simple startup of the matrix"""
        matrix = ConnectionManager(self.loop, self.dialect, self.version, 0, 0)

        await matrix.stoploop()

        assert matrix is not None

    async def test_matrixaddremove(self):
        """Test adding and removing vehicles from the matrix"""
        matrix = ConnectionManager(self.loop, self.dialect, self.version, 0, 0)
        matrix.onPacketAttach(self.newpacketcallbackVeh)

        await matrix.addVehicleLink(self.VehA.name, self.VehA.target_system, self.linkB)
        await matrix.addVehicleLink(self.VehB.name, self.VehB.target_system, self.linkB)
        await matrix.addVehicleLink(self.VehC.name, self.VehC.target_system, self.linkD)

        # now wait for a bit - 0.02 sec
        await asyncio.sleep(0.02)

        assert len(matrix.getAllVeh()) == 3
        assert len(matrix.linkdict) == 2

        # remove a link - it will remove the associated veh C too
        await matrix.removeLink(self.linkD)

        # now wait for a bit - 0.02 sec
        await asyncio.sleep(0.02)

        assert len(matrix.getAllVeh()) == 2
        assert len(matrix.linkdict) == 1

        # remove a vehicle
        await matrix.removeVehicle(self.VehA.name)

        # now wait for a bit - 0.02 sec
        await asyncio.sleep(0.02)

        await matrix.stoploop()

        # assert. It should be VehA and linkB left
        assert len(matrix.getAllVeh()) == 1
        assert len(matrix.linkdict) == 1

    async def test_linkretry_tcp(self):
        """For each of the TCP link types, test that they
        keep re-trying to connect, by only adding in the
        other side of the link 0.5 sec after startup"""
        matrix = ConnectionManager(
            self.loop, self.dialect, self.version, 0, 0, 0.05)
        matrix.onPacketAttach(self.newpacketcallbackVeh)

        await matrix.addVehicleLink(self.VehA.name, self.VehA.target_system, self.linkA)
        await matrix.addVehicleLink(self.VehB.name, self.VehB.target_system, self.linkB)

        # now wait for a bit
        await asyncio.sleep(0.10)

        # now connect the other sides
        tcpserver = TCPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=True, name='tcpserver:127.0.0.1:15001')
        tcpclient = TCPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=False, name='tcpclient:127.0.0.1:15020')
        await self.loop.create_server(lambda: tcpserver, self.ip, 15001)
        await self.loop.create_connection(lambda: tcpclient, self.ip, 15020)

        # send packets on each link and wait
        await asyncio.sleep(0.20)

        pkt = self.mod.MAVLink_heartbeat_message(
            5, 4, 0, 0, 0, int(self.version))
        pktbytes = pkt.pack(self.mavUAS, force_mavlink1=False)
        pktbytesone = pkt.pack(self.mavoneUAS, force_mavlink1=False)
        tcpserver.send_data(pktbytes)
        tcpclient.send_data(pktbytesone)

        await asyncio.sleep(0.20)

        await matrix.stoploop()

        tcpserver.close()
        tcpclient.close()

        # assert the links are all still there
        assert len(matrix.getAllVeh()) == 2
        assert len(matrix.linkdict) == 2

        # assert packets were recived on both links (vehicles) in the matrix
        assert self.vehpkts[self.VehA.name][0].get_msgbuf() == pktbytes
        assert self.vehpkts[self.VehB.name][0].get_msgbuf() == pktbytesone

    async def test_linkretry_udp(self):
        """For each of the UDP link types, test that they
        keep re-trying to connect, by only adding in the
        other side of the link 0.5 sec after startup"""
        matrix = ConnectionManager(
            self.loop, self.dialect, self.version, 0, 0, 0.05)
        matrix.onPacketAttach(self.newpacketcallbackVeh)

        self.VehA.onPacketTxAttach(matrix.outgoingPacket)
        self.VehB.onPacketTxAttach(matrix.outgoingPacket)

        await matrix.addVehicleLink(self.VehA.name, self.VehA.target_system, self.linkC)
        await matrix.addVehicleLink(self.VehB.name, self.VehB.target_system, self.linkD)

        # now wait for a bit - 0.02 sec
        await asyncio.sleep(0.02)

        # now connect the other sides
        udpserver = UDPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=True, name='udpserver:127.0.0.1:15002')
        udpclient = UDPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=False, name='udpclient:127.0.0.1:15021')
        await self.loop.create_datagram_endpoint(lambda: udpserver,
                                                 local_addr=(self.ip, 15002))
        await self.loop.create_datagram_endpoint(lambda: udpclient,
                                                 remote_addr=(self.ip, 15021))

        # send packets on each link and wait 0.02 sec
        await asyncio.sleep(0.02)

        pkt = self.mod.MAVLink_heartbeat_message(
            5, 4, 0, 0, 0, int(self.version))
        pktbytes = pkt.pack(self.mavUAS, force_mavlink1=False)
        pktbytesone = pkt.pack(self.mavoneUAS, force_mavlink1=False)

        # need to send a packet from client to server to init the link
        self.VehA.sendPacket(self.VehA.mod.MAVLINK_MSG_ID_HEARTBEAT,
                             type=self.VehA.mod.MAV_TYPE_GCS,
                             autopilot=self.VehA.mod.MAV_AUTOPILOT_INVALID,
                             base_mode=0,
                             custom_mode=0,
                             system_status=0,
                             mavlink_version=int(self.VehA.mavversion))

        await asyncio.sleep(0.02)

        udpserver.send_data(pktbytes)
        udpclient.send_data(pktbytesone)

        await asyncio.sleep(0.02)

        await matrix.stoploop()

        udpserver.close()
        udpclient.close()

        # assert the links are all still there
        assert len(matrix.getAllVeh()) == 2
        assert len(matrix.linkdict) == 2

        # assert packets were recived on both links (vehicles) in the matrix
        assert len(self.vehpkts) == 2
        assert self.vehpkts[self.VehA.name][0].get_msgbuf() == pktbytes
        assert self.vehpkts[self.VehB.name][0].get_msgbuf() == pktbytesone

    async def test_incomingdistribution(self):
        """Test incoming packets (from vehicle) are distributed
        correctly"""
        # -VehA: LinkA,LinkB, VehB: LinkB, VehC: LinkC
        matrix = ConnectionManager(
            self.loop, self.dialect, self.version, 0, 0, 0.05)
        matrix.onPacketAttach(self.newpacketcallbackVeh)

        await matrix.addVehicleLink(self.VehA.name, self.VehA.target_system, self.linkA)
        await matrix.addVehicleLink(self.VehA.name, self.VehA.target_system, self.linkB)
        await matrix.addVehicleLink(self.VehB.name, self.VehB.target_system, self.linkB)
        await matrix.addVehicleLink(self.VehC.name, self.VehC.target_system, self.linkD)

        # now wait for a bit
        await asyncio.sleep(0.10)

        # now connect the other sides
        tcpserver = TCPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=True, name='tcpserver:127.0.0.1:15001')
        tcpclient = TCPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=False, name='tcpclient:127.0.0.1:15020')
        udpclient = UDPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=False, name='udpclient:127.0.0.1:15021')
        await self.loop.create_server(lambda: tcpserver, self.ip, 15001)
        await self.loop.create_connection(lambda: tcpclient, self.ip, 15020)
        await self.loop.create_datagram_endpoint(lambda: udpclient,
                                                 remote_addr=(self.ip, 15021))

        # send packets on each link and wait
        await asyncio.sleep(0.10)

        pkt = self.mod.MAVLink_heartbeat_message(
            5, 4, 0, 0, 0, int(self.version))
        pktbytes = pkt.pack(self.mavUAS, force_mavlink1=False)
        pktbytesone = pkt.pack(self.mavoneUAS, force_mavlink1=False)

        # send packet to VehA on LinkA
        tcpserver.send_data(pktbytes)
        await asyncio.sleep(0.10)

        # send new (updated) packet to VehA on LinkB
        pktupdate = self.mod.MAVLink_heartbeat_message(
            5, 3, 0, 0, 0, int(self.version))
        pktbytesupdate = pktupdate.pack(self.mavUAS, force_mavlink1=False)
        tcpclient.send_data(pktbytesupdate)

        # need a small sleep here otherwise the linkB gets confused
        await asyncio.sleep(0.10)

        # send packet to VehB on linkB
        tcpclient.send_data(pktbytesone)
        await asyncio.sleep(0.10)

        # send packet to VehC on LinkC
        udpclient.send_data(pktbytes)

        # wait for packets to send
        await asyncio.sleep(0.10)

        # and close everything
        await matrix.stoploop()

        tcpserver.close()
        tcpclient.close()
        udpclient.close()

        # assert the links are all still there
        assert len(matrix.getAllVeh()) == 3
        assert len(matrix.linkdict) == 3

        # assert packets were recived
        assert self.vehpkts[self.VehA.name][0].get_msgbuf() == pktbytes
        assert self.vehpkts[self.VehA.name][1].get_msgbuf() == pktbytesupdate
        assert self.vehpkts[self.VehB.name][0].get_msgbuf() == pktbytesone
        assert self.vehpkts[self.VehC.name][0].get_msgbuf() == pktbytes

    async def test_outgoingdistribution(self):
        """Test outgoing packets (from gcs) are distributed
        correctly"""
        # -VehA: LinkA,LinkB, VehB: LinkB, VehC: LinkC
        await self.VehA.setHearbeatRate(0)
        await self.VehB.setHearbeatRate(0)
        await self.VehC.setHearbeatRate(0)

        matrix = ConnectionManager(
            self.loop, self.dialect, self.version, 0, 0, 0.05)
        matrix.onPacketAttach(self.newpacketcallbackVeh)

        self.VehA.onPacketTxAttach(matrix.outgoingPacket)
        self.VehB.onPacketTxAttach(matrix.outgoingPacket)
        self.VehC.onPacketTxAttach(matrix.outgoingPacket)

        await matrix.addVehicleLink(self.VehA.name, self.VehA.target_system, self.linkA)
        await matrix.addVehicleLink(self.VehA.name, self.VehA.target_system, self.linkB)
        await matrix.addVehicleLink(self.VehB.name, self.VehB.target_system, self.linkB)
        await matrix.addVehicleLink(self.VehC.name, self.VehC.target_system, self.linkC)

        # now wait for a bit
        await asyncio.sleep(0.15)

        # now connect the other sides
        tcpserver = TCPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=True, name='tcpserver:127.0.0.1:15001')
        tcpclient = TCPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=False, name='tcpclient:127.0.0.1:15020')
        udpserver = UDPConnection(rxcallback=self.newpacketcallbackLnk,
                                  dialect=self.dialect, mavversion=self.version,
                                  srcsystem=0, srccomp=0,
                                  server=True, name='udpserver:127.0.0.1:15002')
        await self.loop.create_server(lambda: tcpserver, self.ip, 15001)
        await self.loop.create_connection(lambda: tcpclient, self.ip, 15020)
        await self.loop.create_datagram_endpoint(lambda: udpserver,
                                                 local_addr=(self.ip, 15002))

        # send packets on each link and wait
        await asyncio.sleep(0.15)

        # send packet from the GCS of VehA, VehB and VehC
        pktbytesA = self.VehA.sendPacket(self.mod.MAVLINK_MSG_ID_HEARTBEAT,
                                         type=self.mod.MAV_TYPE_GCS,
                                         autopilot=self.mod.MAV_AUTOPILOT_INVALID,
                                         base_mode=0,
                                         custom_mode=0,
                                         system_status=0,
                                         mavlink_version=int(self.VehA.mavversion))
        await asyncio.sleep(0.10)
        pktbytesB = self.VehB.sendPacket(self.mod.MAVLINK_MSG_ID_HEARTBEAT,
                                         type=self.mod.MAV_TYPE_GCS,
                                         autopilot=self.mod.MAV_AUTOPILOT_INVALID,
                                         base_mode=0,
                                         custom_mode=0,
                                         system_status=0,
                                         mavlink_version=int(self.VehB.mavversion))
        await asyncio.sleep(0.10)
        pktbytesC = self.VehC.sendPacket(self.mod.MAVLINK_MSG_ID_HEARTBEAT,
                                         type=self.mod.MAV_TYPE_GCS,
                                         autopilot=self.mod.MAV_AUTOPILOT_INVALID,
                                         base_mode=0,
                                         custom_mode=0,
                                         system_status=0,
                                         mavlink_version=int(self.VehC.mavversion))

        # wait for packets to send
        await asyncio.sleep(0.15)

        # and close everything
        await matrix.stoploop()

        tcpserver.close()
        tcpclient.close()
        udpserver.close()

        # assert the links are all still there
        assert len(matrix.getAllVeh()) == 3
        assert len(matrix.linkdict) == 3

        # assert packets were recived on the endpoints
        assert self.rxdata['tcpserver:127.0.0.1:15001'][0].get_msgbuf(
        ) == pktbytesA
        assert self.rxdata['tcpclient:127.0.0.1:15020'][0].get_msgbuf(
        ) == pktbytesC
        assert self.rxdata['tcpclient:127.0.0.1:15020'][1].get_msgbuf(
        ) == pktbytesB
        assert self.rxdata['udpserver:127.0.0.1:15002'][0].get_msgbuf(
        ) == pktbytesC