def __init__(self, compare_frame_controller: CompareFrameController,
                 generator_tab_controller: GeneratorTabController,
                 project_manager: ProjectManager, parent):
        super().__init__(parent)

        self.project_manager = project_manager
        self.compare_frame_controller = compare_frame_controller
        self.generator_tab_controller = generator_tab_controller
        self.proto_analyzer = compare_frame_controller.proto_analyzer

        self.simulator_config = SimulatorConfiguration(self.project_manager)
        self.sim_expression_parser = SimulatorExpressionParser(
            self.simulator_config)
        SimulatorItem.simulator_config = self.simulator_config
        SimulatorItem.expression_parser = self.sim_expression_parser

        self.ui = Ui_SimulatorTab()
        self.ui.setupUi(self)
        util.set_splitter_stylesheet(self.ui.splitter)
        util.set_splitter_stylesheet(self.ui.splitterLeftRight)

        self.ui.splitter.setSizes([self.width() / 0.7, self.width() / 0.3])

        self.ui.treeProtocols.setHeaderHidden(True)
        self.tree_model = self.generator_tab_controller.tree_model
        self.ui.treeProtocols.setModel(self.tree_model)

        self.participant_table_model = ParticipantTableModel(
            project_manager.participants)
        self.ui.tableViewParticipants.setModel(self.participant_table_model)
        self.participant_table_model.update()

        self.simulator_message_field_model = SimulatorMessageFieldModel(self)
        self.ui.tblViewFieldValues.setModel(self.simulator_message_field_model)
        self.ui.tblViewFieldValues.setItemDelegateForColumn(
            1,
            ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS,
                             parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(
            2,
            ComboBoxDelegate(SimulatorProtocolLabel.VALUE_TYPES,
                             parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(
            3,
            ProtocolValueDelegate(controller=self,
                                  parent=self.ui.tblViewFieldValues))
        self.project_manager.reload_field_types()
        self.update_field_name_column()

        self.simulator_message_table_model = SimulatorMessageTableModel(
            self.project_manager, self)
        self.ui.tblViewMessage.setModel(self.simulator_message_table_model)

        self.ui.ruleCondLineEdit.setValidator(
            RuleExpressionValidator(self.sim_expression_parser,
                                    is_formula=False))
        self.completer_model = QStringListModel([])
        self.ui.ruleCondLineEdit.setCompleter(
            QCompleter(self.completer_model, self.ui.ruleCondLineEdit))
        self.ui.ruleCondLineEdit.setToolTip(
            self.sim_expression_parser.rule_condition_help)

        self.simulator_scene = SimulatorScene(
            mode=0, simulator_config=self.simulator_config)
        self.simulator_scene.tree_root_item = compare_frame_controller.proto_tree_model.rootItem
        self.ui.gvSimulator.setScene(self.simulator_scene)
        self.ui.gvSimulator.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.ui.gvSimulator.proto_analyzer = compare_frame_controller.proto_analyzer

        self.__active_item = None

        self.ui.listViewSimulate.setModel(
            SimulatorParticipantListModel(self.simulator_config))
        self.ui.spinBoxNRepeat.setValue(
            self.project_manager.simulator_num_repeat)
        self.ui.spinBoxTimeout.setValue(
            self.project_manager.simulator_timeout_ms)
        self.ui.spinBoxRetries.setValue(self.project_manager.simulator_retries)
        self.ui.comboBoxError.setCurrentIndex(
            self.project_manager.simulator_error_handling_index)

        # place save/load button at corner of tab widget
        frame = QFrame(parent=self)
        frame.setLayout(QHBoxLayout())
        frame.setFrameStyle(frame.NoFrame)
        self.ui.btnSave = QToolButton(self.ui.tab)
        self.ui.btnSave.setIcon(QIcon.fromTheme("document-save"))
        frame.layout().addWidget(self.ui.btnSave)

        self.ui.btnLoad = QToolButton(self.ui.tab)
        self.ui.btnLoad.setIcon(QIcon.fromTheme("document-open"))
        frame.layout().addWidget(self.ui.btnLoad)
        frame.layout().setContentsMargins(0, 0, 0, 0)
        self.ui.tabWidget.setCornerWidget(frame)

        self.ui.splitterLeftRight.setSizes(
            [0.2 * self.width(), 0.8 * self.width()])

        self.create_connects()
Exemplo n.º 2
0
    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)
class SimulatorTabController(QWidget):
    open_in_analysis_requested = pyqtSignal(str)
    rx_file_saved = pyqtSignal(str)

    def __init__(self, compare_frame_controller: CompareFrameController,
                 generator_tab_controller: GeneratorTabController,
                 project_manager: ProjectManager, parent):
        super().__init__(parent)

        self.project_manager = project_manager
        self.compare_frame_controller = compare_frame_controller
        self.generator_tab_controller = generator_tab_controller
        self.proto_analyzer = compare_frame_controller.proto_analyzer

        self.simulator_config = SimulatorConfiguration(self.project_manager)
        self.sim_expression_parser = SimulatorExpressionParser(
            self.simulator_config)
        SimulatorItem.simulator_config = self.simulator_config
        SimulatorItem.expression_parser = self.sim_expression_parser

        self.ui = Ui_SimulatorTab()
        self.ui.setupUi(self)
        util.set_splitter_stylesheet(self.ui.splitter)
        util.set_splitter_stylesheet(self.ui.splitterLeftRight)

        self.ui.splitter.setSizes([self.width() / 0.7, self.width() / 0.3])

        self.ui.treeProtocols.setHeaderHidden(True)
        self.tree_model = self.generator_tab_controller.tree_model
        self.ui.treeProtocols.setModel(self.tree_model)

        self.participant_table_model = ParticipantTableModel(
            project_manager.participants)
        self.ui.tableViewParticipants.setModel(self.participant_table_model)
        self.participant_table_model.update()

        self.simulator_message_field_model = SimulatorMessageFieldModel(self)
        self.ui.tblViewFieldValues.setModel(self.simulator_message_field_model)
        self.ui.tblViewFieldValues.setItemDelegateForColumn(
            1,
            ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS,
                             parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(
            2,
            ComboBoxDelegate(SimulatorProtocolLabel.VALUE_TYPES,
                             parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(
            3,
            ProtocolValueDelegate(controller=self,
                                  parent=self.ui.tblViewFieldValues))
        self.project_manager.reload_field_types()
        self.update_field_name_column()

        self.simulator_message_table_model = SimulatorMessageTableModel(
            self.project_manager, self)
        self.ui.tblViewMessage.setModel(self.simulator_message_table_model)

        self.ui.ruleCondLineEdit.setValidator(
            RuleExpressionValidator(self.sim_expression_parser,
                                    is_formula=False))
        self.completer_model = QStringListModel([])
        self.ui.ruleCondLineEdit.setCompleter(
            QCompleter(self.completer_model, self.ui.ruleCondLineEdit))
        self.ui.ruleCondLineEdit.setToolTip(
            self.sim_expression_parser.rule_condition_help)

        self.simulator_scene = SimulatorScene(
            mode=0, simulator_config=self.simulator_config)
        self.simulator_scene.tree_root_item = compare_frame_controller.proto_tree_model.rootItem
        self.ui.gvSimulator.setScene(self.simulator_scene)
        self.ui.gvSimulator.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.ui.gvSimulator.proto_analyzer = compare_frame_controller.proto_analyzer

        self.__active_item = None

        self.ui.listViewSimulate.setModel(
            SimulatorParticipantListModel(self.simulator_config))
        self.ui.spinBoxNRepeat.setValue(
            self.project_manager.simulator_num_repeat)
        self.ui.spinBoxTimeout.setValue(
            self.project_manager.simulator_timeout_ms)
        self.ui.spinBoxRetries.setValue(self.project_manager.simulator_retries)
        self.ui.comboBoxError.setCurrentIndex(
            self.project_manager.simulator_error_handling_index)

        # place save/load button at corner of tab widget
        frame = QFrame(parent=self)
        frame.setLayout(QHBoxLayout())
        frame.setFrameStyle(frame.NoFrame)
        self.ui.btnSave = QToolButton(self.ui.tab)
        self.ui.btnSave.setIcon(QIcon.fromTheme("document-save"))
        frame.layout().addWidget(self.ui.btnSave)

        self.ui.btnLoad = QToolButton(self.ui.tab)
        self.ui.btnLoad.setIcon(QIcon.fromTheme("document-open"))
        frame.layout().addWidget(self.ui.btnLoad)
        frame.layout().setContentsMargins(0, 0, 0, 0)
        self.ui.tabWidget.setCornerWidget(frame)

        self.ui.splitterLeftRight.setSizes(
            [0.2 * self.width(), 0.8 * self.width()])

        self.create_connects()

    def refresh_field_types_for_labels(self):
        for msg in self.simulator_config.get_all_messages():
            for lbl in (lbl for lbl in msg.message_type
                        if lbl.field_type is not None):
                msg.message_type.change_field_type_of_label(
                    lbl,
                    self.field_types_by_caption.get(lbl.field_type.caption,
                                                    None))

        self.update_field_name_column()
        self.update_ui()

    @property
    def field_types(self):
        return self.project_manager.field_types

    @property
    def field_types_by_caption(self):
        return self.project_manager.field_types_by_caption

    def update_field_name_column(self):
        field_types = [ft.caption for ft in self.field_types]
        self.ui.tblViewFieldValues.setItemDelegateForColumn(
            0,
            ComboBoxDelegate(field_types,
                             is_editable=True,
                             return_index=False,
                             parent=self.ui.tblViewFieldValues))

    def create_connects(self):
        self.ui.btnChooseCommand.clicked.connect(
            self.on_btn_choose_command_clicked)
        self.ui.lineEditTriggerCommand.textChanged.connect(
            self.on_line_edit_trigger_command_text_changed)
        self.ui.checkBoxPassTranscriptSTDIN.clicked.connect(
            self.on_check_box_pass_transcript_STDIN_clicked)
        self.ui.doubleSpinBoxSleep.editingFinished.connect(
            self.on_spinbox_sleep_editing_finished)
        self.ui.ruleCondLineEdit.textChanged.connect(
            self.on_rule_cond_line_edit_text_changed)
        self.ui.btnStartSim.clicked.connect(self.on_btn_simulate_clicked)
        self.ui.goto_combobox.currentIndexChanged.connect(
            self.on_goto_combobox_index_changed)
        self.ui.spinBoxRepeat.valueChanged.connect(
            self.on_repeat_value_changed)
        self.ui.cbViewType.currentIndexChanged.connect(
            self.on_view_type_changed)
        self.ui.tblViewMessage.create_label_triggered.connect(
            self.create_simulator_label)
        self.ui.tblViewMessage.open_modulator_dialog_clicked.connect(
            self.open_modulator_dialog)
        self.ui.tblViewMessage.selectionModel().selectionChanged.connect(
            self.on_table_selection_changed)
        self.ui.tabWidget.currentChanged.connect(self.on_selected_tab_changed)
        self.ui.btnSave.clicked.connect(self.on_btn_save_clicked)
        self.ui.btnLoad.clicked.connect(self.on_btn_load_clicked)

        self.ui.listViewSimulate.model().participant_simulate_changed.connect(
            self.on_participant_simulate_changed)

        self.ui.btnAddParticipant.clicked.connect(
            self.ui.tableViewParticipants.on_add_action_triggered)
        self.ui.btnRemoveParticipant.clicked.connect(
            self.ui.tableViewParticipants.on_remove_action_triggered)
        self.ui.btnUp.clicked.connect(
            self.ui.tableViewParticipants.on_move_up_action_triggered)
        self.ui.btnDown.clicked.connect(
            self.ui.tableViewParticipants.on_move_down_action_triggered)
        self.participant_table_model.participant_edited.connect(
            self.on_participant_edited)

        self.tree_model.modelReset.connect(self.refresh_tree)

        self.simulator_scene.selectionChanged.connect(
            self.on_simulator_scene_selection_changed)
        self.simulator_scene.files_dropped.connect(self.on_files_dropped)

        self.simulator_message_field_model.protocol_label_updated.connect(
            self.item_updated)
        self.ui.gvSimulator.message_updated.connect(self.item_updated)
        self.ui.gvSimulator.consolidate_messages_clicked.connect(
            self.consolidate_messages)

        self.simulator_config.items_added.connect(self.refresh_message_table)
        self.simulator_config.items_updated.connect(self.refresh_message_table)
        self.simulator_config.items_moved.connect(self.refresh_message_table)
        self.simulator_config.items_deleted.connect(self.refresh_message_table)
        self.simulator_config.participants_changed.connect(
            self.on_participants_changed)
        self.simulator_config.item_dict_updated.connect(
            self.on_item_dict_updated)
        self.simulator_config.active_participants_updated.connect(
            self.on_active_participants_updated)

        self.ui.gvSimulator.message_updated.connect(
            self.on_message_source_or_destination_updated)

        self.ui.spinBoxNRepeat.valueChanged.connect(
            self.on_spinbox_num_repeat_value_changed)
        self.ui.spinBoxTimeout.valueChanged.connect(
            self.on_spinbox_timeout_value_changed)
        self.ui.comboBoxError.currentIndexChanged.connect(
            self.on_combobox_error_handling_index_changed)
        self.ui.spinBoxRetries.valueChanged.connect(
            self.on_spinbox_retries_value_changed)

        self.ui.tblViewFieldValues.item_link_clicked.connect(
            self.on_table_item_link_clicked)
        self.ui.tblViewMessage.edit_label_triggered.connect(
            self.on_edit_label_triggered)

        self.ui.spinBoxCounterStart.editingFinished.connect(
            self.on_spinbox_counter_start_editing_finished)
        self.ui.spinBoxCounterStep.editingFinished.connect(
            self.on_spinbox_counter_step_editing_finished)

    def consolidate_messages(self):
        self.simulator_config.consolidate_messages()

    def on_repeat_value_changed(self, value):
        self.active_item.repeat = value
        self.simulator_config.items_updated.emit([self.active_item])

    def on_item_dict_updated(self):
        self.completer_model.setStringList(
            self.sim_expression_parser.get_identifiers())

    def on_selected_tab_changed(self, index: int):
        if index == 0:
            if self.active_item is not None:
                self.ui.gvSimulator.jump_to_item(self.active_item)
            else:
                self.update_ui()
        else:
            self.ui.tblViewMessage.resize_columns()
            self.update_vertical_table_header()

    def refresh_message_table(self):
        self.simulator_message_table_model.protocol.messages[:] = self.simulator_config.get_all_messages(
        )
        self.simulator_message_table_model.update()

        if isinstance(self.active_item, SimulatorMessage):
            self.simulator_message_field_model.update()

        self.ui.tblViewMessage.resize_columns()
        self.update_ui()

    def load_config_from_xml_tag(self, xml_tag, update_before=True):
        if xml_tag is None:
            return

        if update_before:
            self.simulator_config.on_project_updated()

        self.simulator_config.load_from_xml(xml_tag,
                                            self.proto_analyzer.message_types)
        self.project_manager.project_updated.emit()

    def load_simulator_file(self, filename: str):
        try:
            tree = ET.parse(filename)
            self.load_config_from_xml_tag(tree.getroot(), update_before=False)
        except Exception as e:
            logger.exception(e)

    def save_simulator_file(self, filename: str):
        tag = self.simulator_config.save_to_xml(standalone=True)
        util.write_xml_to_file(tag, filename)

    def close_all(self):
        self.simulator_scene.clear_all()

    @pyqtSlot(int, int, int)
    def create_simulator_label(self, msg_index: int, start: int, end: int):
        con = self.simulator_message_table_model.protocol
        start, end = con.convert_range(start, end - 1,
                                       self.ui.cbViewType.currentIndex(), 0,
                                       False, msg_index)
        lbl = self.simulator_config.add_label(
            start=start, end=end, parent_item=con.messages[msg_index])

        try:
            index = self.simulator_message_field_model.message_type.index(lbl)
            self.ui.tblViewFieldValues.edit(
                self.simulator_message_field_model.createIndex(index, 0))
        except ValueError:
            pass

    @pyqtSlot()
    def open_modulator_dialog(self):
        selected_message = self.simulator_message_table_model.protocol.messages[
            self.ui.tblViewMessage.selected_rows[0]]
        preselected_index = selected_message.modulator_index

        modulator_dialog = ModulatorDialog(self.project_manager.modulators,
                                           tree_model=self.tree_model,
                                           parent=self)
        modulator_dialog.ui.comboBoxCustomModulations.setCurrentIndex(
            preselected_index)
        modulator_dialog.showMaximized()
        modulator_dialog.initialize(selected_message.encoded_bits_str[0:10])

        modulator_dialog.finished.connect(self.refresh_modulators)
        modulator_dialog.finished.connect(
            self.generator_tab_controller.refresh_pause_list)

    @pyqtSlot()
    def refresh_modulators(self):
        # update Generator tab ...
        cBoxModulations = self.generator_tab_controller.ui.cBoxModulations
        current_index = cBoxModulations.currentIndex()
        cBoxModulations.clear()

        for modulator in self.project_manager.modulators:
            cBoxModulations.addItem(modulator.name)

        cBoxModulations.setCurrentIndex(current_index)

        # update Simulator tab ...
        index = self.sender().ui.comboBoxCustomModulations.currentIndex()

        for row in self.ui.tblViewMessage.selected_rows:
            self.simulator_message_table_model.protocol.messages[
                row].modulator_index = index

    def update_goto_combobox(self, active_item: SimulatorGotoAction):
        assert isinstance(active_item, SimulatorGotoAction)
        goto_combobox = self.ui.goto_combobox

        goto_combobox.blockSignals(True)
        goto_combobox.clear()
        goto_combobox.addItem("Select item ...")
        goto_combobox.addItems(active_item.get_valid_goto_targets())
        goto_combobox.setCurrentIndex(-1)
        goto_combobox.blockSignals(False)

        index = goto_combobox.findText(self.active_item.goto_target)

        if index == -1:
            index = 0

        goto_combobox.setCurrentIndex(index)

    def update_ui(self):
        if self.active_item is not None:
            text = self.tr("Detail view for item #") + self.active_item.index()

            if isinstance(self.active_item, SimulatorMessage):
                text += " (" + self.active_item.message_type.name + ")"
                self.ui.spinBoxRepeat.setValue(self.active_item.repeat)
                self.ui.lblEncodingDecoding.setText(
                    self.active_item.decoder.name)

            self.ui.lblMsgFieldsValues.setText(text)
        else:
            self.ui.lblMsgFieldsValues.setText(self.tr("Detail view for item"))

    def update_vertical_table_header(self):
        self.simulator_message_table_model.refresh_vertical_header()
        self.ui.tblViewMessage.resize_vertical_header()

    @pyqtSlot()
    def on_rule_cond_line_edit_text_changed(self):
        self.active_item.condition = self.ui.ruleCondLineEdit.text()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_view_type_changed(self):
        self.simulator_message_table_model.proto_view = self.ui.cbViewType.currentIndex(
        )
        self.simulator_message_table_model.update()
        self.ui.tblViewMessage.resize_columns()

    @pyqtSlot()
    def on_goto_combobox_index_changed(self):
        if not isinstance(self.active_item, SimulatorGotoAction):
            return

        self.active_item.goto_target = None if self.ui.goto_combobox.currentIndex(
        ) == 0 else self.ui.goto_combobox.currentText()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_simulator_scene_selection_changed(self):
        selected_items = self.simulator_scene.selectedItems()
        self.active_item = selected_items[
            0].model_item if selected_items else None

        self.update_ui()

    @pyqtSlot()
    def on_table_selection_changed(self):
        selection = self.ui.tblViewMessage.selectionModel().selection()

        if selection.isEmpty():
            self.active_item = None
            self.ui.lNumSelectedColumns.setText("0")
        else:
            max_row = numpy.max([rng.bottom() for rng in selection])
            self.active_item = self.simulator_message_table_model.protocol.messages[
                max_row]
            _, _, start, end = self.ui.tblViewMessage.selection_range()
            self.ui.lNumSelectedColumns.setText(str(end - start))

        self.update_ui()

    @property
    def active_item(self):
        return self.__active_item

    @active_item.setter
    def active_item(self, value):
        self.__active_item = value

        if isinstance(self.active_item, SimulatorGotoAction):
            self.update_goto_combobox(self.active_item)

            self.ui.detail_view_widget.setCurrentIndex(1)
        elif isinstance(self.active_item, SimulatorMessage):
            self.simulator_message_field_model.update()
            self.ui.spinBoxRepeat.setValue(self.active_item.repeat)
            self.ui.lblEncodingDecoding.setText(self.active_item.decoder.name)

            self.ui.detail_view_widget.setCurrentIndex(2)
        elif (isinstance(self.active_item, SimulatorRuleCondition)
              and self.active_item.type != ConditionType.ELSE):
            self.ui.ruleCondLineEdit.setText(self.active_item.condition)
            self.ui.detail_view_widget.setCurrentIndex(3)
        elif isinstance(self.active_item, SimulatorTriggerCommandAction):
            self.ui.lineEditTriggerCommand.setText(self.active_item.command)
            self.ui.checkBoxPassTranscriptSTDIN.setChecked(
                self.active_item.pass_transcript)
            self.ui.detail_view_widget.setCurrentIndex(4)
        elif isinstance(self.active_item, SimulatorSleepAction):
            self.ui.doubleSpinBoxSleep.setValue(self.active_item.sleep_time)
            self.ui.detail_view_widget.setCurrentIndex(5)
        elif isinstance(self.active_item, SimulatorCounterAction):
            self.ui.spinBoxCounterStart.setValue(self.active_item.start)
            self.ui.spinBoxCounterStep.setValue(self.active_item.step)
            self.ui.detail_view_widget.setCurrentIndex(6)
        else:
            self.ui.detail_view_widget.setCurrentIndex(0)

        self.update_ui()

    @pyqtSlot()
    def on_btn_simulate_clicked(self):
        if not self.simulator_config.protocol_valid():
            QMessageBox.critical(
                self, self.tr("Invalid protocol configuration"),
                self.
                tr("There are some problems with your protocol configuration. Please fix them first."
                   ))
            return

        if not len(self.simulator_config.get_all_messages()):
            QMessageBox.critical(self, self.tr("No messages found"),
                                 self.tr("Please add at least one message."))
            return

        num_simulated = len(
            [p for p in self.project_manager.participants if p.simulate])
        if num_simulated == 0:
            if self.ui.listViewSimulate.model().rowCount() == 0:
                QMessageBox.critical(
                    self, self.tr("No active participants"),
                    self.
                    tr("You have no active participants.<br>"
                       "Please add a participant in the <i>Participants tab</i> and "
                       "assign it to at least one message as <i>source</i> or <i>destination.</i>"
                       ))
                return
            else:
                QMessageBox.critical(
                    self, self.tr("No participant for simulation selected"),
                    self.tr("Please check at least one participant from the "
                            "<i>Simulate these participants</i> list."))
                return

        try:
            self.get_simulator_dialog().exec_()
        except Exception as e:
            Errors.exception(e)

    def get_simulator_dialog(self) -> SimulatorDialog:
        protos = [
            p for proto_list in self.tree_model.protocols.values()
            for p in proto_list
        ]
        signals = [p.signal for p in protos if p.signal is not None]

        s = SimulatorDialog(self.simulator_config,
                            self.project_manager.modulators,
                            self.sim_expression_parser,
                            self.project_manager,
                            signals=signals,
                            signal_tree_model=self.tree_model,
                            parent=self)

        s.rx_parameters_changed.connect(
            self.project_manager.on_simulator_rx_parameters_changed)
        s.sniff_parameters_changed.connect(
            self.project_manager.on_simulator_sniff_parameters_changed)
        s.tx_parameters_changed.connect(
            self.project_manager.on_simulator_tx_parameters_changed)
        s.open_in_analysis_requested.connect(
            self.open_in_analysis_requested.emit)
        s.rx_file_saved.connect(self.rx_file_saved.emit)

        return s

    @pyqtSlot()
    def on_btn_choose_command_clicked(self):
        file_name, ok = QFileDialog.getOpenFileName(self,
                                                    self.tr("Choose program"),
                                                    QDir.homePath())

        if file_name is not None and ok:
            self.ui.lineEditTriggerCommand.setText(file_name)

    @pyqtSlot()
    def on_line_edit_trigger_command_text_changed(self):
        self.active_item.command = self.ui.lineEditTriggerCommand.text()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_check_box_pass_transcript_STDIN_clicked(self):
        self.active_item.pass_transcript = self.ui.checkBoxPassTranscriptSTDIN.isChecked(
        )
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_spinbox_counter_start_editing_finished(self):
        self.active_item.start = self.ui.spinBoxCounterStart.value()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_spinbox_counter_step_editing_finished(self):
        self.active_item.step = self.ui.spinBoxCounterStep.value()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_spinbox_sleep_editing_finished(self):
        self.active_item.sleep_time = self.ui.doubleSpinBoxSleep.value()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_participants_changed(self):
        self.update_vertical_table_header()
        self.participant_table_model.update()
        self.ui.listViewSimulate.model().update()

    def item_updated(self, item: SimulatorItem):
        self.simulator_config.items_updated.emit([item])

    @pyqtSlot()
    def refresh_tree(self):
        self.ui.treeProtocols.expandAll()

    @pyqtSlot()
    def on_btn_save_clicked(self):
        filename = FileOperator.get_save_file_name(
            initial_name="myprofile.sim.xml", caption="Save simulator profile")
        if filename:
            self.save_simulator_file(filename)

    @pyqtSlot()
    def on_btn_load_clicked(self):
        dialog = FileOperator.get_open_dialog(False,
                                              parent=self,
                                              name_filter="simulator")
        if dialog.exec_():
            self.load_simulator_file(dialog.selectedFiles()[0])

    @pyqtSlot()
    def on_participant_edited(self):
        self.project_manager.project_updated.emit()

    @pyqtSlot(int)
    def on_spinbox_num_repeat_value_changed(self, value):
        self.project_manager.simulator_num_repeat = value

    @pyqtSlot(int)
    def on_spinbox_timeout_value_changed(self, value):
        self.project_manager.simulator_timeout_ms = value

    @pyqtSlot(int)
    def on_spinbox_retries_value_changed(self, value):
        self.project_manager.simulator_retries = value

    @pyqtSlot(int)
    def on_combobox_error_handling_index_changed(self, index: int):
        self.project_manager.simulator_error_handling_index = index

    @pyqtSlot()
    def on_message_source_or_destination_updated(self):
        self.simulator_config.update_active_participants()

    @pyqtSlot(int, int)
    def on_table_item_link_clicked(self, row: int, column: int):
        try:
            lbl = self.simulator_message_field_model.message_type[
                row]  # type: SimulatorProtocolLabel
            assert lbl.is_checksum_label
            assert isinstance(self.active_item, SimulatorMessage)
        except (IndexError, AssertionError):
            return

        d = QDialog(parent=self)
        layout = QHBoxLayout()
        layout.addWidget(
            ChecksumWidget(lbl.label, self.active_item,
                           self.ui.cbViewType.currentIndex()))
        d.setLayout(layout)
        d.show()

    @pyqtSlot(Participant)
    def on_participant_simulate_changed(self, participant: Participant):
        self.simulator_scene.refresh_participant(participant)

    @pyqtSlot()
    def on_active_participants_updated(self):
        self.ui.listViewSimulate.model().update()

    @pyqtSlot(int)
    def on_edit_label_triggered(self, label_index: int):
        view_type = self.ui.cbViewType.currentIndex()
        protocol_label_dialog = ProtocolLabelDialog(
            message=self.ui.tblViewMessage.selected_message,
            viewtype=view_type,
            selected_index=label_index,
            parent=self)
        protocol_label_dialog.finished.connect(
            self.on_protocol_label_dialog_finished)
        protocol_label_dialog.showMaximized()

    @pyqtSlot()
    def on_protocol_label_dialog_finished(self):
        self.simulator_message_field_model.update()
        self.simulator_message_table_model.update()
        self.update_ui()

    @pyqtSlot(list)
    def on_files_dropped(self, file_urls: list):
        for filename in (file_url.toLocalFile() for file_url in file_urls
                         if file_url.isLocalFile()):
            self.load_simulator_file(filename)
Exemplo n.º 4
0
    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)
Exemplo n.º 5
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.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()
Exemplo n.º 6
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))
Exemplo n.º 7
0
    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)
Exemplo n.º 8
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()
Exemplo n.º 9
0
    def __init__(self, compare_frame_controller: CompareFrameController,
                 generator_tab_controller: GeneratorTabController,
                 project_manager: ProjectManager, parent):
        super().__init__(parent)

        self.project_manager = project_manager
        self.compare_frame_controller = compare_frame_controller
        self.generator_tab_controller = generator_tab_controller
        self.proto_analyzer = compare_frame_controller.proto_analyzer

        self.simulator_config = SimulatorConfiguration(self.project_manager)
        self.sim_expression_parser = SimulatorExpressionParser(self.simulator_config)
        SimulatorItem.simulator_config = self.simulator_config
        SimulatorItem.expression_parser = self.sim_expression_parser

        self.ui = Ui_SimulatorTab()
        self.ui.setupUi(self)
        util.set_splitter_stylesheet(self.ui.splitter)
        util.set_splitter_stylesheet(self.ui.splitterLeftRight)

        self.ui.splitter.setSizes([self.width() / 0.7, self.width() / 0.3])

        self.ui.treeProtocols.setHeaderHidden(True)
        self.tree_model = self.generator_tab_controller.tree_model
        self.ui.treeProtocols.setModel(self.tree_model)

        self.participant_table_model = ParticipantTableModel(project_manager.participants)
        self.ui.tableViewParticipants.setModel(self.participant_table_model)
        self.participant_table_model.update()

        self.simulator_message_field_model = SimulatorMessageFieldModel(self)
        self.ui.tblViewFieldValues.setModel(self.simulator_message_field_model)
        self.ui.tblViewFieldValues.setItemDelegateForColumn(1, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS,
                                                                                parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(2, ComboBoxDelegate(SimulatorProtocolLabel.VALUE_TYPES,
                                                                                parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(3, ProtocolValueDelegate(controller=self,
                                                                                     parent=self.ui.tblViewFieldValues))
        self.project_manager.reload_field_types()
        self.update_field_name_column()

        self.simulator_message_table_model = SimulatorMessageTableModel(self.project_manager, self)
        self.ui.tblViewMessage.setModel(self.simulator_message_table_model)

        self.ui.ruleCondLineEdit.setValidator(RuleExpressionValidator(self.sim_expression_parser, is_formula=False))
        self.completer_model = QStringListModel([])
        self.ui.ruleCondLineEdit.setCompleter(QCompleter(self.completer_model, self.ui.ruleCondLineEdit))
        self.ui.ruleCondLineEdit.setToolTip(self.sim_expression_parser.rule_condition_help)

        self.simulator_scene = SimulatorScene(mode=0, simulator_config=self.simulator_config)
        self.simulator_scene.tree_root_item = compare_frame_controller.proto_tree_model.rootItem
        self.ui.gvSimulator.setScene(self.simulator_scene)
        self.ui.gvSimulator.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.ui.gvSimulator.proto_analyzer = compare_frame_controller.proto_analyzer

        self.__active_item = None

        self.ui.listViewSimulate.setModel(SimulatorParticipantListModel(self.simulator_config))
        self.ui.spinBoxNRepeat.setValue(self.project_manager.simulator_num_repeat)
        self.ui.spinBoxTimeout.setValue(self.project_manager.simulator_timeout_ms)
        self.ui.spinBoxRetries.setValue(self.project_manager.simulator_retries)
        self.ui.comboBoxError.setCurrentIndex(self.project_manager.simulator_error_handling_index)

        # place save/load button at corner of tab widget
        frame = QFrame(parent=self)
        frame.setLayout(QHBoxLayout())
        frame.setFrameStyle(frame.NoFrame)
        self.ui.btnSave = QToolButton(self.ui.tab)
        self.ui.btnSave.setIcon(QIcon.fromTheme("document-save"))
        frame.layout().addWidget(self.ui.btnSave)

        self.ui.btnLoad = QToolButton(self.ui.tab)
        self.ui.btnLoad.setIcon(QIcon.fromTheme("document-open"))
        frame.layout().addWidget(self.ui.btnLoad)
        frame.layout().setContentsMargins(0, 0, 0, 0)
        self.ui.tabWidget.setCornerWidget(frame)

        self.ui.splitterLeftRight.setSizes([0.2 * self.width(), 0.8 * self.width()])

        self.create_connects()
Exemplo n.º 10
0
class SimulatorTabController(QWidget):
    open_in_analysis_requested = pyqtSignal(str)
    rx_file_saved = pyqtSignal(str)

    def __init__(self, compare_frame_controller: CompareFrameController,
                 generator_tab_controller: GeneratorTabController,
                 project_manager: ProjectManager, parent):
        super().__init__(parent)

        self.project_manager = project_manager
        self.compare_frame_controller = compare_frame_controller
        self.generator_tab_controller = generator_tab_controller
        self.proto_analyzer = compare_frame_controller.proto_analyzer

        self.simulator_config = SimulatorConfiguration(self.project_manager)
        self.sim_expression_parser = SimulatorExpressionParser(self.simulator_config)
        SimulatorItem.simulator_config = self.simulator_config
        SimulatorItem.expression_parser = self.sim_expression_parser

        self.ui = Ui_SimulatorTab()
        self.ui.setupUi(self)
        util.set_splitter_stylesheet(self.ui.splitter)
        util.set_splitter_stylesheet(self.ui.splitterLeftRight)

        self.ui.splitter.setSizes([self.width() / 0.7, self.width() / 0.3])

        self.ui.treeProtocols.setHeaderHidden(True)
        self.tree_model = self.generator_tab_controller.tree_model
        self.ui.treeProtocols.setModel(self.tree_model)

        self.participant_table_model = ParticipantTableModel(project_manager.participants)
        self.ui.tableViewParticipants.setModel(self.participant_table_model)
        self.participant_table_model.update()

        self.simulator_message_field_model = SimulatorMessageFieldModel(self)
        self.ui.tblViewFieldValues.setModel(self.simulator_message_field_model)
        self.ui.tblViewFieldValues.setItemDelegateForColumn(1, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS,
                                                                                parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(2, ComboBoxDelegate(SimulatorProtocolLabel.VALUE_TYPES,
                                                                                parent=self.ui.tblViewFieldValues))
        self.ui.tblViewFieldValues.setItemDelegateForColumn(3, ProtocolValueDelegate(controller=self,
                                                                                     parent=self.ui.tblViewFieldValues))
        self.project_manager.reload_field_types()
        self.update_field_name_column()

        self.simulator_message_table_model = SimulatorMessageTableModel(self.project_manager, self)
        self.ui.tblViewMessage.setModel(self.simulator_message_table_model)

        self.ui.ruleCondLineEdit.setValidator(RuleExpressionValidator(self.sim_expression_parser, is_formula=False))
        self.completer_model = QStringListModel([])
        self.ui.ruleCondLineEdit.setCompleter(QCompleter(self.completer_model, self.ui.ruleCondLineEdit))
        self.ui.ruleCondLineEdit.setToolTip(self.sim_expression_parser.rule_condition_help)

        self.simulator_scene = SimulatorScene(mode=0, simulator_config=self.simulator_config)
        self.simulator_scene.tree_root_item = compare_frame_controller.proto_tree_model.rootItem
        self.ui.gvSimulator.setScene(self.simulator_scene)
        self.ui.gvSimulator.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.ui.gvSimulator.proto_analyzer = compare_frame_controller.proto_analyzer

        self.__active_item = None

        self.ui.listViewSimulate.setModel(SimulatorParticipantListModel(self.simulator_config))
        self.ui.spinBoxNRepeat.setValue(self.project_manager.simulator_num_repeat)
        self.ui.spinBoxTimeout.setValue(self.project_manager.simulator_timeout_ms)
        self.ui.spinBoxRetries.setValue(self.project_manager.simulator_retries)
        self.ui.comboBoxError.setCurrentIndex(self.project_manager.simulator_error_handling_index)

        # place save/load button at corner of tab widget
        frame = QFrame(parent=self)
        frame.setLayout(QHBoxLayout())
        frame.setFrameStyle(frame.NoFrame)
        self.ui.btnSave = QToolButton(self.ui.tab)
        self.ui.btnSave.setIcon(QIcon.fromTheme("document-save"))
        frame.layout().addWidget(self.ui.btnSave)

        self.ui.btnLoad = QToolButton(self.ui.tab)
        self.ui.btnLoad.setIcon(QIcon.fromTheme("document-open"))
        frame.layout().addWidget(self.ui.btnLoad)
        frame.layout().setContentsMargins(0, 0, 0, 0)
        self.ui.tabWidget.setCornerWidget(frame)

        self.ui.splitterLeftRight.setSizes([0.2 * self.width(), 0.8 * self.width()])

        self.create_connects()

    def refresh_field_types_for_labels(self):
        for msg in self.simulator_config.get_all_messages():
            for lbl in (lbl for lbl in msg.message_type if lbl.field_type is not None):
                msg.message_type.change_field_type_of_label(lbl, self.field_types_by_caption.get(lbl.field_type.caption,
                                                                                                 None))

        self.update_field_name_column()
        self.update_ui()

    @property
    def field_types(self):
        return self.project_manager.field_types

    @property
    def field_types_by_caption(self):
        return self.project_manager.field_types_by_caption

    def update_field_name_column(self):
        field_types = [ft.caption for ft in self.field_types]
        self.ui.tblViewFieldValues.setItemDelegateForColumn(0, ComboBoxDelegate(field_types, is_editable=True,
                                                                                return_index=False,
                                                                                parent=self.ui.tblViewFieldValues))

    def create_connects(self):
        self.ui.btnChooseCommand.clicked.connect(self.on_btn_choose_command_clicked)
        self.ui.lineEditTriggerCommand.textChanged.connect(self.on_line_edit_trigger_command_text_changed)
        self.ui.checkBoxPassTranscriptSTDIN.clicked.connect(self.on_check_box_pass_transcript_STDIN_clicked)
        self.ui.doubleSpinBoxSleep.editingFinished.connect(self.on_spinbox_sleep_editing_finished)
        self.ui.ruleCondLineEdit.textChanged.connect(self.on_rule_cond_line_edit_text_changed)
        self.ui.btnStartSim.clicked.connect(self.on_btn_simulate_clicked)
        self.ui.goto_combobox.currentIndexChanged.connect(self.on_goto_combobox_index_changed)
        self.ui.spinBoxRepeat.valueChanged.connect(self.on_repeat_value_changed)
        self.ui.cbViewType.currentIndexChanged.connect(self.on_view_type_changed)
        self.ui.tblViewMessage.create_label_triggered.connect(self.create_simulator_label)
        self.ui.tblViewMessage.open_modulator_dialog_clicked.connect(self.open_modulator_dialog)
        self.ui.tblViewMessage.selectionModel().selectionChanged.connect(self.on_table_selection_changed)
        self.ui.tabWidget.currentChanged.connect(self.on_selected_tab_changed)
        self.ui.btnSave.clicked.connect(self.on_btn_save_clicked)
        self.ui.btnLoad.clicked.connect(self.on_btn_load_clicked)

        self.ui.listViewSimulate.model().participant_simulate_changed.connect(self.on_participant_simulate_changed)

        self.ui.btnAddParticipant.clicked.connect(self.ui.tableViewParticipants.on_add_action_triggered)
        self.ui.btnRemoveParticipant.clicked.connect(self.ui.tableViewParticipants.on_remove_action_triggered)
        self.ui.btnUp.clicked.connect(self.ui.tableViewParticipants.on_move_up_action_triggered)
        self.ui.btnDown.clicked.connect(self.ui.tableViewParticipants.on_move_down_action_triggered)
        self.participant_table_model.participant_edited.connect(self.on_participant_edited)

        self.tree_model.modelReset.connect(self.refresh_tree)

        self.simulator_scene.selectionChanged.connect(self.on_simulator_scene_selection_changed)
        self.simulator_scene.files_dropped.connect(self.on_files_dropped)

        self.simulator_message_field_model.protocol_label_updated.connect(self.item_updated)
        self.ui.gvSimulator.message_updated.connect(self.item_updated)
        self.ui.gvSimulator.consolidate_messages_clicked.connect(self.consolidate_messages)

        self.simulator_config.items_added.connect(self.refresh_message_table)
        self.simulator_config.items_updated.connect(self.refresh_message_table)
        self.simulator_config.items_moved.connect(self.refresh_message_table)
        self.simulator_config.items_deleted.connect(self.refresh_message_table)
        self.simulator_config.participants_changed.connect(self.on_participants_changed)
        self.simulator_config.item_dict_updated.connect(self.on_item_dict_updated)
        self.simulator_config.active_participants_updated.connect(self.on_active_participants_updated)

        self.ui.gvSimulator.message_updated.connect(self.on_message_source_or_destination_updated)

        self.ui.spinBoxNRepeat.valueChanged.connect(self.on_spinbox_num_repeat_value_changed)
        self.ui.spinBoxTimeout.valueChanged.connect(self.on_spinbox_timeout_value_changed)
        self.ui.comboBoxError.currentIndexChanged.connect(self.on_combobox_error_handling_index_changed)
        self.ui.spinBoxRetries.valueChanged.connect(self.on_spinbox_retries_value_changed)

        self.ui.tblViewFieldValues.item_link_clicked.connect(self.on_table_item_link_clicked)
        self.ui.tblViewMessage.edit_label_triggered.connect(self.on_edit_label_triggered)

        self.ui.spinBoxCounterStart.editingFinished.connect(self.on_spinbox_counter_start_editing_finished)
        self.ui.spinBoxCounterStep.editingFinished.connect(self.on_spinbox_counter_step_editing_finished)

    def consolidate_messages(self):
        self.simulator_config.consolidate_messages()

    def on_repeat_value_changed(self, value):
        self.active_item.repeat = value
        self.simulator_config.items_updated.emit([self.active_item])

    def on_item_dict_updated(self):
        self.completer_model.setStringList(self.sim_expression_parser.get_identifiers())

    def on_selected_tab_changed(self, index: int):
        if index == 0:
            if self.active_item is not None:
                self.ui.gvSimulator.jump_to_item(self.active_item)
            else:
                self.update_ui()
        else:
            self.ui.tblViewMessage.resize_columns()
            self.update_vertical_table_header()

    def refresh_message_table(self):
        self.simulator_message_table_model.protocol.messages[:] = self.simulator_config.get_all_messages()
        self.simulator_message_table_model.update()

        if isinstance(self.active_item, SimulatorMessage):
            self.simulator_message_field_model.update()

        self.ui.tblViewMessage.resize_columns()
        self.update_ui()

    def load_config_from_xml_tag(self, xml_tag, update_before=True):
        if xml_tag is None:
            return

        if update_before:
            self.simulator_config.on_project_updated()

        self.simulator_config.load_from_xml(xml_tag, self.proto_analyzer.message_types)
        self.project_manager.project_updated.emit()

    def load_simulator_file(self, filename: str):
        try:
            tree = ET.parse(filename)
            self.load_config_from_xml_tag(tree.getroot(), update_before=False)
        except Exception as e:
            logger.exception(e)

    def save_simulator_file(self, filename: str):
        tag = self.simulator_config.save_to_xml(standalone=True)
        util.write_xml_to_file(tag, filename)

    def close_all(self):
        self.simulator_scene.clear_all()

    @pyqtSlot(int, int, int)
    def create_simulator_label(self, msg_index: int, start: int, end: int):
        con = self.simulator_message_table_model.protocol
        start, end = con.convert_range(start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index)
        lbl = self.simulator_config.add_label(start=start, end=end, parent_item=con.messages[msg_index])

        try:
            index = self.simulator_message_field_model.message_type.index(lbl)
            self.ui.tblViewFieldValues.edit(self.simulator_message_field_model.createIndex(index, 0))
        except ValueError:
            pass

    @pyqtSlot()
    def open_modulator_dialog(self):
        selected_message = self.simulator_message_table_model.protocol.messages[self.ui.tblViewMessage.selected_rows[0]]
        preselected_index = selected_message.modulator_index

        modulator_dialog = ModulatorDialog(self.project_manager.modulators, tree_model=self.tree_model, parent=self)
        modulator_dialog.ui.comboBoxCustomModulations.setCurrentIndex(preselected_index)
        modulator_dialog.showMaximized()
        modulator_dialog.initialize(selected_message.encoded_bits_str[0:10])

        modulator_dialog.finished.connect(self.refresh_modulators)
        modulator_dialog.finished.connect(self.generator_tab_controller.refresh_pause_list)

    @pyqtSlot()
    def refresh_modulators(self):
        # update Generator tab ...
        cBoxModulations = self.generator_tab_controller.ui.cBoxModulations
        current_index = cBoxModulations.currentIndex()
        cBoxModulations.clear()

        for modulator in self.project_manager.modulators:
            cBoxModulations.addItem(modulator.name)

        cBoxModulations.setCurrentIndex(current_index)

        # update Simulator tab ...
        index = self.sender().ui.comboBoxCustomModulations.currentIndex()

        for row in self.ui.tblViewMessage.selected_rows:
            self.simulator_message_table_model.protocol.messages[row].modulator_index = index

    def update_goto_combobox(self, active_item: SimulatorGotoAction):
        assert isinstance(active_item, SimulatorGotoAction)
        goto_combobox = self.ui.goto_combobox

        goto_combobox.blockSignals(True)
        goto_combobox.clear()
        goto_combobox.addItem("Select item ...")
        goto_combobox.addItems(active_item.get_valid_goto_targets())
        goto_combobox.setCurrentIndex(-1)
        goto_combobox.blockSignals(False)

        index = goto_combobox.findText(self.active_item.goto_target)

        if index == -1:
            index = 0

        goto_combobox.setCurrentIndex(index)

    def update_ui(self):
        if self.active_item is not None:
            text = self.tr("Detail view for item #") + self.active_item.index()

            if isinstance(self.active_item, SimulatorMessage):
                text += " (" + self.active_item.message_type.name + ")"
                self.ui.spinBoxRepeat.setValue(self.active_item.repeat)
                self.ui.lblEncodingDecoding.setText(self.active_item.decoder.name)

            self.ui.lblMsgFieldsValues.setText(text)
        else:
            self.ui.lblMsgFieldsValues.setText(self.tr("Detail view for item"))

    def update_vertical_table_header(self):
        self.simulator_message_table_model.refresh_vertical_header()
        self.ui.tblViewMessage.resize_vertical_header()

    @pyqtSlot()
    def on_rule_cond_line_edit_text_changed(self):
        self.active_item.condition = self.ui.ruleCondLineEdit.text()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_view_type_changed(self):
        self.simulator_message_table_model.proto_view = self.ui.cbViewType.currentIndex()
        self.simulator_message_table_model.update()
        self.ui.tblViewMessage.resize_columns()

    @pyqtSlot()
    def on_goto_combobox_index_changed(self):
        if not isinstance(self.active_item, SimulatorGotoAction):
            return

        self.active_item.goto_target = None if self.ui.goto_combobox.currentIndex() == 0 else self.ui.goto_combobox.currentText()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_simulator_scene_selection_changed(self):
        selected_items = self.simulator_scene.selectedItems()
        self.active_item = selected_items[0].model_item if selected_items else None

        self.update_ui()

    @pyqtSlot()
    def on_table_selection_changed(self):
        selection = self.ui.tblViewMessage.selectionModel().selection()

        if selection.isEmpty():
            self.active_item = None
            self.ui.lNumSelectedColumns.setText("0")
        else:
            max_row = numpy.max([rng.bottom() for rng in selection])
            self.active_item = self.simulator_message_table_model.protocol.messages[max_row]
            _, _, start, end = self.ui.tblViewMessage.selection_range()
            self.ui.lNumSelectedColumns.setText(str(end - start))

        self.update_ui()

    @property
    def active_item(self):
        return self.__active_item

    @active_item.setter
    def active_item(self, value):
        self.__active_item = value

        if isinstance(self.active_item, SimulatorGotoAction):
            self.update_goto_combobox(self.active_item)

            self.ui.detail_view_widget.setCurrentIndex(1)
        elif isinstance(self.active_item, SimulatorMessage):
            self.simulator_message_field_model.update()
            self.ui.spinBoxRepeat.setValue(self.active_item.repeat)
            self.ui.lblEncodingDecoding.setText(self.active_item.decoder.name)

            self.ui.detail_view_widget.setCurrentIndex(2)
        elif (isinstance(self.active_item, SimulatorRuleCondition) and
              self.active_item.type != ConditionType.ELSE):
            self.ui.ruleCondLineEdit.setText(self.active_item.condition)
            self.ui.detail_view_widget.setCurrentIndex(3)
        elif isinstance(self.active_item, SimulatorTriggerCommandAction):
            self.ui.lineEditTriggerCommand.setText(self.active_item.command)
            self.ui.checkBoxPassTranscriptSTDIN.setChecked(self.active_item.pass_transcript)
            self.ui.detail_view_widget.setCurrentIndex(4)
        elif isinstance(self.active_item, SimulatorSleepAction):
            self.ui.doubleSpinBoxSleep.setValue(self.active_item.sleep_time)
            self.ui.detail_view_widget.setCurrentIndex(5)
        elif isinstance(self.active_item, SimulatorCounterAction):
            self.ui.spinBoxCounterStart.setValue(self.active_item.start)
            self.ui.spinBoxCounterStep.setValue(self.active_item.step)
            self.ui.detail_view_widget.setCurrentIndex(6)
        else:
            self.ui.detail_view_widget.setCurrentIndex(0)

        self.update_ui()

    @pyqtSlot()
    def on_btn_simulate_clicked(self):
        if not self.simulator_config.protocol_valid():
            QMessageBox.critical(self, self.tr("Invalid protocol configuration"),
                                 self.tr(
                                     "There are some problems with your protocol configuration. Please fix them first."))
            return

        if not len(self.simulator_config.get_all_messages()):
            QMessageBox.critical(self, self.tr("No messages found"), self.tr("Please add at least one message."))
            return

        num_simulated = len([p for p in self.project_manager.participants if p.simulate])
        if num_simulated == 0:
            if self.ui.listViewSimulate.model().rowCount() == 0:
                QMessageBox.critical(self, self.tr("No active participants"),
                                     self.tr("You have no active participants.<br>"
                                             "Please add a participant in the <i>Participants tab</i> and "
                                             "assign it to at least one message as <i>source</i> or <i>destination.</i>"))
                return
            else:
                QMessageBox.critical(self, self.tr("No participant for simulation selected"),
                                     self.tr("Please check at least one participant from the "
                                             "<i>Simulate these participants</i> list."))
                return

        try:
            self.get_simulator_dialog().exec_()
        except Exception as e:
            Errors.generic_error("An error occurred", str(e))

    def get_simulator_dialog(self) -> SimulatorDialog:
        protos = [p for proto_list in self.tree_model.protocols.values() for p in proto_list]
        signals = [p.signal for p in protos if p.signal is not None]

        s = SimulatorDialog(self.simulator_config, self.project_manager.modulators,
                            self.sim_expression_parser, self.project_manager, signals=signals,
                            signal_tree_model=self.tree_model, parent=self)

        s.rx_parameters_changed.connect(self.project_manager.on_simulator_rx_parameters_changed)
        s.sniff_parameters_changed.connect(self.project_manager.on_simulator_sniff_parameters_changed)
        s.tx_parameters_changed.connect(self.project_manager.on_simulator_tx_parameters_changed)
        s.open_in_analysis_requested.connect(self.open_in_analysis_requested.emit)
        s.rx_file_saved.connect(self.rx_file_saved.emit)

        return s

    @pyqtSlot()
    def on_btn_choose_command_clicked(self):
        file_name, ok = QFileDialog.getOpenFileName(self, self.tr("Choose program"), QDir.homePath())

        if file_name is not None and ok:
            self.ui.lineEditTriggerCommand.setText(file_name)

    @pyqtSlot()
    def on_line_edit_trigger_command_text_changed(self):
        self.active_item.command = self.ui.lineEditTriggerCommand.text()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_check_box_pass_transcript_STDIN_clicked(self):
        self.active_item.pass_transcript = self.ui.checkBoxPassTranscriptSTDIN.isChecked()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_spinbox_counter_start_editing_finished(self):
        self.active_item.start = self.ui.spinBoxCounterStart.value()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_spinbox_counter_step_editing_finished(self):
        self.active_item.step = self.ui.spinBoxCounterStep.value()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_spinbox_sleep_editing_finished(self):
        self.active_item.sleep_time = self.ui.doubleSpinBoxSleep.value()
        self.item_updated(self.active_item)

    @pyqtSlot()
    def on_participants_changed(self):
        self.update_vertical_table_header()
        self.participant_table_model.update()
        self.ui.listViewSimulate.model().update()

    def item_updated(self, item: SimulatorItem):
        self.simulator_config.items_updated.emit([item])

    @pyqtSlot()
    def refresh_tree(self):
        self.ui.treeProtocols.expandAll()

    @pyqtSlot()
    def on_btn_save_clicked(self):
        filename = FileOperator.get_save_file_name(initial_name="myprofile.sim.xml", caption="Save simulator profile")
        if filename:
            self.save_simulator_file(filename)

    @pyqtSlot()
    def on_btn_load_clicked(self):
        dialog = FileOperator.get_open_dialog(False, parent=self, name_filter="simulator")
        if dialog.exec_():
            self.load_simulator_file(dialog.selectedFiles()[0])

    @pyqtSlot()
    def on_participant_edited(self):
        self.project_manager.project_updated.emit()

    @pyqtSlot(int)
    def on_spinbox_num_repeat_value_changed(self, value):
        self.project_manager.simulator_num_repeat = value

    @pyqtSlot(int)
    def on_spinbox_timeout_value_changed(self, value):
        self.project_manager.simulator_timeout_ms = value

    @pyqtSlot(int)
    def on_spinbox_retries_value_changed(self, value):
        self.project_manager.simulator_retries = value

    @pyqtSlot(int)
    def on_combobox_error_handling_index_changed(self, index: int):
        self.project_manager.simulator_error_handling_index = index

    @pyqtSlot()
    def on_message_source_or_destination_updated(self):
        self.simulator_config.update_active_participants()

    @pyqtSlot(int, int)
    def on_table_item_link_clicked(self, row: int, column: int):
        try:
            lbl = self.simulator_message_field_model.message_type[row]  # type: SimulatorProtocolLabel
            assert lbl.is_checksum_label
            assert isinstance(self.active_item, SimulatorMessage)
        except (IndexError, AssertionError):
            return

        d = QDialog(parent=self)
        layout = QHBoxLayout()
        layout.addWidget(ChecksumWidget(lbl.label, self.active_item, self.ui.cbViewType.currentIndex()))
        d.setLayout(layout)
        d.show()

    @pyqtSlot(Participant)
    def on_participant_simulate_changed(self, participant: Participant):
        self.simulator_scene.refresh_participant(participant)

    @pyqtSlot()
    def on_active_participants_updated(self):
        self.ui.listViewSimulate.model().update()

    @pyqtSlot(int)
    def on_edit_label_triggered(self, label_index: int):
        view_type = self.ui.cbViewType.currentIndex()
        protocol_label_dialog = ProtocolLabelDialog(message=self.ui.tblViewMessage.selected_message,
                                                    viewtype=view_type, selected_index=label_index, parent=self)
        protocol_label_dialog.finished.connect(self.on_protocol_label_dialog_finished)
        protocol_label_dialog.showMaximized()

    @pyqtSlot()
    def on_protocol_label_dialog_finished(self):
        self.simulator_message_field_model.update()
        self.simulator_message_table_model.update()
        self.update_ui()

    @pyqtSlot(list)
    def on_files_dropped(self, file_urls: list):
        for filename in (file_url.toLocalFile() for file_url in file_urls if file_url.isLocalFile()):
            self.load_simulator_file(filename)