def __init__(self, compare_frame_controller: CompareFrameController, project_manager: ProjectManager, parent=None): super().__init__(parent) self.ui = Ui_GeneratorTab() self.ui.setupUi(self) self.project_manager = project_manager self.ui.treeProtocols.setHeaderHidden(True) self.tree_model = GeneratorTreeModel(compare_frame_controller) self.tree_model.set_root_item(compare_frame_controller.proto_tree_model.rootItem) self.tree_model.controller = self self.ui.treeProtocols.setModel(self.tree_model) self.table_model = GeneratorTableModel(compare_frame_controller.proto_tree_model.rootItem, [Modulator("Modulation")], compare_frame_controller.decodings) self.table_model.controller = self self.ui.tableMessages.setModel(self.table_model) self.label_list_model = GeneratorListModel(None) self.ui.listViewProtoLabels.setModel(self.label_list_model) self.network_sdr_button_orig_tooltip = self.ui.btnNetworkSDRSend.toolTip() self.set_network_sdr_send_button_visibility() self.set_rfcat_button_visibility() self.network_sdr_plugin = NetworkSDRInterfacePlugin() self.rfcat_plugin = RfCatPlugin() self.init_rfcat_plugin() self.refresh_modulators() self.on_selected_modulation_changed() self.set_fuzzing_ui_status() self.ui.prBarGeneration.hide() self.create_connects(compare_frame_controller)
def test_protocol_sniffer(self): samples_per_symbol = 100 center = 0.0942 noise = 0.1 tolerance = 2 modulation_type = "FSK" sample_rate = 1e6 device_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME sniffer = ProtocolSniffer(samples_per_symbol=samples_per_symbol, center=center, center_spacing=0.1, noise=noise, tolerance=tolerance, modulation_type=modulation_type, bits_per_symbol=1, device=device_name, backend_handler=BackendHandler(), network_raw_mode=True) port = self.get_free_port() sniffer.rcv_device.set_server_port(port) self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin(raw_mode=True) self.network_sdr_plugin_sender.client_port = port sniffer.sniff() QTest.qWait(10) data = ["101010", "000111", "1111000"] pause = 10 * samples_per_symbol modulator = Modulator("test") modulator.samples_per_symbol = samples_per_symbol modulator.sample_rate = sample_rate modulator.modulation_type = modulation_type modulator.parameters[1] = 20e3 modulator.parameters[0] = 10e3 packages = [] for d in data: packages.append(modulator.modulate(list(map(int, d)), pause)) # verify modulation was correct pa = ProtocolAnalyzer(None) signal = Signal("", "", sample_rate=sample_rate) signal.iq_array = IQArray.concatenate(packages) signal.modulation_type = modulation_type signal.samples_per_symbol = samples_per_symbol signal.tolerance = tolerance signal.noise_threshold = noise signal.center = center pa.signal = signal pa.get_protocol_from_signal() self.assertEqual(pa.plain_bits_str, data) # send data send_data = IQArray.concatenate(packages) self.network_sdr_plugin_sender.send_raw_data(send_data, 1) time.sleep(1) # Send enough pauses to end sniffing self.network_sdr_plugin_sender.send_raw_data(IQArray(None, np.float32, 10 * 2 * samples_per_symbol), 1) time.sleep(1) sniffer.stop() self.assertEqual(sniffer.plain_bits_str, data)
def test_protocol_sniffer(self): bit_len = 100 center = 0.0942 noise = 0.1 tolerance = 2 modulation_type = 1 sample_rate = 1e6 device_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME sniffer = ProtocolSniffer(bit_len=bit_len, center=center, noise=noise, tolerance=tolerance, modulation_type=modulation_type, device=device_name, backend_handler=BackendHandler(), network_raw_mode=True) port = self.get_free_port() sniffer.rcv_device.set_server_port(port) self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin(raw_mode=True) self.network_sdr_plugin_sender.client_port = port sniffer.sniff() QTest.qWait(10) data = ["101010", "000111", "1111000"] pause = 10 * bit_len modulator = Modulator("test") modulator.samples_per_bit = bit_len modulator.sample_rate = sample_rate modulator.modulation_type = modulation_type modulator.param_for_one = 20e3 modulator.param_for_zero = 10e3 packages = [] for d in data: packages.append(modulator.modulate(list(map(int, d)), pause)) # verify modulation was correct pa = ProtocolAnalyzer(None) signal = Signal("", "", sample_rate=sample_rate) signal._fulldata = np.concatenate(packages) signal.modulation_type = modulation_type signal.bit_len = bit_len signal.tolerance = tolerance signal.noise_threshold = noise signal.qad_center = center pa.signal = signal pa.get_protocol_from_signal() self.assertEqual(pa.plain_bits_str, data) # send data send_data = np.concatenate(packages) self.network_sdr_plugin_sender.send_raw_data(send_data, 1) time.sleep(1) # Send enough pauses to end sniffing self.network_sdr_plugin_sender.send_raw_data(np.zeros(10 * bit_len, dtype=np.complex64), 1) time.sleep(1) sniffer.stop() self.assertEqual(sniffer.plain_bits_str, data)
def setUp(self): self.form = MainController() self.cfc = self.form.compare_frame_controller self.stc = self.form.simulator_tab_controller self.gtc = self.form.generator_tab_controller self.form.add_signalfile(get_path_for_data_file("esaver.complex")) self.sframe = self.form.signal_tab_controller.signal_frames[0] self.sim_frame = self.form.simulator_tab_controller self.form.ui.tabWidget.setCurrentIndex(3) self.cfc.proto_analyzer.auto_assign_labels() SettingsProxy.OVERWRITE_RECEIVE_BUFFER_SIZE = 100 * 10**6 self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin( raw_mode=True)
def __init__(self, compare_frame_controller: CompareFrameController, project_manager: ProjectManager, parent=None): super().__init__(parent) self.ui = Ui_GeneratorTab() self.ui.setupUi(self) self.ui.treeProtocols.setHeaderHidden(True) self.tree_model = GeneratorTreeModel(compare_frame_controller) self.tree_model.set_root_item(compare_frame_controller.proto_tree_model.rootItem) self.tree_model.controller = self self.ui.treeProtocols.setModel(self.tree_model) self.has_default_modulation = True self.table_model = GeneratorTableModel(compare_frame_controller.proto_tree_model.rootItem, [Modulator("Modulation")], compare_frame_controller.decodings) self.table_model.controller = self self.ui.tableMessages.setModel(self.table_model) self.label_list_model = GeneratorListModel(None) self.ui.listViewProtoLabels.setModel(self.label_list_model) self.network_sdr_button_orig_tooltip = self.ui.btnNetworkSDRSend.toolTip() self.set_network_sdr_send_button_visibility() self.set_rfcat_button_visibility() self.network_sdr_plugin = NetworkSDRInterfacePlugin() self.rfcat_plugin = RfCatPlugin() self.init_rfcat_plugin() self.refresh_modulators() self.on_selected_modulation_changed() self.set_fuzzing_ui_status() self.project_manager = project_manager self.ui.prBarGeneration.hide() self.create_connects(compare_frame_controller)
def test_sdr_interface_plugin(self): si = NetworkSDRInterfacePlugin() test_bits = [ "10101011111", "1010100011000111110001011001010101010101", "1010100011000111110001011001010100100", "1101010101011000011", "11010101010110000110", "11100010101001110000", "111100000011011101010101010000101010101010100001010011010101010011" ] for bits in test_bits: byte_vals = si.bit_str_to_bytearray(bits) self.assertEqual(len(byte_vals), int(math.ceil(len(bits) / 8)), msg=bits) recalculated = si.bytearray_to_bit_str(byte_vals) if len(bits) % 8 == 0: self.assertEqual(bits, recalculated) elif bits.endswith("1"): self.assertEqual(bits, recalculated.rstrip("0")) else: self.assertTrue(recalculated.startswith(bits))
def test_sdr_interface_plugin(self): si = NetworkSDRInterfacePlugin(resume_on_full_receive_buffer=True) test_bits = [ "10101011111", "1010100011000111110001011001010101010101", "1010100011000111110001011001010100100", "1101010101011000011", "11010101010110000110", "11100010101001110000", "111100000011011101010101010000101010101010100001010011010101010011" ] for bits in test_bits: byte_vals = si.bit_str_to_bytearray(bits) self.assertEqual(len(byte_vals), int(math.ceil(len(bits) / 8)), msg=bits) recalculated = si.bytearray_to_bit_str(byte_vals) if len(bits) % 8 == 0: self.assertEqual(bits, recalculated) elif bits.endswith("1"): self.assertEqual(bits, recalculated.rstrip("0")) else: self.assertTrue(recalculated.startswith(bits))
def test_open_simulator_dialog_and_send_mismatching_message(self): stc = self.form.simulator_tab_controller assert isinstance(stc, SimulatorTabController) self.__setup_project() self.add_all_signals_to_simulator() stc.simulator_scene.select_all_items() for msg in stc.simulator_scene.get_selected_messages(): msg.destination = self.dennis stc.ui.gvSimulator.message_updated.emit(msg) list_model = stc.ui.listViewSimulate.model() self.assertEqual(list_model.rowCount(), 2) list_model.setData(list_model.createIndex(1, 0), Qt.Checked, role=Qt.CheckStateRole) dialog = stc.get_simulator_dialog() network_sdr_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText( network_sdr_name) dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText( network_sdr_name) send_port = self.get_free_port() dialog.simulator.sender.device.set_client_port(send_port) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", send_port)) s.listen(1) rcv_port = self.get_free_port() dialog.simulator.sniffer.rcv_device.set_server_port(rcv_port) dialog.ui.btnStartStop.click() QTest.qWait(100) modulator = dialog.project_manager.modulators[0] # type: Modulator sender = NetworkSDRInterfacePlugin(raw_mode=True, sending=True) sender.client_port = rcv_port sender.send_raw_data(modulator.modulate("1" * 352), 1) sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1) sender.send_raw_data(modulator.modulate("10" * 176), 1) sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1) QTest.qWait(1000) simulator_log = dialog.ui.textEditSimulation.toPlainText() self.assertIn("Received message 1", simulator_log) self.assertIn("preamble: 11111111", simulator_log) self.assertIn("Mismatch for label: preamble", simulator_log) dialog.close() s.close()
class TestSimulator(QtTestCase): def setUp(self): super().setUp() SettingsProxy.OVERWRITE_RECEIVE_BUFFER_SIZE = 10 * 10**6 self.num_zeros_for_pause = 1000 def test_performance(self): self.form = MainController() self.cfc = self.form.compare_frame_controller self.stc = self.form.simulator_tab_controller self.gtc = self.form.generator_tab_controller self.form.add_signalfile(get_path_for_data_file("esaver.complex")) self.sframe = self.form.signal_tab_controller.signal_frames[0] self.sim_frame = self.form.simulator_tab_controller self.form.ui.tabWidget.setCurrentIndex(3) self.cfc.proto_analyzer.auto_assign_labels() self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin( raw_mode=True) part_a = Participant("Device A", shortname="A", color_index=0) part_b = Participant("Device B", shortname="B", color_index=1) part_b.simulate = True self.form.project_manager.participants.append(part_a) self.form.project_manager.participants.append(part_b) self.form.project_manager.project_updated.emit() sniffer = ProtocolSniffer(100, 0.01, 0.1, 5, 1, NetworkSDRInterfacePlugin.NETWORK_SDR_NAME, BackendHandler(), network_raw_mode=True) sender = EndlessSender(BackendHandler(), NetworkSDRInterfacePlugin.NETWORK_SDR_NAME) simulator = Simulator(self.stc.simulator_config, self.gtc.modulators, self.stc.sim_expression_parser, self.form.project_manager, sniffer=sniffer, sender=sender) pause = 100000 msg_a = SimulatorMessage( part_b, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [0, 0, 1, 1] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, pause=pause, message_type=MessageType("empty_message_type"), source=part_a) msg_b = SimulatorMessage( part_a, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [1, 1, 0, 0] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, pause=pause, message_type=MessageType("empty_message_type"), source=part_b) self.stc.simulator_config.add_items([msg_a, msg_b], 0, None) self.stc.simulator_config.update_active_participants() port = self.get_free_port() sniffer = simulator.sniffer sniffer.rcv_device.set_server_port(port) self.network_sdr_plugin_sender.client_port = port sender = simulator.sender port = self.get_free_port() sender.device.set_client_port(port) sender.device._VirtualDevice__dev.name = "simulator_sender" current_index = Value("L") elapsed = Value("f") target_num_samples = 113600 - pause receive_process = Process(target=receive, args=(port, current_index, target_num_samples, elapsed)) receive_process.daemon = True receive_process.start() # Ensure receiver is running time.sleep(2) # spy = QSignalSpy(self.network_sdr_plugin_receiver.rcv_index_changed) simulator.start() modulator = Modulator("test_modulator") modulator.samples_per_bit = 100 modulator.carrier_freq_hz = 55e3 # yappi.start() self.network_sdr_plugin_sender.send_raw_data( modulator.modulate(msg_a.encoded_bits), 1) QTest.qWait(10) # send some zeros to simulate the end of a message self.network_sdr_plugin_sender.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) QTest.qWait(100) receive_process.join(10) logger.info("PROCESS TIME: {0:.2f}ms".format(elapsed.value)) self.assertEqual(current_index.value, target_num_samples) self.assertLess(elapsed.value, 200) # timeout = spy.wait(2000) # yappi.get_func_stats().print_all() # yappi.get_thread_stats().print_all() def test_simulation_flow(self): """ test a simulation flow with an increasing sequence number :return: """ profile = self.get_path_for_filename("testprofile.sim.xml") self.form.add_files([profile]) self.assertEqual( len(self.form.simulator_tab_controller.simulator_scene. get_all_message_items()), 6) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = self.form.simulator_tab_controller.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) QTest.qWait(10) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) QTest.qWait(10) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(1500) conn, addr = s.accept() msg = next(msg for msg in dialog.simulator_config.get_all_messages() if msg.source.name == "Alice") checksum_label = next( lbl for lbl in msg.message_type if lbl.is_checksum_label).label # type: ChecksumLabel modulator = dialog.project_manager.modulators[0] # type: Modulator preamble_str = "10101010" sync_str = "1001" preamble = list(map(int, preamble_str)) sync = list(map(int, sync_str)) seq = list(map(int, "00000010")) data = list(map(int, "11001101")) seq_num = int("".join(map(str, seq)), 2) checksum = list(checksum_label.calculate_checksum(seq + data)) msg1 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg1), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 1) seq = list(map(int, "{0:08b}".format(seq_num + 2))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg2 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg2), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 3) seq = list(map(int, "{0:08b}".format(seq_num + 4))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg3 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg3), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 5) QTest.qWait(50) self.assertTrue(simulator.simulation_is_finished()) time.sleep(1) conn.close() s.close() QTest.qWait(100) def test_external_program_simulator(self): stc = self.form.simulator_tab_controller stc.ui.btnAddParticipant.click() stc.ui.btnAddParticipant.click() stc.simulator_scene.add_counter_action(None, 0) action = next(item for item in stc.simulator_scene.items() if isinstance(item, CounterActionItem)) action.model_item.start = 3 action.model_item.step = 2 counter_item_str = "item" + str( action.model_item.index()) + ".counter_value" stc.ui.gvSimulator.add_empty_message(42) stc.ui.gvSimulator.add_empty_message(42) stc.ui.cbViewType.setCurrentIndex(0) stc.create_simulator_label(0, 10, 20) stc.create_simulator_label(1, 10, 20) messages = stc.simulator_config.get_all_messages() messages[0].source = stc.project_manager.participants[0] messages[0].destination = stc.project_manager.participants[1] messages[0].destination.simulate = True messages[1].source = stc.project_manager.participants[1] messages[1].destination = stc.project_manager.participants[0] stc.simulator_scene.add_trigger_command_action(None, 200) stc.simulator_scene.add_sleep_action(None, 200) lbl1 = messages[0].message_type[0] # type: SimulatorProtocolLabel lbl2 = messages[1].message_type[0] # type: SimulatorProtocolLabel lbl1.value_type_index = 3 lbl1.external_program = get_path_for_data_file( "external_program_simulator.py") + " " + counter_item_str lbl2.value_type_index = 3 lbl2.external_program = get_path_for_data_file( "external_program_simulator.py") + " " + counter_item_str action = next(item for item in stc.simulator_scene.items() if isinstance(item, SleepActionItem)) action.model_item.sleep_time = 0.001 stc.simulator_scene.clearSelection() action = next(item for item in stc.simulator_scene.items() if isinstance(item, TriggerCommandActionItem)) action.setSelected(True) self.assertEqual(stc.ui.detail_view_widget.currentIndex(), 4) fname = tempfile.mktemp() self.assertFalse(os.path.isfile(fname)) external_command = "cmd.exe /C copy NUL {}".format( fname) if os.name == "nt" else "touch {}".format(fname) stc.ui.lineEditTriggerCommand.setText(external_command) self.assertEqual(action.model_item.command, external_command) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = stc.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) QTest.qWait(10) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) QTest.qWait(10) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(1500) conn, addr = s.accept() modulator = dialog.project_manager.modulators[0] # type: Modulator self.alice.send_raw_data(modulator.modulate("100" + "10101010" * 42), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(bits[0], "101010101") QTest.qWait(500) self.assertTrue(simulator.simulation_is_finished()) conn.close() s.close() QTest.qWait(100) self.assertTrue(os.path.isfile(fname)) def __demodulate(self, connection): QTest.qWait(100) data = connection.recv(65536) while len(data) % 8 != 0: data += connection.recv(65536) arr = np.array(np.frombuffer(data, dtype=np.complex64)) signal = Signal("", "") signal._fulldata = arr pa = ProtocolAnalyzer(signal) pa.get_protocol_from_signal() return pa.plain_bits_str
def test_external_program_simulator(self): stc = self.form.simulator_tab_controller stc.ui.btnAddParticipant.click() stc.ui.btnAddParticipant.click() stc.simulator_scene.add_counter_action(None, 0) action = next(item for item in stc.simulator_scene.items() if isinstance(item, CounterActionItem)) action.model_item.start = 3 action.model_item.step = 2 counter_item_str = "item" + str( action.model_item.index()) + ".counter_value" stc.ui.gvSimulator.add_empty_message(42) stc.ui.gvSimulator.add_empty_message(42) stc.ui.cbViewType.setCurrentIndex(0) stc.create_simulator_label(0, 10, 20) stc.create_simulator_label(1, 10, 20) messages = stc.simulator_config.get_all_messages() messages[0].source = stc.project_manager.participants[0] messages[0].destination = stc.project_manager.participants[1] messages[0].destination.simulate = True messages[1].source = stc.project_manager.participants[1] messages[1].destination = stc.project_manager.participants[0] stc.simulator_scene.add_trigger_command_action(None, 200) stc.simulator_scene.add_sleep_action(None, 200) lbl1 = messages[0].message_type[0] # type: SimulatorProtocolLabel lbl2 = messages[1].message_type[0] # type: SimulatorProtocolLabel lbl1.value_type_index = 3 lbl1.external_program = get_path_for_data_file( "external_program_simulator.py") + " " + counter_item_str lbl2.value_type_index = 3 lbl2.external_program = get_path_for_data_file( "external_program_simulator.py") + " " + counter_item_str action = next(item for item in stc.simulator_scene.items() if isinstance(item, SleepActionItem)) action.model_item.sleep_time = 0.001 stc.simulator_scene.clearSelection() action = next(item for item in stc.simulator_scene.items() if isinstance(item, TriggerCommandActionItem)) action.setSelected(True) self.assertEqual(stc.ui.detail_view_widget.currentIndex(), 4) fname = tempfile.mktemp() self.assertFalse(os.path.isfile(fname)) external_command = "cmd.exe /C copy NUL {}".format( fname) if os.name == "nt" else "touch {}".format(fname) stc.ui.lineEditTriggerCommand.setText(external_command) self.assertEqual(action.model_item.command, external_command) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = stc.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) QTest.qWait(10) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) QTest.qWait(10) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(1500) conn, addr = s.accept() modulator = dialog.project_manager.modulators[0] # type: Modulator self.alice.send_raw_data(modulator.modulate("100" + "10101010" * 42), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(bits[0], "101010101") QTest.qWait(500) self.assertTrue(simulator.simulation_is_finished()) conn.close() s.close() QTest.qWait(100) self.assertTrue(os.path.isfile(fname))
def test_simulation_flow(self): """ test a simulation flow with an increasing sequence number :return: """ profile = self.get_path_for_filename("testprofile.sim.xml") self.form.add_files([profile]) self.assertEqual( len(self.form.simulator_tab_controller.simulator_scene. get_all_message_items()), 6) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = self.form.simulator_tab_controller.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) QTest.qWait(10) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) QTest.qWait(10) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(1500) conn, addr = s.accept() msg = next(msg for msg in dialog.simulator_config.get_all_messages() if msg.source.name == "Alice") checksum_label = next( lbl for lbl in msg.message_type if lbl.is_checksum_label).label # type: ChecksumLabel modulator = dialog.project_manager.modulators[0] # type: Modulator preamble_str = "10101010" sync_str = "1001" preamble = list(map(int, preamble_str)) sync = list(map(int, sync_str)) seq = list(map(int, "00000010")) data = list(map(int, "11001101")) seq_num = int("".join(map(str, seq)), 2) checksum = list(checksum_label.calculate_checksum(seq + data)) msg1 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg1), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 1) seq = list(map(int, "{0:08b}".format(seq_num + 2))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg2 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg2), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 3) seq = list(map(int, "{0:08b}".format(seq_num + 4))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg3 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg3), 1) self.alice.send_raw_data( np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 5) QTest.qWait(50) self.assertTrue(simulator.simulation_is_finished()) time.sleep(1) conn.close() s.close() QTest.qWait(100)
def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rate=None, bandwidth=None, gain=None, if_gain=None, baseband_gain=None, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, is_ringbuffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler freq = config.DEFAULT_FREQUENCY if freq is None else freq sample_rate = config.DEFAULT_SAMPLE_RATE if sample_rate is None else sample_rate bandwidth = config.DEFAULT_BANDWIDTH if bandwidth is None else bandwidth gain = config.DEFAULT_GAIN if gain is None else gain if_gain = config.DEFAULT_IF_GAIN if if_gain is None else if_gain baseband_gain = config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: from urh.dev.gr.ReceiverThread import ReceiverThread self.__dev = ReceiverThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent, is_ringbuffer=is_ringbuffer) self.__dev.index_changed.connect(self.emit_index_changed) elif mode == Mode.send: from urh.dev.gr.SenderThread import SenderThread self.__dev = SenderThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len(samples_to_send) elif mode == Mode.spectrum: from urh.dev.gr.SpectrumThread import SpectrumThread self.__dev = SpectrumThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) else: raise ValueError("Unknown mode") self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect(self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): is_ringbuffer = self.mode == Mode.spectrum or is_ringbuffer if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, is_ringbuffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, sample_rate, device_number=0, is_ringbuffer=is_ringbuffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, sample_rate, device_number=0, is_ringbuffer=is_ringbuffer) else: raise NotImplementedError("Native Backend for {0} not yet implemented".format(name)) elif name == "test": # For Unittests Only self.__dev = Device(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, is_ringbuffer) self.__dev.BYTES_PER_SAMPLE = 4 else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip self.__dev.rcv_index_changed.connect(self.emit_index_changed) if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats, skip_device_parameters=True) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin(raw_mode=raw_mode, spectrum=self.mode == Mode.spectrum) self.__dev.rcv_index_changed.connect(self.emit_index_changed) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend")
class TestProtocolSniffer(QtTestCase): def setUp(self): super().setUp() SettingsProxy.OVERWRITE_RECEIVE_BUFFER_SIZE = 100 * 10**6 def test_protocol_sniffer(self): bit_len = 100 center = 0.0942 noise = 0.1 tolerance = 2 modulation_type = 1 sample_rate = 1e6 device_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME sniffer = ProtocolSniffer(bit_len=bit_len, center=center, noise=noise, tolerance=tolerance, modulation_type=modulation_type, device=device_name, backend_handler=BackendHandler(), network_raw_mode=True) port = self.get_free_port() sniffer.rcv_device.set_server_port(port) self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin( raw_mode=True) self.network_sdr_plugin_sender.client_port = port sniffer.sniff() QTest.qWait(10) data = ["101010", "000111", "1111000"] pause = 10 * bit_len modulator = Modulator("test") modulator.samples_per_bit = bit_len modulator.sample_rate = sample_rate modulator.modulation_type = modulation_type modulator.param_for_one = 20e3 modulator.param_for_zero = 10e3 packages = [] for d in data: packages.append(modulator.modulate(list(map(int, d)), pause)) # verify modulation was correct pa = ProtocolAnalyzer(None) signal = Signal("", "", sample_rate=sample_rate) signal._fulldata = np.concatenate(packages) signal.modulation_type = modulation_type signal.bit_len = bit_len signal.tolerance = tolerance signal.noise_threshold = noise signal.qad_center = center pa.signal = signal pa.get_protocol_from_signal() self.assertEqual(pa.plain_bits_str, data) # send data send_data = np.concatenate(packages) chunk_size = 128 for i in range(0, len(send_data), chunk_size): self.network_sdr_plugin_sender.send_raw_data( send_data[i:i + chunk_size], 1) QTest.qWait(10) # Send enough pauses to end sniffing for i in range(10): self.network_sdr_plugin_sender.send_raw_data( np.zeros(bit_len, dtype=np.complex64), 1) QTest.qWait(10) sniffer.stop() self.assertEqual(sniffer.plain_bits_str, data) # needed to prevent crash on windows QTest.qWait(10)
def test_open_simulator_dialog_and_send_mismatching_message(self): def __wait_for_simulator_log_message(dialog, log_message): n = 0 while not any(log_message in msg for msg in dialog.simulator.log_messages): if n < 50: time.sleep(0.5) else: self.fail("Did not receive log message \"{}\"".format( log_message)) n += 1 stc = self.form.simulator_tab_controller assert isinstance(stc, SimulatorTabController) self.__setup_project() self.add_all_signals_to_simulator() stc.simulator_scene.select_all_items() stc.simulator_config.project_manager.simulator_timeout_ms = 999999999 for msg in stc.simulator_scene.get_selected_messages(): msg.destination = self.dennis stc.ui.gvSimulator.message_updated.emit(msg) list_model = stc.ui.listViewSimulate.model() self.assertEqual(list_model.rowCount(), 2) list_model.setData(list_model.createIndex(1, 0), Qt.Checked, role=Qt.CheckStateRole) dialog = stc.get_simulator_dialog() network_sdr_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText( network_sdr_name) rcv_port = util.get_free_port() dialog.simulator.sniffer.rcv_device.set_server_port(rcv_port) dialog.simulator.sniffer.adaptive_noise = False dialog.simulator.sniffer.automatic_center = False dialog.ui.btnStartStop.click() __wait_for_simulator_log_message(dialog, "Waiting for message 1") modulator = dialog.project_manager.modulators[0] # type: Modulator sender = NetworkSDRInterfacePlugin(raw_mode=True, sending=True) sender.client_port = rcv_port sender.send_raw_data(modulator.modulate("1" * 352), 1) time.sleep(0.5) sender.send_raw_data(IQArray(None, np.float32, 2000), 1) __wait_for_simulator_log_message(dialog, "Waiting for message 2") sender.send_raw_data(modulator.modulate("10" * 176), 1) time.sleep(0.5) sender.send_raw_data(IQArray(None, np.float32, 2000), 1) __wait_for_simulator_log_message(dialog, "Mismatch for label:") dialog.on_timer_timeout() # enforce writing to text view simulator_log = dialog.ui.textEditSimulation.toPlainText() self.assertIn("Received message 1", simulator_log) self.assertIn("preamble: 11111111", simulator_log) self.assertIn("Mismatch for label: preamble", simulator_log) dialog.close()
class GeneratorTabController(QWidget): def __init__(self, compare_frame_controller: CompareFrameController, project_manager: ProjectManager, parent=None): super().__init__(parent) self.ui = Ui_GeneratorTab() self.ui.setupUi(self) util.set_splitter_stylesheet(self.ui.splitter) self.project_manager = project_manager self.ui.treeProtocols.setHeaderHidden(True) self.tree_model = GeneratorTreeModel(compare_frame_controller) self.tree_model.set_root_item(compare_frame_controller.proto_tree_model.rootItem) self.tree_model.controller = self self.ui.treeProtocols.setModel(self.tree_model) self.table_model = GeneratorTableModel(compare_frame_controller.proto_tree_model.rootItem, compare_frame_controller.decodings) self.table_model.controller = self self.ui.tableMessages.setModel(self.table_model) self.label_list_model = GeneratorListModel(None) self.ui.listViewProtoLabels.setModel(self.label_list_model) self.network_sdr_button_orig_tooltip = self.ui.btnNetworkSDRSend.toolTip() self.set_network_sdr_send_button_visibility() self.set_rfcat_button_visibility() self.network_sdr_plugin = NetworkSDRInterfacePlugin() self.rfcat_plugin = RfCatPlugin() self.init_rfcat_plugin() self.modulation_msg_indices = [] self.refresh_modulators() self.on_selected_modulation_changed() self.set_fuzzing_ui_status() self.ui.prBarGeneration.hide() self.create_connects(compare_frame_controller) self.set_modulation_profile_status() def __get_modulator_of_message(self, message: Message) -> Modulator: if message.modulator_index > len(self.modulators) - 1: message.modulator_index = 0 return self.modulators[message.modulator_index] @property def selected_message_index(self) -> int: min_row, _, _, _ = self.ui.tableMessages.selection_range() return min_row # @property def selected_message(self) -> Message: selected_msg_index = self.selected_message_index if selected_msg_index == -1 or selected_msg_index >= len(self.table_model.protocol.messages): return None return self.table_model.protocol.messages[selected_msg_index] @property def active_groups(self): return self.tree_model.groups @property def modulators(self): return self.project_manager.modulators @property def total_modulated_samples(self) -> int: return sum(int(len(msg.encoded_bits) * self.__get_modulator_of_message(msg).samples_per_bit + msg.pause) for msg in self.table_model.protocol.messages) @modulators.setter def modulators(self, value): assert type(value) == list self.project_manager.modulators = value def create_connects(self, compare_frame_controller): compare_frame_controller.proto_tree_model.modelReset.connect(self.refresh_tree) compare_frame_controller.participant_changed.connect(self.table_model.refresh_vertical_header) self.ui.btnEditModulation.clicked.connect(self.show_modulation_dialog) self.ui.cBoxModulations.currentIndexChanged.connect(self.on_selected_modulation_changed) self.ui.tableMessages.selectionModel().selectionChanged.connect(self.on_table_selection_changed) self.ui.tableMessages.encodings_updated.connect(self.on_table_selection_changed) self.table_model.undo_stack.indexChanged.connect(self.on_undo_stack_index_changed) self.table_model.protocol.qt_signals.line_duplicated.connect(self.refresh_pause_list) self.table_model.protocol.qt_signals.fuzzing_started.connect(self.on_fuzzing_started) self.table_model.protocol.qt_signals.current_fuzzing_message_changed.connect( self.on_current_fuzzing_message_changed) self.table_model.protocol.qt_signals.fuzzing_finished.connect(self.on_fuzzing_finished) self.table_model.first_protocol_added.connect(self.on_first_protocol_added) self.label_list_model.protolabel_fuzzing_status_changed.connect(self.set_fuzzing_ui_status) self.ui.cbViewType.currentIndexChanged.connect(self.on_view_type_changed) self.ui.btnSend.clicked.connect(self.on_btn_send_clicked) self.ui.btnSave.clicked.connect(self.on_btn_save_clicked) self.ui.btnOpen.clicked.connect(self.on_btn_open_clicked) self.project_manager.project_updated.connect(self.on_project_updated) self.table_model.vertical_header_color_status_changed.connect( self.ui.tableMessages.on_vertical_header_color_status_changed) self.label_list_model.protolabel_removed.connect(self.handle_proto_label_removed) self.ui.lWPauses.item_edit_clicked.connect(self.edit_pause_item) self.ui.lWPauses.edit_all_items_clicked.connect(self.edit_all_pause_items) self.ui.lWPauses.itemSelectionChanged.connect(self.on_lWpauses_selection_changed) self.ui.lWPauses.lost_focus.connect(self.on_lWPauses_lost_focus) self.ui.lWPauses.doubleClicked.connect(self.on_lWPauses_double_clicked) self.ui.btnGenerate.clicked.connect(self.generate_file) self.label_list_model.protolabel_fuzzing_status_changed.connect(self.handle_plabel_fuzzing_state_changed) self.ui.btnFuzz.clicked.connect(self.on_btn_fuzzing_clicked) self.ui.tableMessages.create_label_triggered.connect(self.create_fuzzing_label) self.ui.tableMessages.edit_label_triggered.connect(self.show_fuzzing_dialog) self.ui.listViewProtoLabels.selection_changed.connect(self.handle_label_selection_changed) self.ui.listViewProtoLabels.edit_on_item_triggered.connect(self.show_fuzzing_dialog) self.ui.btnNetworkSDRSend.clicked.connect(self.on_btn_network_sdr_clicked) self.ui.btnRfCatSend.clicked.connect(self.on_btn_rfcat_clicked) self.network_sdr_plugin.sending_status_changed.connect(self.on_network_sdr_sending_status_changed) self.network_sdr_plugin.sending_stop_requested.connect(self.on_network_sdr_sending_stop_requested) self.network_sdr_plugin.current_send_message_changed.connect(self.on_send_message_changed) @pyqtSlot() def refresh_tree(self): self.tree_model.beginResetModel() self.tree_model.endResetModel() self.ui.treeProtocols.expandAll() @pyqtSlot() def refresh_table(self): self.table_model.update() self.ui.tableMessages.resize_columns() is_data_there = self.table_model.display_data is not None and len(self.table_model.display_data) > 0 self.ui.btnSend.setEnabled(is_data_there) self.ui.btnGenerate.setEnabled(is_data_there) @pyqtSlot() def refresh_label_list(self): self.label_list_model.message = self.selected_message self.label_list_model.update() @property def generator_undo_stack(self) -> QUndoStack: return self.table_model.undo_stack @pyqtSlot() def on_selected_modulation_changed(self): cur_ind = self.ui.cBoxModulations.currentIndex() min_row, max_row, _, _ = self.ui.tableMessages.selection_range() if min_row > -1: # set modulation for selected messages for row in range(min_row, max_row + 1): try: self.table_model.protocol.messages[row].modulator_index = cur_ind except IndexError: continue self.show_modulation_info() def refresh_modulators(self): current_index = 0 if type(self.sender()) == ModulatorDialog: current_index = self.sender().ui.comboBoxCustomModulations.currentIndex() self.ui.cBoxModulations.clear() for modulator in self.modulators: self.ui.cBoxModulations.addItem(modulator.name) self.ui.cBoxModulations.setCurrentIndex(current_index) def bootstrap_modulator(self, protocol: ProtocolAnalyzer): """ Set initial parameters for default modulator if it was not edited by user previously :return: """ if len(self.modulators) != 1 or len(self.table_model.protocol.messages) == 0: return modulator = self.modulators[0] modulator.samples_per_bit = protocol.messages[0].bit_len if protocol.signal: modulator.sample_rate = protocol.signal.sample_rate modulator.modulation_type = protocol.signal.modulation_type auto_freq = modulator.estimate_carrier_frequency(protocol.signal, protocol) if auto_freq is not None and auto_freq != 0: modulator.carrier_freq_hz = auto_freq self.show_modulation_info() def show_modulation_info(self): cur_ind = self.ui.cBoxModulations.currentIndex() cur_mod = self.modulators[cur_ind] self.ui.lCarrierFreqValue.setText(cur_mod.carrier_frequency_str) self.ui.lCarrierPhaseValue.setText(cur_mod.carrier_phase_str) self.ui.lBitLenValue.setText(cur_mod.bit_len_str) self.ui.lSampleRateValue.setText(cur_mod.sample_rate_str) mod_type = cur_mod.modulation_type_str self.ui.lModTypeValue.setText(mod_type) if mod_type == "ASK": prefix = "Amplitude" elif mod_type == "PSK": prefix = "Phase" elif mod_type in ("FSK", "GFSK"): prefix = "Frequency" else: prefix = "Unknown Modulation Type (This should not happen...)" self.ui.lParamForZero.setText(prefix + " for 0:") self.ui.lParamForZeroValue.setText(cur_mod.param_for_zero_str) self.ui.lParamForOne.setText(prefix + " for 1:") self.ui.lParamForOneValue.setText(cur_mod.param_for_one_str) def prepare_modulation_dialog(self) -> (ModulatorDialog, Message): preselected_index = self.ui.cBoxModulations.currentIndex() min_row, max_row, start, end = self.ui.tableMessages.selection_range() if min_row > -1: try: selected_message = self.table_model.protocol.messages[min_row] preselected_index = selected_message.modulator_index except IndexError: selected_message = Message([1, 0, 1, 0, 1, 0, 1, 0], 0, [], MessageType("empty")) else: selected_message = Message([1, 0, 1, 0, 1, 0, 1, 0], 0, [], MessageType("empty")) if len(self.table_model.protocol.messages) > 0: selected_message.bit_len = self.table_model.protocol.messages[0].bit_len for m in self.modulators: m.default_sample_rate = self.project_manager.device_conf["sample_rate"] modulator_dialog = ModulatorDialog(self.modulators, tree_model=self.tree_model, parent=self.parent()) modulator_dialog.ui.comboBoxCustomModulations.setCurrentIndex(preselected_index) modulator_dialog.finished.connect(self.refresh_modulators) modulator_dialog.finished.connect(self.refresh_pause_list) return modulator_dialog, selected_message def set_modulation_profile_status(self): visible = constants.SETTINGS.value("multiple_modulations", False, bool) self.ui.cBoxModulations.setVisible(visible) def init_rfcat_plugin(self): self.set_rfcat_button_visibility() self.rfcat_plugin = RfCatPlugin() self.rfcat_plugin.current_send_message_changed.connect(self.on_send_message_changed) self.ui.btnRfCatSend.setEnabled(self.rfcat_plugin.rfcat_is_found) @pyqtSlot() def on_undo_stack_index_changed(self): self.refresh_table() self.refresh_pause_list() self.refresh_label_list() self.refresh_estimated_time() self.set_fuzzing_ui_status() @pyqtSlot() def show_modulation_dialog(self): modulator_dialog, message = self.prepare_modulation_dialog() modulator_dialog.showMaximized() modulator_dialog.initialize(message.encoded_bits_str[0:10]) self.project_manager.modulation_was_edited = True @pyqtSlot() def on_table_selection_changed(self): min_row, max_row, start, end = self.ui.tableMessages.selection_range() if min_row == -1: self.ui.lEncodingValue.setText("-") # self.ui.lEncodingValue.setToolTip("") self.label_list_model.message = None return container = self.table_model.protocol message = container.messages[min_row] self.label_list_model.message = message decoder_name = message.decoder.name metrics = QFontMetrics(self.ui.lEncodingValue.font()) elidedName = metrics.elidedText(decoder_name, Qt.ElideRight, self.ui.lEncodingValue.width()) self.ui.lEncodingValue.setText(elidedName) self.ui.lEncodingValue.setToolTip(decoder_name) self.ui.cBoxModulations.blockSignals(True) self.ui.cBoxModulations.setCurrentIndex(message.modulator_index) self.show_modulation_info() self.ui.cBoxModulations.blockSignals(False) @pyqtSlot(int) def edit_pause_item(self, index: int): message = self.table_model.protocol.messages[index] cur_len = message.pause new_len, ok = QInputDialog.getInt(self, self.tr("Enter new Pause Length"), self.tr("Pause Length:"), cur_len, 0) if ok: message.pause = new_len self.refresh_pause_list() @pyqtSlot() def edit_all_pause_items(self): message = self.table_model.protocol.messages[0] cur_len = message.pause new_len, ok = QInputDialog.getInt(self, self.tr("Enter new Pause Length"), self.tr("Pause Length:"), cur_len, 0) if ok: for message in self.table_model.protocol.messages: message.pause = new_len self.refresh_pause_list() @pyqtSlot() def on_lWPauses_double_clicked(self): sel_indexes = [index.row() for index in self.ui.lWPauses.selectedIndexes()] if len(sel_indexes) > 0: self.edit_pause_item(sel_indexes[0]) @pyqtSlot() def refresh_pause_list(self): self.ui.lWPauses.clear() fmt_str = "Pause ({1:d}-{2:d}) <{0:d} samples ({3})>" for i, pause in enumerate(self.table_model.protocol.pauses): sr = self.__get_modulator_of_message(self.table_model.protocol.messages[i]).sample_rate item = fmt_str.format(pause, i + 1, i + 2, Formatter.science_time(pause / sr)) self.ui.lWPauses.addItem(item) self.refresh_estimated_time() @pyqtSlot() def on_lWpauses_selection_changed(self): rows = [index.row() for index in self.ui.lWPauses.selectedIndexes()] if len(rows) == 0: return self.ui.tableMessages.show_pause_active = True self.ui.tableMessages.pause_row = rows[0] self.ui.tableMessages.viewport().update() self.ui.tableMessages.scrollTo(self.table_model.index(rows[0], 0)) @pyqtSlot() def on_lWPauses_lost_focus(self): self.ui.tableMessages.show_pause_active = False self.ui.tableMessages.viewport().update() @pyqtSlot() def generate_file(self): try: total_samples = self.total_modulated_samples buffer = self.prepare_modulation_buffer(total_samples, show_error=False) if buffer is None: Errors.generic_error(self.tr("File too big"), self.tr("This file would get too big to save.")) self.unsetCursor() return modulated_samples = self.modulate_data(buffer) try: sample_rate = self.modulators[0].sample_rate except Exception as e: logger.exception(e) sample_rate = 1e6 FileOperator.save_data_dialog("generated.complex", modulated_samples, sample_rate=sample_rate, parent=self) except Exception as e: Errors.generic_error(self.tr("Failed to generate data"), str(e), traceback.format_exc()) self.unsetCursor() def prepare_modulation_buffer(self, total_samples: int, show_error=True) -> np.ndarray: memory_size_for_buffer = total_samples * 8 logger.debug("Allocating {0:.2f}MB for modulated samples".format(memory_size_for_buffer / (1024 ** 2))) try: # allocate it three times as we need the same amount for the sending process np.zeros(3*total_samples, dtype=np.complex64) except MemoryError: # will go into continuous mode in this case if show_error: Errors.not_enough_ram_for_sending_precache(3*memory_size_for_buffer) return None return np.zeros(total_samples, dtype=np.complex64) def modulate_data(self, buffer: np.ndarray) -> np.ndarray: """ :param buffer: Buffer in which the modulated data shall be written, initialized with zeros :return: """ self.ui.prBarGeneration.show() self.ui.prBarGeneration.setValue(0) self.ui.prBarGeneration.setMaximum(self.table_model.row_count) self.modulation_msg_indices.clear() pos = 0 for i in range(0, self.table_model.row_count): message = self.table_model.protocol.messages[i] modulator = self.__get_modulator_of_message(message) # We do not need to modulate the pause extra, as result is already initialized with zeros modulated = modulator.modulate(start=0, data=message.encoded_bits, pause=0) buffer[pos:pos + len(modulated)] = modulated pos += len(modulated) + message.pause self.modulation_msg_indices.append(pos) self.ui.prBarGeneration.setValue(i + 1) QApplication.instance().processEvents() self.ui.prBarGeneration.hide() return buffer @pyqtSlot(int) def show_fuzzing_dialog(self, label_index: int): view = self.ui.cbViewType.currentIndex() if self.label_list_model.message is not None: msg_index = self.table_model.protocol.messages.index(self.label_list_model.message) fdc = FuzzingDialog(protocol=self.table_model.protocol, label_index=label_index, msg_index=msg_index, proto_view=view, parent=self) fdc.show() fdc.finished.connect(self.refresh_label_list) fdc.finished.connect(self.refresh_table) fdc.finished.connect(self.set_fuzzing_ui_status) @pyqtSlot() def handle_plabel_fuzzing_state_changed(self): self.refresh_table() self.label_list_model.update() @pyqtSlot(ProtocolLabel) def handle_proto_label_removed(self, plabel: ProtocolLabel): self.refresh_label_list() self.refresh_table() self.set_fuzzing_ui_status() @pyqtSlot() def on_btn_fuzzing_clicked(self): fuz_mode = "Successive" if self.ui.rbConcurrent.isChecked(): fuz_mode = "Concurrent" elif self.ui.rBExhaustive.isChecked(): fuz_mode = "Exhaustive" self.setCursor(Qt.WaitCursor) fuzz_action = Fuzz(self.table_model.protocol, fuz_mode) self.table_model.undo_stack.push(fuzz_action) for row in fuzz_action.added_message_indices: self.table_model.update_checksums_for_row(row) self.unsetCursor() self.ui.tableMessages.setFocus() @pyqtSlot() def set_fuzzing_ui_status(self): btn_was_enabled = self.ui.btnFuzz.isEnabled() fuzz_active = any(lbl.active_fuzzing for msg in self.table_model.protocol.messages for lbl in msg.message_type) self.ui.btnFuzz.setEnabled(fuzz_active) if self.ui.btnFuzz.isEnabled() and not btn_was_enabled: font = self.ui.btnFuzz.font() font.setBold(True) self.ui.btnFuzz.setFont(font) else: font = self.ui.btnFuzz.font() font.setBold(False) self.ui.btnFuzz.setFont(font) self.ui.btnFuzz.setStyleSheet("") has_same_message = self.table_model.protocol.multiple_fuzz_labels_per_message self.ui.rBSuccessive.setEnabled(has_same_message) self.ui.rBExhaustive.setEnabled(has_same_message) self.ui.rbConcurrent.setEnabled(has_same_message) def refresh_existing_encodings(self, encodings_from_file): """ Refresh existing encodings for messages, when encoding was changed by user in dialog :return: """ update = False for msg in self.table_model.protocol.messages: i = next((i for i, d in enumerate(encodings_from_file) if d.name == msg.decoder.name), 0) if msg.decoder != encodings_from_file[i]: update = True msg.decoder = encodings_from_file[i] msg.clear_decoded_bits() msg.clear_encoded_bits() if update: self.refresh_table() self.refresh_estimated_time() @pyqtSlot() def refresh_estimated_time(self): c = self.table_model.protocol if c.num_messages == 0: self.ui.lEstimatedTime.setText("Estimated Time: ") return avg_msg_len = numpy.mean([len(msg.encoded_bits) for msg in c.messages]) avg_bit_len = numpy.mean([m.samples_per_bit for m in self.modulators]) avg_sample_rate = numpy.mean([m.sample_rate for m in self.modulators]) pause_samples = sum(c.pauses) nsamples = c.num_messages * avg_msg_len * avg_bit_len + pause_samples self.ui.lEstimatedTime.setText( locale.format_string("Estimated Time: %.04f seconds", nsamples / avg_sample_rate)) @pyqtSlot(int, int, int) def create_fuzzing_label(self, msg_index: int, start: int, end: int): con = self.table_model.protocol start, end = con.convert_range(start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index) lbl = con.create_fuzzing_label(start, end, msg_index) self.show_fuzzing_dialog(con.protocol_labels.index(lbl)) @pyqtSlot() def handle_label_selection_changed(self): rows = [index.row() for index in self.ui.listViewProtoLabels.selectedIndexes()] if len(rows) == 0: return maxrow = numpy.max(rows) try: label = self.table_model.protocol.protocol_labels[maxrow] except IndexError: return if label.show and self.selected_message: start, end = self.selected_message.get_label_range(lbl=label, view=self.table_model.proto_view, decode=False) indx = self.table_model.index(0, int((start + end) / 2)) self.ui.tableMessages.scrollTo(indx) @pyqtSlot() def on_view_type_changed(self): self.setCursor(Qt.WaitCursor) self.table_model.proto_view = self.ui.cbViewType.currentIndex() self.ui.tableMessages.resize_columns() self.unsetCursor() @pyqtSlot() def on_btn_send_clicked(self): try: total_samples = self.total_modulated_samples buffer = self.prepare_modulation_buffer(total_samples) if buffer is not None: modulated_data = self.modulate_data(buffer) else: # Enter continuous mode modulated_data = None try: if modulated_data is not None: try: dialog = SendDialog(self.project_manager, modulated_data=modulated_data, modulation_msg_indices=self.modulation_msg_indices, parent=self) except MemoryError: # Not enough memory for device buffer so we need to create a continuous send dialog del modulated_data Errors.not_enough_ram_for_sending_precache(None) dialog = ContinuousSendDialog(self.project_manager, self.table_model.protocol.messages, self.modulators, total_samples, parent=self) else: dialog = ContinuousSendDialog(self.project_manager, self.table_model.protocol.messages, self.modulators, total_samples, parent=self) except OSError as e: logger.exception(e) return if dialog.has_empty_device_list: Errors.no_device() dialog.close() return dialog.device_parameters_changed.connect(self.project_manager.set_device_parameters) dialog.show() dialog.graphics_view.show_full_scene(reinitialize=True) except Exception as e: Errors.generic_error(self.tr("Failed to generate data"), str(e), traceback.format_exc()) self.unsetCursor() @pyqtSlot() def on_btn_save_clicked(self): filename = FileOperator.get_save_file_name("profile.fuzz.xml", caption="Save fuzz profile") if filename: self.table_model.protocol.to_xml_file(filename, decoders=self.project_manager.decodings, participants=self.project_manager.participants, modulators=self.modulators) @pyqtSlot() def on_btn_open_clicked(self): dialog = FileOperator.get_open_dialog(directory_mode=False, parent=self, name_filter="fuzz") if dialog.exec_(): for filename in dialog.selectedFiles(): self.load_from_file(filename) def load_from_file(self, filename: str): try: self.modulators = ProjectManager.read_modulators_from_file(filename) self.table_model.protocol.from_xml_file(filename) self.refresh_pause_list() self.refresh_estimated_time() self.refresh_modulators() self.show_modulation_info() self.refresh_table() self.set_fuzzing_ui_status() except: logger.error("You done something wrong to the xml fuzzing profile.") @pyqtSlot() def on_project_updated(self): self.table_model.refresh_vertical_header() def set_network_sdr_send_button_visibility(self): is_plugin_enabled = PluginManager().is_plugin_enabled("NetworkSDRInterface") self.ui.btnNetworkSDRSend.setVisible(is_plugin_enabled) def set_rfcat_button_visibility(self): is_plugin_enabled = PluginManager().is_plugin_enabled("RfCat") self.ui.btnRfCatSend.setVisible(is_plugin_enabled) @pyqtSlot() def on_btn_network_sdr_clicked(self): if not self.network_sdr_plugin.is_sending: messages = self.table_model.protocol.messages sample_rates = [self.__get_modulator_of_message(msg).sample_rate for msg in messages] self.network_sdr_plugin.start_message_sending_thread(messages, sample_rates) else: self.network_sdr_plugin.stop_sending_thread() @pyqtSlot(bool) def on_network_sdr_sending_status_changed(self, is_sending: bool): self.ui.btnNetworkSDRSend.setChecked(is_sending) self.ui.btnNetworkSDRSend.setEnabled(True) self.ui.btnNetworkSDRSend.setToolTip( "Sending in progress" if is_sending else self.network_sdr_button_orig_tooltip) if not is_sending: self.ui.tableMessages.clearSelection() @pyqtSlot() def on_network_sdr_sending_stop_requested(self): self.ui.btnNetworkSDRSend.setToolTip("Stopping sending") self.ui.btnNetworkSDRSend.setEnabled(False) @pyqtSlot(int) def on_send_message_changed(self, message_index: int): self.ui.tableMessages.selectRow(message_index) @pyqtSlot() def on_btn_rfcat_clicked(self): if not self.rfcat_plugin.is_sending: messages = self.table_model.protocol.messages sample_rates = [self.__get_modulator_of_message(msg).sample_rate for msg in messages] self.rfcat_plugin.start_message_sending_thread(messages, sample_rates, self.modulators, self.project_manager) else: self.rfcat_plugin.stop_sending_thread() @pyqtSlot(int) def on_fuzzing_started(self, num_values: int): self.ui.stackedWidgetFuzzing.setCurrentWidget(self.ui.pageFuzzingProgressBar) self.ui.progressBarFuzzing.setMaximum(num_values) self.ui.progressBarFuzzing.setValue(0) QApplication.instance().processEvents() @pyqtSlot() def on_fuzzing_finished(self): self.ui.stackedWidgetFuzzing.setCurrentWidget(self.ui.pageFuzzingUI) # Calculate Checksums for Fuzzed Messages self.setCursor(Qt.WaitCursor) self.unsetCursor() @pyqtSlot(int) def on_current_fuzzing_message_changed(self, current_message: int): self.ui.progressBarFuzzing.setValue(current_message) QApplication.instance().processEvents() @pyqtSlot(ProtocolAnalyzer) def on_first_protocol_added(self, protocol: ProtocolAnalyzer): if not self.project_manager.modulation_was_edited: self.bootstrap_modulator(protocol)
class TestSimulator(QtTestCase): TIMEOUT = 0.5 def setUp(self): super().setUp() SettingsProxy.OVERWRITE_RECEIVE_BUFFER_SIZE = 50000 self.num_zeros_for_pause = 1000 def test_simulation_flow(self): """ test a simulation flow with an increasing sequence number :return: """ profile = self.get_path_for_filename("testprofile.sim.xml") self.form.add_files([profile]) self.assertEqual(len(self.form.simulator_tab_controller.simulator_scene.get_all_message_items()), 6) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = self.form.simulator_tab_controller.get_simulator_dialog() # type: SimulatorDialog dialog.project_manager.simulator_timeout_ms = 999999999 name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(250) while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(1) conn, addr = s.accept() msg = next(msg for msg in dialog.simulator_config.get_all_messages() if msg.source.name == "Alice") checksum_label = next(lbl for lbl in msg.message_type if lbl.is_checksum_label).label # type: ChecksumLabel modulator = dialog.project_manager.modulators[0] # type: Modulator preamble_str = "10101010" sync_str = "1001" preamble = list(map(int, preamble_str)) sync = list(map(int, sync_str)) seq = list(map(int, "00000010")) data = list(map(int, "11001101")) seq_num = int("".join(map(str, seq)), 2) checksum = list(checksum_label.calculate_checksum(seq + data)) msg1 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg1), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message 2" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 2") time.sleep(1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str), msg=bits) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 1) seq = list(map(int, "{0:08b}".format(seq_num + 2))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg2 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg2), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message 4" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 4") time.sleep(1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 3) seq = list(map(int, "{0:08b}".format(seq_num + 4))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg3 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg3), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message 6" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 6") time.sleep(1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 5) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s) def test_external_program_simulator(self): stc = self.form.simulator_tab_controller # type: SimulatorTabController stc.ui.btnAddParticipant.click() stc.ui.btnAddParticipant.click() stc.project_manager.simulator_timeout_ms = 999999999 stc.simulator_scene.add_counter_action(None, 0) action = next(item for item in stc.simulator_scene.items() if isinstance(item, CounterActionItem)) action.model_item.start = 3 action.model_item.step = 2 counter_item_str = "item" + str(action.model_item.index()) + ".counter_value" stc.ui.gvSimulator.add_empty_message(42) stc.ui.gvSimulator.add_empty_message(42) stc.ui.cbViewType.setCurrentIndex(0) stc.create_simulator_label(0, 10, 20) stc.create_simulator_label(1, 10, 20) messages = stc.simulator_config.get_all_messages() messages[0].source = stc.project_manager.participants[0] messages[0].destination = stc.project_manager.participants[1] messages[0].destination.simulate = True messages[1].source = stc.project_manager.participants[1] messages[1].destination = stc.project_manager.participants[0] stc.simulator_scene.add_trigger_command_action(None, 200) stc.simulator_scene.add_sleep_action(None, 200) lbl1 = messages[0].message_type[0] # type: SimulatorProtocolLabel lbl2 = messages[1].message_type[0] # type: SimulatorProtocolLabel ext_program = get_path_for_data_file("external_program_simulator.py") + " " + counter_item_str if sys.platform == "win32": ext_program = sys.executable + " " + ext_program lbl1.value_type_index = 3 lbl1.external_program = ext_program lbl2.value_type_index = 3 lbl2.external_program = ext_program action = next(item for item in stc.simulator_scene.items() if isinstance(item, SleepActionItem)) action.model_item.sleep_time = 0.000000001 stc.simulator_scene.clearSelection() action = next(item for item in stc.simulator_scene.items() if isinstance(item, TriggerCommandActionItem)) action.setSelected(True) self.assertEqual(stc.ui.detail_view_widget.currentIndex(), 4) file_name = os.path.join(tempfile.gettempdir(), "external_test") if os.path.isfile(file_name): os.remove(file_name) self.assertFalse(os.path.isfile(file_name)) external_command = "cmd.exe /C copy NUL {}".format(file_name) if os.name == "nt" else "touch {}".format(file_name) stc.ui.lineEditTriggerCommand.setText(external_command) self.assertEqual(action.model_item.command, external_command) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = stc.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) QTest.qWait(100) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(250) while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(1) conn, addr = s.accept() modulator = dialog.project_manager.modulators[0] # type: Modulator self.alice.send_raw_data(modulator.modulate("100" + "10101010" * 42), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message") time.sleep(1) time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(bits[0].rstrip("0"), "101010101") while simulator.is_simulating: logger.debug("Wait for simulator to finish") time.sleep(1) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s) self.assertTrue(os.path.isfile(file_name)) def __demodulate(self, connection: socket.socket): connection.settimeout(0.1) time.sleep(self.TIMEOUT) total_data = [] while True: try: data = connection.recv(65536) if data: total_data.append(data) else: break except socket.timeout: break if len(total_data) == 0: logger.error("Did not receive any data from socket.") arr = np.array(np.frombuffer(b"".join(total_data), dtype=np.complex64)) signal = Signal("", "") signal._fulldata = arr pa = ProtocolAnalyzer(signal) pa.get_protocol_from_signal() return pa.plain_bits_str
def test_simulation_flow(self): """ test a simulation flow with an increasing sequence number :return: """ profile = self.get_path_for_filename("testprofile.sim.xml") self.form.add_files([profile]) self.assertEqual(len(self.form.simulator_tab_controller.simulator_scene.get_all_message_items()), 6) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = self.form.simulator_tab_controller.get_simulator_dialog() # type: SimulatorDialog dialog.project_manager.simulator_timeout_ms = 999999999 name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(250) while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(1) conn, addr = s.accept() msg = next(msg for msg in dialog.simulator_config.get_all_messages() if msg.source.name == "Alice") checksum_label = next(lbl for lbl in msg.message_type if lbl.is_checksum_label).label # type: ChecksumLabel modulator = dialog.project_manager.modulators[0] # type: Modulator preamble_str = "10101010" sync_str = "1001" preamble = list(map(int, preamble_str)) sync = list(map(int, sync_str)) seq = list(map(int, "00000010")) data = list(map(int, "11001101")) seq_num = int("".join(map(str, seq)), 2) checksum = list(checksum_label.calculate_checksum(seq + data)) msg1 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg1), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message 2" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 2") time.sleep(1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str), msg=bits) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 1) seq = list(map(int, "{0:08b}".format(seq_num + 2))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg2 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg2), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message 4" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 4") time.sleep(1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 3) seq = list(map(int, "{0:08b}".format(seq_num + 4))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg3 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg3), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message 6" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 6") time.sleep(1) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 5) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s)
def test_external_program_simulator(self): stc = self.form.simulator_tab_controller # type: SimulatorTabController stc.ui.btnAddParticipant.click() stc.ui.btnAddParticipant.click() stc.project_manager.simulator_timeout_ms = 999999999 stc.simulator_scene.add_counter_action(None, 0) action = next(item for item in stc.simulator_scene.items() if isinstance(item, CounterActionItem)) action.model_item.start = 3 action.model_item.step = 2 counter_item_str = "item" + str(action.model_item.index()) + ".counter_value" stc.ui.gvSimulator.add_empty_message(42) stc.ui.gvSimulator.add_empty_message(42) stc.ui.cbViewType.setCurrentIndex(0) stc.create_simulator_label(0, 10, 20) stc.create_simulator_label(1, 10, 20) messages = stc.simulator_config.get_all_messages() messages[0].source = stc.project_manager.participants[0] messages[0].destination = stc.project_manager.participants[1] messages[0].destination.simulate = True messages[1].source = stc.project_manager.participants[1] messages[1].destination = stc.project_manager.participants[0] stc.simulator_scene.add_trigger_command_action(None, 200) stc.simulator_scene.add_sleep_action(None, 200) lbl1 = messages[0].message_type[0] # type: SimulatorProtocolLabel lbl2 = messages[1].message_type[0] # type: SimulatorProtocolLabel ext_program = get_path_for_data_file("external_program_simulator.py") + " " + counter_item_str if sys.platform == "win32": ext_program = sys.executable + " " + ext_program lbl1.value_type_index = 3 lbl1.external_program = ext_program lbl2.value_type_index = 3 lbl2.external_program = ext_program action = next(item for item in stc.simulator_scene.items() if isinstance(item, SleepActionItem)) action.model_item.sleep_time = 0.000000001 stc.simulator_scene.clearSelection() action = next(item for item in stc.simulator_scene.items() if isinstance(item, TriggerCommandActionItem)) action.setSelected(True) self.assertEqual(stc.ui.detail_view_widget.currentIndex(), 4) file_name = os.path.join(tempfile.gettempdir(), "external_test") if os.path.isfile(file_name): os.remove(file_name) self.assertFalse(os.path.isfile(file_name)) external_command = "cmd.exe /C copy NUL {}".format(file_name) if os.name == "nt" else "touch {}".format(file_name) stc.ui.lineEditTriggerCommand.setText(external_command) self.assertEqual(action.model_item.command, external_command) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = stc.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) QTest.qWait(100) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() QTest.qWait(250) while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(1) conn, addr = s.accept() modulator = dialog.project_manager.modulators[0] # type: Modulator self.alice.send_raw_data(modulator.modulate("100" + "10101010" * 42), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) while not any("Sending message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message") time.sleep(1) time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(bits[0].rstrip("0"), "101010101") while simulator.is_simulating: logger.debug("Wait for simulator to finish") time.sleep(1) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s) self.assertTrue(os.path.isfile(file_name))
def test_performance(self): self.form = MainController() self.cfc = self.form.compare_frame_controller self.stc = self.form.simulator_tab_controller self.gtc = self.form.generator_tab_controller self.form.add_signalfile(get_path_for_data_file("esaver.coco")) self.sframe = self.form.signal_tab_controller.signal_frames[0] self.sim_frame = self.form.simulator_tab_controller self.form.ui.tabWidget.setCurrentIndex(3) self.cfc.proto_analyzer.auto_assign_labels() self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin(raw_mode=True) part_a = Participant("Device A", shortname="A", color_index=0) part_b = Participant("Device B", shortname="B", color_index=1) part_b.simulate = True self.form.project_manager.participants.append(part_a) self.form.project_manager.participants.append(part_b) self.form.project_manager.project_updated.emit() sniffer = ProtocolSniffer(100, 0.01, 0.1, 5, 1, NetworkSDRInterfacePlugin.NETWORK_SDR_NAME, BackendHandler(), network_raw_mode=True) sender = EndlessSender(BackendHandler(), NetworkSDRInterfacePlugin.NETWORK_SDR_NAME) simulator = Simulator(self.stc.simulator_config, self.gtc.modulators, self.stc.sim_expression_parser, self.form.project_manager, sniffer=sniffer, sender=sender) pause = 100 msg_a = SimulatorMessage(part_b, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [0, 0, 1, 1] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, pause=pause, message_type=MessageType("empty_message_type"), source=part_a) msg_b = SimulatorMessage(part_a, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [1, 1, 0, 0] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, pause=pause, message_type=MessageType("empty_message_type"), source=part_b) self.stc.simulator_config.add_items([msg_a, msg_b], 0, None) self.stc.simulator_config.update_active_participants() port = self.get_free_port() sniffer = simulator.sniffer sniffer.rcv_device.set_server_port(port) self.network_sdr_plugin_sender.client_port = port sender = simulator.sender port = self.get_free_port() sender.device.set_client_port(port) sender.device._VirtualDevice__dev.name = "simulator_sender" current_index = Value("L") elapsed = Value("f") target_num_samples = 13600 + pause receive_process = Process(target=receive, args=(port, current_index, target_num_samples, elapsed)) receive_process.daemon = True receive_process.start() # Ensure receiver is running time.sleep(2) # spy = QSignalSpy(self.network_sdr_plugin_receiver.rcv_index_changed) simulator.start() modulator = Modulator("test_modulator") modulator.samples_per_bit = 100 modulator.carrier_freq_hz = 55e3 # yappi.start() self.network_sdr_plugin_sender.send_raw_data(modulator.modulate(msg_a.encoded_bits), 1) time.sleep(0.5) # send some zeros to simulate the end of a message self.network_sdr_plugin_sender.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) time.sleep(0.5) receive_process.join(15) logger.info("PROCESS TIME: {0:.2f}ms".format(elapsed.value)) # self.assertEqual(current_index.value, target_num_samples) self.assertLess(elapsed.value, 200) # timeout = spy.wait(2000) # yappi.get_func_stats().print_all() # yappi.get_thread_stats().print_all()
def test_open_simulator_dialog_and_send_mismatching_message(self): stc = self.form.simulator_tab_controller assert isinstance(stc, SimulatorTabController) self.__setup_project() self.add_all_signals_to_simulator() stc.simulator_scene.select_all_items() stc.simulator_config.project_manager.simulator_timeout_ms = 999999999 for msg in stc.simulator_scene.get_selected_messages(): msg.destination = self.dennis stc.ui.gvSimulator.message_updated.emit(msg) list_model = stc.ui.listViewSimulate.model() self.assertEqual(list_model.rowCount(), 2) list_model.setData(list_model.createIndex(1, 0), Qt.Checked, role=Qt.CheckStateRole) dialog = stc.get_simulator_dialog() network_sdr_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText( network_sdr_name) rcv_port = self.get_free_port() dialog.simulator.sniffer.rcv_device.set_server_port(rcv_port) dialog.simulator.sniffer.adaptive_noise = False dialog.simulator.sniffer.automatic_center = False dialog.ui.btnStartStop.click() while not any("Waiting for message 1" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message 1") time.sleep(1) modulator = dialog.project_manager.modulators[0] # type: Modulator sender = NetworkSDRInterfacePlugin(raw_mode=True, sending=True) sender.client_port = rcv_port sender.send_raw_data(modulator.modulate("1" * 352), 1) time.sleep(0.5) sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1) while not any("Waiting for message 2" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator wait for message 2") time.sleep(1) sender.send_raw_data(modulator.modulate("10" * 176), 1) time.sleep(0.5) sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1) while not any("Mismatch for label:" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for mismatching message") time.sleep(1) QTest.qWait(250) QApplication.processEvents() QTest.qWait(100) simulator_log = dialog.ui.textEditSimulation.toPlainText() self.assertIn("Received message 1", simulator_log) self.assertIn("preamble: 11111111", simulator_log) self.assertIn("Mismatch for label: preamble", simulator_log) dialog.close()
class VirtualDevice(QObject): """ Wrapper class for providing sending methods for grc and native devices """ started = pyqtSignal() stopped = pyqtSignal() index_changed = pyqtSignal(int, int) sender_needs_restart = pyqtSignal() def __init__(self, backend_handler, name: str, mode: Mode, bw, freq, gain, samp_rate, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, is_ringbuffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[ name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: self.__dev = ReceiverThread(samp_rate, freq, gain, bw, parent=parent, is_ringbuffer=is_ringbuffer) self.__dev.index_changed.connect(self.emit_index_changed) elif mode == Mode.send: self.__dev = SenderThread(samp_rate, freq, gain, bw, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len(samples_to_send) elif mode == Mode.spectrum: self.__dev = SpectrumThread(samp_rate, freq, gain, bw, parent=parent) else: raise ValueError("Unknown mode") self.__dev.usrp_ip = device_ip self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect( self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): is_ringbuffer = self.mode == Mode.spectrum or is_ringbuffer if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(bw, freq, gain, samp_rate, is_ringbuffer=is_ringbuffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, samp_rate, device_number=0, is_ringbuffer=is_ringbuffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, samp_rate, device_number=0, is_ringbuffer=is_ringbuffer) else: raise NotImplementedError( "Native Backend for {0} not yet implemented".format( name)) else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip self.__dev.rcv_index_changed.connect(self.emit_index_changed) if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats, skip_device_parameters=True) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin(raw_mode=raw_mode) self.__dev.rcv_index_changed.connect(self.emit_index_changed) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend") @property def bandwidth(self): return self.__dev.bandwidth @bandwidth.setter def bandwidth(self, value): self.__dev.bandwidth = value @property def bandwidth_is_adjustable(self): if self.backend == Backends.grc: return True elif self.backend == Backends.native: return self.__dev.bandwidth_is_adjustable elif self.backend == Backends.network: return True else: raise ValueError("Unsupported Backend") @property def frequency(self): if self.backend == Backends.grc: return self.__dev.freq elif self.backend == Backends.native: return self.__dev.frequency else: raise ValueError("Unsupported Backend") @frequency.setter def frequency(self, value): if self.backend == Backends.grc: self.__dev.freq = value elif self.backend == Backends.native: self.__dev.frequency = value elif self.backend == Backends.network: pass else: raise ValueError("Unsupported Backend") @property def gain(self): return self.__dev.gain @gain.setter def gain(self, value): self.__dev.gain = value @property def sample_rate(self): return self.__dev.sample_rate @sample_rate.setter def sample_rate(self, value): self.__dev.sample_rate = value @property def samples_to_send(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend in (Backends.native, Backends.network): return self.__dev.samples_to_send else: raise ValueError("Unsupported Backend") @samples_to_send.setter def samples_to_send(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: self.__dev.init_send_parameters(value, self.num_sending_repeats, skip_device_parameters=True) elif self.backend == Backends.network: self.__dev.samples_to_send = value else: raise ValueError("Unsupported Backend") @property def ip(self): if self.backend == Backends.grc: return self.__dev.usrp_ip elif self.backend == Backends.native: return self.__dev.device_ip else: raise ValueError("Unsupported Backend") @ip.setter def ip(self, value): if self.backend == Backends.grc: self.__dev.usrp_ip = value elif self.backend == Backends.native: self.__dev.device_ip = value elif self.backend in (Backends.none, Backends.network): pass else: raise ValueError("Unsupported Backend") @property def port(self): if self.backend in (Backends.grc, Backends.native): return self.__dev.port else: raise ValueError( "Port only for gnuradio socket (grc backend) and native backend" ) @port.setter def port(self, value): if self.backend in (Backends.grc, Backends.native): self.__dev.port = value else: raise ValueError( "Port only for gnuradio socket (grc backend) and native backend" ) @property def data(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.samples_to_send else: return self.__dev.receive_buffer elif self.backend == Backends.network: if self.mode == Mode.send: raise NotImplementedError("Todo") else: if self.__dev.raw_mode: return self.__dev.receive_buffer else: return self.__dev.received_bits else: raise ValueError("Unsupported Backend") @data.setter def data(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.samples_to_send = value else: self.__dev.receive_buffer = value else: raise ValueError("Unsupported Backend") def free_data(self): if self.backend == Backends.grc: del self.__dev.data elif self.backend == Backends.native: del self.__dev.samples_to_send del self.__dev.receive_buffer elif self.backend == Backends.network: self.__dev.free_data() elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") @property def num_sending_repeats(self): if self.mode == Mode.send: if self.backend == Backends.grc: return self.__dev.max_repeats elif self.backend == Backends.native: return self.__dev.sending_repeats else: raise ValueError("Unsupported Backend") @num_sending_repeats.setter def num_sending_repeats(self, value): if self.mode == Mode.send: if self.backend == Backends.grc: if value != self.__dev.max_repeats: self.__dev.max_repeats = value self.__dev.current_iteration = 0 elif self.backend in (Backends.native, Backends.network): self.__dev.sending_repeats = value else: raise ValueError("Unsupported Backend") @property def current_index(self): if self.backend == Backends.grc: return self.__dev.current_index elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_recv_index elif self.backend == Backends.network: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_receive_index else: raise ValueError("Unsupported Backend") @current_index.setter def current_index(self, value): if self.backend == Backends.grc: self.__dev.current_index = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_recv_index = value elif self.backend == Backends.network: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_receive_index = value else: raise ValueError("Unsupported Backend") @property def current_iteration(self): if self.backend == Backends.grc: return self.__dev.current_iteration elif self.backend in (Backends.native, Backends.network): return self.__dev.current_sending_repeat else: raise ValueError("Unsupported Backend") @current_iteration.setter def current_iteration(self, value): if self.backend == Backends.grc: self.__dev.current_iteration = value elif self.backend in (Backends.native, Backends.network): self.__dev.current_sending_repeat = value else: raise ValueError("Unsupported Backend") @property def sending_finished(self): if self.backend == Backends.grc: return self.__dev.current_iteration is None elif self.backend == Backends.native: return self.__dev.sending_finished elif self.backend == Backends.network: return self.__dev.current_sent_sample == len(self.samples_to_send) else: raise ValueError("Unsupported Backend") @property def spectrum(self): if self.mode == Mode.spectrum: if self.backend == Backends.grc: return self.__dev.x, self.__dev.y elif self.backend == Backends.native: w = np.abs(np.fft.fft(self.__dev.receive_buffer)) freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate) idx = np.argsort(freqs) return freqs[idx].astype(np.float32), w[idx].astype(np.float32) else: raise ValueError("Spectrum x only available in spectrum mode") def start(self): if self.backend == Backends.grc: self.__dev.setTerminationEnabled(True) self.__dev.terminate() time.sleep(0.1) self.__dev.start( ) # Already connected to started signal in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.start_tx_mode(resume=True) else: self.__dev.start_rx_mode() self.emit_started_signal() elif self.backend == Backends.network: if self.mode == Mode.receive: self.__dev.start_tcp_server_for_receiving() else: self.__dev.start_raw_sending_thread() self.emit_started_signal() else: raise ValueError("Unsupported Backend") def stop(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.stop_tx_mode(msg) else: self.__dev.stop_rx_mode(msg) self.emit_stopped_signal() elif self.backend == Backends.network: self.__dev.stop_tcp_server() self.emit_stopped_signal() elif self.backend == Backends.none: pass else: logger.error("Stop device: Unsupported backend " + str(self.backend)) def stop_on_error(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: self.read_errors() # Clear errors self.__dev.stop_rx_mode("Stop on error") self.__dev.stop_tx_mode("Stop on error") self.emit_stopped_signal() else: raise ValueError("Unsupported Backend") def cleanup(self): if self.backend == Backends.grc: if self.mode == Mode.send: self.__dev.socket.close() time.sleep(0.1) self.__dev.quit() self.data = None elif self.backend == Backends.native: self.data = None elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") def emit_stopped_signal(self): self.stopped.emit() def emit_started_signal(self): self.started.emit() def emit_sender_needs_restart(self): self.sender_needs_restart.emit() def emit_index_changed(self, old, new): self.index_changed.emit(old, new) def read_errors(self): if self.backend == Backends.grc: return self.__dev.read_errors() elif self.backend == Backends.native: errors = "\n\n".join(self.__dev.errors) self.__dev.errors.clear() return errors elif self.backend == Backends.network: return "" else: raise ValueError("Unsupported Backend") def set_server_port(self, port: int): if self.backend == Backends.network: self.__dev.server_port = port else: raise ValueError( "Setting port only supported for NetworkSDR Plugin") def set_client_port(self, port: int): if self.backend == Backends.network: self.__dev.client_port = port else: raise ValueError( "Setting port only supported for NetworkSDR Plugin")
class TestSimulator(QtTestCase): TIMEOUT = 0.25 def setUp(self): super().setUp() settings.OVERWRITE_RECEIVE_BUFFER_SIZE = 50000 Modulator.FORCE_DTYPE = np.float32 self.num_zeros_for_pause = 1000 def test_simulation_flow(self): """ test a simulation flow with an increasing sequence number :return: """ if sys.platform == "win32" and struct.calcsize("P") * 8 == 32: print("Skipping test on 32 Bit windows as CI is slow.") self.assertTrue(True) return profile = self.get_path_for_filename("testprofile.sim.xml") self.form.add_files([profile]) self.assertEqual( len(self.form.simulator_tab_controller.simulator_scene. get_all_message_items()), 6) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = self.form.simulator_tab_controller.get_simulator_dialog( ) # type: SimulatorDialog dialog.project_manager.simulator_timeout_ms = 999999999 name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(self.TIMEOUT) conn, addr = s.accept() msg = next(msg for msg in dialog.simulator_config.get_all_messages() if msg.source.name == "Alice") checksum_label = next( lbl for lbl in msg.message_type if lbl.is_checksum_label).label # type: ChecksumLabel modulator = dialog.project_manager.modulators[0] # type: Modulator preamble_str = "10101010" sync_str = "1001" preamble = list(map(int, preamble_str)) sync = list(map(int, sync_str)) seq = list(map(int, "00000010")) data = list(map(int, "11001101")) seq_num = int("".join(map(str, seq)), 2) checksum = list(checksum_label.calculate_checksum(seq + data)) msg1 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg1), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, self.num_zeros_for_pause), 1) while not any("Sending message 2" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 2") time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str), msg=bits) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 1) seq = list(map(int, "{0:08b}".format(seq_num + 2))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg2 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg2), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, self.num_zeros_for_pause), 1) while not any("Sending message 4" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 4") time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 3) seq = list(map(int, "{0:08b}".format(seq_num + 4))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg3 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg3), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, self.num_zeros_for_pause), 1) while not any("Sending message 6" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 6") time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 5) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s) def test_external_program_simulator(self): if sys.platform == "win32" and struct.calcsize("P") * 8 == 32: print("Skipping test on 32 Bit windows as CI is slow.") self.assertTrue(True) return stc = self.form.simulator_tab_controller # type: SimulatorTabController stc.ui.btnAddParticipant.click() stc.ui.btnAddParticipant.click() stc.project_manager.simulator_timeout_ms = 999999999 stc.simulator_scene.add_counter_action(None, 0) action = next(item for item in stc.simulator_scene.items() if isinstance(item, CounterActionItem)) action.model_item.start = 3 action.model_item.step = 2 counter_item_str = "item" + str( action.model_item.index()) + ".counter_value" stc.ui.gvSimulator.add_empty_message(42) stc.ui.gvSimulator.add_empty_message(42) stc.ui.cbViewType.setCurrentIndex(0) stc.create_simulator_label(0, 10, 20) stc.create_simulator_label(1, 10, 20) messages = stc.simulator_config.get_all_messages() messages[0].source = stc.project_manager.participants[0] messages[0].destination = stc.project_manager.participants[1] messages[0].destination.simulate = True messages[1].source = stc.project_manager.participants[1] messages[1].destination = stc.project_manager.participants[0] stc.simulator_scene.add_trigger_command_action(None, 200) stc.simulator_scene.add_sleep_action(None, 200) lbl1 = messages[0].message_type[0] # type: SimulatorProtocolLabel lbl2 = messages[1].message_type[0] # type: SimulatorProtocolLabel ext_program = get_path_for_data_file( "external_program_simulator.py") + " " + counter_item_str if sys.platform == "win32": ext_program = sys.executable + " " + ext_program lbl1.value_type_index = 3 lbl1.external_program = ext_program lbl2.value_type_index = 3 lbl2.external_program = ext_program action = next(item for item in stc.simulator_scene.items() if isinstance(item, SleepActionItem)) action.model_item.sleep_time = 0.000000001 stc.simulator_scene.clearSelection() action = next(item for item in stc.simulator_scene.items() if isinstance(item, TriggerCommandActionItem)) action.setSelected(True) self.assertEqual(stc.ui.detail_view_widget.currentIndex(), 4) file_name = os.path.join(tempfile.gettempdir(), "external_test") if os.path.isfile(file_name): os.remove(file_name) self.assertFalse(os.path.isfile(file_name)) external_command = "cmd.exe /C copy NUL {}".format( file_name) if os.name == "nt" else "touch {}".format(file_name) stc.ui.lineEditTriggerCommand.setText(external_command) self.assertEqual(action.model_item.command, external_command) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = stc.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(self.TIMEOUT) conn, addr = s.accept() modulator = dialog.project_manager.modulators[0] # type: Modulator self.alice.send_raw_data(modulator.modulate("100" + "10101010" * 42), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, 2 * self.num_zeros_for_pause), 1) while not any("Sending message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message") time.sleep(self.TIMEOUT) time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(bits[0].rstrip("0"), "101010101") while simulator.is_simulating: logger.debug("Wait for simulator to finish") time.sleep(self.TIMEOUT) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s) self.assertTrue(os.path.isfile(file_name)) def __demodulate(self, connection: socket.socket): connection.settimeout(self.TIMEOUT) time.sleep(self.TIMEOUT) total_data = [] while True: try: data = connection.recv(65536) if data: total_data.append(data) else: break except socket.timeout: break if len(total_data) == 0: logger.error("Did not receive any data from socket.") arr = IQArray( np.array(np.frombuffer(b"".join(total_data), dtype=np.complex64))) signal = Signal("", "") signal.iq_array = arr pa = ProtocolAnalyzer(signal) pa.get_protocol_from_signal() return pa.plain_bits_str
def __init__(self, backend_handler, name: str, mode: Mode, bw, freq, gain, samp_rate, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, is_ringbuffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[ name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: self.__dev = ReceiverThread(samp_rate, freq, gain, bw, parent=parent, is_ringbuffer=is_ringbuffer) self.__dev.index_changed.connect(self.emit_index_changed) elif mode == Mode.send: self.__dev = SenderThread(samp_rate, freq, gain, bw, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len(samples_to_send) elif mode == Mode.spectrum: self.__dev = SpectrumThread(samp_rate, freq, gain, bw, parent=parent) else: raise ValueError("Unknown mode") self.__dev.usrp_ip = device_ip self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect( self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): is_ringbuffer = self.mode == Mode.spectrum or is_ringbuffer if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(bw, freq, gain, samp_rate, is_ringbuffer=is_ringbuffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, samp_rate, device_number=0, is_ringbuffer=is_ringbuffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, samp_rate, device_number=0, is_ringbuffer=is_ringbuffer) else: raise NotImplementedError( "Native Backend for {0} not yet implemented".format( name)) else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip self.__dev.rcv_index_changed.connect(self.emit_index_changed) if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats, skip_device_parameters=True) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin(raw_mode=raw_mode) self.__dev.rcv_index_changed.connect(self.emit_index_changed) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend")
class GeneratorTabController(QWidget): def __init__(self, compare_frame_controller: CompareFrameController, project_manager: ProjectManager, parent=None): super().__init__(parent) self.ui = Ui_GeneratorTab() self.ui.setupUi(self) self.ui.treeProtocols.setHeaderHidden(True) self.tree_model = GeneratorTreeModel(compare_frame_controller) self.tree_model.set_root_item( compare_frame_controller.proto_tree_model.rootItem) self.tree_model.controller = self self.ui.treeProtocols.setModel(self.tree_model) self.has_default_modulation = True self.table_model = GeneratorTableModel( compare_frame_controller.proto_tree_model.rootItem, [Modulator("Modulation")], compare_frame_controller.decodings) self.table_model.controller = self self.ui.tableMessages.setModel(self.table_model) self.label_list_model = GeneratorListModel(None) self.ui.listViewProtoLabels.setModel(self.label_list_model) self.network_sdr_button_orig_tooltip = self.ui.btnNetworkSDRSend.toolTip( ) self.set_network_sdr_send_button_visibility() self.set_rfcat_button_visibility() self.network_sdr_plugin = NetworkSDRInterfacePlugin() self.rfcat_plugin = RfCatPlugin() self.init_rfcat_plugin() self.refresh_modulators() self.on_selected_modulation_changed() self.set_fuzzing_ui_status() self.project_manager = project_manager self.ui.prBarGeneration.hide() self.create_connects(compare_frame_controller) @property def selected_message_index(self) -> int: min_row, _, _, _ = self.ui.tableMessages.selection_range() return min_row # @property def selected_message(self) -> Message: selected_msg_index = self.selected_message_index if selected_msg_index == -1 or selected_msg_index >= len( self.table_model.protocol.messages): return None return self.table_model.protocol.messages[selected_msg_index] @property def active_groups(self): return self.tree_model.groups @property def modulators(self): return self.table_model.protocol.modulators @property def total_modulated_samples(self) -> int: return sum( int( len(msg.encoded_bits) * self.modulators[msg.modulator_indx].samples_per_bit + msg.pause) for msg in self.table_model.protocol.messages) @modulators.setter def modulators(self, value): assert type(value) == list self.table_model.protocol.modulators = value def create_connects(self, compare_frame_controller): compare_frame_controller.proto_tree_model.modelReset.connect( self.refresh_tree) compare_frame_controller.participant_changed.connect( self.table_model.refresh_vertical_header) self.ui.btnEditModulation.clicked.connect(self.show_modulation_dialog) self.ui.cBoxModulations.currentIndexChanged.connect( self.on_selected_modulation_changed) self.ui.tableMessages.selectionModel().selectionChanged.connect( self.on_table_selection_changed) self.ui.tableMessages.encodings_updated.connect( self.on_table_selection_changed) self.table_model.undo_stack.indexChanged.connect( self.on_undo_stack_index_changed) self.table_model.protocol.qt_signals.line_duplicated.connect( self.refresh_pause_list) self.table_model.protocol.qt_signals.fuzzing_started.connect( self.on_fuzzing_started) self.table_model.protocol.qt_signals.current_fuzzing_message_changed.connect( self.on_current_fuzzing_message_changed) self.table_model.protocol.qt_signals.fuzzing_finished.connect( self.on_fuzzing_finished) self.label_list_model.protolabel_fuzzing_status_changed.connect( self.set_fuzzing_ui_status) self.ui.cbViewType.currentIndexChanged.connect( self.on_view_type_changed) self.ui.btnSend.clicked.connect(self.on_btn_send_clicked) self.ui.btnSave.clicked.connect(self.on_btn_save_clicked) self.project_manager.project_updated.connect(self.on_project_updated) self.label_list_model.protolabel_removed.connect( self.handle_proto_label_removed) self.ui.lWPauses.item_edit_clicked.connect(self.edit_pause_item) self.ui.lWPauses.itemSelectionChanged.connect( self.on_lWpauses_selection_changed) self.ui.lWPauses.lost_focus.connect(self.on_lWPauses_lost_focus) self.ui.lWPauses.doubleClicked.connect(self.on_lWPauses_double_clicked) self.ui.btnGenerate.clicked.connect(self.generate_file) self.label_list_model.protolabel_fuzzing_status_changed.connect( self.handle_plabel_fuzzing_state_changed) self.ui.btnFuzz.clicked.connect(self.on_btn_fuzzing_clicked) self.ui.tableMessages.create_fuzzing_label_clicked.connect( self.create_fuzzing_label) self.ui.tableMessages.edit_fuzzing_label_clicked.connect( self.show_fuzzing_dialog) self.ui.listViewProtoLabels.selection_changed.connect( self.handle_label_selection_changed) self.ui.listViewProtoLabels.edit_on_item_triggered.connect( self.show_fuzzing_dialog) self.ui.btnNetworkSDRSend.clicked.connect( self.on_btn_network_sdr_clicked) self.ui.btnRfCatSend.clicked.connect(self.on_btn_rfcat_clicked) self.network_sdr_plugin.sending_status_changed.connect( self.on_network_sdr_sending_status_changed) self.network_sdr_plugin.sending_stop_requested.connect( self.on_network_sdr_sending_stop_requested) self.network_sdr_plugin.current_send_message_changed.connect( self.on_send_message_changed) @pyqtSlot() def refresh_tree(self): self.tree_model.beginResetModel() self.tree_model.endResetModel() self.ui.treeProtocols.expandAll() @pyqtSlot() def refresh_table(self): self.table_model.update() self.ui.tableMessages.resize_columns() is_data_there = self.table_model.display_data is not None and len( self.table_model.display_data) > 0 self.ui.btnSend.setEnabled(is_data_there) self.ui.btnGenerate.setEnabled(is_data_there) @pyqtSlot() def refresh_label_list(self): self.label_list_model.message = self.selected_message self.label_list_model.update() @property def generator_undo_stack(self) -> QUndoStack: return self.table_model.undo_stack @pyqtSlot() def on_selected_modulation_changed(self): cur_ind = self.ui.cBoxModulations.currentIndex() min_row, max_row, _, _ = self.ui.tableMessages.selection_range() if min_row > -1: # Modulation für Selektierte Blöcke setzen for row in range(min_row, max_row + 1): try: self.table_model.protocol.messages[ row].modulator_indx = cur_ind except IndexError: continue self.show_modulation_info() def refresh_modulators(self): current_index = 0 if type(self.sender()) == ModulatorDialogController: current_index = self.sender( ).ui.comboBoxCustomModulations.currentIndex() self.ui.cBoxModulations.clear() for modulator in self.modulators: self.ui.cBoxModulations.addItem(modulator.name) self.ui.cBoxModulations.setCurrentIndex(current_index) def show_modulation_info(self): show = not self.has_default_modulation or self.modulators[ 0] != Modulator("Modulation") if not show: self.ui.btnEditModulation.setStyleSheet("background: orange") font = QFont() font.setBold(True) self.ui.btnEditModulation.setFont(font) else: self.ui.btnEditModulation.setStyleSheet("") self.ui.btnEditModulation.setFont(QFont()) cur_ind = self.ui.cBoxModulations.currentIndex() cur_mod = self.modulators[cur_ind] self.ui.lCarrierFreqValue.setText(cur_mod.carrier_frequency_str) self.ui.lCarrierPhaseValue.setText(cur_mod.carrier_phase_str) self.ui.lBitLenValue.setText(cur_mod.bit_len_str) self.ui.lSampleRateValue.setText(cur_mod.sample_rate_str) mod_type = cur_mod.modulation_type_str self.ui.lModTypeValue.setText(mod_type) if mod_type == "ASK": prefix = "Amplitude" elif mod_type == "PSK": prefix = "Phase" elif mod_type in ("FSK", "GFSK"): prefix = "Frequency" else: prefix = "Unknown Modulation Type (This should not happen...)" self.ui.lParamForZero.setText(prefix + " for 0:") self.ui.lParamForZeroValue.setText(cur_mod.param_for_zero_str) self.ui.lParamForOne.setText(prefix + " for 1:") self.ui.lParamForOneValue.setText(cur_mod.param_for_one_str) def prepare_modulation_dialog( self) -> (ModulatorDialogController, Message): preselected_index = self.ui.cBoxModulations.currentIndex() min_row, max_row, start, end = self.ui.tableMessages.selection_range() if min_row > -1: try: selected_message = self.table_model.protocol.messages[min_row] preselected_index = selected_message.modulator_indx except IndexError: selected_message = Message([True, False, True, False], 0, [], MessageType("empty")) else: selected_message = Message([True, False, True, False], 0, [], MessageType("empty")) if len(self.table_model.protocol.messages) > 0: selected_message.bit_len = self.table_model.protocol.messages[ 0].bit_len for m in self.modulators: m.default_sample_rate = self.project_manager.device_conf[ "sample_rate"] modulator_dialog = ModulatorDialogController(self.modulators, parent=self.parent()) modulator_dialog.ui.treeViewSignals.setModel(self.tree_model) modulator_dialog.ui.treeViewSignals.expandAll() modulator_dialog.ui.comboBoxCustomModulations.setCurrentIndex( preselected_index) modulator_dialog.finished.connect(self.refresh_modulators) modulator_dialog.finished.connect(self.refresh_pause_list) return modulator_dialog, selected_message def initialize_modulation_dialog(self, bits: str, dialog: ModulatorDialogController): dialog.on_modulation_type_changed( ) # for drawing modulated signal initially dialog.original_bits = bits dialog.ui.linEdDataBits.setText(bits) dialog.ui.gVOriginalSignal.signal_tree_root = self.tree_model.rootItem dialog.draw_original_signal() dialog.ui.gVModulated.show_full_scene(reinitialize=True) dialog.ui.gVData.show_full_scene(reinitialize=True) dialog.ui.gVData.auto_fit_view() dialog.ui.gVCarrier.show_full_scene(reinitialize=True) dialog.ui.gVCarrier.auto_fit_view() def init_rfcat_plugin(self): self.set_rfcat_button_visibility() self.rfcat_plugin = RfCatPlugin() self.rfcat_plugin.current_send_message_changed.connect( self.on_send_message_changed) self.ui.btnRfCatSend.setEnabled(self.rfcat_plugin.rfcat_is_found) @pyqtSlot() def on_undo_stack_index_changed(self): self.refresh_table() self.refresh_pause_list() self.refresh_label_list() self.refresh_estimated_time() self.set_fuzzing_ui_status() @pyqtSlot() def show_modulation_dialog(self): modulator_dialog, message = self.prepare_modulation_dialog() modulator_dialog.showMaximized() self.initialize_modulation_dialog(message.encoded_bits_str[0:10], modulator_dialog) self.has_default_modulation = False @pyqtSlot() def on_table_selection_changed(self): min_row, max_row, start, end = self.ui.tableMessages.selection_range() if min_row == -1: self.ui.lEncodingValue.setText("-") # self.ui.lEncodingValue.setToolTip("") self.label_list_model.message = None return container = self.table_model.protocol message = container.messages[min_row] self.label_list_model.message = message decoder_name = message.decoder.name metrics = QFontMetrics(self.ui.lEncodingValue.font()) elidedName = metrics.elidedText(decoder_name, Qt.ElideRight, self.ui.lEncodingValue.width()) self.ui.lEncodingValue.setText(elidedName) self.ui.lEncodingValue.setToolTip(decoder_name) self.ui.cBoxModulations.blockSignals(True) self.ui.cBoxModulations.setCurrentIndex(message.modulator_indx) self.show_modulation_info() self.ui.cBoxModulations.blockSignals(False) @pyqtSlot(int) def edit_pause_item(self, index: int): message = self.table_model.protocol.messages[index] cur_len = message.pause new_len, ok = QInputDialog.getInt(self, self.tr("Enter new Pause Length"), self.tr("Pause Length:"), cur_len, 0) if ok: message.pause = new_len self.refresh_pause_list() @pyqtSlot() def on_lWPauses_double_clicked(self): sel_indexes = [ index.row() for index in self.ui.lWPauses.selectedIndexes() ] if len(sel_indexes) > 0: self.edit_pause_item(sel_indexes[0]) @pyqtSlot() def refresh_pause_list(self): self.ui.lWPauses.clear() fmt_str = "Pause ({1:d}-{2:d}) <{0:d} samples ({3})>" for i, pause in enumerate(self.table_model.protocol.pauses): sr = self.modulators[self.table_model.protocol.messages[i]. modulator_indx].sample_rate item = fmt_str.format(pause, i + 1, i + 2, Formatter.science_time(pause / sr)) self.ui.lWPauses.addItem(item) @pyqtSlot() def on_lWpauses_selection_changed(self): rows = [index.row() for index in self.ui.lWPauses.selectedIndexes()] if len(rows) == 0: return self.ui.tableMessages.show_pause_active = True self.ui.tableMessages.pause_row = rows[0] self.ui.tableMessages.viewport().update() self.ui.tableMessages.scrollTo(self.table_model.index(rows[0], 0)) @pyqtSlot() def on_lWPauses_lost_focus(self): self.ui.tableMessages.show_pause_active = False self.ui.tableMessages.viewport().update() @pyqtSlot() def generate_file(self): try: total_samples = self.total_modulated_samples buffer = self.prepare_modulation_buffer(total_samples, show_error=False) if buffer is None: Errors.generic_error( self.tr("File too big"), self.tr("This file would get too big to save.")) self.unsetCursor() return modulated_samples = self.modulate_data(buffer) FileOperator.save_data_dialog("", modulated_samples, parent=self) except Exception as e: Errors.generic_error(self.tr("Failed to generate data"), str(e), traceback.format_exc()) self.unsetCursor() def prepare_modulation_buffer(self, total_samples: int, show_error=True) -> np.ndarray: memory_size_for_buffer = total_samples * 8 logger.debug("Allocating {0:.2f}MB for modulated samples".format( memory_size_for_buffer / (1024**2))) try: return np.zeros(total_samples, dtype=np.complex64) except MemoryError: if show_error: Errors.not_enough_ram_for_sending_precache( memory_size_for_buffer) return None def modulate_data(self, buffer: np.ndarray) -> np.ndarray: """ :param buffer: Buffer in which the modulated data shall be written, initialized with zeros :return: """ self.ui.prBarGeneration.show() self.ui.prBarGeneration.setValue(0) self.ui.prBarGeneration.setMaximum(self.table_model.row_count) pos = 0 for i in range(0, self.table_model.row_count): message = self.table_model.protocol.messages[i] modulator = self.modulators[message.modulator_indx] # We do not need to modulate the pause extra, as result is already initialized with zeros modulator.modulate(start=pos, data=message.encoded_bits, pause=0) buffer[pos:pos + len(modulator.modulated_samples )] = modulator.modulated_samples pos += len(modulator.modulated_samples) + message.pause self.ui.prBarGeneration.setValue(i + 1) QApplication.instance().processEvents() self.ui.prBarGeneration.hide() return buffer @pyqtSlot(int) def show_fuzzing_dialog(self, label_index: int): view = self.ui.cbViewType.currentIndex() if self.label_list_model.message is not None: msg_index = self.table_model.protocol.messages.index( self.label_list_model.message) fdc = FuzzingDialogController(protocol=self.table_model.protocol, label_index=label_index, msg_index=msg_index, proto_view=view, parent=self) fdc.show() fdc.finished.connect(self.refresh_label_list) fdc.finished.connect(self.refresh_table) fdc.finished.connect(self.set_fuzzing_ui_status) @pyqtSlot() def handle_plabel_fuzzing_state_changed(self): self.refresh_table() self.label_list_model.update() @pyqtSlot(ProtocolLabel) def handle_proto_label_removed(self, plabel: ProtocolLabel): self.refresh_label_list() self.refresh_table() self.set_fuzzing_ui_status() @pyqtSlot() def on_btn_fuzzing_clicked(self): fuz_mode = "Successive" if self.ui.rbConcurrent.isChecked(): fuz_mode = "Concurrent" elif self.ui.rBExhaustive.isChecked(): fuz_mode = "Exhaustive" self.setCursor(Qt.WaitCursor) fuzz_action = Fuzz(self.table_model.protocol, fuz_mode) self.table_model.undo_stack.push(fuzz_action) self.unsetCursor() @pyqtSlot() def set_fuzzing_ui_status(self): btn_was_enabled = self.ui.btnFuzz.isEnabled() fuzz_active = any(lbl.active_fuzzing for msg in self.table_model.protocol.messages for lbl in msg.message_type) self.ui.btnFuzz.setEnabled(fuzz_active) if self.ui.btnFuzz.isEnabled() and not btn_was_enabled: font = self.ui.btnFuzz.font() font.setBold(True) self.ui.btnFuzz.setFont(font) else: font = self.ui.btnFuzz.font() font.setBold(False) self.ui.btnFuzz.setFont(font) self.ui.btnFuzz.setStyleSheet("") has_same_message = self.table_model.protocol.multiple_fuzz_labels_per_message self.ui.rBSuccessive.setEnabled(has_same_message) self.ui.rBExhaustive.setEnabled(has_same_message) self.ui.rbConcurrent.setEnabled(has_same_message) def refresh_existing_encodings(self, encodings_from_file): """ Refresh existing encodings for messages, when encoding was changed by user in dialog :return: """ update = False for msg in self.table_model.protocol.messages: i = next((i for i, d in enumerate(encodings_from_file) if d.name == msg.decoder.name), 0) if msg.decoder != encodings_from_file[i]: update = True msg.decoder = encodings_from_file[i] msg.clear_decoded_bits() msg.clear_encoded_bits() if update: self.refresh_table() self.refresh_estimated_time() @pyqtSlot() def refresh_estimated_time(self): c = self.table_model.protocol if c.num_messages == 0: self.ui.lEstimatedTime.setText("Estimated Time: ") return avg_msg_len = numpy.mean([len(msg.encoded_bits) for msg in c.messages]) avg_bit_len = numpy.mean([m.samples_per_bit for m in self.modulators]) avg_sample_rate = numpy.mean([m.sample_rate for m in self.modulators]) pause_samples = sum(c.pauses) nsamples = c.num_messages * avg_msg_len * avg_bit_len + pause_samples self.ui.lEstimatedTime.setText( locale.format_string("Estimated Time: %.04f seconds", nsamples / avg_sample_rate)) @pyqtSlot(int, int, int) def create_fuzzing_label(self, msg_index: int, start: int, end: int): con = self.table_model.protocol start, end = con.convert_range(start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index) lbl = con.create_fuzzing_label(start, end, msg_index) self.show_fuzzing_dialog(con.protocol_labels.index(lbl)) @pyqtSlot() def handle_label_selection_changed(self): rows = [ index.row() for index in self.ui.listViewProtoLabels.selectedIndexes() ] if len(rows) == 0: return maxrow = numpy.max(rows) try: label = self.table_model.protocol.protocol_labels[maxrow] except IndexError: return if label.show and self.selected_message: start, end = self.selected_message.get_label_range( lbl=label, view=self.table_model.proto_view, decode=False) indx = self.table_model.index(0, int((start + end) / 2)) self.ui.tableMessages.scrollTo(indx) @pyqtSlot() def on_view_type_changed(self): self.setCursor(Qt.WaitCursor) self.table_model.proto_view = self.ui.cbViewType.currentIndex() self.ui.tableMessages.resize_columns() self.unsetCursor() @pyqtSlot() def on_btn_send_clicked(self): try: total_samples = self.total_modulated_samples buffer = self.prepare_modulation_buffer(total_samples) if buffer is not None: modulated_data = self.modulate_data(buffer) else: # Enter continuous mode modulated_data = None try: if modulated_data is not None: try: dialog = SendDialogController( self.project_manager, modulated_data=modulated_data, parent=self) except MemoryError: # Not enough memory for device buffer so we need to create a continuous send dialog del modulated_data Errors.not_enough_ram_for_sending_precache(None) dialog = ContinuousSendDialogController( self.project_manager, self.table_model.protocol.messages, self.modulators, total_samples, parent=self) else: dialog = ContinuousSendDialogController( self.project_manager, self.table_model.protocol.messages, self.modulators, total_samples, parent=self) except OSError as e: logger.error(repr(e)) return if dialog.has_empty_device_list: Errors.no_device() dialog.close() return dialog.recording_parameters.connect( self.project_manager.set_recording_parameters) dialog.show() dialog.graphics_view.show_full_scene(reinitialize=True) except Exception as e: Errors.generic_error(self.tr("Failed to generate data"), str(e), traceback.format_exc()) self.unsetCursor() @pyqtSlot() def on_btn_save_clicked(self): filename = FileOperator.get_save_file_name("profile.fuzz", caption="Save fuzz profile") if filename: self.table_model.protocol.to_xml_file(filename) def load_from_file(self, filename: str): try: self.table_model.protocol.from_xml_file(filename) self.refresh_pause_list() self.refresh_estimated_time() self.refresh_modulators() self.show_modulation_info() self.refresh_table() self.set_fuzzing_ui_status() except: logger.error( "You done something wrong to the xml fuzzing profile.") @pyqtSlot() def on_project_updated(self): self.table_model.participants = self.project_manager.participants self.table_model.refresh_vertical_header() def set_network_sdr_send_button_visibility(self): is_plugin_enabled = PluginManager().is_plugin_enabled( "NetworkSDRInterface") self.ui.btnNetworkSDRSend.setVisible(is_plugin_enabled) def set_rfcat_button_visibility(self): is_plugin_enabled = PluginManager().is_plugin_enabled("RfCat") self.ui.btnRfCatSend.setVisible(is_plugin_enabled) @pyqtSlot() def on_btn_network_sdr_clicked(self): if not self.network_sdr_plugin.is_sending: messages = self.table_model.protocol.messages sample_rates = [ self.modulators[msg.modulator_indx].sample_rate for msg in messages ] self.network_sdr_plugin.start_message_sending_thread( messages, sample_rates) else: self.network_sdr_plugin.stop_sending_thread() @pyqtSlot(bool) def on_network_sdr_sending_status_changed(self, is_sending: bool): self.ui.btnNetworkSDRSend.setChecked(is_sending) self.ui.btnNetworkSDRSend.setEnabled(True) self.ui.btnNetworkSDRSend.setToolTip( "Sending in progress" if is_sending else self. network_sdr_button_orig_tooltip) if not is_sending: self.ui.tableMessages.clearSelection() @pyqtSlot() def on_network_sdr_sending_stop_requested(self): self.ui.btnNetworkSDRSend.setToolTip("Stopping sending") self.ui.btnNetworkSDRSend.setEnabled(False) @pyqtSlot(int) def on_send_message_changed(self, message_index: int): self.ui.tableMessages.selectRow(message_index) @pyqtSlot() def on_btn_rfcat_clicked(self): if not self.rfcat_plugin.is_sending: messages = self.table_model.protocol.messages sample_rates = [ self.modulators[msg.modulator_indx].sample_rate for msg in messages ] self.rfcat_plugin.start_message_sending_thread( messages, sample_rates, self.modulators, self.project_manager) else: self.rfcat_plugin.stop_sending_thread() @pyqtSlot(int) def on_fuzzing_started(self, num_values: int): self.ui.stackedWidgetFuzzing.setCurrentWidget( self.ui.pageFuzzingProgressBar) self.ui.progressBarFuzzing.setMaximum(num_values) self.ui.progressBarFuzzing.setValue(0) QApplication.instance().processEvents() @pyqtSlot() def on_fuzzing_finished(self): self.ui.stackedWidgetFuzzing.setCurrentWidget(self.ui.pageFuzzingUI) @pyqtSlot(int) def on_current_fuzzing_message_changed(self, current_message: int): self.ui.progressBarFuzzing.setValue(current_message) QApplication.instance().processEvents()
class VirtualDevice(QObject): """ Wrapper class for providing sending methods for grc and native devices """ started = pyqtSignal() stopped = pyqtSignal() sender_needs_restart = pyqtSignal() fatal_error_occurred = pyqtSignal(str) ready_for_action = pyqtSignal() data_received = pyqtSignal(np.ndarray) # for direct demodulation in sniffer continuous_send_msg = "Continuous send mode is not supported for GNU Radio backend. " \ "You can change the configured device backend in options." def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rate=None, bandwidth=None, gain=None, if_gain=None, baseband_gain=None, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, resume_on_full_receive_buffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler freq = config.DEFAULT_FREQUENCY if freq is None else freq sample_rate = config.DEFAULT_SAMPLE_RATE if sample_rate is None else sample_rate bandwidth = config.DEFAULT_BANDWIDTH if bandwidth is None else bandwidth gain = config.DEFAULT_GAIN if gain is None else gain if_gain = config.DEFAULT_IF_GAIN if if_gain is None else if_gain baseband_gain = config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain resume_on_full_receive_buffer = self.mode == Mode.spectrum or resume_on_full_receive_buffer if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: from urh.dev.gr.ReceiverThread import ReceiverThread self.__dev = ReceiverThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif mode == Mode.send: from urh.dev.gr.SenderThread import SenderThread self.__dev = SenderThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len(samples_to_send) if samples_to_send is not None else 2 ** 15 elif mode == Mode.spectrum: from urh.dev.gr.SpectrumThread import SpectrumThread self.__dev = SpectrumThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) else: raise ValueError("Unknown mode") self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect(self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, sample_rate, device_number=0, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, sample_rate, bandwidth, device_number=0, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name == "limesdr": from urh.dev.native.LimeSDR import LimeSDR self.__dev = LimeSDR(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.startswith("airspy"): from urh.dev.native.AirSpy import AirSpy self.__dev = AirSpy(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.startswith("usrp"): from urh.dev.native.USRP import USRP self.__dev = USRP(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.startswith("sdrplay"): from urh.dev.native.SDRPlay import SDRPlay self.__dev = SDRPlay(freq, gain, bandwidth, gain, if_gain=if_gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name == "soundcard": from urh.dev.native.SoundCard import SoundCard self.__dev = SoundCard(sample_rate, resume_on_full_receive_buffer=resume_on_full_receive_buffer) else: raise NotImplementedError("Native Backend for {0} not yet implemented".format(name)) elif name == "test": # For Unittests Only self.__dev = Device(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin(raw_mode=raw_mode, resume_on_full_receive_buffer=resume_on_full_receive_buffer, spectrum=self.mode == Mode.spectrum, sending=self.mode == Mode.send) self.__dev.send_connection_established.connect(self.emit_ready_for_action) self.__dev.receive_server_started.connect(self.emit_ready_for_action) self.__dev.error_occurred.connect(self.emit_fatal_error_occurred) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend") if hasattr(self.__dev, "data_received"): self.__dev.data_received.connect(self.data_received.emit) if mode == Mode.spectrum: self.__dev.is_in_spectrum_mode = True @property def has_multi_device_support(self): return hasattr(self.__dev, "has_multi_device_support") and self.__dev.has_multi_device_support @property def device_serial(self): if hasattr(self.__dev, "device_serial"): return self.__dev.device_serial else: return None @device_serial.setter def device_serial(self, value): if hasattr(self.__dev, "device_serial"): self.__dev.device_serial = value @property def device_number(self): if hasattr(self.__dev, "device_number"): return self.__dev.device_number else: return None @device_number.setter def device_number(self, value): if hasattr(self.__dev, "device_number"): self.__dev.device_number = value @property def bandwidth(self): return self.__dev.bandwidth @bandwidth.setter def bandwidth(self, value): self.__dev.bandwidth = value @property def bandwidth_is_adjustable(self): if self.backend == Backends.grc: return True elif self.backend == Backends.native: return self.__dev.bandwidth_is_adjustable elif self.backend == Backends.network: return True else: raise ValueError("Unsupported Backend") @property def frequency(self): if self.backend == Backends.grc: return self.__dev.freq elif self.backend == Backends.native: return self.__dev.frequency else: raise ValueError("Unsupported Backend") @frequency.setter def frequency(self, value): if self.backend == Backends.grc: self.__dev.freq = value elif self.backend == Backends.native: self.__dev.frequency = value elif self.backend == Backends.network: pass else: raise ValueError("Unsupported Backend") @property def num_samples_to_send(self) -> int: if self.backend in (Backends.native, Backends.network): return self.__dev.num_samples_to_send else: raise ValueError(self.continuous_send_msg) @num_samples_to_send.setter def num_samples_to_send(self, value: int): if self.backend in (Backends.native, Backends.network): self.__dev.num_samples_to_send = value else: raise ValueError(self.continuous_send_msg) @property def is_send_continuous(self) -> bool: if self.backend in (Backends.native, Backends.network): return self.__dev.sending_is_continuous else: raise ValueError(self.continuous_send_msg) @is_send_continuous.setter def is_send_continuous(self, value: bool): if self.backend in (Backends.native, Backends.network): self.__dev.sending_is_continuous = value else: raise ValueError(self.continuous_send_msg) @property def is_raw_mode(self) -> bool: if self.backend == Backends.network: return self.__dev.raw_mode else: return True @property def continuous_send_ring_buffer(self): if self.backend in (Backends.native, Backends.network): return self.__dev.continuous_send_ring_buffer else: raise ValueError(self.continuous_send_msg) @continuous_send_ring_buffer.setter def continuous_send_ring_buffer(self, value): if self.backend in (Backends.native, Backends.network): self.__dev.continuous_send_ring_buffer = value else: raise ValueError(self.continuous_send_msg) @property def is_in_spectrum_mode(self): if self.backend in (Backends.grc, Backends.native, Backends.network): return self.__dev.is_in_spectrum_mode else: raise ValueError("Unsupported Backend") @is_in_spectrum_mode.setter def is_in_spectrum_mode(self, value: bool): if self.backend in (Backends.grc, Backends.native, Backends.network): self.__dev.is_in_spectrum_mode = value else: raise ValueError("Unsupported Backend") @property def gain(self): return self.__dev.gain @gain.setter def gain(self, value): try: self.__dev.gain = value except AttributeError as e: logger.warning(str(e)) @property def if_gain(self): try: return self.__dev.if_gain except AttributeError as e: logger.warning(str(e)) @if_gain.setter def if_gain(self, value): try: self.__dev.if_gain = value except AttributeError as e: logger.warning(str(e)) @property def baseband_gain(self): return self.__dev.baseband_gain @baseband_gain.setter def baseband_gain(self, value): self.__dev.baseband_gain = value @property def sample_rate(self): return self.__dev.sample_rate @sample_rate.setter def sample_rate(self, value): self.__dev.sample_rate = value @property def channel_index(self) -> int: return self.__dev.channel_index @channel_index.setter def channel_index(self, value: int): self.__dev.channel_index = value @property def antenna_index(self) -> int: return self.__dev.antenna_index @antenna_index.setter def antenna_index(self, value: int): self.__dev.antenna_index = value @property def freq_correction(self): return self.__dev.freq_correction @freq_correction.setter def freq_correction(self, value): self.__dev.freq_correction = value @property def direct_sampling_mode(self) -> int: return self.__dev.direct_sampling_mode @direct_sampling_mode.setter def direct_sampling_mode(self, value): self.__dev.direct_sampling_mode = value @property def emit_data_received_signal(self): return self.__dev.emit_data_received_signal @emit_data_received_signal.setter def emit_data_received_signal(self, value): self.__dev.emit_data_received_signal = value @property def samples_to_send(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend in (Backends.native, Backends.network): return self.__dev.samples_to_send else: raise ValueError("Unsupported Backend") @samples_to_send.setter def samples_to_send(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: self.__dev.init_send_parameters(value, self.num_sending_repeats) elif self.backend == Backends.network: self.__dev.samples_to_send = value else: raise ValueError("Unsupported Backend") @property def ip(self): if self.backend == Backends.grc: return self.__dev.device_ip elif self.backend == Backends.native: return self.__dev.device_ip else: raise ValueError("Unsupported Backend") @ip.setter def ip(self, value): if self.backend == Backends.grc: self.__dev.device_ip = value elif self.backend == Backends.native: self.__dev.device_ip = value elif self.backend in (Backends.none, Backends.network): pass else: raise ValueError("Unsupported Backend") @property def port(self): if self.backend in (Backends.grc, Backends.native, Backends.network): return self.__dev.port else: raise ValueError("Unsupported Backend") @port.setter def port(self, value): if self.backend in (Backends.grc, Backends.native, Backends.network): self.__dev.port = value else: raise ValueError("Unsupported Backend") @property def data(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.samples_to_send else: return self.__dev.receive_buffer elif self.backend == Backends.network: if self.mode == Mode.send: raise NotImplementedError("Todo") else: if self.__dev.raw_mode: return self.__dev.receive_buffer else: return self.__dev.received_bits else: raise ValueError("Unsupported Backend") @data.setter def data(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.samples_to_send = value else: self.__dev.receive_buffer = value else: logger.warning("{}:{} has no data".format(self.__class__.__name__, self.backend.name)) def free_data(self): if self.backend == Backends.grc: self.__dev.data = None elif self.backend == Backends.native: self.__dev.samples_to_send = None self.__dev.receive_buffer = None elif self.backend == Backends.network: self.__dev.free_data() elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") @property def resume_on_full_receive_buffer(self) -> bool: return self.__dev.resume_on_full_receive_buffer @resume_on_full_receive_buffer.setter def resume_on_full_receive_buffer(self, value: bool): if value != self.__dev.resume_on_full_receive_buffer: self.__dev.resume_on_full_receive_buffer = value if self.backend == Backends.native: self.__dev.receive_buffer = None elif self.backend == Backends.grc: self.__dev.data = None @property def num_sending_repeats(self): return self.__dev.sending_repeats @num_sending_repeats.setter def num_sending_repeats(self, value): self.__dev.sending_repeats = value @property def current_index(self): if self.backend == Backends.grc: return self.__dev.current_index elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_recv_index elif self.backend == Backends.network: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_receive_index else: raise ValueError("Unsupported Backend") @current_index.setter def current_index(self, value): if self.backend == Backends.grc: self.__dev.current_index = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_recv_index = value elif self.backend == Backends.network: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_receive_index = value else: raise ValueError("Unsupported Backend") @property def current_iteration(self): if self.backend == Backends.grc: return self.__dev.current_iteration elif self.backend in (Backends.native, Backends.network): return self.__dev.current_sending_repeat else: raise ValueError("Unsupported Backend") @current_iteration.setter def current_iteration(self, value): if self.backend == Backends.grc: self.__dev.current_iteration = value elif self.backend in (Backends.native, Backends.network): self.__dev.current_sending_repeat = value else: raise ValueError("Unsupported Backend") @property def sending_finished(self): if self.backend == Backends.grc: return self.__dev.current_iteration is None elif self.backend in (Backends.native, Backends.network): return self.__dev.sending_finished else: raise ValueError("Unsupported Backend") @property def spectrum(self): if self.mode == Mode.spectrum: if self.backend == Backends.grc: return self.__dev.x, self.__dev.y elif self.backend == Backends.native or self.backend == Backends.network: w = np.abs(np.fft.fft(self.__dev.receive_buffer)) freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate) idx = np.argsort(freqs) return freqs[idx].astype(np.float32), w[idx].astype(np.float32) else: raise ValueError("Spectrum x only available in spectrum mode") def start(self): if self.backend == Backends.grc: self.__dev.setTerminationEnabled(True) self.__dev.terminate() time.sleep(0.1) self.__dev.start() # Already connected to started signal in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.start_tx_mode(resume=True) else: self.__dev.start_rx_mode() self.emit_started_signal() elif self.backend == Backends.network: if self.mode == Mode.receive or self.mode == Mode.spectrum: self.__dev.start_tcp_server_for_receiving() else: self.__dev.start_raw_sending_thread() self.emit_started_signal() else: raise ValueError("Unsupported Backend") def stop(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.stop_tx_mode(msg) else: self.__dev.stop_rx_mode(msg) self.emit_stopped_signal() elif self.backend == Backends.network: self.__dev.stop_tcp_server() self.__dev.stop_sending_thread() self.emit_stopped_signal() elif self.backend == Backends.none: pass else: logger.error("Stop device: Unsupported backend " + str(self.backend)) def stop_on_error(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: self.read_messages() # Clear errors self.__dev.stop_rx_mode("Stop on error") self.__dev.stop_tx_mode("Stop on error") self.emit_stopped_signal() else: raise ValueError("Unsupported Backend") def cleanup(self): if self.backend == Backends.grc: if self.mode == Mode.send: self.__dev.socket.close() time.sleep(0.1) self.__dev.quit() self.data = None elif self.backend == Backends.native: self.data = None elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") def emit_stopped_signal(self): self.stopped.emit() def emit_started_signal(self): self.started.emit() def emit_sender_needs_restart(self): self.sender_needs_restart.emit() def read_messages(self) -> str: """ returns a string of new device messages separated by newlines :return: """ if self.backend == Backends.grc: errors = self.__dev.read_errors() if "FATAL: " in errors: self.fatal_error_occurred.emit(errors[errors.index("FATAL: "):]) return errors elif self.backend == Backends.native: messages = "\n".join(self.__dev.device_messages) self.__dev.device_messages.clear() if messages and not messages.endswith("\n"): messages += "\n" if "successfully started" in messages: self.ready_for_action.emit() elif "failed to start" in messages: self.fatal_error_occurred.emit(messages[messages.index("failed to start"):]) return messages elif self.backend == Backends.network: return "" else: raise ValueError("Unsupported Backend") def set_server_port(self, port: int): if self.backend == Backends.network: self.__dev.server_port = port else: raise ValueError("Setting port only supported for NetworkSDR Plugin") def set_client_port(self, port: int): if self.backend == Backends.network: self.__dev.client_port = port else: raise ValueError("Setting port only supported for NetworkSDR Plugin") def get_device_list(self): if hasattr(self.__dev, "get_device_list"): return self.__dev.get_device_list() else: return [] def increase_gr_port(self): if self.backend == Backends.grc: self.__dev.gr_port += 1 logger.info("Retry with port " + str(self.__dev.gr_port)) else: raise ValueError("Only for GR backend") def emit_ready_for_action(self): """ Notify observers that device is successfully initialized :return: """ self.ready_for_action.emit() def emit_fatal_error_occurred(self, msg: str): self.fatal_error_occurred.emit(msg)
class VirtualDevice(QObject): """ Wrapper class for providing sending methods for grc and native devices """ started = pyqtSignal() stopped = pyqtSignal() index_changed = pyqtSignal(int, int) sender_needs_restart = pyqtSignal() def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rate=None, bandwidth=None, gain=None, if_gain=None, baseband_gain=None, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, is_ringbuffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler freq = config.DEFAULT_FREQUENCY if freq is None else freq sample_rate = config.DEFAULT_SAMPLE_RATE if sample_rate is None else sample_rate bandwidth = config.DEFAULT_BANDWIDTH if bandwidth is None else bandwidth gain = config.DEFAULT_GAIN if gain is None else gain if_gain = config.DEFAULT_IF_GAIN if if_gain is None else if_gain baseband_gain = config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[ name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: from urh.dev.gr.ReceiverThread import ReceiverThread self.__dev = ReceiverThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent, is_ringbuffer=is_ringbuffer) self.__dev.index_changed.connect(self.emit_index_changed) elif mode == Mode.send: from urh.dev.gr.SenderThread import SenderThread self.__dev = SenderThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len(samples_to_send) elif mode == Mode.spectrum: from urh.dev.gr.SpectrumThread import SpectrumThread self.__dev = SpectrumThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) else: raise ValueError("Unknown mode") self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect( self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): is_ringbuffer = self.mode == Mode.spectrum or is_ringbuffer if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, is_ringbuffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, sample_rate, device_number=0, is_ringbuffer=is_ringbuffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, sample_rate, bandwidth, device_number=0, is_ringbuffer=is_ringbuffer) elif name == "limesdr": from urh.dev.native.LimeSDR import LimeSDR self.__dev = LimeSDR(freq, gain, sample_rate, bandwidth, gain, is_ringbuffer=is_ringbuffer) elif name.startswith("airspy"): from urh.dev.native.AirSpy import AirSpy self.__dev = AirSpy(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, is_ringbuffer=is_ringbuffer) else: raise NotImplementedError( "Native Backend for {0} not yet implemented".format( name)) elif name == "test": # For Unittests Only self.__dev = Device(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, is_ringbuffer) self.__dev.BYTES_PER_SAMPLE = 4 else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip self.__dev.rcv_index_changed.connect(self.emit_index_changed) if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin( raw_mode=raw_mode, spectrum=self.mode == Mode.spectrum) self.__dev.rcv_index_changed.connect(self.emit_index_changed) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend") @property def bandwidth(self): return self.__dev.bandwidth @bandwidth.setter def bandwidth(self, value): self.__dev.bandwidth = value @property def bandwidth_is_adjustable(self): if self.backend == Backends.grc: return True elif self.backend == Backends.native: return self.__dev.bandwidth_is_adjustable elif self.backend == Backends.network: return True else: raise ValueError("Unsupported Backend") @property def frequency(self): if self.backend == Backends.grc: return self.__dev.freq elif self.backend == Backends.native: return self.__dev.frequency else: raise ValueError("Unsupported Backend") @frequency.setter def frequency(self, value): if self.backend == Backends.grc: self.__dev.freq = value elif self.backend == Backends.native: self.__dev.frequency = value elif self.backend == Backends.network: pass else: raise ValueError("Unsupported Backend") @property def gain(self): return self.__dev.gain @gain.setter def gain(self, value): self.__dev.gain = value @property def if_gain(self): return self.__dev.if_gain @if_gain.setter def if_gain(self, value): self.__dev.if_gain = value @property def baseband_gain(self): return self.__dev.baseband_gain @baseband_gain.setter def baseband_gain(self, value): self.__dev.baseband_gain = value @property def sample_rate(self): return self.__dev.sample_rate @sample_rate.setter def sample_rate(self, value): self.__dev.sample_rate = value @property def channel_index(self) -> int: return self.__dev.channel_index @channel_index.setter def channel_index(self, value: int): self.__dev.channel_index = value @property def antenna_index(self) -> int: return self.__dev.antenna_index @antenna_index.setter def antenna_index(self, value: int): self.__dev.antenna_index = value @property def freq_correction(self): return self.__dev.freq_correction @freq_correction.setter def freq_correction(self, value): self.__dev.freq_correction = value @property def direct_sampling_mode(self) -> int: return self.__dev.direct_sampling_mode @direct_sampling_mode.setter def direct_sampling_mode(self, value): self.__dev.direct_sampling_mode = value @property def samples_to_send(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend in (Backends.native, Backends.network): return self.__dev.samples_to_send else: raise ValueError("Unsupported Backend") @samples_to_send.setter def samples_to_send(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: self.__dev.init_send_parameters(value, self.num_sending_repeats) elif self.backend == Backends.network: self.__dev.samples_to_send = value else: raise ValueError("Unsupported Backend") @property def device_args(self): return self.__dev.device_args @device_args.setter def device_args(self, value): self.__dev.device_args = value @property def ip(self): if self.backend == Backends.grc: return self.__dev.device_ip elif self.backend == Backends.native: return self.__dev.device_ip else: raise ValueError("Unsupported Backend") @ip.setter def ip(self, value): if self.backend == Backends.grc: self.__dev.device_ip = value elif self.backend == Backends.native: self.__dev.device_ip = value elif self.backend in (Backends.none, Backends.network): pass else: raise ValueError("Unsupported Backend") @property def port(self): if self.backend in (Backends.grc, Backends.native, Backends.network): return self.__dev.port else: raise ValueError("Unsupported Backend") @port.setter def port(self, value): if self.backend in (Backends.grc, Backends.native, Backends.network): self.__dev.port = value else: raise ValueError("Unsupported Backend") @property def data(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.samples_to_send else: return self.__dev.receive_buffer elif self.backend == Backends.network: if self.mode == Mode.send: raise NotImplementedError("Todo") else: if self.__dev.raw_mode: return self.__dev.receive_buffer else: return self.__dev.received_bits else: raise ValueError("Unsupported Backend") @data.setter def data(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.samples_to_send = value else: self.__dev.receive_buffer = value else: logger.warning("{}:{} has no data".format(self.__class__.__name__, self.backend.name)) def free_data(self): if self.backend == Backends.grc: self.__dev.data = None elif self.backend == Backends.native: self.__dev.samples_to_send = None self.__dev.receive_buffer = None elif self.backend == Backends.network: self.__dev.free_data() elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") @property def num_sending_repeats(self): if self.mode == Mode.send: if self.backend == Backends.grc: return self.__dev.max_repeats elif self.backend == Backends.native: return self.__dev.sending_repeats else: raise ValueError("Unsupported Backend") @num_sending_repeats.setter def num_sending_repeats(self, value): if self.mode == Mode.send: if self.backend == Backends.grc: if value != self.__dev.max_repeats: self.__dev.max_repeats = value self.__dev.current_iteration = 0 elif self.backend in (Backends.native, Backends.network): self.__dev.sending_repeats = value else: raise ValueError("Unsupported Backend") @property def current_index(self): if self.backend == Backends.grc: return self.__dev.current_index elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_recv_index elif self.backend == Backends.network: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_receive_index else: raise ValueError("Unsupported Backend") @current_index.setter def current_index(self, value): if self.backend == Backends.grc: self.__dev.current_index = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_recv_index = value elif self.backend == Backends.network: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_receive_index = value else: raise ValueError("Unsupported Backend") @property def current_iteration(self): if self.backend == Backends.grc: return self.__dev.current_iteration elif self.backend in (Backends.native, Backends.network): return self.__dev.current_sending_repeat else: raise ValueError("Unsupported Backend") @current_iteration.setter def current_iteration(self, value): if self.backend == Backends.grc: self.__dev.current_iteration = value elif self.backend in (Backends.native, Backends.network): self.__dev.current_sending_repeat = value else: raise ValueError("Unsupported Backend") @property def sending_finished(self): if self.backend == Backends.grc: return self.__dev.current_iteration is None elif self.backend == Backends.native: return self.__dev.sending_finished elif self.backend == Backends.network: return self.__dev.current_sent_sample == len(self.samples_to_send) else: raise ValueError("Unsupported Backend") @property def spectrum(self): if self.mode == Mode.spectrum: if self.backend == Backends.grc: return self.__dev.x, self.__dev.y elif self.backend == Backends.native or self.backend == Backends.network: w = np.abs(np.fft.fft(self.__dev.receive_buffer)) freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate) idx = np.argsort(freqs) return freqs[idx].astype(np.float32), w[idx].astype(np.float32) else: raise ValueError("Spectrum x only available in spectrum mode") def start(self): if self.backend == Backends.grc: self.__dev.setTerminationEnabled(True) self.__dev.terminate() time.sleep(0.1) self.__dev.start( ) # Already connected to started signal in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.start_tx_mode(resume=True) else: self.__dev.start_rx_mode() self.emit_started_signal() elif self.backend == Backends.network: if self.mode == Mode.receive or self.mode == Mode.spectrum: self.__dev.start_tcp_server_for_receiving() else: self.__dev.start_raw_sending_thread() self.emit_started_signal() else: raise ValueError("Unsupported Backend") def stop(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.stop_tx_mode(msg) else: self.__dev.stop_rx_mode(msg) self.emit_stopped_signal() elif self.backend == Backends.network: self.__dev.stop_tcp_server() self.emit_stopped_signal() elif self.backend == Backends.none: pass else: logger.error("Stop device: Unsupported backend " + str(self.backend)) def stop_on_error(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: self.read_messages() # Clear errors self.__dev.stop_rx_mode("Stop on error") self.__dev.stop_tx_mode("Stop on error") self.emit_stopped_signal() else: raise ValueError("Unsupported Backend") def cleanup(self): if self.backend == Backends.grc: if self.mode == Mode.send: self.__dev.socket.close() time.sleep(0.1) self.__dev.quit() self.data = None elif self.backend == Backends.native: self.data = None elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") def emit_stopped_signal(self): self.stopped.emit() def emit_started_signal(self): self.started.emit() def emit_sender_needs_restart(self): self.sender_needs_restart.emit() def emit_index_changed(self, old, new): self.index_changed.emit(old, new) def read_messages(self): if self.backend == Backends.grc: return self.__dev.read_errors() elif self.backend == Backends.native: messages = "\n".join(self.__dev.device_messages) if messages and not messages.endswith("\n"): messages += "\n" self.__dev.device_messages.clear() return messages elif self.backend == Backends.network: return "" else: raise ValueError("Unsupported Backend") def set_server_port(self, port: int): if self.backend == Backends.network: self.__dev.server_port = port else: raise ValueError( "Setting port only supported for NetworkSDR Plugin") def set_client_port(self, port: int): if self.backend == Backends.network: self.__dev.client_port = port else: raise ValueError( "Setting port only supported for NetworkSDR Plugin") def increase_gr_port(self): if self.backend == Backends.grc: self.__dev.gr_port += 1 logger.info("Retry with port " + str(self.__dev.gr_port)) else: raise ValueError("Only for GR backend")
def test_external_program_simulator(self): if sys.platform == "win32" and struct.calcsize("P") * 8 == 32: print("Skipping test on 32 Bit windows as CI is slow.") self.assertTrue(True) return stc = self.form.simulator_tab_controller # type: SimulatorTabController stc.ui.btnAddParticipant.click() stc.ui.btnAddParticipant.click() stc.project_manager.simulator_timeout_ms = 999999999 stc.simulator_scene.add_counter_action(None, 0) action = next(item for item in stc.simulator_scene.items() if isinstance(item, CounterActionItem)) action.model_item.start = 3 action.model_item.step = 2 counter_item_str = "item" + str( action.model_item.index()) + ".counter_value" stc.ui.gvSimulator.add_empty_message(42) stc.ui.gvSimulator.add_empty_message(42) stc.ui.cbViewType.setCurrentIndex(0) stc.create_simulator_label(0, 10, 20) stc.create_simulator_label(1, 10, 20) messages = stc.simulator_config.get_all_messages() messages[0].source = stc.project_manager.participants[0] messages[0].destination = stc.project_manager.participants[1] messages[0].destination.simulate = True messages[1].source = stc.project_manager.participants[1] messages[1].destination = stc.project_manager.participants[0] stc.simulator_scene.add_trigger_command_action(None, 200) stc.simulator_scene.add_sleep_action(None, 200) lbl1 = messages[0].message_type[0] # type: SimulatorProtocolLabel lbl2 = messages[1].message_type[0] # type: SimulatorProtocolLabel ext_program = get_path_for_data_file( "external_program_simulator.py") + " " + counter_item_str if sys.platform == "win32": ext_program = sys.executable + " " + ext_program lbl1.value_type_index = 3 lbl1.external_program = ext_program lbl2.value_type_index = 3 lbl2.external_program = ext_program action = next(item for item in stc.simulator_scene.items() if isinstance(item, SleepActionItem)) action.model_item.sleep_time = 0.000000001 stc.simulator_scene.clearSelection() action = next(item for item in stc.simulator_scene.items() if isinstance(item, TriggerCommandActionItem)) action.setSelected(True) self.assertEqual(stc.ui.detail_view_widget.currentIndex(), 4) file_name = os.path.join(tempfile.gettempdir(), "external_test") if os.path.isfile(file_name): os.remove(file_name) self.assertFalse(os.path.isfile(file_name)) external_command = "cmd.exe /C copy NUL {}".format( file_name) if os.name == "nt" else "touch {}".format(file_name) stc.ui.lineEditTriggerCommand.setText(external_command) self.assertEqual(action.model_item.command, external_command) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = stc.get_simulator_dialog() name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(self.TIMEOUT) conn, addr = s.accept() modulator = dialog.project_manager.modulators[0] # type: Modulator self.alice.send_raw_data(modulator.modulate("100" + "10101010" * 42), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, 2 * self.num_zeros_for_pause), 1) while not any("Sending message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message") time.sleep(self.TIMEOUT) time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(bits[0].rstrip("0"), "101010101") while simulator.is_simulating: logger.debug("Wait for simulator to finish") time.sleep(self.TIMEOUT) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s) self.assertTrue(os.path.isfile(file_name))
def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rate=None, bandwidth=None, gain=None, if_gain=None, baseband_gain=None, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, resume_on_full_receive_buffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler freq = config.DEFAULT_FREQUENCY if freq is None else freq sample_rate = config.DEFAULT_SAMPLE_RATE if sample_rate is None else sample_rate bandwidth = config.DEFAULT_BANDWIDTH if bandwidth is None else bandwidth gain = config.DEFAULT_GAIN if gain is None else gain if_gain = config.DEFAULT_IF_GAIN if if_gain is None else if_gain baseband_gain = config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain resume_on_full_receive_buffer = self.mode == Mode.spectrum or resume_on_full_receive_buffer if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: from urh.dev.gr.ReceiverThread import ReceiverThread self.__dev = ReceiverThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif mode == Mode.send: from urh.dev.gr.SenderThread import SenderThread self.__dev = SenderThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len(samples_to_send) if samples_to_send is not None else 2 ** 15 elif mode == Mode.spectrum: from urh.dev.gr.SpectrumThread import SpectrumThread self.__dev = SpectrumThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) else: raise ValueError("Unknown mode") self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect(self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, sample_rate, device_number=0, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, sample_rate, bandwidth, device_number=0, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name == "limesdr": from urh.dev.native.LimeSDR import LimeSDR self.__dev = LimeSDR(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.startswith("airspy"): from urh.dev.native.AirSpy import AirSpy self.__dev = AirSpy(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.startswith("usrp"): from urh.dev.native.USRP import USRP self.__dev = USRP(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name.startswith("sdrplay"): from urh.dev.native.SDRPlay import SDRPlay self.__dev = SDRPlay(freq, gain, bandwidth, gain, if_gain=if_gain, resume_on_full_receive_buffer=resume_on_full_receive_buffer) elif name == "soundcard": from urh.dev.native.SoundCard import SoundCard self.__dev = SoundCard(sample_rate, resume_on_full_receive_buffer=resume_on_full_receive_buffer) else: raise NotImplementedError("Native Backend for {0} not yet implemented".format(name)) elif name == "test": # For Unittests Only self.__dev = Device(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin(raw_mode=raw_mode, resume_on_full_receive_buffer=resume_on_full_receive_buffer, spectrum=self.mode == Mode.spectrum, sending=self.mode == Mode.send) self.__dev.send_connection_established.connect(self.emit_ready_for_action) self.__dev.receive_server_started.connect(self.emit_ready_for_action) self.__dev.error_occurred.connect(self.emit_fatal_error_occurred) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend") if hasattr(self.__dev, "data_received"): self.__dev.data_received.connect(self.data_received.emit) if mode == Mode.spectrum: self.__dev.is_in_spectrum_mode = True
def test_simulation_flow(self): """ test a simulation flow with an increasing sequence number :return: """ if sys.platform == "win32" and struct.calcsize("P") * 8 == 32: print("Skipping test on 32 Bit windows as CI is slow.") self.assertTrue(True) return profile = self.get_path_for_filename("testprofile.sim.xml") self.form.add_files([profile]) self.assertEqual( len(self.form.simulator_tab_controller.simulator_scene. get_all_message_items()), 6) port = self.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port dialog = self.form.simulator_tab_controller.get_simulator_dialog( ) # type: SimulatorDialog dialog.project_manager.simulator_timeout_ms = 999999999 name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) dialog.device_settings_tx_widget.ui.cbDevice.setCurrentText(name) simulator = dialog.simulator simulator.sniffer.rcv_device.set_server_port(port) port = self.get_free_port() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) s.bind(("", port)) s.listen(1) simulator.sender.device.set_client_port(port) dialog.ui.btnStartStop.click() while not any("Waiting for message" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message") time.sleep(self.TIMEOUT) conn, addr = s.accept() msg = next(msg for msg in dialog.simulator_config.get_all_messages() if msg.source.name == "Alice") checksum_label = next( lbl for lbl in msg.message_type if lbl.is_checksum_label).label # type: ChecksumLabel modulator = dialog.project_manager.modulators[0] # type: Modulator preamble_str = "10101010" sync_str = "1001" preamble = list(map(int, preamble_str)) sync = list(map(int, sync_str)) seq = list(map(int, "00000010")) data = list(map(int, "11001101")) seq_num = int("".join(map(str, seq)), 2) checksum = list(checksum_label.calculate_checksum(seq + data)) msg1 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg1), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, self.num_zeros_for_pause), 1) while not any("Sending message 2" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 2") time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str), msg=bits) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 1) seq = list(map(int, "{0:08b}".format(seq_num + 2))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg2 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg2), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, self.num_zeros_for_pause), 1) while not any("Sending message 4" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 4") time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 3) seq = list(map(int, "{0:08b}".format(seq_num + 4))) checksum = list(checksum_label.calculate_checksum(seq + data)) msg3 = preamble + sync + seq + data + checksum self.alice.send_raw_data(modulator.modulate(msg3), 1) time.sleep(self.TIMEOUT) self.alice.send_raw_data( IQArray(None, np.float32, self.num_zeros_for_pause), 1) while not any("Sending message 6" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to send message 6") time.sleep(self.TIMEOUT) bits = self.__demodulate(conn) self.assertEqual(len(bits), 1) bits = bits[0] self.assertTrue(bits.startswith(preamble_str + sync_str)) bits = bits.replace(preamble_str + sync_str, "") self.assertEqual(int(bits, 2), seq_num + 5) NetworkSDRInterfacePlugin.shutdown_socket(conn) NetworkSDRInterfacePlugin.shutdown_socket(s)
class VirtualDevice(QObject): """ Wrapper class for providing sending methods for grc and native devices """ started = pyqtSignal() stopped = pyqtSignal() sender_needs_restart = pyqtSignal() fatal_error_occurred = pyqtSignal(str) ready_for_action = pyqtSignal() data_received = pyqtSignal( np.ndarray) # for direct demodulation in sniffer continuous_send_msg = "Continuous send mode is not supported for GNU Radio backend. " \ "You can change the configured device backend in options." def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rate=None, bandwidth=None, gain=None, if_gain=None, baseband_gain=None, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, resume_on_full_receive_buffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler freq = config.DEFAULT_FREQUENCY if freq is None else freq sample_rate = config.DEFAULT_SAMPLE_RATE if sample_rate is None else sample_rate bandwidth = config.DEFAULT_BANDWIDTH if bandwidth is None else bandwidth gain = config.DEFAULT_GAIN if gain is None else gain if_gain = config.DEFAULT_IF_GAIN if if_gain is None else if_gain baseband_gain = config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain resume_on_full_receive_buffer = self.mode == Mode.spectrum or resume_on_full_receive_buffer if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[ name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: from urh.dev.gr.ReceiverThread import ReceiverThread self.__dev = ReceiverThread( freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent, resume_on_full_receive_buffer=resume_on_full_receive_buffer ) elif mode == Mode.send: from urh.dev.gr.SenderThread import SenderThread self.__dev = SenderThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len( samples_to_send) if samples_to_send is not None else 2**15 elif mode == Mode.spectrum: from urh.dev.gr.SpectrumThread import SpectrumThread self.__dev = SpectrumThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) else: raise ValueError("Unknown mode") self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect( self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, sample_rate, device_number=0, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, sample_rate, bandwidth, device_number=0, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name == "limesdr": from urh.dev.native.LimeSDR import LimeSDR self.__dev = LimeSDR(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.startswith("airspy"): from urh.dev.native.AirSpy import AirSpy self.__dev = AirSpy(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.startswith("usrp"): from urh.dev.native.USRP import USRP self.__dev = USRP(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.startswith("sdrplay"): from urh.dev.native.SDRPlay import SDRPlay self.__dev = SDRPlay(freq, gain, bandwidth, gain, if_gain=if_gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name == "soundcard": from urh.dev.native.SoundCard import SoundCard self.__dev = SoundCard(sample_rate, resume_on_full_receive_buffer= resume_on_full_receive_buffer) else: raise NotImplementedError( "Native Backend for {0} not yet implemented".format( name)) elif name == "test": # For Unittests Only self.__dev = Device(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin( raw_mode=raw_mode, resume_on_full_receive_buffer=resume_on_full_receive_buffer, spectrum=self.mode == Mode.spectrum, sending=self.mode == Mode.send) self.__dev.send_connection_established.connect( self.emit_ready_for_action) self.__dev.receive_server_started.connect( self.emit_ready_for_action) self.__dev.error_occurred.connect(self.emit_fatal_error_occurred) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend") if hasattr(self.__dev, "data_received"): self.__dev.data_received.connect(self.data_received.emit) if mode == Mode.spectrum: self.__dev.is_in_spectrum_mode = True @property def has_multi_device_support(self): return hasattr( self.__dev, "has_multi_device_support") and self.__dev.has_multi_device_support @property def device_serial(self): if hasattr(self.__dev, "device_serial"): return self.__dev.device_serial else: return None @device_serial.setter def device_serial(self, value): if hasattr(self.__dev, "device_serial"): self.__dev.device_serial = value @property def device_number(self): if hasattr(self.__dev, "device_number"): return self.__dev.device_number else: return None @device_number.setter def device_number(self, value): if hasattr(self.__dev, "device_number"): self.__dev.device_number = value @property def bandwidth(self): return self.__dev.bandwidth @bandwidth.setter def bandwidth(self, value): self.__dev.bandwidth = value @property def bandwidth_is_adjustable(self): if self.backend == Backends.grc: return True elif self.backend == Backends.native: return self.__dev.bandwidth_is_adjustable elif self.backend == Backends.network: return True else: raise ValueError("Unsupported Backend") @property def frequency(self): if self.backend == Backends.grc: return self.__dev.freq elif self.backend == Backends.native: return self.__dev.frequency else: raise ValueError("Unsupported Backend") @frequency.setter def frequency(self, value): if self.backend == Backends.grc: self.__dev.freq = value elif self.backend == Backends.native: self.__dev.frequency = value elif self.backend == Backends.network: pass else: raise ValueError("Unsupported Backend") @property def num_samples_to_send(self) -> int: if self.backend in (Backends.native, Backends.network): return self.__dev.num_samples_to_send else: raise ValueError(self.continuous_send_msg) @num_samples_to_send.setter def num_samples_to_send(self, value: int): if self.backend in (Backends.native, Backends.network): self.__dev.num_samples_to_send = value else: raise ValueError(self.continuous_send_msg) @property def is_send_continuous(self) -> bool: if self.backend in (Backends.native, Backends.network): return self.__dev.sending_is_continuous else: raise ValueError(self.continuous_send_msg) @is_send_continuous.setter def is_send_continuous(self, value: bool): if self.backend in (Backends.native, Backends.network): self.__dev.sending_is_continuous = value else: raise ValueError(self.continuous_send_msg) @property def is_raw_mode(self) -> bool: if self.backend == Backends.network: return self.__dev.raw_mode else: return True @property def continuous_send_ring_buffer(self): if self.backend in (Backends.native, Backends.network): return self.__dev.continuous_send_ring_buffer else: raise ValueError(self.continuous_send_msg) @continuous_send_ring_buffer.setter def continuous_send_ring_buffer(self, value): if self.backend in (Backends.native, Backends.network): self.__dev.continuous_send_ring_buffer = value else: raise ValueError(self.continuous_send_msg) @property def is_in_spectrum_mode(self): if self.backend in (Backends.grc, Backends.native, Backends.network): return self.__dev.is_in_spectrum_mode else: raise ValueError("Unsupported Backend") @is_in_spectrum_mode.setter def is_in_spectrum_mode(self, value: bool): if self.backend in (Backends.grc, Backends.native, Backends.network): self.__dev.is_in_spectrum_mode = value else: raise ValueError("Unsupported Backend") @property def gain(self): return self.__dev.gain @gain.setter def gain(self, value): try: self.__dev.gain = value except AttributeError as e: logger.warning(str(e)) @property def if_gain(self): try: return self.__dev.if_gain except AttributeError as e: logger.warning(str(e)) @if_gain.setter def if_gain(self, value): try: self.__dev.if_gain = value except AttributeError as e: logger.warning(str(e)) @property def baseband_gain(self): return self.__dev.baseband_gain @baseband_gain.setter def baseband_gain(self, value): self.__dev.baseband_gain = value @property def sample_rate(self): return self.__dev.sample_rate @sample_rate.setter def sample_rate(self, value): self.__dev.sample_rate = value @property def channel_index(self) -> int: return self.__dev.channel_index @channel_index.setter def channel_index(self, value: int): self.__dev.channel_index = value @property def antenna_index(self) -> int: return self.__dev.antenna_index @antenna_index.setter def antenna_index(self, value: int): self.__dev.antenna_index = value @property def freq_correction(self): return self.__dev.freq_correction @freq_correction.setter def freq_correction(self, value): self.__dev.freq_correction = value @property def direct_sampling_mode(self) -> int: return self.__dev.direct_sampling_mode @direct_sampling_mode.setter def direct_sampling_mode(self, value): self.__dev.direct_sampling_mode = value @property def emit_data_received_signal(self): return self.__dev.emit_data_received_signal @emit_data_received_signal.setter def emit_data_received_signal(self, value): self.__dev.emit_data_received_signal = value @property def samples_to_send(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend in (Backends.native, Backends.network): return self.__dev.samples_to_send else: raise ValueError("Unsupported Backend") @samples_to_send.setter def samples_to_send(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: self.__dev.init_send_parameters(value, self.num_sending_repeats) elif self.backend == Backends.network: self.__dev.samples_to_send = value else: raise ValueError("Unsupported Backend") @property def ip(self): if self.backend == Backends.grc: return self.__dev.device_ip elif self.backend == Backends.native: return self.__dev.device_ip else: raise ValueError("Unsupported Backend") @ip.setter def ip(self, value): if self.backend == Backends.grc: self.__dev.device_ip = value elif self.backend == Backends.native: self.__dev.device_ip = value elif self.backend in (Backends.none, Backends.network): pass else: raise ValueError("Unsupported Backend") @property def port(self): if self.backend in (Backends.grc, Backends.native, Backends.network): return self.__dev.port else: raise ValueError("Unsupported Backend") @port.setter def port(self, value): if self.backend in (Backends.grc, Backends.native, Backends.network): self.__dev.port = value else: raise ValueError("Unsupported Backend") @property def data(self): if self.backend == Backends.grc: return self.__dev.data elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.samples_to_send else: return self.__dev.receive_buffer elif self.backend == Backends.network: if self.mode == Mode.send: raise NotImplementedError("Todo") else: if self.__dev.raw_mode: return self.__dev.receive_buffer else: return self.__dev.received_bits else: raise ValueError("Unsupported Backend") @data.setter def data(self, value): if self.backend == Backends.grc: self.__dev.data = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.samples_to_send = value else: self.__dev.receive_buffer = value else: logger.warning("{}:{} has no data".format(self.__class__.__name__, self.backend.name)) def free_data(self): if self.backend == Backends.grc: self.__dev.data = None elif self.backend == Backends.native: self.__dev.samples_to_send = None self.__dev.receive_buffer = None elif self.backend == Backends.network: self.__dev.free_data() elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") @property def resume_on_full_receive_buffer(self) -> bool: return self.__dev.resume_on_full_receive_buffer @resume_on_full_receive_buffer.setter def resume_on_full_receive_buffer(self, value: bool): if value != self.__dev.resume_on_full_receive_buffer: self.__dev.resume_on_full_receive_buffer = value if self.backend == Backends.native: self.__dev.receive_buffer = None elif self.backend == Backends.grc: self.__dev.data = None @property def num_sending_repeats(self): return self.__dev.sending_repeats @num_sending_repeats.setter def num_sending_repeats(self, value): self.__dev.sending_repeats = value @property def current_index(self): if self.backend == Backends.grc: return self.__dev.current_index elif self.backend == Backends.native: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_recv_index elif self.backend == Backends.network: if self.mode == Mode.send: return self.__dev.current_sent_sample else: return self.__dev.current_receive_index else: raise ValueError("Unsupported Backend") @current_index.setter def current_index(self, value): if self.backend == Backends.grc: self.__dev.current_index = value elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_recv_index = value elif self.backend == Backends.network: if self.mode == Mode.send: self.__dev.current_sent_sample = value else: self.__dev.current_receive_index = value else: raise ValueError("Unsupported Backend") @property def current_iteration(self): if self.backend == Backends.grc: return self.__dev.current_iteration elif self.backend in (Backends.native, Backends.network): return self.__dev.current_sending_repeat else: raise ValueError("Unsupported Backend") @current_iteration.setter def current_iteration(self, value): if self.backend == Backends.grc: self.__dev.current_iteration = value elif self.backend in (Backends.native, Backends.network): self.__dev.current_sending_repeat = value else: raise ValueError("Unsupported Backend") @property def sending_finished(self): if self.backend == Backends.grc: return self.__dev.current_iteration is None elif self.backend in (Backends.native, Backends.network): return self.__dev.sending_finished else: raise ValueError("Unsupported Backend") @property def spectrum(self): if self.mode == Mode.spectrum: if self.backend == Backends.grc: return self.__dev.x, self.__dev.y elif self.backend == Backends.native or self.backend == Backends.network: w = np.abs(np.fft.fft(self.__dev.receive_buffer)) freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate) idx = np.argsort(freqs) return freqs[idx].astype(np.float32), w[idx].astype(np.float32) else: raise ValueError("Spectrum x only available in spectrum mode") def start(self): if self.backend == Backends.grc: self.__dev.setTerminationEnabled(True) self.__dev.terminate() time.sleep(0.1) self.__dev.start( ) # Already connected to started signal in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.start_tx_mode(resume=True) else: self.__dev.start_rx_mode() self.emit_started_signal() elif self.backend == Backends.network: if self.mode == Mode.receive or self.mode == Mode.spectrum: self.__dev.start_tcp_server_for_receiving() else: self.__dev.start_raw_sending_thread() self.emit_started_signal() else: raise ValueError("Unsupported Backend") def stop(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: if self.mode == Mode.send: self.__dev.stop_tx_mode(msg) else: self.__dev.stop_rx_mode(msg) self.emit_stopped_signal() elif self.backend == Backends.network: self.__dev.stop_tcp_server() self.__dev.stop_sending_thread() self.emit_stopped_signal() elif self.backend == Backends.none: pass else: logger.error("Stop device: Unsupported backend " + str(self.backend)) def stop_on_error(self, msg: str): if self.backend == Backends.grc: self.__dev.stop(msg) # Already connected to stopped in constructor elif self.backend == Backends.native: self.read_messages() # Clear errors self.__dev.stop_rx_mode("Stop on error") self.__dev.stop_tx_mode("Stop on error") self.emit_stopped_signal() else: raise ValueError("Unsupported Backend") def cleanup(self): if self.backend == Backends.grc: if self.mode == Mode.send: self.__dev.socket.close() time.sleep(0.1) self.__dev.quit() self.data = None elif self.backend == Backends.native: self.data = None elif self.backend == Backends.none: pass else: raise ValueError("Unsupported Backend") def emit_stopped_signal(self): self.stopped.emit() def emit_started_signal(self): self.started.emit() def emit_sender_needs_restart(self): self.sender_needs_restart.emit() def read_messages(self) -> str: """ returns a string of new device messages separated by newlines :return: """ if self.backend == Backends.grc: errors = self.__dev.read_errors() if "FATAL: " in errors: self.fatal_error_occurred.emit( errors[errors.index("FATAL: "):]) return errors elif self.backend == Backends.native: messages = "\n".join(self.__dev.device_messages) self.__dev.device_messages.clear() if messages and not messages.endswith("\n"): messages += "\n" if "successfully started" in messages: self.ready_for_action.emit() elif "failed to start" in messages: self.fatal_error_occurred.emit( messages[messages.index("failed to start"):]) return messages elif self.backend == Backends.network: return "" else: raise ValueError("Unsupported Backend") def set_server_port(self, port: int): if self.backend == Backends.network: self.__dev.server_port = port else: raise ValueError( "Setting port only supported for NetworkSDR Plugin") def set_client_port(self, port: int): if self.backend == Backends.network: self.__dev.client_port = port else: raise ValueError( "Setting port only supported for NetworkSDR Plugin") def get_device_list(self): if hasattr(self.__dev, "get_device_list"): return self.__dev.get_device_list() else: return [] def increase_gr_port(self): if self.backend == Backends.grc: self.__dev.gr_port += 1 logger.info("Retry with port " + str(self.__dev.gr_port)) else: raise ValueError("Only for GR backend") def emit_ready_for_action(self): """ Notify observers that device is successfully initialized :return: """ self.ready_for_action.emit() def emit_fatal_error_occurred(self, msg: str): self.fatal_error_occurred.emit(msg)
def test_performance(self): self.form = MainController() self.cfc = self.form.compare_frame_controller self.stc = self.form.simulator_tab_controller self.gtc = self.form.generator_tab_controller self.form.add_signalfile(get_path_for_data_file("esaver.complex16s")) self.sframe = self.form.signal_tab_controller.signal_frames[0] self.sim_frame = self.form.simulator_tab_controller self.form.ui.tabWidget.setCurrentIndex(3) self.cfc.proto_analyzer.auto_assign_labels() self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin(raw_mode=True) part_a = Participant("Device A", shortname="A", color_index=0) part_b = Participant("Device B", shortname="B", color_index=1) part_b.simulate = True self.form.project_manager.participants.append(part_a) self.form.project_manager.participants.append(part_b) self.form.project_manager.project_updated.emit() sniffer = ProtocolSniffer(100, 0.01, 0.01, 0.1, 5, "FSK", 1, NetworkSDRInterfacePlugin.NETWORK_SDR_NAME, BackendHandler(), network_raw_mode=True) sender = EndlessSender(BackendHandler(), NetworkSDRInterfacePlugin.NETWORK_SDR_NAME) simulator = Simulator(self.stc.simulator_config, self.gtc.modulators, self.stc.sim_expression_parser, self.form.project_manager, sniffer=sniffer, sender=sender) pause = 100 msg_a = SimulatorMessage(part_b, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [0, 0, 1, 1] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, pause=pause, message_type=MessageType("empty_message_type"), source=part_a) msg_b = SimulatorMessage(part_a, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [1, 1, 0, 0] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, pause=pause, message_type=MessageType("empty_message_type"), source=part_b) self.stc.simulator_config.add_items([msg_a, msg_b], 0, None) self.stc.simulator_config.update_active_participants() port = self.get_free_port() sniffer = simulator.sniffer sniffer.rcv_device.set_server_port(port) self.network_sdr_plugin_sender.client_port = port sender = simulator.sender port = self.get_free_port() sender.device.set_client_port(port) sender.device._VirtualDevice__dev.name = "simulator_sender" current_index = Value("L") elapsed = Value("f") target_num_samples = 13600 + pause receive_process = Process(target=receive, args=(port, current_index, target_num_samples, elapsed)) receive_process.daemon = True receive_process.start() # Ensure receiver is running time.sleep(2) # spy = QSignalSpy(self.network_sdr_plugin_receiver.rcv_index_changed) simulator.start() modulator = Modulator("test_modulator") modulator.samples_per_symbol = 100 modulator.carrier_freq_hz = 55e3 # yappi.start() self.network_sdr_plugin_sender.send_raw_data(modulator.modulate(msg_a.encoded_bits), 1) time.sleep(0.5) # send some zeros to simulate the end of a message self.network_sdr_plugin_sender.send_raw_data(np.zeros(self.num_zeros_for_pause, dtype=np.complex64), 1) time.sleep(0.5) receive_process.join(15) logger.info("PROCESS TIME: {0:.2f}ms".format(elapsed.value)) # self.assertEqual(current_index.value, target_num_samples) self.assertLess(elapsed.value, 200) # timeout = spy.wait(2000) # yappi.get_func_stats().print_all() # yappi.get_thread_stats().print_all()
class TestSimulator(QtTestCase): def setUp(self): self.form = MainController() self.cfc = self.form.compare_frame_controller self.stc = self.form.simulator_tab_controller self.gtc = self.form.generator_tab_controller self.form.add_signalfile(get_path_for_data_file("esaver.complex")) self.sframe = self.form.signal_tab_controller.signal_frames[0] self.sim_frame = self.form.simulator_tab_controller self.form.ui.tabWidget.setCurrentIndex(3) self.cfc.proto_analyzer.auto_assign_labels() SettingsProxy.OVERWRITE_RECEIVE_BUFFER_SIZE = 100 * 10**6 self.network_sdr_plugin_sender = NetworkSDRInterfacePlugin( raw_mode=True) def test_performance(self): part_a = Participant("Device A", shortname="A", color_index=0) part_b = Participant("Device B", shortname="B", color_index=1) part_b.simulate = True self.form.project_manager.participants.append(part_a) self.form.project_manager.participants.append(part_b) self.form.project_manager.project_updated.emit() sniffer = ProtocolSniffer(100, 0.01, 0.001, 5, 1, NetworkSDRInterfacePlugin.NETWORK_SDR_NAME, BackendHandler(), network_raw_mode=True, real_time=True) sender = EndlessSender(BackendHandler(), NetworkSDRInterfacePlugin.NETWORK_SDR_NAME) simulator = Simulator(self.stc.simulator_config, self.gtc.modulators, self.stc.sim_expression_parser, self.form.project_manager, sniffer=sniffer, sender=sender) msg_a = SimulatorMessage(part_b, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [0, 0, 1, 1] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, 100000, MessageType("empty_message_type"), source=part_a) msg_b = SimulatorMessage(part_a, [1, 0] * 16 + [1, 1, 0, 0] * 8 + [1, 1, 0, 0] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, 100000, MessageType("empty_message_type"), source=part_b) self.stc.simulator_config.add_items([msg_a, msg_b], 0, None) self.stc.simulator_config.update_active_participants() port = self.__get_free_port() sniffer = simulator.sniffer sniffer.rcv_device.set_server_port(port) self.network_sdr_plugin_sender.client_port = port sender = simulator.sender port = self.__get_free_port() sender.device.set_client_port(port) sender.device._VirtualDevice__dev.name = "simulator_sender" current_index = Value("L") elapsed = Value("f") target_num_samples = 113600 receive_process = Process(target=receive, args=(port, current_index, target_num_samples, elapsed)) receive_process.daemon = True receive_process.start() # Ensure receiver is running time.sleep(1) # spy = QSignalSpy(self.network_sdr_plugin_receiver.rcv_index_changed) simulator.start() modulator = Modulator("test_modulator") modulator.samples_per_bit = 100 modulator.carrier_freq_hz = 55e3 modulator.modulate(msg_a.encoded_bits) # yappi.start() self.network_sdr_plugin_sender.send_raw_data( modulator.modulated_samples, 1) QTest.qWait(100) receive_process.join(10) print("PROCESS TIME: {0:.2f}ms".format(elapsed.value)) self.assertEqual(current_index.value, target_num_samples) self.assertLess(elapsed.value, 200) # timeout = spy.wait(2000) # yappi.get_func_stats().print_all() # yappi.get_thread_stats().print_all() def __get_free_port(self): import socket s = socket.socket() s.bind(("", 0)) port = s.getsockname()[1] s.close() return port
def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rate=None, bandwidth=None, gain=None, if_gain=None, baseband_gain=None, samples_to_send=None, device_ip=None, sending_repeats=1, parent=None, resume_on_full_receive_buffer=False, raw_mode=True, portnumber=1234): super().__init__(parent) self.name = name self.mode = mode self.backend_handler = backend_handler freq = config.DEFAULT_FREQUENCY if freq is None else freq sample_rate = config.DEFAULT_SAMPLE_RATE if sample_rate is None else sample_rate bandwidth = config.DEFAULT_BANDWIDTH if bandwidth is None else bandwidth gain = config.DEFAULT_GAIN if gain is None else gain if_gain = config.DEFAULT_IF_GAIN if if_gain is None else if_gain baseband_gain = config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain resume_on_full_receive_buffer = self.mode == Mode.spectrum or resume_on_full_receive_buffer if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: self.backend = self.backend_handler.device_backends[ name.lower()].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none self.__dev = None return if self.backend == Backends.grc: if mode == Mode.receive: from urh.dev.gr.ReceiverThread import ReceiverThread self.__dev = ReceiverThread( freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent, resume_on_full_receive_buffer=resume_on_full_receive_buffer ) elif mode == Mode.send: from urh.dev.gr.SenderThread import SenderThread self.__dev = SenderThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) self.__dev.data = samples_to_send self.__dev.samples_per_transmission = len( samples_to_send) if samples_to_send is not None else 2**15 elif mode == Mode.spectrum: from urh.dev.gr.SpectrumThread import SpectrumThread self.__dev = SpectrumThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, parent=parent) else: raise ValueError("Unknown mode") self.__dev.device = name self.__dev.started.connect(self.emit_started_signal) self.__dev.stopped.connect(self.emit_stopped_signal) self.__dev.sender_needs_restart.connect( self.emit_sender_needs_restart) elif self.backend == Backends.native: name = self.name.lower() if name in map(str.lower, BackendHandler.DEVICE_NAMES): if name == "hackrf": from urh.dev.native.HackRF import HackRF self.__dev = HackRF(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR self.__dev = RTLSDR(freq, gain, sample_rate, device_number=0, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP self.__dev = RTLSDRTCP(freq, gain, sample_rate, bandwidth, device_number=0, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name == "limesdr": from urh.dev.native.LimeSDR import LimeSDR self.__dev = LimeSDR(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.startswith("airspy"): from urh.dev.native.AirSpy import AirSpy self.__dev = AirSpy(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.startswith("usrp"): from urh.dev.native.USRP import USRP self.__dev = USRP(freq, gain, sample_rate, bandwidth, gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name.startswith("sdrplay"): from urh.dev.native.SDRPlay import SDRPlay self.__dev = SDRPlay(freq, gain, bandwidth, gain, if_gain=if_gain, resume_on_full_receive_buffer= resume_on_full_receive_buffer) elif name == "soundcard": from urh.dev.native.SoundCard import SoundCard self.__dev = SoundCard(sample_rate, resume_on_full_receive_buffer= resume_on_full_receive_buffer) else: raise NotImplementedError( "Native Backend for {0} not yet implemented".format( name)) elif name == "test": # For Unittests Only self.__dev = Device(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, resume_on_full_receive_buffer) else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber self.__dev.device_ip = device_ip if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats) elif self.backend == Backends.network: self.__dev = NetworkSDRInterfacePlugin( raw_mode=raw_mode, resume_on_full_receive_buffer=resume_on_full_receive_buffer, spectrum=self.mode == Mode.spectrum, sending=self.mode == Mode.send) self.__dev.send_connection_established.connect( self.emit_ready_for_action) self.__dev.receive_server_started.connect( self.emit_ready_for_action) self.__dev.error_occurred.connect(self.emit_fatal_error_occurred) self.__dev.samples_to_send = samples_to_send elif self.backend == Backends.none: self.__dev = None else: raise ValueError("Unsupported Backend") if hasattr(self.__dev, "data_received"): self.__dev.data_received.connect(self.data_received.emit) if mode == Mode.spectrum: self.__dev.is_in_spectrum_mode = True
def test_open_simulator_dialog_and_send_mismatching_message(self): stc = self.form.simulator_tab_controller assert isinstance(stc, SimulatorTabController) self.__setup_project() self.add_all_signals_to_simulator() stc.simulator_scene.select_all_items() stc.simulator_config.project_manager.simulator_timeout_ms = 999999999 for msg in stc.simulator_scene.get_selected_messages(): msg.destination = self.dennis stc.ui.gvSimulator.message_updated.emit(msg) list_model = stc.ui.listViewSimulate.model() self.assertEqual(list_model.rowCount(), 2) list_model.setData(list_model.createIndex(1, 0), Qt.Checked, role=Qt.CheckStateRole) dialog = stc.get_simulator_dialog() network_sdr_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(network_sdr_name) rcv_port = self.get_free_port() dialog.simulator.sniffer.rcv_device.set_server_port(rcv_port) dialog.simulator.sniffer.adaptive_noise = False dialog.simulator.sniffer.automatic_center = False dialog.ui.btnStartStop.click() while not any("Waiting for message 1" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator to wait for message 1") time.sleep(1) modulator = dialog.project_manager.modulators[0] # type: Modulator sender = NetworkSDRInterfacePlugin(raw_mode=True, sending=True) sender.client_port = rcv_port sender.send_raw_data(modulator.modulate("1" * 352), 1) time.sleep(0.5) sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1) while not any("Waiting for message 2" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for simulator wait for message 2") time.sleep(1) sender.send_raw_data(modulator.modulate("10" * 176), 1) time.sleep(0.5) sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1) while not any("Mismatch for label:" in msg for msg in dialog.simulator.log_messages): logger.debug("Waiting for mismatching message") time.sleep(1) dialog.on_timer_timeout() # enforce writing to text view simulator_log = dialog.ui.textEditSimulation.toPlainText() self.assertIn("Received message 1", simulator_log) self.assertIn("preamble: 11111111", simulator_log) self.assertIn("Mismatch for label: preamble", simulator_log) dialog.close()