diff --git a/cflib/crtp/radiodriver.py b/cflib/crtp/radiodriver.py
index 1aa9cad6342cf8b51ab075db7cf13cbd6929ed54..a0a86a8d42c80d6236fa150edd549057bf74df59 100644
--- a/cflib/crtp/radiodriver.py
+++ b/cflib/crtp/radiodriver.py
@@ -153,6 +153,41 @@ class RadioDriver(CRTPDriver):
         an error message.
         """
 
+        devid, channel, datarate, address = self.parse_uri(uri)
+        self.uri = uri
+
+        if self._radio_manager is None:
+            self._radio_manager = _RadioManager(devid,
+                                                channel,
+                                                datarate,
+                                                address)
+        else:
+            raise Exception('Link already open!')
+
+        with self._radio_manager as cradio:
+            if cradio.version >= 0.4:
+                cradio.set_arc(_nr_of_arc_retries)
+            else:
+                logger.warning('Radio version <0.4 will be obsoleted soon!')
+
+        # Prepare the inter-thread communication queue
+        self.in_queue = queue.Queue()
+        # Limited size out queue to avoid "ReadBack" effect
+        self.out_queue = queue.Queue(1)
+
+        # Launch the comm thread
+        self._thread = _RadioDriverThread(self._radio_manager,
+                                          self.in_queue,
+                                          self.out_queue,
+                                          link_quality_callback,
+                                          link_error_callback,
+                                          self)
+        self._thread.start()
+
+        self.link_error_callback = link_error_callback
+
+    @staticmethod
+    def parse_uri(uri):
         # check if the URI is a radio URI
         if not re.search('^radio://', uri):
             raise WrongUriType('Not a radio URI')
@@ -165,8 +200,6 @@ class RadioDriver(CRTPDriver):
         uri_data = re.search('^radio://([0-9a-fA-F]+)((/([0-9]+))'
                              '((/(250K|1M|2M))?(/([A-F0-9]+))?)?)?$', uri)
 
-        self.uri = uri
-
         if len(uri_data.group(1)) < 10 and uri_data.group(1).isdigit():
             devid = int(uri_data.group(1))
         else:
@@ -195,35 +228,7 @@ class RadioDriver(CRTPDriver):
             new_addr = struct.unpack('<BBBBB', binascii.unhexlify(addr))
             address = new_addr
 
-        if self._radio_manager is None:
-            self._radio_manager = _RadioManager(devid,
-                                                channel,
-                                                datarate,
-                                                address)
-        else:
-            raise Exception('Link already open!')
-
-        with self._radio_manager as cradio:
-            if cradio.version >= 0.4:
-                cradio.set_arc(_nr_of_arc_retries)
-            else:
-                logger.warning('Radio version <0.4 will be obsoleted soon!')
-
-        # Prepare the inter-thread communication queue
-        self.in_queue = queue.Queue()
-        # Limited size out queue to avoid "ReadBack" effect
-        self.out_queue = queue.Queue(1)
-
-        # Launch the comm thread
-        self._thread = _RadioDriverThread(self._radio_manager,
-                                          self.in_queue,
-                                          self.out_queue,
-                                          link_quality_callback,
-                                          link_error_callback,
-                                          self)
-        self._thread.start()
-
-        self.link_error_callback = link_error_callback
+        return devid, channel, datarate, address
 
     def receive_packet(self, time=0):
         """
diff --git a/sys-test/__init__.py b/sys-test/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/sys-test/swarm_test_rig/__init__.py b/sys-test/swarm_test_rig/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7dc36c6a406d6eee3cf820aa19b66589f28f78f8
--- /dev/null
+++ b/sys-test/swarm_test_rig/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+#
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
+#  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
+#  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
+#   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
+#
+#  Copyright (C) 2019 Bitcraze AB
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+#  MA  02110-1301, USA.
+
diff --git a/sys-test/swarm_test_rig/cload_all_nrf.sh b/sys-test/swarm_test_rig/cload_all_nrf.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7da86e8f3e4f9b45264c9e662294837885eaabeb
--- /dev/null
+++ b/sys-test/swarm_test_rig/cload_all_nrf.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+file=$1
+
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74201
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74202
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74203
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74204
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74205
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74206
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74207
+python3 -m cfloader flash $file nrf51-fw -w radio://0/42/2M/E7E7E74208
diff --git a/sys-test/swarm_test_rig/cload_all_stm.sh b/sys-test/swarm_test_rig/cload_all_stm.sh
new file mode 100755
index 0000000000000000000000000000000000000000..630a1b29c487d63fa8ac171ee5b13b079d03824c
--- /dev/null
+++ b/sys-test/swarm_test_rig/cload_all_stm.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+file=$1
+
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74201
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74202
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74203
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74204
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74205
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74206
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74207
+python3 -m cfloader flash $file stm32-fw -w radio://0/42/2M/E7E7E74208
diff --git a/sys-test/swarm_test_rig/test_connection.py b/sys-test/swarm_test_rig/test_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..e89ad03cae0bd66afafbe0e89ddb5d00d6b30788
--- /dev/null
+++ b/sys-test/swarm_test_rig/test_connection.py
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+#
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
+#  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
+#  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
+#   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
+#
+#  Copyright (C) 2019 Bitcraze AB
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+#  MA  02110-1301, USA.
+
+import unittest
+import time
+
+import cflib.crtp
+from cflib.crazyflie.swarm import Swarm
+from cflib.crtp import RadioDriver
+from cflib.drivers.crazyradio import Crazyradio
+
+
+class TestSwarmConnection(unittest.TestCase):
+    def setUp(self):
+
+        self.all_uris = [
+            'radio://0/42/2M/E7E7E74201',
+            'radio://0/42/2M/E7E7E74202',
+            'radio://0/42/2M/E7E7E74203',
+            'radio://0/42/2M/E7E7E74204',
+            'radio://0/42/2M/E7E7E74205',
+            'radio://0/42/2M/E7E7E74206',
+            'radio://0/42/2M/E7E7E74207',
+            'radio://0/42/2M/E7E7E74208',
+            'radio://0/42/2M/E7E7E74209',
+            'radio://0/42/2M/E7E7E7420A',
+        ]
+
+    def test_that_connection_time_scales_with_more_devices(self):
+        cflib.crtp.init_drivers(enable_debug_driver=False)
+
+        self.restart_devices(self.all_uris)
+
+        EXPECTED_CONNECTION_TIME = 5
+
+        for nr_of_devices in range(1, len(self.all_uris)):
+            uris = self.all_uris[:nr_of_devices]
+
+            start_time = time.time()
+            with Swarm(uris):
+                connected_time = time.time()
+
+            actual = connected_time - start_time
+            max_expected = EXPECTED_CONNECTION_TIME * nr_of_devices
+            print('Connection time for', nr_of_devices, ':', actual,
+                  ', per device:', actual / nr_of_devices)
+            self.assertLess(actual, max_expected)
+
+    def restart_devices(self, uris):
+        def send_packets(uris, value):
+            for uri in uris:
+                devid, channel, datarate, address = RadioDriver.parse_uri(uri)
+                radio.set_channel(channel)
+                radio.set_data_rate(datarate)
+                radio.set_address(address)
+
+                received_packet = False
+                for i in range(100):
+                    result = radio.send_packet((0xf3, 0xfe, value))
+                    if result.ack:
+                        received_packet = True
+                        break
+
+                self.assertTrue(received_packet)
+
+        BOOTLOADER_CMD_SYSOFF = 0x02
+        BOOTLOADER_CMD_SYSON = 0x03
+
+        radio = Crazyradio()
+        send_packets(uris, BOOTLOADER_CMD_SYSOFF)
+        time.sleep(0.1)
+        send_packets(uris, BOOTLOADER_CMD_SYSON)
+        radio.close()
+        time.sleep(5)