class SimulatorDialog(QDialog):
    rx_parameters_changed = pyqtSignal(dict)
    tx_parameters_changed = pyqtSignal(dict)
    sniff_parameters_changed = pyqtSignal(dict)
    open_in_analysis_requested = pyqtSignal(str)
    rx_file_saved = pyqtSignal(str)

    def __init__(self, simulator_config, modulators,
                 expression_parser, project_manager: ProjectManager, signals: list = None,
                 signal_tree_model=None,
                 parent=None):
        super().__init__(parent)
        self.ui = Ui_DialogSimulator()
        self.ui.setupUi(self)

        self.setAttribute(Qt.WA_DeleteOnClose)

        self.simulator_config = simulator_config  # type: SimulatorConfiguration
        self.rx_needed = self.simulator_config.rx_needed
        self.tx_needed = self.simulator_config.tx_needed

        self.current_transcript_index = 0

        self.simulator_scene = SimulatorScene(mode=1,
                                              simulator_config=self.simulator_config)
        self.ui.gvSimulator.setScene(self.simulator_scene)
        self.project_manager = project_manager

        self.update_interval = 25

        self.timer = QTimer(self)

        self.backend_handler = BackendHandler()
        if self.rx_needed:
            self.device_settings_rx_widget = DeviceSettingsWidget(project_manager,
                                                                  is_tx=False,
                                                                  backend_handler=self.backend_handler)

            self.sniff_settings_widget = SniffSettingsWidget(self.device_settings_rx_widget.ui.cbDevice.currentText(),
                                                             project_manager,
                                                             signal=None,
                                                             backend_handler=self.backend_handler,
                                                             network_raw_mode=True, signals=signals)

            self.device_settings_rx_widget.device = self.sniff_settings_widget.sniffer.rcv_device

            self.sniff_settings_widget.ui.lineEdit_sniff_OutputFile.hide()
            self.sniff_settings_widget.ui.label_sniff_OutputFile.hide()
            self.sniff_settings_widget.ui.label_sniff_viewtype.hide()
            self.sniff_settings_widget.ui.checkBox_sniff_Timestamp.hide()
            self.sniff_settings_widget.ui.comboBox_sniff_viewtype.hide()

            self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(0, self.device_settings_rx_widget)
            self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(1, self.sniff_settings_widget)

            sniffer = self.sniff_settings_widget.sniffer

            self.scene_manager = SniffSceneManager(np.array([]), parent=self)
            self.ui.graphicsViewPreview.setScene(self.scene_manager.scene)
        else:
            self.device_settings_rx_widget = self.sniff_settings_widget = self.scene_manager = None
            self.ui.tabWidgetSimulatorSettings.setTabEnabled(1, False)
            self.ui.graphicsViewPreview.hide()
            self.ui.btnSaveRX.hide()
            self.ui.checkBoxCaptureFullRX.hide()

            sniffer = None

        if self.tx_needed:
            self.device_settings_tx_widget = DeviceSettingsWidget(project_manager, is_tx=True,
                                                                  backend_handler=self.backend_handler,
                                                                  continuous_send_mode=True)
            self.device_settings_tx_widget.ui.spinBoxNRepeat.hide()
            self.device_settings_tx_widget.ui.labelNRepeat.hide()

            self.modulation_settings_widget = ModulationSettingsWidget(modulators, signal_tree_model=signal_tree_model,
                                                                       parent=None)

            self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(0, self.device_settings_tx_widget)
            self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(1, self.modulation_settings_widget)
            send_device = self.device_settings_tx_widget.ui.cbDevice.currentText()
            sender = EndlessSender(self.backend_handler, send_device)
        else:
            self.device_settings_tx_widget = self.modulation_settings_widget = None
            self.ui.tabWidgetSimulatorSettings.setTabEnabled(2, False)

            sender = None

        self.simulator = Simulator(self.simulator_config, modulators, expression_parser, project_manager,
                                   sniffer=sniffer, sender=sender)

        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.device = self.simulator.sender.device

        self.update_buttons()
        self.create_connects()

        if self.device_settings_rx_widget:
            self.device_settings_rx_widget.bootstrap(project_manager.simulator_rx_conf)

        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.bootstrap(project_manager.simulator_tx_conf)

        self.ui.textEditTranscript.setFont(util.get_monospace_font())

        if constants.SETTINGS.value('default_view', 0, int) == 1:
            self.ui.radioButtonTranscriptHex.setChecked(True)

    def create_connects(self):
        if self.rx_needed:
            self.device_settings_rx_widget.selected_device_changed.connect(self.on_selected_rx_device_changed)
            self.device_settings_rx_widget.device_parameters_changed.connect(self.rx_parameters_changed.emit)

            self.sniff_settings_widget.sniff_parameters_changed.connect(self.sniff_parameters_changed.emit)

            self.ui.btnSaveRX.clicked.connect(self.on_btn_save_rx_clicked)
            self.ui.checkBoxCaptureFullRX.clicked.connect(self.on_checkbox_capture_full_rx_clicked)

            self.ui.btnTestSniffSettings.clicked.connect(self.on_btn_test_sniff_settings_clicked)
            self.ui.btnOpenInAnalysis.clicked.connect(self.on_btn_open_in_analysis_clicked)

        if self.tx_needed:
            self.device_settings_tx_widget.selected_device_changed.connect(self.on_selected_tx_device_changed)
            self.device_settings_tx_widget.device_parameters_changed.connect(self.tx_parameters_changed.emit)

        self.ui.radioButtonTranscriptBit.clicked.connect(self.on_radio_button_transcript_bit_clicked)
        self.ui.radioButtonTranscriptHex.clicked.connect(self.on_radio_button_transcript_hex_clicked)

        self.simulator_scene.selectionChanged.connect(self.update_buttons)
        self.simulator_config.items_updated.connect(self.update_buttons)

        self.ui.btnLogAll.clicked.connect(self.on_btn_log_all_clicked)
        self.ui.btnLogNone.clicked.connect(self.on_btn_log_none_clicked)
        self.ui.btnToggleLog.clicked.connect(self.on_btn_toggle_clicked)

        self.ui.btnStartStop.clicked.connect(self.on_btn_start_stop_clicked)
        self.ui.btnSaveLog.clicked.connect(self.on_btn_save_log_clicked)
        self.ui.btnSaveTranscript.clicked.connect(self.on_btn_save_transcript_clicked)
        self.timer.timeout.connect(self.on_timer_timeout)
        self.simulator.simulation_started.connect(self.on_simulation_started)
        self.simulator.simulation_stopped.connect(self.on_simulation_stopped)

    def update_buttons(self):
        selectable_items = self.simulator_scene.selectable_items()
        all_items_selected = all(item.model_item.logging_active for item in selectable_items)
        any_item_selected = any(item.model_item.logging_active for item in selectable_items)
        self.ui.btnToggleLog.setEnabled(len(self.simulator_scene.selectedItems()))
        self.ui.btnLogAll.setEnabled(not all_items_selected)
        self.ui.btnLogNone.setEnabled(any_item_selected)

    def __get_full_transcript(self) -> list:
        return self.simulator.transcript.get_for_all_participants(all_rounds=True,
                                                                  use_bit=self.ui.radioButtonTranscriptBit.isChecked())

    def update_view(self):
        for device_message in filter(None, map(str.rstrip, self.simulator.device_messages())):
            self.ui.textEditDevices.append(device_message)

        for log_msg in filter(None, map(str.rstrip, self.simulator.read_log_messages())):
            self.ui.textEditSimulation.append(log_msg)

        transcript = self.__get_full_transcript()
        for line in transcript[self.current_transcript_index:]:
            self.ui.textEditTranscript.append(line)

        self.current_transcript_index = len(transcript)
        current_repeat = str(self.simulator.current_repeat + 1) if self.simulator.is_simulating else "-"
        self.ui.lblCurrentRepeatValue.setText(current_repeat)

        current_item = self.simulator.current_item.index() if self.simulator.is_simulating else "-"
        self.ui.lblCurrentItemValue.setText(current_item)

    def update_rx_graphics_view(self):
        if self.scene_manager is None or not self.ui.graphicsViewPreview.isEnabled():
            return

        self.scene_manager.end = self.simulator.sniffer.rcv_device.current_index
        self.scene_manager.init_scene()
        self.scene_manager.show_full_scene()
        self.ui.graphicsViewPreview.update()

    def reset(self):
        self.ui.textEditDevices.clear()
        self.ui.textEditSimulation.clear()
        self.ui.textEditTranscript.clear()
        self.current_transcript_index = 0
        self.ui.lblCurrentRepeatValue.setText("-")
        self.ui.lblCurrentItemValue.setText("-")

    def emit_editing_finished_signals(self):
        if self.device_settings_rx_widget:
            self.device_settings_rx_widget.emit_editing_finished_signals()

        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.emit_editing_finished_signals()

        if self.sniff_settings_widget:
            self.sniff_settings_widget.emit_editing_finished_signals()

    def update_transcript_view(self):
        self.ui.textEditTranscript.setText("\n".join(self.__get_full_transcript()))

    def closeEvent(self, event: QCloseEvent):
        self.timer.stop()
        self.simulator.stop()
        time.sleep(0.1)
        self.simulator.cleanup()

        self.emit_editing_finished_signals()
        if self.device_settings_rx_widget:
            self.device_settings_rx_widget.emit_device_parameters_changed()
        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.emit_device_parameters_changed()
        if self.sniff_settings_widget:
            self.sniff_settings_widget.emit_sniff_parameters_changed()

        super().closeEvent(event)

    @pyqtSlot()
    def on_simulation_started(self):
        for i in range(3):
            self.ui.tabWidgetSimulatorSettings.setTabEnabled(i, False)
        self.ui.checkBoxCaptureFullRX.setDisabled(True)
        self.reset()
        self.timer.start(self.update_interval)
        self.ui.btnStartStop.setIcon(QIcon.fromTheme("media-playback-stop"))
        self.ui.btnStartStop.setText("Stop")

        if not self.rx_needed:
            return

        rx_device = self.simulator.sniffer.rcv_device
        for item in self.scene_manager.scene.items():
            if isinstance(item, QGraphicsTextItem):
                self.scene_manager.scene.removeItem(item)

        if hasattr(rx_device.data, "real"):
            self.ui.graphicsViewPreview.setEnabled(True)
            if self.ui.checkBoxCaptureFullRX.isChecked():
                self.scene_manager.plot_data = rx_device.data.real
            else:
                self.scene_manager.data_array = rx_device.data.real
        else:
            self.ui.graphicsViewPreview.setEnabled(False)
            if self.ui.checkBoxCaptureFullRX.isChecked():
                self.scene_manager.plot_data = np.array([])
            else:
                self.scene_manager.data_array = np.array([])
            self.scene_manager.scene.addText("Could not generate RX preview.")

    @pyqtSlot()
    def on_simulation_stopped(self):
        self.ui.tabWidgetSimulatorSettings.setTabEnabled(0, True)
        self.ui.tabWidgetSimulatorSettings.setTabEnabled(1, self.rx_needed)
        self.ui.tabWidgetSimulatorSettings.setTabEnabled(2, self.tx_needed)

        self.timer.stop()
        self.update_view()
        self.ui.btnStartStop.setIcon(QIcon.fromTheme("media-playback-start"))
        self.ui.btnStartStop.setText("Start")
        self.ui.checkBoxCaptureFullRX.setEnabled(True)

    @pyqtSlot()
    def on_btn_log_all_clicked(self):
        self.simulator_scene.log_all_items(True)

    @pyqtSlot()
    def on_btn_log_none_clicked(self):
        self.simulator_scene.log_all_items(False)

    @pyqtSlot()
    def on_btn_toggle_clicked(self):
        self.simulator_scene.log_toggle_selected_items()

    @pyqtSlot()
    def on_btn_save_log_clicked(self):
        file_path = QFileDialog.getSaveFileName(self, "Save log", "", "Log file (*.log)")

        if file_path[0] == "":
            return

        log_string = self.ui.textEditSimulation.toPlainText()

        try:
            with open(str(file_path[0]), "w") as f:
                f.write(log_string)
        except Exception as e:
            QMessageBox.critical(self, "Error saving log", e.args[0])

    @pyqtSlot()
    def on_btn_save_transcript_clicked(self):
        file_path = QFileDialog.getSaveFileName(self, "Save transcript", "", "Text file (*.txt)")

        if file_path[0] == "":
            return

        transcript = self.ui.textEditTranscript.toPlainText()

        try:
            with open(str(file_path[0]), "w") as f:
                f.write(transcript)
        except Exception as e:
            QMessageBox.critical(self, "Error saving transcript", e.args[0])

    @pyqtSlot()
    def on_btn_start_stop_clicked(self):
        if self.simulator.is_simulating:
            self.simulator.stop()
        else:
            if self.rx_needed:
                self.device_settings_rx_widget.emit_editing_finished_signals()
                self.sniff_settings_widget.emit_editing_finished_signals()

                self.simulator.sniffer.rcv_device.current_index = 0
                self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = not self.ui.checkBoxCaptureFullRX.isChecked()

            if self.tx_needed:
                self.device_settings_tx_widget.emit_editing_finished_signals()

            self.simulator.start()

    @pyqtSlot()
    def on_timer_timeout(self):
        self.update_view()
        self.update_rx_graphics_view()

    @pyqtSlot()
    def on_selected_rx_device_changed(self):
        dev_name = self.device_settings_rx_widget.ui.cbDevice.currentText()
        self.simulator.sniffer.device_name = dev_name
        self.device_settings_rx_widget.device = self.simulator.sniffer.rcv_device

    @pyqtSlot()
    def on_selected_tx_device_changed(self):
        old_name = self.simulator.sender.device_name
        try:
            dev_name = self.device_settings_tx_widget.ui.cbDevice.currentText()
            self.simulator.sender.device_name = dev_name
            self.device_settings_tx_widget.device = self.simulator.sender.device
        except Exception as e:
            self.device_settings_tx_widget.ui.cbDevice.setCurrentText(old_name)
            Errors.generic_error("Error occurred", str(e))

    @pyqtSlot()
    def on_btn_test_sniff_settings_clicked(self):
        def on_dialog_finished():
            self.device_settings_rx_widget.bootstrap(self.project_manager.simulator_rx_conf)
            self.sniff_settings_widget.bootstrap(self.project_manager.device_conf)

        self.device_settings_rx_widget.emit_device_parameters_changed()
        self.sniff_settings_widget.emit_sniff_parameters_changed()

        psd = ProtocolSniffDialog(self.project_manager, signals=self.sniff_settings_widget.signals, parent=self)
        psd.device_settings_widget.bootstrap(self.project_manager.simulator_rx_conf)
        psd.device_settings_widget.device_parameters_changed.connect(self.rx_parameters_changed.emit)
        psd.sniff_settings_widget.sniff_parameters_changed.connect(self.sniff_parameters_changed.emit)
        psd.finished.connect(on_dialog_finished)
        psd.ui.btnAccept.hide()
        psd.show()

    @pyqtSlot()
    def on_radio_button_transcript_hex_clicked(self):
        self.update_transcript_view()

    @pyqtSlot()
    def on_radio_button_transcript_bit_clicked(self):
        self.update_transcript_view()

    @pyqtSlot()
    def on_checkbox_capture_full_rx_clicked(self):
        self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = not self.ui.checkBoxCaptureFullRX.isChecked()
        if self.ui.checkBoxCaptureFullRX.isChecked():
            self.scene_manager = LiveSceneManager(np.array([]), parent=self)
            self.ui.graphicsViewPreview.setScene(self.scene_manager.scene)
        else:
            self.scene_manager = SniffSceneManager(np.array([]), parent=self)

            self.ui.graphicsViewPreview.setScene(self.scene_manager.scene)

    @pyqtSlot()
    def on_btn_save_rx_clicked(self):
        rx_device = self.simulator.sniffer.rcv_device
        if isinstance(rx_device.data, np.ndarray):
            filename = FileOperator.get_save_file_name("simulation_capture.complex")
            if filename:
                rx_device.data[:rx_device.current_index].tofile(filename)
                self.rx_file_saved.emit(filename)

    @pyqtSlot()
    def on_btn_open_in_analysis_clicked(self):
        text = self.ui.textEditTranscript.toPlainText()
        if len(text) > 0:
            self.open_in_analysis_requested.emit(text)
            self.close()
Beispiel #2
0
class RecvDialog(QWidget):
    device_parameters_changed = pyqtSignal(dict)
    change_tab = pyqtSignal()
    start_after_close = pyqtSignal()

    def __init__(self,
                 project_manager: ProjectManager,
                 is_tx: bool,
                 continuous_send_mode=False,
                 parent=None,
                 testing_mode=False):
        super().__init__(parent)
        self.is_tx = is_tx
        self.update_interval = 25

        # This flag is needed. Will cause memory leak otherwise.
        # self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWindowFlags(Qt.Window)

        self.testing_mode = testing_mode

        self.ui = Ui_SendRecvDialog()
        self.ui.setupUi(self)
        self.setFixedSize(QtCore.QSize(1000, 300))
        # self.setMaximumSize(QtCore.QSize(500, 500))

        util.set_splitter_stylesheet(self.ui.splitter)

        self.graphics_view = None  # type: QGraphicsView

        self.backend_handler = BackendHandler()

        self.ui.btnStop.setEnabled(False)
        # self.ui.btnSave.setEnabled(False)

        self.start = 0
        self.hide_send_ui_items()

        self.device_settings_widget = DeviceSettingsWidget(
            project_manager,
            is_tx,
            backend_handler=self.backend_handler,
            continuous_send_mode=continuous_send_mode)
        self.device_settings_widget.setMaximumSize(500, 300)

        # self.ui.scrollAreaWidgetContents_2.layout().insertWidget(0, self.device_settings_widget)

        if testing_mode:
            self.device_settings_widget.ui.cbDevice.setCurrentText(
                NetworkSDRInterfacePlugin.NETWORK_SDR_NAME)

        self.timer = QTimer(self)

        try:
            self.restoreGeometry(
                constants.SETTINGS.value("{}/geometry".format(
                    self.__class__.__name__)))
        except TypeError:
            pass

        self.ui.splitter.setSizes([0.3 * self.width(), 0.7 * self.width()])
        # self.ui.splitter.setFixedSize(0.3 * self.width(), 0.7 * self.width())

    @property
    def is_rx(self) -> bool:
        return not self.is_tx

    @property
    def has_empty_device_list(self):
        return self.device_settings_widget.ui.cbDevice.count() == 0

    @property
    def device(self) -> VirtualDevice:
        return self.device_settings_widget.device

    @device.setter
    def device(self, value):
        self.device_settings_widget.device = value

    @property
    def selected_device_name(self) -> str:
        return self.device_settings_widget.ui.cbDevice.currentText()

    def _eliminate_graphic_view(self):
        if self.graphics_view is not None:
            self.graphics_view.eliminate()

        self.graphics_view = None

    def hide_send_ui_items(self):
        for item in ("sliderYscale1", "sliderYscale2", "label_y_scale",
                     "label_y_scale2", "btnMon", "btnNuke2", "btnNuke1",
                     "lcdNumber", "btnRecordIQ", "btnConf", "btnSave",
                     "lblCurrentRepeatValue", "progressBarMessage",
                     "lblRepeatText", "lSamplesSentText", "progressBarSample",
                     "labelCurrentMessage"):
            getattr(self.ui, item).hide()

    def hide_receive_ui_items(self):
        for item in ("lSamplesCaptured", "lSamplesCapturedText", "lSignalSize",
                     "lSignalSizeText", "lTime", "lTimeText",
                     "labelReceiveBufferFull",
                     "lReceiveBufferFullText"):  #btnSave
            getattr(self.ui, item).hide()

    def set_device_ui_items_enabled(self, enabled: bool):
        self.device_settings_widget.setEnabled(enabled)

    def create_connects(self):
        self.ui.btnStart.clicked.connect(self.on_start_clicked)
        self.ui.btnStop.clicked.connect(self.on_stop_clicked)
        self.ui.btnClear.clicked.connect(self.on_clear_clicked)

        self.timer.timeout.connect(self.update_view)
        self.ui.sliderYscale.valueChanged.connect(
            self.on_slider_y_scale_value_changed)

        self.device_settings_widget.selected_device_changed.connect(
            self.on_selected_device_changed)
        self.device_settings_widget.device_parameters_changed.connect(
            self.device_parameters_changed.emit)

    def _create_device_connects(self):

        self.device.stopped.connect(self.on_device_stopped)
        self.device.started.connect(self.on_device_started)
        self.device.sender_needs_restart.connect(self._restart_device_thread)

    def reset(self):
        self.device.current_index = 0
        self.device.current_iteration = 0
        self.ui.lSamplesCaptured.setText("0")
        self.ui.lSignalSize.setText("0")
        self.ui.lTime.setText("0")
        self.ui.lblCurrentRepeatValue.setText("-")
        self.ui.progressBarSample.setValue(0)
        self.ui.progressBarMessage.setValue(0)
        # self.ui.btnSave.setEnabled(False)

    # def init_device(self):
    #     pass

    def save_before_close(self):
        return True

    def emit_editing_finished_signals(self):
        self.device_settings_widget.emit_editing_finished_signals()

    @pyqtSlot()
    def on_selected_device_changed(self):
        if hasattr(self.scene_manager, "plot_data"):
            self.scene_manager.plot_data = None

        self.init_device()

        self.graphics_view.scene_manager = self.scene_manager
        self.graphics_view.setScene(self.scene_manager.scene)

    @pyqtSlot()
    def on_start_clicked(self):
        self.emit_editing_finished_signals()

    @pyqtSlot()
    def on_stop_clicked(self):
        self.device.stop("Stopped receiving: Stop button clicked")

    @pyqtSlot()
    def on_device_stopped(self):
        if self.graphics_view is not None:
            self.graphics_view.capturing_data = False
        self.set_device_ui_items_enabled(True)
        self.ui.btnStart.setEnabled(True)
        self.ui.btnSetting.setEnabled(True)
        self.ui.btnStop.setEnabled(False)
        # self.ui.btnStop.setEnabled(False)
        # self.ui.btnSave.setEnabled(self.device.current_index > 0)
        self.device_settings_widget.ui.comboBoxDeviceIdentifier.setEnabled(
            True)
        self.device_settings_widget.ui.btnRefreshDeviceIdentifier.setEnabled(
            True)
        self.device_settings_widget.set_bandwidth_status()

        self.timer.stop()
        self.update_view()

    @pyqtSlot()
    def on_device_started(self):
        self.ui.txtEditErrors.clear()
        if self.graphics_view is not None:
            self.graphics_view.capturing_data = True
        #---------------------------------------
        self.ui.btnSave.setEnabled(True)
        # ---------------------------------------
        self.ui.btnStart.setEnabled(False)
        self.ui.btnStop.setEnabled(True)
        # self.ui.btnSetting.setEnabled(True)

        self.device_settings_widget.ui.comboBoxDeviceIdentifier.setEnabled(
            False)
        self.device_settings_widget.ui.btnRefreshDeviceIdentifier.setEnabled(
            False)

        self.timer.start(self.update_interval)

    def __parse_error_messages(self, messages):
        messages = messages.lower()

        if "no devices found for" in messages:
            self.device.stop_on_error("Could not establish connection to USRP")
            Errors.usrp_found()
            self.on_clear_clicked()

        elif any(e in messages
                 for e in ("hackrf_error_not_found", "hackrf_error_libusb")):
            self.device.stop_on_error(
                "Could not establish connection to HackRF")
            Errors.hackrf_not_found()
            self.on_clear_clicked()

        elif "no module named gnuradio" in messages:
            self.device.stop_on_error("Did not find gnuradio.")
            Errors.gnuradio_not_installed()
            self.on_clear_clicked()

        elif "rtlsdr-open: error code: -1" in messages:
            self.device.stop_on_error("Could not open a RTL-SDR device.")
            self.on_clear_clicked()

        elif "rtlsdr-open: error code: -12" in messages:
            self.device.stop_on_error("Could not open a RTL-SDR device")
            Errors.rtlsdr_sdr_driver()
            self.on_clear_clicked()

        elif "Address already in use" in messages:
            self._restart_device_thread()

    def update_view(self):
        try:
            self.ui.sliderYscale.setValue(
                int(self.graphics_view.transform().m22()))
        except AttributeError:
            return

        txt = self.ui.txtEditErrors.toPlainText()
        new_messages = self.device.read_messages()

        self.__parse_error_messages(new_messages)

        if len(new_messages) > 1:
            self.ui.txtEditErrors.setPlainText(txt + new_messages)

        self.ui.lSamplesCaptured.setText(
            Formatter.big_value_with_suffix(self.device.current_index,
                                            decimals=1))
        self.ui.lSignalSize.setText(
            locale.format_string("%.2f Мб",
                                 (8 * self.device.current_index) / (1024**2)))
        self.ui.lTime.setText(
            locale.format_string(
                "%.2f с", self.device.current_index / self.device.sample_rate))

        # if self.is_rx and self.device.data is not None and len(self.device.data) > 0:
        #     self.ui.labelReceiveBufferFull.setText("{0}%".format(int(100 * self.device.current_index /
        #                                                              len(self.device.data))))

        if self.device.current_index == 0:
            return False

        return True

    def _restart_device_thread(self):
        self.device.stop("Restarting with new port")

        if self.device.backend == Backends.grc:
            self.device.increase_gr_port()

        self.device.start()

    @pyqtSlot()
    def on_clear_clicked(self):
        pass

    def closeEvent(self, event: QCloseEvent):

        if self.device.backend is not Backends.none:
            self.emit_editing_finished_signals()

        self.timer.stop()

        self.device.stop("Dialog closed. Killing recording process.")
        logger.debug("Device stopped successfully.")

        if not self.testing_mode:
            if not self.save_before_close():
                event.ignore()
                return

        time.sleep(0.1)
        if self.device.backend not in (Backends.none, Backends.network):
            # Backend none is selected, when no device is available
            logger.debug("Cleaning up device")
            self.device.cleanup()
            logger.debug("Successfully cleaned up device")
            self.device_settings_widget.emit_device_parameters_changed()

        constants.SETTINGS.setValue(
            "{}/geometry".format(self.__class__.__name__), self.saveGeometry())

        if self.device is not None:
            self.device.free_data()

        self.scene_manager.eliminate()

        self._eliminate_graphic_view()
        self.on_stop_clicked()

        self.start_after_close.emit()
        super().closeEvent(event)

    @pyqtSlot(int)
    def on_slider_y_scale_value_changed(self, new_value: int):
        pass
Beispiel #3
0
class SimulatorDialog(QDialog):
    rx_parameters_changed = pyqtSignal(dict)
    tx_parameters_changed = pyqtSignal(dict)
    sniff_parameters_changed = pyqtSignal(dict)
    open_in_analysis_requested = pyqtSignal(str)
    rx_file_saved = pyqtSignal(str)

    def __init__(self, simulator_config, modulators,
                 expression_parser, project_manager: ProjectManager, signals: list = None,
                 signal_tree_model=None,
                 parent=None):
        super().__init__(parent)
        self.ui = Ui_DialogSimulator()
        self.ui.setupUi(self)

        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowFlags(Qt.Window)

        self.simulator_config = simulator_config  # type: SimulatorConfiguration
        self.rx_needed = self.simulator_config.rx_needed
        self.tx_needed = self.simulator_config.tx_needed

        self.current_transcript_index = 0

        self.simulator_scene = SimulatorScene(mode=1,
                                              simulator_config=self.simulator_config)
        self.ui.gvSimulator.setScene(self.simulator_scene)
        self.project_manager = project_manager

        self.update_interval = 25

        self.timer = QTimer(self)

        self.backend_handler = BackendHandler()
        if self.rx_needed:
            self.device_settings_rx_widget = DeviceSettingsWidget(project_manager,
                                                                  is_tx=False,
                                                                  backend_handler=self.backend_handler)

            self.sniff_settings_widget = SniffSettingsWidget(self.device_settings_rx_widget.ui.cbDevice.currentText(),
                                                             project_manager,
                                                             signal=None,
                                                             backend_handler=self.backend_handler,
                                                             network_raw_mode=True, signals=signals)

            self.device_settings_rx_widget.device = self.sniff_settings_widget.sniffer.rcv_device

            self.sniff_settings_widget.ui.lineEdit_sniff_OutputFile.hide()
            self.sniff_settings_widget.ui.label_sniff_OutputFile.hide()
            self.sniff_settings_widget.ui.label_sniff_viewtype.hide()
            self.sniff_settings_widget.ui.checkBox_sniff_Timestamp.hide()
            self.sniff_settings_widget.ui.comboBox_sniff_viewtype.hide()

            self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(0, self.device_settings_rx_widget)
            self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(1, self.sniff_settings_widget)

            sniffer = self.sniff_settings_widget.sniffer

            self.scene_manager = SniffSceneManager(np.array([], dtype=sniffer.rcv_device.data_type), parent=self)
            self.ui.graphicsViewPreview.setScene(self.scene_manager.scene)
        else:
            self.device_settings_rx_widget = self.sniff_settings_widget = self.scene_manager = None
            self.ui.tabWidgetSimulatorSettings.setTabEnabled(1, False)
            self.ui.graphicsViewPreview.hide()
            self.ui.btnSaveRX.hide()
            self.ui.checkBoxCaptureFullRX.hide()

            sniffer = None

        if self.tx_needed:
            self.device_settings_tx_widget = DeviceSettingsWidget(project_manager, is_tx=True,
                                                                  backend_handler=self.backend_handler,
                                                                  continuous_send_mode=True)
            self.device_settings_tx_widget.ui.spinBoxNRepeat.hide()
            self.device_settings_tx_widget.ui.labelNRepeat.hide()

            self.modulation_settings_widget = ModulationSettingsWidget(modulators, signal_tree_model=signal_tree_model,
                                                                       parent=None)

            self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(0, self.device_settings_tx_widget)
            self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(1, self.modulation_settings_widget)
            send_device = self.device_settings_tx_widget.ui.cbDevice.currentText()
            sender = EndlessSender(self.backend_handler, send_device)
        else:
            self.device_settings_tx_widget = self.modulation_settings_widget = None
            self.ui.tabWidgetSimulatorSettings.setTabEnabled(2, False)

            sender = None

        self.simulator = Simulator(self.simulator_config, modulators, expression_parser, project_manager,
                                   sniffer=sniffer, sender=sender)

        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.device = self.simulator.sender.device

        self.update_buttons()
        self.create_connects()

        if self.device_settings_rx_widget:
            self.device_settings_rx_widget.bootstrap(project_manager.simulator_rx_conf)

        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.bootstrap(project_manager.simulator_tx_conf)

        self.ui.textEditTranscript.setFont(util.get_monospace_font())

        if settings.read('default_view', 0, int) == 1:
            self.ui.radioButtonTranscriptHex.setChecked(True)

    def create_connects(self):
        if self.rx_needed:
            self.device_settings_rx_widget.selected_device_changed.connect(self.on_selected_rx_device_changed)
            self.device_settings_rx_widget.device_parameters_changed.connect(self.rx_parameters_changed.emit)

            self.sniff_settings_widget.sniff_parameters_changed.connect(self.sniff_parameters_changed.emit)

            self.ui.btnSaveRX.clicked.connect(self.on_btn_save_rx_clicked)
            self.ui.checkBoxCaptureFullRX.clicked.connect(self.on_checkbox_capture_full_rx_clicked)

            self.ui.btnTestSniffSettings.clicked.connect(self.on_btn_test_sniff_settings_clicked)
            self.ui.btnOpenInAnalysis.clicked.connect(self.on_btn_open_in_analysis_clicked)

        if self.tx_needed:
            self.device_settings_tx_widget.selected_device_changed.connect(self.on_selected_tx_device_changed)
            self.device_settings_tx_widget.device_parameters_changed.connect(self.tx_parameters_changed.emit)

        self.ui.radioButtonTranscriptBit.clicked.connect(self.on_radio_button_transcript_bit_clicked)
        self.ui.radioButtonTranscriptHex.clicked.connect(self.on_radio_button_transcript_hex_clicked)

        self.simulator_scene.selectionChanged.connect(self.update_buttons)
        self.simulator_config.items_updated.connect(self.update_buttons)

        self.ui.btnLogAll.clicked.connect(self.on_btn_log_all_clicked)
        self.ui.btnLogNone.clicked.connect(self.on_btn_log_none_clicked)
        self.ui.btnToggleLog.clicked.connect(self.on_btn_toggle_clicked)

        self.ui.btnStartStop.clicked.connect(self.on_btn_start_stop_clicked)
        self.ui.btnSaveLog.clicked.connect(self.on_btn_save_log_clicked)
        self.ui.btnSaveTranscript.clicked.connect(self.on_btn_save_transcript_clicked)
        self.timer.timeout.connect(self.on_timer_timeout)
        self.simulator.simulation_started.connect(self.on_simulation_started)
        self.simulator.simulation_stopped.connect(self.on_simulation_stopped)

    def update_buttons(self):
        selectable_items = self.simulator_scene.selectable_items()
        all_items_selected = all(item.model_item.logging_active for item in selectable_items)
        any_item_selected = any(item.model_item.logging_active for item in selectable_items)
        self.ui.btnToggleLog.setEnabled(len(self.simulator_scene.selectedItems()))
        self.ui.btnLogAll.setEnabled(not all_items_selected)
        self.ui.btnLogNone.setEnabled(any_item_selected)

    def __get_full_transcript(self) -> list:
        return self.simulator.transcript.get_for_all_participants(all_rounds=True,
                                                                  use_bit=self.ui.radioButtonTranscriptBit.isChecked())

    def update_view(self):
        for device_message in filter(None, map(str.rstrip, self.simulator.device_messages())):
            self.ui.textEditDevices.append(device_message)

        for log_msg in filter(None, map(str.rstrip, self.simulator.read_log_messages())):
            self.ui.textEditSimulation.append(log_msg)

        transcript = self.__get_full_transcript()
        for line in transcript[self.current_transcript_index:]:
            self.ui.textEditTranscript.append(line)

        self.current_transcript_index = len(transcript)
        current_repeat = str(self.simulator.current_repeat + 1) if self.simulator.is_simulating else "-"
        self.ui.lblCurrentRepeatValue.setText(current_repeat)

        current_item = self.simulator.current_item.index() if self.simulator.is_simulating else "-"
        self.ui.lblCurrentItemValue.setText(current_item)

    def update_rx_graphics_view(self):
        if self.scene_manager is None or not self.ui.graphicsViewPreview.isEnabled():
            return

        self.scene_manager.end = self.simulator.sniffer.rcv_device.current_index
        self.scene_manager.init_scene()
        self.scene_manager.show_full_scene()
        self.ui.graphicsViewPreview.update()

    def reset(self):
        self.ui.textEditDevices.clear()
        self.ui.textEditSimulation.clear()
        self.ui.textEditTranscript.clear()
        self.current_transcript_index = 0
        self.ui.lblCurrentRepeatValue.setText("-")
        self.ui.lblCurrentItemValue.setText("-")

    def emit_editing_finished_signals(self):
        if self.device_settings_rx_widget:
            self.device_settings_rx_widget.emit_editing_finished_signals()

        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.emit_editing_finished_signals()

        if self.sniff_settings_widget:
            self.sniff_settings_widget.emit_editing_finished_signals()

    def update_transcript_view(self):
        self.ui.textEditTranscript.setText("\n".join(self.__get_full_transcript()))

    def closeEvent(self, event: QCloseEvent):
        self.timer.stop()
        self.simulator.stop()

        self.simulator.cleanup()

        self.emit_editing_finished_signals()
        if self.device_settings_rx_widget:
            self.device_settings_rx_widget.emit_device_parameters_changed()
        if self.device_settings_tx_widget:
            self.device_settings_tx_widget.emit_device_parameters_changed()
        if self.sniff_settings_widget:
            self.sniff_settings_widget.emit_sniff_parameters_changed()

        super().closeEvent(event)

    @pyqtSlot()
    def on_simulation_started(self):
        for i in range(3):
            self.ui.tabWidgetSimulatorSettings.setTabEnabled(i, False)
        self.ui.checkBoxCaptureFullRX.setDisabled(True)
        self.reset()
        self.timer.start(self.update_interval)
        self.ui.btnStartStop.setIcon(QIcon.fromTheme("media-playback-stop"))
        self.ui.btnStartStop.setText("Stop")

        if not self.rx_needed:
            return

        rx_device = self.simulator.sniffer.rcv_device
        for item in self.scene_manager.scene.items():
            if isinstance(item, QGraphicsTextItem):
                self.scene_manager.scene.removeItem(item)

        if hasattr(rx_device.data, "real"):
            self.ui.graphicsViewPreview.setEnabled(True)
            if self.ui.checkBoxCaptureFullRX.isChecked():
                self.scene_manager.plot_data = rx_device.data.real
            else:
                self.scene_manager.data_array = rx_device.data.real
        else:
            self.ui.graphicsViewPreview.setEnabled(False)
            if self.ui.checkBoxCaptureFullRX.isChecked():
                self.scene_manager.plot_data = np.array([], dtype=rx_device.data_type)
            else:
                self.scene_manager.data_array = np.array([], dtype=rx_device.data_type)
            self.scene_manager.scene.addText("Could not generate RX preview.")

    @pyqtSlot()
    def on_simulation_stopped(self):
        self.ui.tabWidgetSimulatorSettings.setTabEnabled(0, True)
        self.ui.tabWidgetSimulatorSettings.setTabEnabled(1, self.rx_needed)
        self.ui.tabWidgetSimulatorSettings.setTabEnabled(2, self.tx_needed)

        self.timer.stop()
        self.update_view()
        self.ui.btnStartStop.setIcon(QIcon.fromTheme("media-playback-start"))
        self.ui.btnStartStop.setText("Start")
        self.ui.checkBoxCaptureFullRX.setEnabled(True)

    @pyqtSlot()
    def on_btn_log_all_clicked(self):
        self.simulator_scene.log_all_items(True)

    @pyqtSlot()
    def on_btn_log_none_clicked(self):
        self.simulator_scene.log_all_items(False)

    @pyqtSlot()
    def on_btn_toggle_clicked(self):
        self.simulator_scene.log_toggle_selected_items()

    @pyqtSlot()
    def on_btn_save_log_clicked(self):
        file_path = QFileDialog.getSaveFileName(self, "Save log", "", "Log file (*.log)")

        if file_path[0] == "":
            return

        log_string = self.ui.textEditSimulation.toPlainText()

        try:
            with open(str(file_path[0]), "w") as f:
                f.write(log_string)
        except Exception as e:
            QMessageBox.critical(self, "Error saving log", e.args[0])

    @pyqtSlot()
    def on_btn_save_transcript_clicked(self):
        file_path = QFileDialog.getSaveFileName(self, "Save transcript", "", "Text file (*.txt)")

        if file_path[0] == "":
            return

        transcript = self.ui.textEditTranscript.toPlainText()

        try:
            with open(str(file_path[0]), "w") as f:
                f.write(transcript)
        except Exception as e:
            QMessageBox.critical(self, "Error saving transcript", e.args[0])

    @pyqtSlot()
    def on_btn_start_stop_clicked(self):
        if self.simulator.is_simulating:
            self.simulator.stop()
        else:
            if self.rx_needed:
                self.device_settings_rx_widget.emit_editing_finished_signals()
                self.sniff_settings_widget.emit_editing_finished_signals()

                self.simulator.sniffer.rcv_device.current_index = 0
                self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = not self.ui.checkBoxCaptureFullRX.isChecked()

            if self.tx_needed:
                self.device_settings_tx_widget.emit_editing_finished_signals()

            self.simulator.start()

    @pyqtSlot()
    def on_timer_timeout(self):
        self.update_view()
        self.update_rx_graphics_view()

    @pyqtSlot()
    def on_selected_rx_device_changed(self):
        dev_name = self.device_settings_rx_widget.ui.cbDevice.currentText()
        self.simulator.sniffer.device_name = dev_name
        self.device_settings_rx_widget.device = self.simulator.sniffer.rcv_device
        self.__set_rx_scene()

    @pyqtSlot()
    def on_selected_tx_device_changed(self):
        old_name = self.simulator.sender.device_name
        try:
            dev_name = self.device_settings_tx_widget.ui.cbDevice.currentText()
            self.simulator.sender.device_name = dev_name
            self.device_settings_tx_widget.device = self.simulator.sender.device
        except Exception as e:
            self.device_settings_tx_widget.ui.cbDevice.setCurrentText(old_name)
            Errors.exception(e)

    @pyqtSlot()
    def on_btn_test_sniff_settings_clicked(self):
        def on_dialog_finished():
            self.device_settings_rx_widget.bootstrap(self.project_manager.simulator_rx_conf)
            self.sniff_settings_widget.bootstrap(self.project_manager.device_conf)

        self.device_settings_rx_widget.emit_device_parameters_changed()
        self.sniff_settings_widget.emit_sniff_parameters_changed()

        psd = ProtocolSniffDialog(self.project_manager, signals=self.sniff_settings_widget.signals, parent=self)
        psd.device_settings_widget.bootstrap(self.project_manager.simulator_rx_conf)
        psd.device_settings_widget.device_parameters_changed.connect(self.rx_parameters_changed.emit)
        psd.sniff_settings_widget.sniff_parameters_changed.connect(self.sniff_parameters_changed.emit)
        psd.finished.connect(on_dialog_finished)
        psd.ui.btnAccept.hide()
        psd.show()

    @pyqtSlot()
    def on_radio_button_transcript_hex_clicked(self):
        self.update_transcript_view()

    @pyqtSlot()
    def on_radio_button_transcript_bit_clicked(self):
        self.update_transcript_view()

    def __set_rx_scene(self):
        if not self.rx_needed:
            return

        if self.ui.checkBoxCaptureFullRX.isChecked():
            self.scene_manager = LiveSceneManager(np.array([], dtype=self.simulator.sniffer.rcv_device.data_type),
                                                  parent=self)
            self.ui.graphicsViewPreview.setScene(self.scene_manager.scene)
        else:
            self.scene_manager = SniffSceneManager(np.array([], dtype=self.simulator.sniffer.rcv_device.data_type),
                                                   parent=self)

            self.ui.graphicsViewPreview.setScene(self.scene_manager.scene)

    @pyqtSlot()
    def on_checkbox_capture_full_rx_clicked(self):
        self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = not self.ui.checkBoxCaptureFullRX.isChecked()
        self.__set_rx_scene()

    @pyqtSlot()
    def on_btn_save_rx_clicked(self):
        rx_device = self.simulator.sniffer.rcv_device
        if isinstance(rx_device.data, np.ndarray) or isinstance(rx_device.data, IQArray):
            data = IQArray(rx_device.data[:rx_device.current_index])
            filename = FileOperator.ask_signal_file_name_and_save("simulation_capture", data,
                                                                  sample_rate=rx_device.sample_rate, parent=self)
            if filename:
                data.tofile(filename)
                self.rx_file_saved.emit(filename)

    @pyqtSlot()
    def on_btn_open_in_analysis_clicked(self):
        text = self.ui.textEditTranscript.toPlainText()
        if len(text) > 0:
            self.open_in_analysis_requested.emit(text)
            self.close()
Beispiel #4
0
class SimulatorDialog(QDialog):
    rx_parameters_changed = pyqtSignal(dict)
    tx_parameters_changed = pyqtSignal(dict)
    sniff_parameters_changed = pyqtSignal(dict)

    def __init__(self,
                 simulator_config,
                 modulators,
                 expression_parser,
                 project_manager: ProjectManager,
                 parent=None):
        super().__init__(parent)
        self.ui = Ui_DialogSimulator()
        self.ui.setupUi(self)

        self.simulator_config = simulator_config

        self.simulator_scene = SimulatorScene(
            mode=1, simulator_config=self.simulator_config)
        self.ui.gvSimulator.setScene(self.simulator_scene)
        self.project_manager = project_manager

        self.update_interval = 25

        self.timer = QTimer(self)

        self.backend_handler = BackendHandler()
        self.device_settings_rx_widget = DeviceSettingsWidget(
            project_manager, is_tx=False, backend_handler=self.backend_handler)

        self.sniff_settings_widget = SniffSettingsWidget(
            self.device_settings_rx_widget.ui.cbDevice.currentText(),
            project_manager,
            signal=None,
            backend_handler=self.backend_handler,
            real_time=True,
            network_raw_mode=True)

        self.device_settings_rx_widget.device = self.sniff_settings_widget.sniffer.rcv_device

        self.sniff_settings_widget.ui.lineEdit_sniff_OutputFile.hide()
        self.sniff_settings_widget.ui.label_sniff_OutputFile.hide()
        self.sniff_settings_widget.ui.label_sniff_viewtype.hide()
        self.sniff_settings_widget.ui.checkBox_sniff_Timestamp.hide()
        self.sniff_settings_widget.ui.comboBox_sniff_viewtype.hide()

        self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(
            0, self.device_settings_rx_widget)
        self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(
            1, self.sniff_settings_widget)

        self.device_settings_tx_widget = DeviceSettingsWidget(
            project_manager, is_tx=True, backend_handler=self.backend_handler)
        self.device_settings_tx_widget.ui.spinBoxNRepeat.hide()
        self.device_settings_tx_widget.ui.labelNRepeat.hide()

        self.modulation_settings_widget = ModulationSettingsWidget(modulators,
                                                                   parent=None)

        self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(
            0, self.device_settings_tx_widget)
        self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(
            1, self.modulation_settings_widget)

        send_device = self.device_settings_tx_widget.ui.cbDevice.currentText()
        self.simulator = Simulator(self.simulator_config,
                                   modulators,
                                   expression_parser,
                                   project_manager,
                                   sniffer=self.sniff_settings_widget.sniffer,
                                   sender=EndlessSender(
                                       self.backend_handler, send_device))

        self.device_settings_tx_widget.device = self.simulator.sender.device

        self.scene_manager = SniffSceneManager(np.array([]), parent=self)
        self.ui.graphicsViewPreview.setScene(self.scene_manager.scene)

        self.update_buttons()
        self.create_connects()

        self.__bootstrap_device_settings(self.device_settings_rx_widget,
                                         project_manager.simulator_rx_conf)
        self.__bootstrap_sniff_settings(self.sniff_settings_widget,
                                        project_manager.simulator_rx_conf)
        self.__bootstrap_device_settings(self.device_settings_tx_widget,
                                         project_manager.simulator_tx_conf)

    @staticmethod
    def __bootstrap_device_settings(device_widget: DeviceSettingsWidget,
                                    config: dict):
        mapping = {
            "frequency": "spinBoxFreq",
            "sample_rate": "spinBoxSampleRate",
            "bandwidth": "spinBoxBandwidth",
            "gain": "spinBoxGain",
            "if_gain": "spinBoxIFGain",
            "baseband_gain": "spinBoxBasebandGain",
            "freq_correction": "spinBoxFreqCorrection"
        }

        if "name" in config:
            device_widget.ui.cbDevice.setCurrentText(config["name"])

        for key, value in config.items():
            widget = mapping.get(key, None)
            if widget:
                getattr(device_widget.ui, widget).setValue(value)
        device_widget.emit_editing_finished_signals()

    @staticmethod
    def __bootstrap_sniff_settings(sniff_widget: SniffSettingsWidget,
                                   config: dict):
        for key, value in config.items():
            if key == "bit_len":
                sniff_widget.ui.spinbox_sniff_BitLen.setValue(value)
            elif key == "center":
                sniff_widget.ui.spinbox_sniff_Center.setValue(value)
            elif key == "noise":
                sniff_widget.ui.spinbox_sniff_Noise.setValue(value)
            elif key == "tolerance":
                sniff_widget.ui.spinbox_sniff_ErrorTolerance.setValue(value)
            elif key == "modulation_index":
                sniff_widget.ui.combox_sniff_Modulation.setCurrentIndex(
                    int(value))
            elif key == "decoding_name":
                sniff_widget.ui.comboBox_sniff_encoding.setCurrentText(value)

        sniff_widget.emit_editing_finished_signals()

    def create_connects(self):
        self.device_settings_rx_widget.selected_device_changed.connect(
            self.on_selected_rx_device_changed)
        self.device_settings_rx_widget.device_parameters_changed.connect(
            self.rx_parameters_changed.emit)

        self.device_settings_tx_widget.selected_device_changed.connect(
            self.on_selected_tx_device_changed)
        self.device_settings_tx_widget.device_parameters_changed.connect(
            self.tx_parameters_changed.emit)

        self.sniff_settings_widget.sniff_parameters_changed.connect(
            self.sniff_parameters_changed.emit)

        self.simulator_scene.selectionChanged.connect(self.update_buttons)
        self.simulator_config.items_updated.connect(self.update_buttons)

        self.ui.btnLogAll.clicked.connect(self.on_btn_log_all_clicked)
        self.ui.btnLogNone.clicked.connect(self.on_btn_log_none_clicked)
        self.ui.btnToggleLog.clicked.connect(self.on_btn_toggle_clicked)

        self.ui.btnStartStop.clicked.connect(self.on_start_stop_clicked)
        self.ui.btnSaveLog.clicked.connect(self.on_save_log_clicked)
        self.timer.timeout.connect(self.on_timer_timeout)
        self.simulator.simulation_started.connect(self.on_simulation_started)
        self.simulator.simulation_stopped.connect(self.on_simulation_stopped)

    def on_btn_log_all_clicked(self):
        self.simulator_scene.log_all_items(True)

    def on_btn_log_none_clicked(self):
        self.simulator_scene.log_all_items(False)

    def on_btn_toggle_clicked(self):
        self.simulator_scene.log_toggle_selected_items()

    def update_buttons(self):
        selectable_items = self.simulator_scene.selectable_items()
        all_items_selected = all(item.model_item.logging_active
                                 for item in selectable_items)
        any_item_selected = any(item.model_item.logging_active
                                for item in selectable_items)
        self.ui.btnToggleLog.setEnabled(
            len(self.simulator_scene.selectedItems()))
        self.ui.btnLogAll.setEnabled(not all_items_selected)
        self.ui.btnLogNone.setEnabled(any_item_selected)

    def update_view(self):
        txt = self.ui.textEditDevices.toPlainText()
        device_messages = self.simulator.device_messages()

        if len(device_messages) > 1:
            self.ui.textEditDevices.setPlainText(txt + device_messages)

        txt = self.ui.textEditSimulation.toPlainText()
        simulator_messages = self.simulator.read_messages()

        if len(simulator_messages) > 1:
            self.ui.textEditSimulation.setPlainText(txt + simulator_messages)

        self.ui.textEditSimulation.verticalScrollBar().setValue(
            self.ui.textEditSimulation.verticalScrollBar().maximum())

        current_repeat = str(self.simulator.current_repeat +
                             1) if self.simulator.is_simulating else "-"
        self.ui.lblCurrentRepeatValue.setText(current_repeat)

        current_item = self.simulator.current_item.index(
        ) if self.simulator.is_simulating else "-"
        self.ui.lblCurrentItemValue.setText(current_item)

    def update_rx_graphics_view(self):
        if not self.ui.graphicsViewPreview.isEnabled():
            return

        self.scene_manager.end = self.simulator.sniffer.rcv_device.current_index
        self.scene_manager.init_scene()
        self.scene_manager.show_full_scene()
        self.ui.graphicsViewPreview.update()

    def on_save_log_clicked(self):
        file_path = QFileDialog.getSaveFileName(self, "Save log", "",
                                                "Log file (*.log)")

        if file_path[0] == "":
            return

        log_string = self.ui.textEditSimulation.toPlainText()

        try:
            with open(str(file_path[0]), "w") as f:
                f.write(log_string)
        except Exception as e:
            QMessageBox.critical(self, "Error saving log", e.args[0])

    def on_start_stop_clicked(self):
        if self.simulator.is_simulating:
            self.simulator.stop()
        else:
            self.device_settings_rx_widget.emit_editing_finished_signals()
            self.device_settings_tx_widget.emit_editing_finished_signals()
            self.sniff_settings_widget.emit_editing_finished_signals()

            self.simulator.start()

    def on_simulation_started(self):
        self.reset()
        self.timer.start(self.update_interval)
        self.ui.btnStartStop.setIcon(QIcon.fromTheme("media-playback-stop"))
        self.ui.btnStartStop.setText("Stop")

        rx_device = self.simulator.sniffer.rcv_device
        for item in self.scene_manager.scene.items():
            if isinstance(item, QGraphicsTextItem):
                self.scene_manager.scene.removeItem(item)

        if hasattr(rx_device.data, "real"):
            self.ui.graphicsViewPreview.setEnabled(True)
            self.scene_manager.data_array = rx_device.data.real
        else:
            self.ui.graphicsViewPreview.setEnabled(False)
            self.scene_manager.data_array = np.array([])
            self.scene_manager.scene.addText("Could not generate RX preview.")

    def on_simulation_stopped(self):
        self.timer.stop()
        self.update_view()
        self.ui.btnStartStop.setIcon(QIcon.fromTheme("media-playback-start"))
        self.ui.btnStartStop.setText("Start")

    def reset(self):
        self.ui.textEditDevices.clear()
        self.ui.textEditSimulation.clear()
        self.ui.lblCurrentRepeatValue.setText("-")
        self.ui.lblCurrentItemValue.setText("-")

    def emit_editing_finished_signals(self):
        self.device_settings_rx_widget.emit_editing_finished_signals()
        self.device_settings_tx_widget.emit_editing_finished_signals()
        self.sniff_settings_widget.emit_editing_finished_signals()

    def closeEvent(self, event: QCloseEvent):
        self.emit_editing_finished_signals()
        self.device_settings_rx_widget.emit_device_parameters_changed()
        self.device_settings_tx_widget.emit_device_parameters_changed()
        self.sniff_settings_widget.emit_sniff_parameters_changed()

        self.timer.stop()
        self.simulator.stop()
        time.sleep(0.1)
        self.simulator.cleanup()

        super().closeEvent(event)

    @pyqtSlot()
    def on_timer_timeout(self):
        self.update_view()
        self.update_rx_graphics_view()

    @pyqtSlot()
    def on_selected_rx_device_changed(self):
        dev_name = self.device_settings_rx_widget.ui.cbDevice.currentText()
        self.simulator.sniffer.device_name = dev_name
        self.device_settings_rx_widget.device = self.simulator.sniffer.rcv_device

    @pyqtSlot()
    def on_selected_tx_device_changed(self):
        old_name = self.simulator.sender.device_name
        try:
            dev_name = self.device_settings_tx_widget.ui.cbDevice.currentText()
            self.simulator.sender.device_name = dev_name
            self.device_settings_tx_widget.device = self.simulator.sender.device
        except Exception as e:
            self.device_settings_tx_widget.ui.cbDevice.setCurrentText(old_name)
            Errors.generic_error("Error occurred", str(e))
Beispiel #5
0
class SendRecvDialog(QDialog):
    device_parameters_changed = pyqtSignal(dict)

    def __init__(self, project_manager: ProjectManager, is_tx: bool, continuous_send_mode=False, parent=None, testing_mode=False):
        super().__init__(parent)
        self.is_tx = is_tx
        self.update_interval = 25

        # This flag is needed. Will cause memory leak otherwise.
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWindowFlags(Qt.Window)
        self.testing_mode = testing_mode

        self.ui = Ui_SendRecvDialog()
        self.ui.setupUi(self)
        util.set_splitter_stylesheet(self.ui.splitter)

        self.graphics_view = None  # type: QGraphicsView

        self.backend_handler = BackendHandler()

        self.ui.btnStop.setEnabled(False)
        self.ui.btnSave.setEnabled(False)

        self.start = 0

        self.device_settings_widget = DeviceSettingsWidget(project_manager, is_tx,
                                                           backend_handler=self.backend_handler,
                                                           continuous_send_mode=continuous_send_mode)
        self.ui.scrollAreaWidgetContents_2.layout().insertWidget(0, self.device_settings_widget)

        if testing_mode:
            self.device_settings_widget.ui.cbDevice.setCurrentText(NetworkSDRInterfacePlugin.NETWORK_SDR_NAME)

        self.timer = QTimer(self)

        try:
            self.restoreGeometry(constants.SETTINGS.value("{}/geometry".format(self.__class__.__name__)))
        except TypeError:
            pass

        self.ui.splitter.setSizes([0.4 * self.width(), 0.6 * self.width()])

    @property
    def is_rx(self) -> bool:
        return not self.is_tx

    @property
    def has_empty_device_list(self):
        return self.device_settings_widget.ui.cbDevice.count() == 0

    @property
    def device(self) -> VirtualDevice:
        return self.device_settings_widget.device

    @device.setter
    def device(self, value):
        self.device_settings_widget.device = value

    @property
    def selected_device_name(self) -> str:
        return self.device_settings_widget.ui.cbDevice.currentText()

    def _eliminate_graphic_view(self):
        if self.graphics_view is not None:
            self.graphics_view.eliminate()

        self.graphics_view = None

    def hide_send_ui_items(self):
        for item in ("lblCurrentRepeatValue", "progressBarMessage",
                     "lblRepeatText", "lSamplesSentText", "progressBarSample", "labelCurrentMessage"):
            getattr(self.ui, item).hide()

    def hide_receive_ui_items(self):
        for item in ("lSamplesCaptured", "lSamplesCapturedText", "lSignalSize", "lSignalSizeText",
                     "lTime", "lTimeText", "btnSave", "labelReceiveBufferFull", "lReceiveBufferFullText"):
            getattr(self.ui, item).hide()

    def set_device_ui_items_enabled(self, enabled: bool):
        self.device_settings_widget.setEnabled(enabled)

    def create_connects(self):
        self.ui.btnStart.clicked.connect(self.on_start_clicked)
        self.ui.btnStop.clicked.connect(self.on_stop_clicked)
        self.ui.btnClear.clicked.connect(self.on_clear_clicked)

        self.timer.timeout.connect(self.update_view)
        self.ui.sliderYscale.valueChanged.connect(self.on_slider_y_scale_value_changed)

        self.device_settings_widget.selected_device_changed.connect(self.on_selected_device_changed)
        self.device_settings_widget.device_parameters_changed.connect(self.device_parameters_changed.emit)

    def _create_device_connects(self):
        self.device.stopped.connect(self.on_device_stopped)
        self.device.started.connect(self.on_device_started)
        self.device.sender_needs_restart.connect(self._restart_device_thread)

    def reset(self):
        self.device.current_index = 0
        self.device.current_iteration = 0
        self.ui.lSamplesCaptured.setText("0")
        self.ui.lSignalSize.setText("0")
        self.ui.lTime.setText("0")
        self.ui.lblCurrentRepeatValue.setText("-")
        self.ui.progressBarSample.setValue(0)
        self.ui.progressBarMessage.setValue(0)
        self.ui.btnSave.setEnabled(False)

    def init_device(self):
        pass

    def save_before_close(self):
        return True

    def emit_editing_finished_signals(self):
        self.device_settings_widget.emit_editing_finished_signals()

    @pyqtSlot()
    def on_selected_device_changed(self):
        if hasattr(self.scene_manager, "plot_data"):
            self.scene_manager.plot_data = None

        self.init_device()

        self.graphics_view.scene_manager = self.scene_manager
        self.graphics_view.setScene(self.scene_manager.scene)

    @pyqtSlot()
    def on_start_clicked(self):
        self.emit_editing_finished_signals()

    @pyqtSlot()
    def on_stop_clicked(self):
        self.device.stop("Stopped receiving: Stop button clicked")

    @pyqtSlot()
    def on_device_stopped(self):
        if self.graphics_view is not None:
            self.graphics_view.capturing_data = False
        self.set_device_ui_items_enabled(True)
        self.ui.btnStart.setEnabled(True)
        self.ui.btnStop.setEnabled(False)
        self.ui.btnSave.setEnabled(self.device.current_index > 0)
        self.device_settings_widget.ui.comboBoxDeviceIdentifier.setEnabled(True)
        self.device_settings_widget.ui.btnRefreshDeviceIdentifier.setEnabled(True)
        self.device_settings_widget.set_bandwidth_status()

        self.timer.stop()
        self.update_view()

    @pyqtSlot()
    def on_device_started(self):
        self.ui.txtEditErrors.clear()
        if self.graphics_view is not None:
            self.graphics_view.capturing_data = True
        self.ui.btnSave.setEnabled(False)
        self.ui.btnStart.setEnabled(False)
        self.ui.btnStop.setEnabled(True)
        self.device_settings_widget.ui.comboBoxDeviceIdentifier.setEnabled(False)
        self.device_settings_widget.ui.btnRefreshDeviceIdentifier.setEnabled(False)

        self.timer.start(self.update_interval)

    def __parse_error_messages(self, messages):
        messages = messages.lower()

        if "no devices found for" in messages:
            self.device.stop_on_error("Could not establish connection to USRP")
            Errors.usrp_found()
            self.on_clear_clicked()

        elif any(e in messages for e in ("hackrf_error_not_found", "hackrf_error_libusb")):
            self.device.stop_on_error("Could not establish connection to HackRF")
            Errors.hackrf_not_found()
            self.on_clear_clicked()

        elif "no module named gnuradio" in messages:
            self.device.stop_on_error("Did not find gnuradio.")
            Errors.gnuradio_not_installed()
            self.on_clear_clicked()

        elif "rtlsdr-open: error code: -1" in messages:
            self.device.stop_on_error("Could not open a RTL-SDR device.")
            self.on_clear_clicked()

        elif "rtlsdr-open: error code: -12" in messages:
            self.device.stop_on_error("Could not open a RTL-SDR device")
            Errors.rtlsdr_sdr_driver()
            self.on_clear_clicked()

        elif "Address already in use" in messages:
            self._restart_device_thread()

    def update_view(self):
        try:
            self.ui.sliderYscale.setValue(int(self.graphics_view.transform().m22()))
        except AttributeError:
            return

        txt = self.ui.txtEditErrors.toPlainText()
        new_messages = self.device.read_messages()

        self.__parse_error_messages(new_messages)

        if len(new_messages) > 1:
            self.ui.txtEditErrors.setPlainText(txt + new_messages)

        self.ui.lSamplesCaptured.setText(Formatter.big_value_with_suffix(self.device.current_index, decimals=1))
        self.ui.lSignalSize.setText(locale.format_string("%.2f", (8 * self.device.current_index) / (1024 ** 2)))
        self.ui.lTime.setText(locale.format_string("%.2f", self.device.current_index / self.device.sample_rate))

        if self.is_rx and self.device.data is not None and len(self.device.data) > 0:
            self.ui.labelReceiveBufferFull.setText("{0}%".format(int(100 * self.device.current_index /
                                                                     len(self.device.data))))

        if self.device.current_index == 0:
            return False

        return True

    def _restart_device_thread(self):
        self.device.stop("Restarting with new port")

        if self.device.backend == Backends.grc:
            self.device.increase_gr_port()

        self.device.start()

    @pyqtSlot()
    def on_clear_clicked(self):
        pass

    def closeEvent(self, event: QCloseEvent):
        if self.device.backend is not Backends.none:
            self.emit_editing_finished_signals()

        self.timer.stop()

        self.device.stop("Dialog closed. Killing recording process.")
        logger.debug("Device stopped successfully.")

        if not self.testing_mode:
            if not self.save_before_close():
                event.ignore()
                return

        time.sleep(0.1)
        if self.device.backend not in (Backends.none, Backends.network):
            # Backend none is selected, when no device is available
            logger.debug("Cleaning up device")
            self.device.cleanup()
            logger.debug("Successfully cleaned up device")
            self.device_settings_widget.emit_device_parameters_changed()

        constants.SETTINGS.setValue("{}/geometry".format(self.__class__.__name__), self.saveGeometry())

        if self.device is not None:
            self.device.free_data()

        self.scene_manager.eliminate()

        self._eliminate_graphic_view()

        super().closeEvent(event)

    @pyqtSlot(int)
    def on_slider_y_scale_value_changed(self, new_value: int):
        # Scale Up = Top Half, Scale Down = Lower Half
        transform = self.graphics_view.transform()
        self.graphics_view.setTransform(QTransform(transform.m11(), transform.m12(), transform.m13(),
                                                   transform.m21(), new_value, transform.m23(),
                                                   transform.m31(), transform.m32(), transform.m33()))