diff --git a/data/ui/signal_frame.ui b/data/ui/signal_frame.ui
index a8c39f15f4..c4af1b7cb1 100644
--- a/data/ui/signal_frame.ui
+++ b/data/ui/signal_frame.ui
@@ -778,43 +778,6 @@ stop:1 rgba(255, 255, 255, 0));
0
- -
-
-
-
- 0
- 150
-
-
-
-
- 30
- 16777215
-
-
-
- QFrame::NoFrame
-
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAlwaysOn
-
-
- false
-
-
- QGraphicsView::AnchorViewCenter
-
-
- Qt::ContainsItemShape
-
-
- QGraphicsView::DontSavePainterState
-
-
-
-
@@ -1308,11 +1271,6 @@ stop:1 rgba(255, 255, 255, 0));
QGraphicsView
urh.ui.views.EpicGraphicView.h
-
- LegendGraphicView
- QGraphicsView
- urh.ui.views.LegendGraphicView.h
-
TextEditProtocolView
QTextEdit
diff --git a/src/urh/ainterpretation/AutoInterpretation.py b/src/urh/ainterpretation/AutoInterpretation.py
index 4416100fbb..dd45db2c32 100644
--- a/src/urh/ainterpretation/AutoInterpretation.py
+++ b/src/urh/ainterpretation/AutoInterpretation.py
@@ -370,11 +370,11 @@ def estimate(iq_array: IQArray, noise: float = None, modulation: str = None) ->
message_indices = merge_message_segments_for_ook(message_indices)
if modulation == "OOK" or modulation == "ASK":
- data = signal_functions.afp_demod(iq_array.data, noise, 0)
+ data = signal_functions.afp_demod(iq_array.data, noise, "ASK")
elif modulation == "FSK":
- data = signal_functions.afp_demod(iq_array.data, noise, 1)
+ data = signal_functions.afp_demod(iq_array.data, noise, "FSK")
elif modulation == "PSK":
- data = signal_functions.afp_demod(iq_array.data, noise, 2)
+ data = signal_functions.afp_demod(iq_array.data, noise, "PSK")
else:
raise ValueError("Unsupported Modulation")
diff --git a/src/urh/ainterpretation/Wavelet.py b/src/urh/ainterpretation/Wavelet.py
index a114678570..d22e3feebe 100644
--- a/src/urh/ainterpretation/Wavelet.py
+++ b/src/urh/ainterpretation/Wavelet.py
@@ -59,7 +59,7 @@ def cwt_haar(x: np.ndarray, scale=10):
# data = np.fromfile("/tmp/psk.complex", dtype=np.complex64)
# data = np.fromfile("/home/joe/GIT/urh/tests/data/psk_generated.complex", dtype=np.complex64)[0:8000]
modulator = Modulator("")
- modulator.modulation_type_str = "PSK"
+ modulator.modulation_type = "PSK"
modulator.param_for_zero = 0
modulator.param_for_one = 180
modulator.carrier_freq_hz = 5e3
diff --git a/src/urh/cli/urh_cli.py b/src/urh/cli/urh_cli.py
index 6c8f941fd9..248bbe48a3 100755
--- a/src/urh/cli/urh_cli.py
+++ b/src/urh/cli/urh_cli.py
@@ -106,7 +106,7 @@ def build_modulator_from_args(arguments: argparse.Namespace):
result.param_for_zero = param_zero
result.param_for_one = param_one
- result.modulation_type_str = arguments.modulation_type
+ result.modulation_type = arguments.modulation_type
result.sample_rate = arguments.sample_rate
return result
@@ -150,7 +150,7 @@ def build_protocol_sniffer_from_args(arguments: argparse.Namespace):
bh = build_backend_handler_from_args(arguments)
result = ProtocolSniffer(arguments.bit_length, arguments.center, arguments.noise, arguments.tolerance,
- Modulator.MODULATION_TYPES.index(arguments.modulation_type),
+ arguments.modulation_type,
arguments.device.lower(), bh)
result.rcv_device.frequency = arguments.frequency
result.rcv_device.sample_rate = arguments.sample_rate
@@ -261,7 +261,7 @@ def parse_project_file(file_path: str):
result["carrier_phase"] = modulator.carrier_phase_deg
result["parameter_zero"] = modulator.param_for_zero
result["parameter_one"] = modulator.param_for_one
- result["modulation_type"] = modulator.modulation_type_str
+ result["modulation_type"] = modulator.modulation_type
return result
diff --git a/src/urh/constants.py b/src/urh/constants.py
index 3099939be1..8fc4485b06 100644
--- a/src/urh/constants.py
+++ b/src/urh/constants.py
@@ -45,14 +45,14 @@ class color:
# ROI-SELECTION COLORS
SELECTION_COLOR = QColor("darkblue") # overwritten by system color (bin/urh)
NOISE_COLOR = QColor("red")
-SELECTION_OPACITY = 0.8
+SELECTION_OPACITY = 1
NOISE_OPACITY = 0.4
# SEPARATION COLORS
-ONES_AREA_COLOR = QColor.fromRgb(0, 128, 128)
-ZEROS_AREA_COLOR = QColor.fromRgb(90, 9, 148)
-SEPARATION_OPACITY = 0.2
-SEPARATION_PADDING = .05 # Prozent
+ONES_AREA_COLOR = Qt.darkGreen
+ZEROS_AREA_COLOR = Qt.darkRed
+SEPARATION_OPACITY = 0.25
+SEPARATION_PADDING = .05 # percent
# PROTOCOL TABLE COLORS
SELECTED_ROW_COLOR = QColor.fromRgb(0, 0, 255)
diff --git a/src/urh/controller/CompareFrameController.py b/src/urh/controller/CompareFrameController.py
index 5cab85ede7..252962fa65 100644
--- a/src/urh/controller/CompareFrameController.py
+++ b/src/urh/controller/CompareFrameController.py
@@ -1046,10 +1046,7 @@ def on_btn_analyze_clicked(self):
self.message_type_table_model.update()
self.ui.tblViewMessageTypes.clearSelection()
except Exception as e:
- logger.exception(e)
- Errors.generic_error("Failed to assign labels",
- "An error occurred during automatic label assignment",
- traceback.format_exc())
+ Errors.exception(e)
self.ui.progressBarLogicAnalyzer.setValue(90)
diff --git a/src/urh/controller/GeneratorTabController.py b/src/urh/controller/GeneratorTabController.py
index 47ff6736e6..17e55f9b1c 100644
--- a/src/urh/controller/GeneratorTabController.py
+++ b/src/urh/controller/GeneratorTabController.py
@@ -231,7 +231,7 @@ def show_modulation_info(self):
self.ui.lCarrierPhaseValue.setText(cur_mod.carrier_phase_str)
self.ui.lBitLenValue.setText(cur_mod.bit_len_str)
self.ui.lSampleRateValue.setText(cur_mod.sample_rate_str)
- mod_type = cur_mod.modulation_type_str
+ mod_type = cur_mod.modulation_type
self.ui.lModTypeValue.setText(mod_type)
if mod_type == "ASK":
prefix = "Amplitude"
@@ -394,7 +394,7 @@ def generate_file(self):
sample_rate = 1e6
FileOperator.save_data_dialog("generated", modulated_samples, sample_rate=sample_rate, parent=self)
except Exception as e:
- Errors.generic_error(self.tr("Failed to generate data"), str(e), traceback.format_exc())
+ Errors.exception(e)
self.unsetCursor()
def prepare_modulation_buffer(self, total_samples: int, show_error=True) -> IQArray:
@@ -606,7 +606,7 @@ def on_btn_send_clicked(self):
dialog.show()
dialog.graphics_view.show_full_scene(reinitialize=True)
except Exception as e:
- Errors.generic_error(self.tr("Failed to generate data"), str(e), traceback.format_exc())
+ Errors.exception(e)
self.unsetCursor()
@pyqtSlot()
diff --git a/src/urh/controller/MainController.py b/src/urh/controller/MainController.py
index 46ac56f9c3..e62e83a50e 100644
--- a/src/urh/controller/MainController.py
+++ b/src/urh/controller/MainController.py
@@ -352,7 +352,7 @@ def close_signal_frame(self, signal_frame: SignalFrame):
self.set_frame_numbers()
self.refresh_main_menu()
except Exception as e:
- Errors.generic_error(self.tr("Failed to close"), str(e), traceback.format_exc())
+ Errors.exception(e)
self.unsetCursor()
def add_files(self, filepaths, group_id=0, enforce_sample_rate=None):
@@ -560,7 +560,7 @@ def on_open_recent_action_triggered(self):
self.add_files(FileOperator.uncompress_archives([action.data()], QDir.tempPath()))
self.unsetCursor()
except Exception as e:
- Errors.generic_error(self.tr("Failed to open"), str(e), traceback.format_exc())
+ Errors.exception(e)
self.unsetCursor()
@pyqtSlot()
@@ -783,7 +783,7 @@ def show_open_dialog(self, directory=False):
self.add_files(file_names)
self.unsetCursor()
except Exception as e:
- Errors.generic_error(self.tr("Failed to open"), str(e), traceback.format_exc())
+ Errors.exception(e)
self.unsetCursor()
@pyqtSlot()
diff --git a/src/urh/controller/SimulatorTabController.py b/src/urh/controller/SimulatorTabController.py
index c8957dae5f..2eb829cabe 100644
--- a/src/urh/controller/SimulatorTabController.py
+++ b/src/urh/controller/SimulatorTabController.py
@@ -442,7 +442,7 @@ def on_btn_simulate_clicked(self):
try:
self.get_simulator_dialog().exec_()
except Exception as e:
- Errors.generic_error("An error occurred", str(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]
diff --git a/src/urh/controller/dialogs/ModulatorDialog.py b/src/urh/controller/dialogs/ModulatorDialog.py
index c0795265ca..35ef802673 100644
--- a/src/urh/controller/dialogs/ModulatorDialog.py
+++ b/src/urh/controller/dialogs/ModulatorDialog.py
@@ -121,7 +121,7 @@ def current_modulator(self):
return mod
def set_ui_for_current_modulator(self):
- index = self.ui.comboBoxModulationType.findText("*(" + self.current_modulator.modulation_type_str + ")",
+ index = self.ui.comboBoxModulationType.findText("*(" + self.current_modulator.modulation_type + ")",
Qt.MatchWildcard)
self.ui.comboBoxModulationType.setCurrentIndex(index)
self.ui.doubleSpinBoxCarrierFreq.setValue(self.current_modulator.carrier_freq_hz)
@@ -443,10 +443,10 @@ def on_gaus_filter_wdith_changed(self):
@pyqtSlot()
def on_modulation_type_changed(self):
- if self.current_modulator.modulation_type_str == self.__cur_selected_mod_type():
+ if self.current_modulator.modulation_type == self.__cur_selected_mod_type():
write_standard_parameters = False
else:
- self.current_modulator.modulation_type_str = self.__cur_selected_mod_type()
+ self.current_modulator.modulation_type = self.__cur_selected_mod_type()
write_standard_parameters = True
self.__set_gauss_ui_visibility(self.__cur_selected_mod_type() == "GFSK")
diff --git a/src/urh/controller/dialogs/SimulatorDialog.py b/src/urh/controller/dialogs/SimulatorDialog.py
index cb8a2dfbd2..bce8d9bde7 100644
--- a/src/urh/controller/dialogs/SimulatorDialog.py
+++ b/src/urh/controller/dialogs/SimulatorDialog.py
@@ -367,7 +367,7 @@ def on_selected_tx_device_changed(self):
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))
+ Errors.exception(e)
@pyqtSlot()
def on_btn_test_sniff_settings_clicked(self):
diff --git a/src/urh/controller/widgets/ModulationSettingsWidget.py b/src/urh/controller/widgets/ModulationSettingsWidget.py
index ab1c77fe70..b2e614d171 100644
--- a/src/urh/controller/widgets/ModulationSettingsWidget.py
+++ b/src/urh/controller/widgets/ModulationSettingsWidget.py
@@ -49,10 +49,10 @@ def show_selected_modulation_infos(self):
self.ui.labelCarrierFrequencyValue.setText(modulator.carrier_frequency_str)
self.ui.labelBitLengthValue.setText(modulator.bit_len_str)
self.ui.labelSampleRateValue.setText(modulator.sample_rate_str)
- self.ui.labelModulationTypeValue.setText(modulator.modulation_type_verbose_str)
+ self.ui.labelModulationTypeValue.setText(modulator.modulation_type_verbose)
prefixes = {"ASK": "Amplitude", "PSK": "Phase", "FSK": "Frequency", "GFSK": "Frequency"}
- self.ui.labelParamZero.setText(prefixes[modulator.modulation_type_str] + " for 0:")
- self.ui.labelParamOne.setText(prefixes[modulator.modulation_type_str] + " for 1:")
+ self.ui.labelParamZero.setText(prefixes[modulator.modulation_type] + " for 0:")
+ self.ui.labelParamOne.setText(prefixes[modulator.modulation_type] + " for 1:")
self.ui.labelParamZeroValue.setText(modulator.param_for_zero_str)
self.ui.labelParamOneValue.setText(modulator.param_for_one_str)
diff --git a/src/urh/controller/widgets/SignalFrame.py b/src/urh/controller/widgets/SignalFrame.py
index 29354aebdd..ff697c922a 100644
--- a/src/urh/controller/widgets/SignalFrame.py
+++ b/src/urh/controller/widgets/SignalFrame.py
@@ -121,7 +121,6 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack, pro
else:
self.ui.lSignalTyp.setText("Complex Signal")
- self.ui.gvLegend.hide()
self.ui.lineEditSignalName.setText(self.signal.name)
self.ui.lSamplesInView.setText("{0:,}".format(self.signal.num_samples))
self.ui.lSamplesTotal.setText("{0:,}".format(self.signal.num_samples))
@@ -134,6 +133,7 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack, pro
self.scene_manager = SignalSceneManager(self.signal, self)
self.ui.gvSignal.scene_manager = self.scene_manager
+ self.scene_manager.scene.setParent(self.ui.gvSignal)
self.ui.gvSignal.setScene(self.scene_manager.scene)
self.jump_sync = True
@@ -178,7 +178,7 @@ def create_connects(self):
self.signal.bit_len_changed.connect(self.ui.spinBoxInfoLen.setValue)
self.signal.qad_center_changed.connect(self.on_signal_qad_center_changed)
self.signal.noise_threshold_changed.connect(self.on_noise_threshold_changed)
- self.signal.modulation_type_changed.connect(self.ui.cbModulationType.setCurrentIndex)
+ self.signal.modulation_type_changed.connect(self.ui.cbModulationType.setCurrentText)
self.signal.tolerance_changed.connect(self.ui.spinBoxTolerance.setValue)
self.signal.protocol_needs_update.connect(self.refresh_protocol)
self.signal.data_edited.connect(self.on_signal_data_edited) # Crop/Delete Mute etc.
@@ -188,7 +188,6 @@ def create_connects(self):
self.signal.saved_status_changed.connect(self.on_signal_data_changed_before_save)
self.ui.btnSaveSignal.clicked.connect(self.save_signal)
self.signal.name_changed.connect(self.ui.lineEditSignalName.setText)
- self.ui.gvLegend.resized.connect(self.on_gv_legend_resized)
self.ui.gvSignal.selection_width_changed.connect(self.start_proto_selection_timer)
self.ui.gvSignal.sel_area_start_end_changed.connect(self.start_proto_selection_timer)
@@ -211,7 +210,6 @@ def create_connects(self):
self.ui.gvSpectrogram.sel_area_start_end_changed.connect(self.update_selection_area)
self.ui.gvSpectrogram.selection_height_changed.connect(self.update_number_selected_samples)
self.ui.gvSignal.sep_area_changed.connect(self.set_qad_center)
- self.ui.gvSignal.sep_area_moving.connect(self.update_legend)
self.ui.sliderYScale.valueChanged.connect(self.on_slider_y_scale_value_changed)
self.ui.spinBoxXZoom.valueChanged.connect(self.on_spinbox_x_zoom_value_changed)
@@ -223,7 +221,7 @@ def create_connects(self):
self.proto_selection_timer.timeout.connect(self.update_number_selected_samples)
self.ui.cbSignalView.currentIndexChanged.connect(self.on_cb_signal_view_index_changed)
- self.ui.cbModulationType.currentIndexChanged.connect(self.on_combobox_modulation_type_index_changed)
+ self.ui.cbModulationType.currentTextChanged.connect(self.on_combobox_modulation_type_text_changed)
self.ui.cbProtoView.currentIndexChanged.connect(self.on_combo_box_proto_view_index_changed)
self.ui.chkBoxShowProtocol.stateChanged.connect(self.set_protocol_visibility)
@@ -252,7 +250,7 @@ def refresh_signal_information(self, block=True):
self.ui.spinBoxCenterOffset.setValue(self.signal.qad_center)
self.ui.spinBoxInfoLen.setValue(self.signal.bit_len)
self.ui.spinBoxNoiseTreshold.setValue(self.signal.noise_threshold_relative)
- self.ui.cbModulationType.setCurrentIndex(self.signal.modulation_type)
+ self.ui.cbModulationType.setCurrentText(self.signal.modulation_type)
self.ui.btnAdvancedModulationSettings.setVisible(self.ui.cbModulationType.currentText() == "ASK")
self.ui.spinBoxTolerance.blockSignals(False)
@@ -419,7 +417,7 @@ def save_signal_as(self):
try:
FileOperator.save_data_dialog(self.signal.name, self.signal.iq_array, self.signal.sample_rate, self.signal.wav_mode)
except Exception as e:
- Errors.generic_error("Error saving file", str(e), traceback.format_exc())
+ Errors.exception(e)
def export_demodulated(self):
try:
@@ -442,9 +440,6 @@ def export_demodulated(self):
QMessageBox.critical(self, self.tr("Error exporting demodulated data"), e.args[0])
def draw_signal(self, full_signal=False):
- gv_legend = self.ui.gvLegend
- gv_legend.y_sep = -self.signal.qad_center
-
self.scene_manager.scene_type = self.ui.cbSignalView.currentIndex()
self.scene_manager.init_scene()
if full_signal:
@@ -452,13 +447,6 @@ def draw_signal(self, full_signal=False):
else:
self.ui.gvSignal.redraw_view()
- legend = LegendScene()
- legend.setBackgroundBrush(constants.BGCOLOR)
- legend.setSceneRect(0, self.scene_manager.scene.sceneRect().y(), gv_legend.width(),
- self.scene_manager.scene.sceneRect().height())
- legend.draw_one_zero_arrows(-self.signal.qad_center)
- gv_legend.setScene(legend)
-
self.ui.gvSignal.y_sep = -self.signal.qad_center
def restore_protocol_selection(self, sel_start, sel_end, start_message, end_message, old_protoview):
@@ -595,7 +583,6 @@ def eliminate(self):
self.proto_analyzer.eliminate()
self.ui.gvSignal.scene_manager.eliminate()
- self.ui.gvLegend.eliminate()
self.ui.gvSignal.eliminate()
self.ui.gvSpectrogram.eliminate()
@@ -682,15 +669,6 @@ def on_protocol_updated(self):
self.ui.txtEdProto.setEnabled(True)
self.ui.txtEdProto.setHtml(self.proto_analyzer.plain_to_html(self.proto_view))
- @pyqtSlot(float)
- def update_legend(self, y_sep):
- if self.ui.gvLegend.isVisible():
- self.ui.gvLegend.y_sep = y_sep
- self.ui.gvLegend.refresh()
- self.ui.spinBoxCenterOffset.blockSignals(True)
- self.ui.spinBoxCenterOffset.setValue(-y_sep)
- self.ui.spinBoxCenterOffset.blockSignals(False)
-
@pyqtSlot()
def handle_protocol_sync_changed(self):
self.sync_protocol = self.ui.chkBoxSyncSelection.isChecked()
@@ -727,13 +705,6 @@ def on_cb_signal_view_index_changed(self):
self.ui.gvSignal.redraw_view(reinitialize=True)
self.ui.labelRSSI.show()
- if self.ui.cbSignalView.currentIndex() == 1:
- self.ui.gvLegend.y_scene = self.scene_manager.scene.sceneRect().y()
- self.ui.gvLegend.scene_height = self.scene_manager.scene.sceneRect().height()
- self.ui.gvLegend.refresh()
- else:
- self.ui.gvLegend.hide()
-
self.ui.gvSignal.auto_fit_view()
self.ui.gvSignal.refresh_selection_area()
qApp.processEvents()
@@ -994,11 +965,9 @@ def refresh_signal(self, draw_full_signal=False):
@pyqtSlot(float)
def on_signal_qad_center_changed(self, qad_center):
self.ui.gvSignal.y_sep = -qad_center
- self.ui.gvLegend.y_sep = -qad_center
if self.ui.cbSignalView.currentIndex() > 0:
self.scene_manager.scene.draw_sep_area(-qad_center)
- self.ui.gvLegend.refresh()
self.ui.spinBoxCenterOffset.blockSignals(False)
self.ui.spinBoxCenterOffset.setValue(qad_center)
@@ -1029,7 +998,7 @@ def contextMenuEvent(self, event: QContextMenuEvent):
def show_modulation_type(self):
self.ui.cbModulationType.blockSignals(True)
- self.ui.cbModulationType.setCurrentIndex(self.signal.modulation_type)
+ self.ui.cbModulationType.setCurrentText(self.signal.modulation_type)
self.ui.cbModulationType.blockSignals(False)
def on_participant_changed(self):
@@ -1050,20 +1019,17 @@ def on_info_btn_clicked(self):
sdc = SignalDetailsDialog(self.signal, self)
sdc.show()
- @pyqtSlot(int)
- def on_combobox_modulation_type_index_changed(self, index: int):
- if index != self.signal.modulation_type:
+ @pyqtSlot(str)
+ def on_combobox_modulation_type_text_changed(self, txt: str):
+ if txt != self.signal.modulation_type:
modulation_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer,
parameter_name="modulation_type",
- parameter_value=index)
+ parameter_value=txt)
self.undo_stack.push(modulation_action)
if self.ui.cbSignalView.currentIndex() == 1:
self.scene_manager.init_scene()
- self.ui.gvLegend.y_scene = self.scene_manager.scene.sceneRect().y()
- self.ui.gvLegend.scene_height = self.scene_manager.scene.sceneRect().height()
- self.ui.gvLegend.refresh()
self.on_slider_y_scale_value_changed()
self.ui.btnAdvancedModulationSettings.setVisible(self.ui.cbModulationType.currentText() == "ASK")
@@ -1090,13 +1056,6 @@ def on_signal_data_changed_before_save(self):
self.ui.lineEditSignalName.setFont(font)
- @pyqtSlot()
- def on_gv_legend_resized(self):
- if self.ui.gvLegend.isVisible():
- self.ui.gvLegend.y_zoom_factor = self.ui.gvSignal.transform().m22()
- self.ui.gvLegend.refresh()
- self.ui.gvLegend.translate(0, 1) # Resize verschiebt sonst Pfeile
-
@pyqtSlot()
def on_btn_show_hide_start_end_clicked(self):
show = self.ui.btnShowHideStartEnd.isChecked()
@@ -1263,7 +1222,6 @@ def on_export_fta_wanted(self):
filename=filename,
include_amplitude=filename.endswith(".fta"))
except Exception as e:
- logger.exception(e)
- Errors.generic_error("Failed to export spectrogram", str(e), traceback.format_exc())
+ Errors.exception(e)
finally:
QApplication.restoreOverrideCursor()
diff --git a/src/urh/controller/widgets/SniffSettingsWidget.py b/src/urh/controller/widgets/SniffSettingsWidget.py
index aeff74714d..eb75848878 100644
--- a/src/urh/controller/widgets/SniffSettingsWidget.py
+++ b/src/urh/controller/widgets/SniffSettingsWidget.py
@@ -33,7 +33,7 @@ def __init__(self, device_name: str, project_manager: ProjectManager, signal=Non
center=self.ui.spinbox_sniff_Center.value(),
noise=self.ui.spinbox_sniff_Noise.value(),
tolerance=self.ui.spinbox_sniff_ErrorTolerance.value(),
- modulation_type=self.ui.combox_sniff_Modulation.currentIndex(),
+ modulation_type=self.ui.combox_sniff_Modulation.currentText(),
device=device_name,
backend_handler=BackendHandler() if backend_handler is None else backend_handler,
network_raw_mode=network_raw_mode)
@@ -77,7 +77,7 @@ def set_val(widget, key: str, default):
set_val(self.ui.spinbox_sniff_Center, "center", signal.qad_center if signal else 0.02)
set_val(self.ui.spinbox_sniff_ErrorTolerance, "tolerance", signal.tolerance if signal else 5)
set_val(self.ui.spinbox_sniff_Noise, "noise", signal.noise_threshold_relative if signal else 0.001)
- set_val(self.ui.combox_sniff_Modulation, "modulation_index", signal.modulation_type if signal else 1)
+ self.ui.combox_sniff_Modulation.setCurrentText(conf_dict.get("modulation_type", signal.modulation_type if signal else "FSK"))
self.ui.comboBox_sniff_encoding.setCurrentText(conf_dict.get("decoding_name", ""))
self.ui.checkBoxAdaptiveNoise.setChecked(bool(conf_dict.get("adaptive_noise", False)))
self.ui.checkBoxAutoCenter.setChecked(bool(conf_dict.get("automatic_center", False)))
@@ -90,7 +90,7 @@ def create_connects(self):
self.ui.spinbox_sniff_Center.editingFinished.connect(self.on_center_edited)
self.ui.spinbox_sniff_BitLen.editingFinished.connect(self.on_bit_len_edited)
self.ui.spinbox_sniff_ErrorTolerance.editingFinished.connect(self.on_tolerance_edited)
- self.ui.combox_sniff_Modulation.currentIndexChanged.connect(self.on_modulation_changed)
+ self.ui.combox_sniff_Modulation.currentTextChanged.connect(self.on_modulation_changed)
self.ui.comboBox_sniff_viewtype.currentIndexChanged.connect(self.on_view_type_changed)
self.ui.lineEdit_sniff_OutputFile.editingFinished.connect(self.on_line_edit_output_file_editing_finished)
self.ui.comboBox_sniff_encoding.currentIndexChanged.connect(self.on_combobox_sniff_encoding_index_changed)
@@ -112,7 +112,7 @@ def emit_sniff_parameters_changed(self):
center=self.sniffer.signal.qad_center,
noise=self.sniffer.signal.noise_threshold,
tolerance=self.sniffer.signal.tolerance,
- modulation_index=self.sniffer.signal.modulation_type,
+ modulation_type=self.sniffer.signal.modulation_type,
decoding_name=self.sniffer.decoder.name,
adaptive_noise=self.sniffer.adaptive_noise,
automatic_center=self.sniffer.automatic_center))
@@ -137,9 +137,9 @@ def on_tolerance_edited(self):
self.sniffer.signal.tolerance = self.ui.spinbox_sniff_ErrorTolerance.value()
self.sniff_setting_edited.emit()
- @pyqtSlot(int)
- def on_modulation_changed(self, new_index: int):
- self.sniffer.signal.silent_set_modulation_type(new_index)
+ @pyqtSlot(str)
+ def on_modulation_changed(self, new_modulation: str):
+ self.sniffer.signal.silent_set_modulation_type(new_modulation)
self.sniff_setting_edited.emit()
@pyqtSlot()
@@ -186,7 +186,7 @@ def on_btn_sniff_use_signal_clicked(self):
self.ui.spinbox_sniff_Center.setValue(signal.qad_center)
self.ui.spinbox_sniff_Noise.setValue(signal.noise_threshold_relative)
self.ui.spinbox_sniff_ErrorTolerance.setValue(signal.tolerance)
- self.ui.combox_sniff_Modulation.setCurrentIndex(signal.modulation_type)
+ self.ui.combox_sniff_Modulation.setCurrentText(signal.modulation_type)
self.emit_editing_finished_signals()
diff --git a/src/urh/cythonext/signal_functions.pyx b/src/urh/cythonext/signal_functions.pyx
index 0ae9d58b85..72ac221427 100644
--- a/src/urh/cythonext/signal_functions.pyx
+++ b/src/urh/cythonext/signal_functions.pyx
@@ -5,6 +5,7 @@ import numpy as np
from libcpp cimport bool
from libc.stdint cimport uint8_t, uint16_t, uint32_t, int64_t
+from libc.stdio cimport printf
from urh.cythonext.util cimport IQ, iq, bit_array_to_number
from cython.parallel import prange
@@ -19,22 +20,33 @@ cdef extern from "math.h" nogil:
# because it can lead to OS X error: https://github.com/jopohl/urh/issues/273
# np.import_array()
+cdef int64_t PAUSE_STATE = -1
+
cdef float complex imag_unit = 1j
cdef float NOISE_FSK_PSK = -4.0
cdef float NOISE_ASK = 0.0
-cpdef float get_noise_for_mod_type(int mod_type):
- if mod_type == 0:
+cdef float get_noise_for_mod_type(str mod_type):
+ if mod_type == "ASK":
return NOISE_ASK
- elif mod_type == 1:
+ elif mod_type == "FSK":
return NOISE_FSK_PSK
- elif mod_type == 2:
+ elif mod_type == "PSK" or mod_type == "OQPSK":
return NOISE_FSK_PSK
- elif mod_type == 3: # ASK + PSK (QAM)
+ elif mod_type == "QAM":
return NOISE_ASK * NOISE_FSK_PSK
else:
return 0
+cdef tuple get_value_range_of_mod_type(str mod_type):
+ if mod_type == "ASK":
+ return 0, 1
+ if mod_type in ("GFSK", "FSK", "OQPSK", "PSK"):
+ return -np.pi, np.pi
+
+ printf("Warning unknown mod type for value range")
+ return 0, 0
+
cdef get_numpy_dtype(iq cython_type):
if str(cython.typeof(cython_type)) == "char":
return np.int8
@@ -239,7 +251,7 @@ cdef void costa_demod(IQ samples, float[::1] result, float noise_sqrd,
else:
result[i] = nco_times_sample.real
-cpdef np.ndarray[np.float32_t, ndim=1] afp_demod(IQ samples, float noise_mag, int mod_type):
+cpdef np.ndarray[np.float32_t, ndim=1] afp_demod(IQ samples, float noise_mag, str mod_type):
if len(samples) <= 2:
return np.zeros(len(samples), dtype=np.float32)
@@ -285,8 +297,8 @@ cpdef np.ndarray[np.float32_t, ndim=1] afp_demod(IQ samples, float noise_mag, in
cdef bool qam = False
- if mod_type == 2 or mod_type == 3: # PSK or QAM
- if mod_type == 3:
+ if mod_type in ("PSK", "QAM", "OQPSK"):
+ if mod_type == "QAM":
qam = True
costa_alpha = calc_costa_alpha((2 * M_PI / 100))
@@ -302,143 +314,102 @@ cpdef np.ndarray[np.float32_t, ndim=1] afp_demod(IQ samples, float noise_mag, in
result[i] = NOISE
continue
- if mod_type == 0: # ASK
+ if mod_type == "ASK":
result[i] = sqrt(magnitude) / max_magnitude
- elif mod_type == 1: # FSK
+ elif mod_type == "FSK":
#tmp = samples[i - 1].conjugate() * c
tmp = (samples[i-1, 0] - imag_unit * samples[i-1, 1]) * (real + imag_unit * imag)
result[i] = atan2(tmp.imag, tmp.real) # Freq
return np.asarray(result)
-cpdef unsigned long long find_signal_start(float[::1] demod_samples, int mod_type):
-
- cdef unsigned long i = 0
- cdef unsigned long ns = len(demod_samples)
- cdef unsigned long l = 100
- if ns < 100:
- l = ns
-
- cdef float dsample = 0
- cdef int has_oversteuern = 0
- cdef int conseq_noise = 0
- cdef int conseq_not_noise = 0
- cdef int behind_oversteuern = 0
- cdef float NOISE = get_noise_for_mod_type(mod_type)
-
- for i in range(0, l):
- dsample = demod_samples[i]
- if dsample > NOISE:
- has_oversteuern = 1
- break
-
- for i in range(0, ns):
- dsample = demod_samples[i]
-
- if dsample == NOISE:
- conseq_noise += 1
- conseq_not_noise = 0
- else:
- conseq_noise = 0
- conseq_not_noise += 1
-
- if has_oversteuern == 1:
- if has_oversteuern and conseq_noise > 100:
- behind_oversteuern = 1
+cdef inline int64_t get_current_state(float sample, float[:] thresholds, float noise_val, int n):
+ if sample == noise_val:
+ return PAUSE_STATE
- if behind_oversteuern and conseq_not_noise == 3:
- return i - 3
+ cdef int i
+ for i in range(n):
+ if sample <= thresholds[i]:
+ return i
- elif conseq_not_noise == 3:
- return i -3
+ return PAUSE_STATE
- return 0
+cpdef int64_t[:, ::1] grab_pulse_lens(float[::1] samples, float center, uint16_t tolerance,
+ str modulation_type, uint16_t bit_length,
+ uint8_t bits_per_symbol=1, float center_spacing=0.1):
+ """
+ Get the pulse lengths after quadrature demodulation
-cpdef unsigned long long find_signal_end(float[::1] demod_samples, int mod_type):
+ arr[i][0] gives type of symbol e.g. (arr[i][0] = 1) and (arr[i][0] = 0) for binary modulation
+ Pause is (arr[i][0] = -1)
+ arr[i][1] gives length of pulse
+ """
+ cdef bool is_ask = modulation_type == "ASK"
+ cdef int64_t i, j, pulse_length = 0, num_samples = len(samples)
+ cdef int64_t cur_index = 0, consecutive_ones = 0, consecutive_zeros = 0, consecutive_pause = 0
+ cdef float s = 0, s_prev = 0
+ cdef int cur_state = 0, new_state = 0, tmp_state = 0
+ cdef float NOISE = get_noise_for_mod_type(modulation_type)
- cdef unsigned long long i = 0
- cdef float dsample = 0
- cdef int conseq_not_noise = 0
- cdef float NOISE = get_noise_for_mod_type(mod_type)
- cdef unsigned long long ns = len(demod_samples)
+ cdef int modulation_order = 2**bits_per_symbol
- for i in range(ns, 0, -1):
- dsample = demod_samples[i]
+ cdef float[:] thresholds = np.empty(modulation_order, dtype=np.float32)
+ cdef tuple min_max_of_mod_type = get_value_range_of_mod_type(modulation_type)
+ cdef float min_of_mod_type = min_max_of_mod_type[0]
+ cdef float max_of_mod_type = min_max_of_mod_type[1]
- if dsample > NOISE:
- conseq_not_noise += 1
+ cdef int n = modulation_order // 2
- if conseq_not_noise == 3:
- return i + 3
+ for i in range(0, n):
+ thresholds[i] = center - (n-(i+1)) * center_spacing
- return ns
+ for i in range(n, modulation_order-1):
+ thresholds[i] = center + (i+1-n) * center_spacing
-cpdef unsigned long long[:, ::1] grab_pulse_lens(float[::1] samples, float center,
- unsigned int tolerance, int modulation_type, unsigned int bit_length):
- """
- Holt sich die Pulslängen aus den quadraturdemodulierten Samples
-
- @param samples: Samples nach der QAD
- @param center: Alles über der Treshold ist ein Einserpuls, alles darunter 0er Puls
- @return: Ein 2D Array arr.
- arr[i] gibt Position an.
- arr[i][0] gibt an ob Einspuls (arr[i][0] = 1) Nullpuls (arr[i][0] = 0) Pause (arr[i][0] = 42)
- arr[i][1] gibt die Länge des Pulses bzw. der Pause an.
- """
- cdef int is_ask = modulation_type == 0
- cdef unsigned long long i, pulse_length = 0
- cdef unsigned long long cur_index = 0, consecutive_ones = 0, consecutive_zeros = 0, consecutive_pause = 0
- cdef float s = 0, s_prev = 0
- cdef unsigned short cur_state = 0, new_state = 0
- cdef float NOISE = get_noise_for_mod_type(modulation_type)
- cdef unsigned long long num_samples = len(samples)
+ thresholds[modulation_order-1] = max_of_mod_type
- cdef unsigned long long[:, ::1] result = np.zeros((num_samples, 2), dtype=np.uint64, order="C")
+ cdef int64_t[:, ::1] result = np.zeros((num_samples, 2), dtype=np.int64, order="C")
if num_samples == 0:
return result
+ cdef int64_t[:] state_count = np.zeros(modulation_order, dtype=np.int64)
+
s_prev = samples[0]
- if s_prev == NOISE:
- cur_state = 42
- elif s_prev > center:
- cur_state = 1
- else:
- cur_state = 0
+ cur_state = get_current_state(s_prev, thresholds, NOISE, modulation_order)
for i in range(num_samples):
pulse_length += 1
s = samples[i]
- if s == NOISE:
- consecutive_pause += 1
- consecutive_ones = 0
- consecutive_zeros = 0
- if cur_state == 42:
- continue
-
- elif s > center:
- consecutive_ones += 1
- consecutive_zeros = 0
- consecutive_pause = 0
- if cur_state == 1:
- continue
+ tmp_state = get_current_state(s, thresholds, NOISE, modulation_order)
+ if tmp_state == PAUSE_STATE:
+ consecutive_pause += 1
else:
- consecutive_zeros += 1
- consecutive_ones = 0
consecutive_pause = 0
- if cur_state == 0:
- continue
- if consecutive_ones > tolerance:
- new_state = 1
- elif consecutive_zeros > tolerance:
- new_state = 0
- elif consecutive_pause > tolerance:
- new_state = 42
+ for j in range(0, modulation_order):
+ if j == tmp_state:
+ state_count[j] += 1
+ else:
+ state_count[j] = 0
+
+ if cur_state == tmp_state:
+ continue
+
+ new_state = -42
+
+ if consecutive_pause > tolerance:
+ new_state = PAUSE_STATE
else:
+ for j in range(0, modulation_order):
+ if state_count[j] > tolerance:
+ new_state = j
+ break
+
+ if new_state == -42:
continue
- if is_ask and cur_state == 42 and (pulse_length - tolerance) < bit_length:
+ if is_ask and cur_state == PAUSE_STATE and (pulse_length - tolerance) < bit_length:
# Aggregate short pauses for ASK
cur_state = 0
@@ -453,7 +424,7 @@ cpdef unsigned long long[:, ::1] grab_pulse_lens(float[::1] samples, float cente
cur_state = new_state
# Append last one
- cdef unsigned long long len_result = len(result)
+ cdef int64_t len_result = len(result)
if cur_index < len_result:
if cur_index > 0 and result[cur_index - 1, 0] == cur_state:
result[cur_index - 1, 1] += pulse_length - tolerance
@@ -464,18 +435,6 @@ cpdef unsigned long long[:, ::1] grab_pulse_lens(float[::1] samples, float cente
return result[:cur_index]
-cpdef unsigned long long estimate_bit_len(float[::1] qad_samples, float qad_center, int tolerance, int mod_type):
-
- start = find_signal_start(qad_samples, mod_type)
- cdef unsigned long long[:, ::1] ppseq = grab_pulse_lens(qad_samples[start:], qad_center, tolerance, mod_type, 0)
- cdef unsigned long long i = 0
- cdef unsigned long long l = len(ppseq)
- for i in range(0, l):
- if ppseq[i, 0] == 1:
- return ppseq[i, 1] # first pulse after pause
-
- return 100
-
cpdef int find_nearest_center(float sample, float[::1] centers, int num_centers) nogil:
cdef int i = 0
cdef float center = 0
@@ -492,9 +451,6 @@ cpdef int find_nearest_center(float sample, float[::1] centers, int num_centers)
return result
-
-from libc.stdlib cimport malloc, free
-
cpdef np.ndarray[np.complex64_t, ndim=1] fir_filter(float complex[::1] input_samples, float complex[::1] filter_taps):
cdef int i = 0, j = 0
cdef int N = len(input_samples)
diff --git a/src/urh/plugins/RfCat/RfCatPlugin.py b/src/urh/plugins/RfCat/RfCatPlugin.py
index f36369f44f..4cebd00b02 100644
--- a/src/urh/plugins/RfCat/RfCatPlugin.py
+++ b/src/urh/plugins/RfCat/RfCatPlugin.py
@@ -167,13 +167,13 @@ def __send_messages(self, messages, sample_rates):
if not self.open_rfcat():
return False
modulation = self.modulators[messages[0].modulator_index].modulation_type
- if modulation == 0: # ASK
+ if modulation == "ASK":
modulation = "MOD_ASK_OOK"
- elif modulation == 1: # FSK
+ elif modulation == "FSK":
modulation = "MOD_2FSK"
- elif modulation == 2: # GFSK
+ elif modulation == "GFSK":
modulation = "MOD_GFSK"
- elif modulation == 3: # PSK
+ elif modulation == "PSK":
modulation = "MOD_MSK"
else: # Fallback
modulation = "MOD_ASK_OOK"
diff --git a/src/urh/signalprocessing/Modulator.py b/src/urh/signalprocessing/Modulator.py
index 40530114af..93e22c82e8 100644
--- a/src/urh/signalprocessing/Modulator.py
+++ b/src/urh/signalprocessing/Modulator.py
@@ -15,14 +15,11 @@
class Modulator(object):
- """
- This class can modulate bits to a carrier.
- Very useful in generation phase.
- """
-
MODULATION_TYPES = ["ASK", "FSK", "PSK", "GFSK"]
- MODULATION_TYPES_VERBOSE = ["Amplitude Shift Keying (ASK)", "Frequency Shift Keying (FSK)",
- "Phase Shift Keying (PSK)", "Gaussian Frequeny Shift Keying (GFSK)"]
+ MODULATION_TYPES_VERBOSE = {"ASK": "Amplitude Shift Keying (ASK)",
+ "FSK": "Frequency Shift Keying (FSK)",
+ "PSK": "Phase Shift Keying (PSK)",
+ "GFSK": "Gaussian Frequeny Shift Keying (GFSK)"}
def __init__(self, name: str):
self.carrier_freq_hz = 40 * 10 ** 3
@@ -32,7 +29,7 @@ def __init__(self, name: str):
self.samples_per_symbol = 100
self.default_sample_rate = 10 ** 6
self.__sample_rate = None
- self.modulation_type = 0
+ self.__modulation_type = "ASK"
self.bits_per_symbol = 1
@@ -64,6 +61,18 @@ def get_dtype():
else:
return np.float32
+ @property
+ def modulation_type(self) -> str:
+ return self.__modulation_type
+
+ @modulation_type.setter
+ def modulation_type(self, value):
+ try:
+ # legacy support when modulation type was saved as int index
+ self.__modulation_type = self.MODULATION_TYPES[int(value)]
+ except (ValueError, IndexError):
+ self.__modulation_type = value
+
@property
def is_binary_modulation(self):
return self.bits_per_symbol == 1
@@ -124,30 +133,18 @@ def sample_rate_str(self):
return self.get_value_with_suffix(self.sample_rate)
@property
- def modulation_type_str(self):
- return self.MODULATION_TYPES[self.modulation_type]
-
- @modulation_type_str.setter
- def modulation_type_str(self, val: str):
- val = val.upper()
- if val in self.MODULATION_TYPES:
- self.modulation_type = self.MODULATION_TYPES.index(val)
-
- @property
- def modulation_type_verbose_str(self):
+ def modulation_type_verbose(self):
return self.MODULATION_TYPES_VERBOSE[self.modulation_type]
@property
def param_for_zero_str(self):
- mod = self.MODULATION_TYPES[self.modulation_type]
units = {"ASK": "%", "FSK": "Hz", "GFSK": "Hz", "PSK": "°"}
- return self.get_value_with_suffix(self.param_for_zero, units[mod])
+ return self.get_value_with_suffix(self.param_for_zero, units[self.modulation_type])
@property
def param_for_one_str(self):
- mod = self.MODULATION_TYPES[self.modulation_type]
units = {"ASK": "%", "FSK": "Hz", "GFSK": "Hz", "PSK": "°"}
- return self.get_value_with_suffix(self.param_for_one, units[mod])
+ return self.get_value_with_suffix(self.param_for_one, units[self.modulation_type])
@property
def carrier_data(self):
@@ -195,8 +192,6 @@ def modulate(self, data=None, pause=0, start=0) -> IQArray:
if len(data) == 0:
return IQArray(None, np.float32, 0)
- mod_type = self.MODULATION_TYPES[self.modulation_type]
-
dtype = self.get_dtype()
a = self.carrier_amplitude * IQArray.min_max_for_dtype(dtype)[1]
@@ -204,13 +199,13 @@ def modulate(self, data=None, pause=0, start=0) -> IQArray:
type_val = array.array(type_code, [0])[0]
parameters = self.parameters
- if mod_type == "ASK":
+ if self.modulation_type == "ASK":
parameters = array.array("f", [a*p/100 for p in parameters])
- elif mod_type == "PSK":
+ elif self.modulation_type == "PSK":
parameters = array.array("f", [p * (math.pi / 180) for p in parameters])
result = signal_functions.modulate_c(data, self.samples_per_symbol,
- mod_type, parameters, self.bits_per_symbol,
+ self.modulation_type, parameters, self.bits_per_symbol,
a, self.carrier_freq_hz,
self.carrier_phase_deg * (np.pi / 180),
self.sample_rate, pause, start, type_val,
@@ -221,10 +216,12 @@ def to_xml(self, index: int) -> ET.Element:
root = ET.Element("modulator")
for attr, val in vars(self).items():
- if attr not in ("data", "_Modulator__sample_rate", "default_sample_rate", "parameters"):
+ if attr not in ("data", "_Modulator__sample_rate", "_Modulator__modulation_type",
+ "default_sample_rate", "parameters"):
root.set(attr, str(val))
root.set("sample_rate", str(self.__sample_rate))
+ root.set("modulation_type", self.__modulation_type)
root.set("index", str(index))
root.set("parameters", ",".join(map(str, self.parameters)))
@@ -248,10 +245,8 @@ def from_xml(tag: ET.Element):
for attrib, value in tag.attrib.items():
if attrib == "index":
continue
- elif attrib == "name":
+ elif attrib == "name" or attrib == "modulation_type":
setattr(result, attrib, str(value))
- elif attrib == "modulation_type":
- setattr(result, attrib, Formatter.str2val(value, int, 0))
elif attrib == "samples_per_bit" or attrib == "samples_per_symbol":
# samples_per_bit as legacy support for older project files
result.samples_per_symbol = Formatter.str2val(value, int, 100)
diff --git a/src/urh/signalprocessing/ProtocolAnalyzer.py b/src/urh/signalprocessing/ProtocolAnalyzer.py
index b61740938b..86ec758c3e 100644
--- a/src/urh/signalprocessing/ProtocolAnalyzer.py
+++ b/src/urh/signalprocessing/ProtocolAnalyzer.py
@@ -9,14 +9,13 @@
from urh import constants
from urh.cythonext import signal_functions
from urh.signalprocessing.Encoding import Encoding
-from urh.signalprocessing.FieldType import FieldType
from urh.signalprocessing.Message import Message
from urh.signalprocessing.MessageType import MessageType
from urh.signalprocessing.Modulator import Modulator
from urh.signalprocessing.Participant import Participant
from urh.signalprocessing.ProtocoLabel import ProtocolLabel
from urh.signalprocessing.Signal import Signal
-from urh.util import util as urh_util
+from urh.util import util as urh_util, util
from urh.util.Logger import logger
@@ -226,10 +225,11 @@ def get_protocol_from_signal(self):
bit_len = signal.bit_len
ppseq = signal_functions.grab_pulse_lens(signal.qad, signal.qad_center, signal.tolerance,
- signal.modulation_type, signal.bit_len)
+ signal.modulation_type, signal.bit_len, signal.bits_per_symbol)
- bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, bit_len, pause_threshold=signal.pause_threshold)
- if signal.message_length_divisor > 1 and signal.modulation_type_str == "ASK":
+ bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, bit_len, self.signal.bits_per_symbol,
+ pause_threshold=signal.pause_threshold)
+ if signal.message_length_divisor > 1 and signal.modulation_type == "ASK":
self.__ensure_message_length_multiple(bit_data, signal.bit_len, pauses, bit_sample_pos,
signal.message_length_divisor)
@@ -271,7 +271,7 @@ def __ensure_message_length_multiple(bit_data, bit_len: int, pauses, bit_sample_
bit_sample_pos[i].extend([bit_sample_pos[i][-1] + (k + 1) * bit_len for k in range(missing_bits - 1)])
bit_sample_pos[i].append(bit_sample_pos[i][-1] + pauses[i])
- def _ppseq_to_bits(self, ppseq, bit_len: int, write_bit_sample_pos=True, pause_threshold=8):
+ def _ppseq_to_bits(self, ppseq, samples_per_symbol: int, bits_per_symbol: int, write_bit_sample_pos=True, pause_threshold=8):
bit_sampl_pos = array.array("L", [])
bit_sample_positions = []
@@ -281,12 +281,12 @@ def _ppseq_to_bits(self, ppseq, bit_len: int, write_bit_sample_pos=True, pause_t
start = 0
total_samples = 0
- pause_type = 42
- zero_pulse_type = 0
- one_pulse_type = 1
+ pause_type = -1
there_was_data = False
+ samples_per_bit = int(samples_per_symbol/bits_per_symbol)
+
if len(ppseq) > 0 and ppseq[0, 0] == pause_type:
start = 1 # Starts with Pause
total_samples = ppseq[0, 1]
@@ -294,19 +294,20 @@ def _ppseq_to_bits(self, ppseq, bit_len: int, write_bit_sample_pos=True, pause_t
for i in range(start, len(ppseq)):
cur_pulse_type = ppseq[i, 0]
num_samples = ppseq[i, 1]
- num_bits_floated = num_samples / bit_len
- num_bits = int(num_bits_floated)
- decimal_place = num_bits_floated - num_bits
+ num_symbols_float = num_samples / samples_per_symbol
+ num_symbols = int(num_symbols_float)
+ decimal_place = num_symbols_float - num_symbols
if decimal_place > 0.5:
- num_bits += 1
+ num_symbols += 1
if cur_pulse_type == pause_type:
# OOK
- if num_bits <= pause_threshold or pause_threshold == 0:
- data_bits.extend([False] * num_bits)
+ if num_symbols <= pause_threshold or pause_threshold == 0:
+ data_bits.extend([0] * (num_symbols * bits_per_symbol))
if write_bit_sample_pos:
- bit_sampl_pos.extend([total_samples + k * bit_len for k in range(num_bits)])
+ bit_sampl_pos.extend([total_samples + k * samples_per_bit
+ for k in range(num_symbols*bits_per_symbol)])
elif not there_was_data:
# Ignore this pause, if there were no information
@@ -325,18 +326,12 @@ def _ppseq_to_bits(self, ppseq, bit_len: int, write_bit_sample_pos=True, pause_t
data_bits[:] = array.array("B", [])
pauses.append(num_samples)
there_was_data = False
-
- elif cur_pulse_type == zero_pulse_type:
- data_bits.extend([False] * num_bits)
- if write_bit_sample_pos:
- bit_sampl_pos.extend([total_samples + k * bit_len for k in range(num_bits)])
-
- elif cur_pulse_type == one_pulse_type:
- if not there_was_data:
- there_was_data = num_bits > 0
- data_bits.extend([True] * num_bits)
+ else:
+ data_bits.extend(util.number_to_bits(cur_pulse_type, bits_per_symbol) * num_symbols)
+ if not there_was_data and num_symbols > 0:
+ there_was_data = True
if write_bit_sample_pos:
- bit_sampl_pos.extend([total_samples + k * bit_len for k in range(num_bits)])
+ bit_sampl_pos.extend([total_samples + k * samples_per_bit for k in range(num_symbols*bits_per_symbol)])
total_samples += num_samples
diff --git a/src/urh/signalprocessing/ProtocolSniffer.py b/src/urh/signalprocessing/ProtocolSniffer.py
index b43f8f0df0..f850cd8d82 100644
--- a/src/urh/signalprocessing/ProtocolSniffer.py
+++ b/src/urh/signalprocessing/ProtocolSniffer.py
@@ -29,7 +29,7 @@ class ProtocolSniffer(ProtocolAnalyzer, QObject):
BUFFER_SIZE_MB = 100
def __init__(self, bit_len: int, center: float, noise: float, tolerance: int,
- modulation_type: int, device: str, backend_handler: BackendHandler, network_raw_mode=False):
+ modulation_type: str, device: str, backend_handler: BackendHandler, network_raw_mode=False):
signal = Signal("", "LiveSignal")
signal.bit_len = bit_len
signal.qad_center = center
@@ -204,9 +204,11 @@ def __demodulate_data(self, data):
self.signal.qad_center = AutoInterpretation.detect_center(self.signal.qad, max_size=150*self.signal.bit_len)
ppseq = grab_pulse_lens(self.signal.qad, self.signal.qad_center,
- self.signal.tolerance, self.signal.modulation_type, self.signal.bit_len)
+ self.signal.tolerance, self.signal.modulation_type, self.signal.bit_len,
+ self.signal.bits_per_symbol)
- bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, bit_len, write_bit_sample_pos=False)
+ bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, bit_len,
+ self.signal.bits_per_symbol, write_bit_sample_pos=False)
for bits, pause in zip(bit_data, pauses):
message = Message(bits, pause, bit_len=bit_len, message_type=self.default_message_type,
diff --git a/src/urh/signalprocessing/Signal.py b/src/urh/signalprocessing/Signal.py
index 915a2a2ffb..1ff2a0431c 100644
--- a/src/urh/signalprocessing/Signal.py
+++ b/src/urh/signalprocessing/Signal.py
@@ -28,7 +28,8 @@ class Signal(QObject):
qad_center_changed = pyqtSignal(float)
name_changed = pyqtSignal(str)
sample_rate_changed = pyqtSignal(float)
- modulation_type_changed = pyqtSignal(int)
+ modulation_type_changed = pyqtSignal(str)
+ bits_per_symbol_changed = pyqtSignal(int)
saved_status_changed = pyqtSignal()
protocol_needs_update = pyqtSignal()
@@ -53,8 +54,8 @@ def __init__(self, filename: str, name="Signal", modulation: str = None, sample_
self.__changed = False
if modulation is None:
modulation = "FSK"
- self.__modulation_type = self.MODULATION_TYPES.index(modulation)
- self.__modulation_order = 2
+ self.__modulation_type = modulation
+ self.__bits_per_symbol = 1
self.__parameter_cache = {mod: {"qad_center": None, "bit_len": None} for mod in self.MODULATION_TYPES}
@@ -148,17 +149,11 @@ def parameter_cache(self, val):
self.__parameter_cache = val
@property
- def modulation_type(self):
+ def modulation_type(self) -> str:
return self.__modulation_type
@modulation_type.setter
- def modulation_type(self, value: int):
- """
- 0 - "ASK", 1 - "FSK", 2 - "PSK", 3 - "APSK (QAM)"
-
- :param value:
- :return:
- """
+ def modulation_type(self, value: str):
if self.__modulation_type != value:
self.__modulation_type = value
self._qad = None
@@ -168,12 +163,18 @@ def modulation_type(self, value: int):
self.protocol_needs_update.emit()
@property
- def modulation_type_str(self):
- return self.MODULATION_TYPES[self.modulation_type]
+ def bits_per_symbol(self):
+ return self.__bits_per_symbol
- @modulation_type_str.setter
- def modulation_type_str(self, value: str):
- self.modulation_type = self.MODULATION_TYPES.index(value)
+ @bits_per_symbol.setter
+ def bits_per_symbol(self, value: int):
+ if self.__bits_per_symbol != value:
+ self.__bits_per_symbol = value
+ self._qad = None
+
+ self.bits_per_symbol_changed.emit(self.__bits_per_symbol)
+ if not self.block_protocol_update:
+ self.protocol_needs_update.emit()
@property
def bit_len(self):
@@ -312,16 +313,6 @@ def save_as(self, filename: str):
self.changed = False
QApplication.instance().restoreOverrideCursor()
- def get_signal_start(self) -> int:
- """
- Index ab dem das Signal losgeht (Nach Übersteuern + Pause am Anfang)
-
- """
- return signal_functions.find_signal_start(self.qad, self.modulation_type)
-
- def get_signal_end(self):
- return signal_functions.find_signal_end(self.qad, self.modulation_type)
-
def quad_demod(self):
return signal_functions.afp_demod(self.iq_array.data, self.noise_threshold, self.modulation_type)
@@ -358,8 +349,8 @@ def create_new(self, start=0, end=0, new_data=None):
def auto_detect(self, emit_update=True, detect_modulation=True, detect_noise=False) -> bool:
kwargs = {"noise": None if detect_noise else self.noise_threshold,
"modulation": None if detect_modulation
- else "OOK" if self.__modulation_order == 2 and self.__modulation_type == 0
- else self.modulation_type_str}
+ else "OOK" if self.bits_per_symbol == 1 and self.modulation_type == "ASK"
+ else self.modulation_type}
estimated_params = AutoInterpretation.estimate(self.iq_array, **kwargs)
if estimated_params is None:
@@ -372,7 +363,7 @@ def auto_detect(self, emit_update=True, detect_modulation=True, detect_noise=Fal
self.noise_threshold = estimated_params["noise"]
if detect_modulation:
- self.modulation_type_str = estimated_params["modulation_type"]
+ self.modulation_type = estimated_params["modulation_type"]
self.qad_center = estimated_params["center"]
self.tolerance = estimated_params["tolerance"]
@@ -420,7 +411,7 @@ def eliminate(self):
self._qad = None
self.parameter_cache.clear()
- def silent_set_modulation_type(self, mod_type: int):
+ def silent_set_modulation_type(self, mod_type: str):
self.__modulation_type = mod_type
def insert_data(self, index: int, data: np.ndarray):
diff --git a/src/urh/ui/actions/ChangeSignalParameter.py b/src/urh/ui/actions/ChangeSignalParameter.py
index cb7e07552b..6223303225 100644
--- a/src/urh/ui/actions/ChangeSignalParameter.py
+++ b/src/urh/ui/actions/ChangeSignalParameter.py
@@ -1,6 +1,5 @@
import copy
-import numpy as np
from PyQt5.QtWidgets import QUndoCommand
from urh.signalprocessing.ProtocolAnalyzer import ProtocolAnalyzer
@@ -18,13 +17,14 @@ def __init__(self, signal: Signal, protocol: ProtocolAnalyzer, parameter_name: s
self.parameter_value = parameter_value
self.orig_value = getattr(self.signal, self.parameter_name)
- fmt2 = "d" if isinstance(self.orig_value, int) else ".4n"
- fmt3 = "d" if isinstance(parameter_value, int) else ".4n"
+ fmt2 = "d" if isinstance(self.orig_value, int) else ".4n" if isinstance(self.orig_value, float) else "s"
+ fmt3 = "d" if isinstance(parameter_value, int) else ".4n" if isinstance(parameter_value, float) else "s"
signal_name = signal.name[:10] + "..." if len(signal.name) > 10 else signal.name
- self.setText(("change {0} of {1} from {2:" + fmt2 + "} to {3:" + fmt3 + "}").format(parameter_name, signal_name,
- self.orig_value,
- parameter_value))
+ self.setText(
+ ("change {0} of {1} from {2:" + fmt2 + "} to {3:" + fmt3 + "}")
+ .format(parameter_name, signal_name, self.orig_value, parameter_value)
+ )
self.protocol = protocol
self.orig_messages = copy.deepcopy(self.protocol.messages)
diff --git a/src/urh/ui/painting/GridScene.py b/src/urh/ui/painting/GridScene.py
index faf7716567..4498c3ada0 100644
--- a/src/urh/ui/painting/GridScene.py
+++ b/src/urh/ui/painting/GridScene.py
@@ -4,6 +4,7 @@
from urh import constants
from urh.ui.painting.ZoomableScene import ZoomableScene
+from urh.util import util
from urh.util.Formatter import Formatter
@@ -17,13 +18,6 @@ def __init__(self, parent=None):
super().__init__(parent)
self.setSceneRect(0,0,10,10)
- def __calc_x_y_scale(self, rect):
- view_rect = self.parent().view_rect() if hasattr(self.parent(), "view_rect") else rect
- parent_width = self.parent().width() if hasattr(self.parent(), "width") else 750
- scale_x = view_rect.width() / parent_width
- scale_y = view_rect.height() / parent_width
- return scale_x, scale_y
-
def drawBackground(self, painter: QPainter, rect: QRectF):
# freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate)
if self.draw_grid and len(self.frequencies) > 0:
@@ -50,7 +44,7 @@ def drawBackground(self, painter: QPainter, rect: QRectF):
+ [QLineF(rect.left(), y, rect.right(), y) for y in np.arange(top, bottom, y_grid_size)]
painter.drawLines(lines)
- scale_x, scale_y = self.__calc_x_y_scale(rect)
+ scale_x, scale_y = util.calc_x_y_scale(rect, self.parent())
painter.scale(scale_x, scale_y)
counter = -1 # Counter for Label for every second line
@@ -91,7 +85,7 @@ def draw_frequency_marker(self, x_pos, frequency):
self.frequency_marker[1].setFont(font)
self.frequency_marker[0].setLine(x_pos, y1, x_pos, y2)
- scale_x, scale_y = self.__calc_x_y_scale(self.sceneRect())
+ scale_x, scale_y = util.calc_x_y_scale(self.sceneRect(), self.parent())
self.frequency_marker[1].setTransform(QTransform.fromScale(scale_x, scale_y), False)
self.frequency_marker[1].setText("Tune to " + Formatter.big_value_with_suffix(frequency, decimals=3))
font_metric = QFontMetrics(self.frequency_marker[1].font())
diff --git a/src/urh/ui/painting/ZoomableScene.py b/src/urh/ui/painting/ZoomableScene.py
index 4af0986aa8..0171f0997d 100644
--- a/src/urh/ui/painting/ZoomableScene.py
+++ b/src/urh/ui/painting/ZoomableScene.py
@@ -1,8 +1,10 @@
-from PyQt5.QtGui import QPen
-from PyQt5.QtWidgets import QGraphicsScene, QGraphicsRectItem, QGraphicsSceneDragDropEvent
+from PyQt5.QtCore import QRectF
+from PyQt5.QtGui import QPen, QFont, QTransform, QFontMetrics
+from PyQt5.QtWidgets import QGraphicsScene, QGraphicsRectItem, QGraphicsSceneDragDropEvent, QGraphicsSimpleTextItem
from urh import constants
from urh.ui.painting.HorizontalSelection import HorizontalSelection
+from urh.util import util
class ZoomableScene(QGraphicsScene):
@@ -11,6 +13,14 @@ def __init__(self, parent=None):
self.noise_area = None
self.ones_area = None
self.zeros_area = None
+
+ self.y_mid = 0
+
+ self.always_show_symbols_legend = False
+
+ self.ones_caption = None
+ self.zeros_caption = None
+
self.ones_arrow = None
self.zeros_arrow = None
self.selection_area = HorizontalSelection(0, 0, 0, 0, fillcolor=constants.SELECTION_COLOR,
@@ -35,7 +45,45 @@ def draw_noise_area(self, y, h):
self.noise_area.setY(y)
self.noise_area.height = h
- def draw_sep_area(self, y_mid):
+ def redraw_legend(self, force_show=False):
+ if not (force_show or self.always_show_symbols_legend):
+ if self.zeros_caption is not None:
+ self.zeros_caption.hide()
+ if self.ones_caption is not None:
+ self.ones_caption.hide()
+ return
+
+ if self.ones_caption is None:
+ font = QFont()
+ font.setPointSize(32)
+ font.setBold(True)
+ self.ones_caption = self.addSimpleText("1", font)
+
+ if self.zeros_caption is None:
+ font = QFont()
+ font.setPointSize(32)
+ font.setBold(True)
+ self.zeros_caption = self.addSimpleText("0", font)
+
+ view_rect = self.parent().view_rect() # type: QRectF
+
+ self.ones_caption.show()
+ self.zeros_caption.show()
+ padding = view_rect.height() / 20
+ scale_x, scale_y = util.calc_x_y_scale(self.ones_area.rect(), self.parent())
+
+ y_mid = self.y_mid
+ fm = QFontMetrics(self.ones_caption.font())
+ self.ones_caption.setPos(view_rect.x() + view_rect.width() - fm.width("1") * scale_x,
+ y_mid - fm.height()*scale_y - padding)
+ self.ones_caption.setTransform(QTransform.fromScale(scale_x, scale_y), False)
+
+ scale_x, scale_y = util.calc_x_y_scale(self.zeros_area.rect(), self.parent())
+
+ self.zeros_caption.setPos(view_rect.x() + view_rect.width() - fm.width("0") * scale_x, y_mid + padding)
+ self.zeros_caption.setTransform(QTransform.fromScale(scale_x, scale_y), False)
+
+ def draw_sep_area(self, y_mid, show_symbols=False):
x = self.sceneRect().x()
y = self.sceneRect().y()
h = self.sceneRect().height()
@@ -49,7 +97,6 @@ def draw_sep_area(self, y_mid):
self.ones_area.setOpacity(constants.SEPARATION_OPACITY)
self.ones_area.setPen(QPen(constants.TRANSPARENT_COLOR, 0))
self.addItem(self.ones_area)
-
else:
self.ones_area.show()
self.ones_area.setRect(x, y, w, h / 2 + y_mid)
@@ -65,6 +112,9 @@ def draw_sep_area(self, y_mid):
self.zeros_area.show()
self.zeros_area.setRect(x, start, w, (y + h) - start)
+ self.y_mid = y_mid
+ self.redraw_legend(show_symbols)
+
def clear(self):
self.noise_area = None
self.ones_area = None
diff --git a/src/urh/ui/ui_signal_frame.py b/src/urh/ui/ui_signal_frame.py
index 410d17376a..f6f15cbb68 100644
--- a/src/urh/ui/ui_signal_frame.py
+++ b/src/urh/ui/ui_signal_frame.py
@@ -316,18 +316,6 @@ def setupUi(self, SignalFrame):
self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_6.setSpacing(0)
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
- self.gvLegend = LegendGraphicView(self.pageSignal)
- self.gvLegend.setMinimumSize(QtCore.QSize(0, 150))
- self.gvLegend.setMaximumSize(QtCore.QSize(30, 16777215))
- self.gvLegend.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.gvLegend.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- self.gvLegend.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
- self.gvLegend.setInteractive(False)
- self.gvLegend.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter)
- self.gvLegend.setRubberBandSelectionMode(QtCore.Qt.ContainsItemShape)
- self.gvLegend.setOptimizationFlags(QtWidgets.QGraphicsView.DontSavePainterState)
- self.gvLegend.setObjectName("gvLegend")
- self.horizontalLayout_6.addWidget(self.gvLegend)
self.gvSignal = EpicGraphicView(self.pageSignal)
self.gvSignal.setEnabled(True)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
@@ -611,7 +599,6 @@ def retranslateUi(self, SignalFrame):
from urh.ui.views.EpicGraphicView import EpicGraphicView
-from urh.ui.views.LegendGraphicView import LegendGraphicView
from urh.ui.views.SpectrogramGraphicView import SpectrogramGraphicView
from urh.ui.views.TextEditProtocolView import TextEditProtocolView
from . import urh_rc
diff --git a/src/urh/ui/views/EditableGraphicView.py b/src/urh/ui/views/EditableGraphicView.py
index 1fcf4edbe3..1ebed49139 100644
--- a/src/urh/ui/views/EditableGraphicView.py
+++ b/src/urh/ui/views/EditableGraphicView.py
@@ -68,6 +68,14 @@ def __init__(self, parent=None):
self.save_as_action.setShortcutContext(Qt.WidgetWithChildrenShortcut)
self.addAction(self.save_as_action)
+ self.show_symbol_legend_action = QAction(self.tr("Show symbol legend"), self)
+ self.show_symbol_legend_action.setShortcut("L")
+ self.show_symbol_legend_action.triggered.connect(self.toggle_symbol_legend)
+ self.show_symbol_legend_action.setShortcutContext(Qt.WidgetWithChildrenShortcut)
+ self.show_symbol_legend_action.setCheckable(True)
+ self.show_symbol_legend_action.setChecked(False)
+ self.addAction(self.show_symbol_legend_action)
+
self.insert_sine_action = QAction(self.tr("Insert sine wave..."), self)
font = self.insert_sine_action.font()
font.setBold(True)
@@ -209,11 +217,18 @@ def create_context_menu(self):
export_demod_action = menu.addAction("Export demodulated...")
export_demod_action.triggered.connect(self.export_demodulated_clicked.emit)
+ menu.addAction(self.show_symbol_legend_action)
+
return menu
def clear_horizontal_selection(self):
self.set_horizontal_selection(0, 0)
+ def toggle_symbol_legend(self):
+ if self.scene_type == 1:
+ self.scene().always_show_symbols_legend = self.show_symbol_legend_action.isChecked()
+ self.scene().draw_sep_area(self.y_sep)
+
@pyqtSlot()
def on_insert_sine_action_triggered(self):
if self.something_is_selected:
diff --git a/src/urh/ui/views/SelectableGraphicView.py b/src/urh/ui/views/SelectableGraphicView.py
index 6fc6030d9b..871ed0ced7 100644
--- a/src/urh/ui/views/SelectableGraphicView.py
+++ b/src/urh/ui/views/SelectableGraphicView.py
@@ -152,7 +152,7 @@ def mouseMoveEvent(self, event: QMouseEvent):
y = self.sceneRect().y()
h = self.sceneRect().height()
if y < y_sep < y + h:
- self.scene().draw_sep_area(y_sep)
+ self.scene().draw_sep_area(y_sep, show_symbols=True)
self.sep_area_moving.emit(y_sep)
elif self.is_pos_in_separea(self.mapToScene(event.pos())):
self.setCursor(Qt.SplitVCursor)
diff --git a/src/urh/ui/views/ZoomableGraphicView.py b/src/urh/ui/views/ZoomableGraphicView.py
index eb953c8973..7af92421ee 100644
--- a/src/urh/ui/views/ZoomableGraphicView.py
+++ b/src/urh/ui/views/ZoomableGraphicView.py
@@ -179,6 +179,9 @@ def redraw_view(self, reinitialize=False):
start, end = vr.x(), vr.x() + vr.width()
self.scene_manager.show_scene_section(start, end, *self._get_sub_path_ranges_and_colors(start, end))
+ if self.scene_type == 1:
+ self.scene().redraw_legend()
+
def _get_sub_path_ranges_and_colors(self, start: float, end: float):
# Overwritten in Epic Graphic View
return None, None
diff --git a/src/urh/util/Errors.py b/src/urh/util/Errors.py
index ed953e41c0..f38156950c 100644
--- a/src/urh/util/Errors.py
+++ b/src/urh/util/Errors.py
@@ -1,7 +1,10 @@
import sys
+import traceback
+
from PyQt5.QtWidgets import QMessageBox, QWidget
from urh.util.Formatter import Formatter
+from urh.util.Logger import logger
class Errors:
@@ -14,6 +17,14 @@ def generic_error(title: str, msg: str, detailed_msg: str = None):
"\n", "
")
QMessageBox.critical(w, title, msg)
+ @staticmethod
+ def exception(exception: Exception):
+ logger.exception(exception)
+ w = QWidget()
+ msg = "Error: " + str(exception).replace("\n", "
") + "
"
+ msg += traceback.format_exc().replace("\n", "
")
+ QMessageBox.critical(w, "An error occurred", msg)
+
@staticmethod
def no_device():
w = QWidget()
diff --git a/src/urh/util/ProjectManager.py b/src/urh/util/ProjectManager.py
index 036af8f05f..a401b58c41 100644
--- a/src/urh/util/ProjectManager.py
+++ b/src/urh/util/ProjectManager.py
@@ -487,7 +487,11 @@ def read_project_file_for_signal(self, signal: Signal):
signal.noise_threshold = float(sig_tag.get("noise_threshold", 0.1))
signal.sample_rate = float(sig_tag.get("sample_rate", 1e6))
signal.bit_len = int(sig_tag.get("bit_length", 100))
- signal.modulation_type = int(sig_tag.get("modulation_type", 0))
+ try:
+ # Legacy support when modulation type was integer
+ signal.modulation_type = Signal.MODULATION_TYPES[int(sig_tag.get("modulation_type", 0))]
+ except (ValueError, IndexError):
+ signal.modulation_type = sig_tag.get("modulation_type", "ASK")
signal.pause_threshold = int(sig_tag.get("pause_threshold", 8))
signal.message_length_divisor = int(sig_tag.get("message_length_divisor", 1))
break
diff --git a/src/urh/util/util.py b/src/urh/util/util.py
index ddbdedbebc..aa8492ff75 100644
--- a/src/urh/util/util.py
+++ b/src/urh/util/util.py
@@ -452,3 +452,14 @@ def set_splitter_stylesheet(splitter: QSplitter):
"stop:0.5 rgba({0}, {1}, {2}, {3}),"
"stop:0.8 rgba(255, 255, 255, 0));"
"image: url(:/icons/icons/splitter_handle_vertical.svg);}}".format(r, g, b, a))
+
+
+def calc_x_y_scale(rect, parent):
+ view_rect = parent.view_rect() if hasattr(parent, "view_rect") else rect
+ parent_width = parent.width() if hasattr(parent, "width") else 750
+ parent_height = parent.height() if hasattr(parent, "height") else 300
+
+ scale_x = view_rect.width() / parent_width
+ scale_y = view_rect.height() / parent_height
+
+ return scale_x, scale_y
diff --git a/tests/PlotTests.py b/tests/PlotTests.py
index 06f3df1fbe..4eaada092f 100644
--- a/tests/PlotTests.py
+++ b/tests/PlotTests.py
@@ -14,7 +14,7 @@
class PlotTests(unittest.TestCase):
def test_plot(self):
modulator = Modulator("gfsk")
- modulator.modulation_type_str = "GFSK"
+ modulator.modulation_type = "GFSK"
modulator.samples_per_symbol = 100
modulator.sample_rate = 1e6
modulator.param_for_one = 20e3
@@ -34,7 +34,7 @@ def test_plot(self):
plt.title("Modulated Wave")
plt.subplot(2, 1, 2)
- qad = signal_functions.afp_demod(np.ascontiguousarray(data), 0, 1)
+ qad = signal_functions.afp_demod(np.ascontiguousarray(data), 0, "FSK")
plt.plot(qad)
plt.title("Quad Demod")
@@ -42,7 +42,7 @@ def test_plot(self):
def test_carrier_auto_detect(self):
signal = Signal(get_path_for_data_file("wsp.complex"), "test")
- signal.modulation_type = 0
+ signal.modulation_type = "ASK"
signal.noise_threshold = 0.035
signal.qad_center = 0.0245
signal.bit_len = 25
diff --git a/tests/auto_interpretation/auto_interpretation_test_util.py b/tests/auto_interpretation/auto_interpretation_test_util.py
index 6b9bcefb8d..99cb7b7541 100644
--- a/tests/auto_interpretation/auto_interpretation_test_util.py
+++ b/tests/auto_interpretation/auto_interpretation_test_util.py
@@ -18,7 +18,7 @@ def demodulate(signal_data, mod_type: str, bit_length, center, noise, tolerance,
signal.iq_array = IQArray(signal_data.view(np.float32))
else:
signal.iq_array = IQArray(signal_data)
- signal.modulation_type = signal.MODULATION_TYPES.index(mod_type)
+ signal.modulation_type = mod_type
signal.bit_len = bit_length
signal.qad_center = center
signal.noise_threshold = noise
diff --git a/tests/auto_interpretation/test_center_detection.py b/tests/auto_interpretation/test_center_detection.py
index 60bd4df504..41c705fecb 100644
--- a/tests/auto_interpretation/test_center_detection.py
+++ b/tests/auto_interpretation/test_center_detection.py
@@ -26,7 +26,7 @@ def generate_rectangular_signal(bits: str, bit_len: int):
def test_noisy_rect(self):
data = Signal(get_path_for_data_file("fsk.complex")).iq_array.data
- rect = afp_demod(data, 0.008, 1)[5:15000]
+ rect = afp_demod(data, 0.008, "FSK")[5:15000]
center = detect_center(rect)
self.assertGreaterEqual(center, -0.0587)
@@ -34,7 +34,7 @@ def test_noisy_rect(self):
def test_ask_center_detection(self):
data = Signal(get_path_for_data_file("ask.complex")).iq_array.data
- rect = afp_demod(data, 0.01111, 0)
+ rect = afp_demod(data, 0.01111, "ASK")
center = detect_center(rect)
self.assertGreaterEqual(center, 0)
@@ -42,7 +42,7 @@ def test_ask_center_detection(self):
def test_enocean_center_detection(self):
data = Signal(get_path_for_data_file("enocean.complex")).iq_array.data
- rect = afp_demod(data, 0.05, 0)
+ rect = afp_demod(data, 0.05, "ASK")
messages = [rect[2107:5432], rect[20428:23758], rect[44216:47546]]
for i, msg in enumerate(messages):
@@ -54,7 +54,7 @@ def test_ask_50_center_detection(self):
message_indices = [(0, 8000), (18000, 26000), (36000, 44000), (54000, 62000), (72000, 80000)]
data = Signal(get_path_for_data_file("ask50.complex")).iq_array.data
- rect = afp_demod(data, 0.0509, 0)
+ rect = afp_demod(data, 0.0509, "ASK")
for start, end in message_indices:
center = detect_center(rect[start:end])
@@ -63,7 +63,7 @@ def test_ask_50_center_detection(self):
def test_homematic_center_detection(self):
data = Signal(get_path_for_data_file("homematic.coco"), "").iq_array.data
- rect = afp_demod(data, 0.0012, 1)
+ rect = afp_demod(data, 0.0012, "FSK")
msg1 = rect[17719:37861]
msg2 = rect[70412:99385]
@@ -78,7 +78,7 @@ def test_homematic_center_detection(self):
def test_noised_homematic_center_detection(self):
data = Signal(get_path_for_data_file("noised_homematic.complex"), "").iq_array.data
- rect = afp_demod(data, 0.0, 1)
+ rect = afp_demod(data, 0.0, "FSK")
center = detect_center(rect)
@@ -87,14 +87,14 @@ def test_noised_homematic_center_detection(self):
def test_fsk_15db_center_detection(self):
data = Signal(get_path_for_data_file("FSK15.complex"), "").iq_array.data
- rect = afp_demod(data, 0, 1)
+ rect = afp_demod(data, 0, "FSK")
center = detect_center(rect)
self.assertGreaterEqual(center, -0.1979)
self.assertLessEqual(center, 0.1131)
def test_fsk_10db_center_detection(self):
data = Signal(get_path_for_data_file("FSK10.complex"), "").iq_array.data
- rect = afp_demod(data, 0, 1)
+ rect = afp_demod(data, 0, "FSK")
center = detect_center(rect)
self.assertGreaterEqual(center, -0.1413)
self.assertLessEqual(center, 0.05)
@@ -107,12 +107,12 @@ def test_fsk_live_capture(self):
filtered_data = moving_average_filter.apply_fir_filter(data.flatten()).view(np.float32)
filtered_data = filtered_data.reshape((len(filtered_data)//2, 2))
- rect = afp_demod(filtered_data, 0.0175, 1)
+ rect = afp_demod(filtered_data, 0.0175, "FSK")
center = detect_center(rect)
self.assertGreaterEqual(center, -0.0148, msg="Filtered")
self.assertLessEqual(center, 0.01, msg="Filtered")
- rect = afp_demod(data, 0.0175, 1)
+ rect = afp_demod(data, 0.0175, "FSK")
center = detect_center(rect)
self.assertGreaterEqual(center, -0.02, msg="Original")
self.assertLessEqual(center, 0.01, msg="Original")
diff --git a/tests/auto_interpretation/test_message_segmentation.py b/tests/auto_interpretation/test_message_segmentation.py
index 64b7b7c099..fa0b641774 100644
--- a/tests/auto_interpretation/test_message_segmentation.py
+++ b/tests/auto_interpretation/test_message_segmentation.py
@@ -47,7 +47,7 @@ def test_message_segmentation_fsk_xavax(self):
def test_segmentation_ask_50(self):
modulator = Modulator("ask50")
- modulator.modulation_type_str = "ASK"
+ modulator.modulation_type = "ASK"
modulator.param_for_zero = 50
modulator.param_for_one = 100
modulator.samples_per_symbol = 100
diff --git a/tests/auto_interpretation/test_modulation_detection.py b/tests/auto_interpretation/test_modulation_detection.py
index d825555da5..76bd39716b 100644
--- a/tests/auto_interpretation/test_modulation_detection.py
+++ b/tests/auto_interpretation/test_modulation_detection.py
@@ -32,7 +32,7 @@ def test_ask50_detection(self):
def test_psk_detection(self):
modulator = Modulator("")
- modulator.modulation_type_str = "PSK"
+ modulator.modulation_type = "PSK"
modulator.param_for_zero = 0
modulator.param_for_one = 180
diff --git a/tests/cli/test_cli_logic.py b/tests/cli/test_cli_logic.py
index 4f2463d4b3..b31d23147e 100644
--- a/tests/cli/test_cli_logic.py
+++ b/tests/cli/test_cli_logic.py
@@ -13,7 +13,7 @@ def test_cli_modulate_messages(self):
modulator = Modulator("test")
modulator.sample_rate = 2e3
modulator.samples_per_symbol = 100
- modulator.modulation_type_str = "ASK"
+ modulator.modulation_type = "ASK"
modulator.param_for_zero = 0
modulator.param_for_one = 100
diff --git a/tests/cli/test_cli_parsing.py b/tests/cli/test_cli_parsing.py
index 8495bd94fb..df3c445758 100644
--- a/tests/cli/test_cli_parsing.py
+++ b/tests/cli/test_cli_parsing.py
@@ -27,7 +27,7 @@ def test_build_modulator_from_args(self):
args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6"
" -p0 0 -p1 1 -mo ASK -cf 1337e3 -ca 0.9 -bl 24 -cp 30".split())
modulator = urh_cli.build_modulator_from_args(args)
- self.assertEqual(modulator.modulation_type_str, "ASK")
+ self.assertEqual(modulator.modulation_type, "ASK")
self.assertEqual(modulator.sample_rate, 2e6)
self.assertEqual(modulator.samples_per_symbol, 24)
self.assertEqual(modulator.param_for_zero, 0)
@@ -45,7 +45,7 @@ def test_build_modulator_from_args(self):
args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6"
" -p0 20e3 -p1=-20e3 -mo FSK -cf 1337e3 -ca 0.9 -bl 24 -cp 30".split())
modulator = urh_cli.build_modulator_from_args(args)
- self.assertEqual(modulator.modulation_type_str, "FSK")
+ self.assertEqual(modulator.modulation_type, "FSK")
self.assertEqual(modulator.param_for_zero, 20e3)
self.assertEqual(modulator.param_for_one, -20e3)
diff --git a/tests/performance/modulator_performance.py b/tests/performance/modulator_performance.py
index 85fc1e2e4a..4b5df9fbce 100644
--- a/tests/performance/modulator_performance.py
+++ b/tests/performance/modulator_performance.py
@@ -6,7 +6,7 @@
def test_fsk_performance():
bit_data = "10" * 100 + "0000011111" + "001101011" * 100 + "111111100000" * 100
modulator = Modulator("Perf")
- modulator.modulation_type_str = "FSK"
+ modulator.modulation_type = "FSK"
t = time.time()
result = modulator.modulate(bit_data, pause=10000000)
elapsed = time.time() - t
@@ -18,7 +18,7 @@ def test_fsk_performance():
def test_ask_performance():
bit_data = "10" * 100 + "0000011111" + "001101011" * 100 + "111111100000" * 1000
modulator = Modulator("Perf")
- modulator.modulation_type_str = "ASK"
+ modulator.modulation_type = "ASK"
t = time.time()
result = modulator.modulate(bit_data, pause=10000000)
elapsed = time.time() - t
@@ -30,7 +30,7 @@ def test_ask_performance():
def test_psk_performance():
bit_data = "10" * 100 + "0000011111" + "001101011" * 100 + "111111100000" * 1000
modulator = Modulator("Perf")
- modulator.modulation_type_str = "PSK"
+ modulator.modulation_type = "PSK"
t = time.time()
result = modulator.modulate(bit_data, pause=10000000)
elapsed = time.time() - t
@@ -41,7 +41,7 @@ def test_psk_performance():
def test_gfsk_performance():
bit_data = "10" * 100 + "0000011111" + "001101011" * 100 + "111111100000" * 100
modulator = Modulator("Perf")
- modulator.modulation_type_str = "GFSK"
+ modulator.modulation_type = "GFSK"
t = time.time()
result = modulator.modulate(bit_data, pause=10000000)
elapsed = time.time() - t
diff --git a/tests/test_demodulations.py b/tests/test_demodulations.py
index 7f6b41a49a..aeac57b339 100644
--- a/tests/test_demodulations.py
+++ b/tests/test_demodulations.py
@@ -1,6 +1,9 @@
+import array
import unittest
from tests.utils_testing import get_path_for_data_file
+from urh.cythonext.signal_functions import modulate_c
+from urh.signalprocessing.IQArray import IQArray
from urh.signalprocessing.ProtocolAnalyzer import ProtocolAnalyzer
from urh.signalprocessing.Signal import Signal
@@ -8,9 +11,9 @@
class TestDemodulations(unittest.TestCase):
def test_ask(self):
signal = Signal(get_path_for_data_file("ask.complex"), "ASK-Test")
- signal.modulation_type = 0
+ signal.modulation_type = "ASK"
signal.bit_len = 295
- signal.qad_center = -0.1667
+ signal.qad_center = 0.0219
self.assertEqual(signal.num_samples, 13710)
proto_analyzer = ProtocolAnalyzer(signal)
@@ -19,7 +22,7 @@ def test_ask(self):
def test_ask_two(self):
signal = Signal(get_path_for_data_file("ask_short.complex"), "ASK-Test2")
- signal.modulation_type = 0
+ signal.modulation_type = "ASK"
signal.noise_threshold = 0.0299
signal.bit_len = 16
signal.qad_center = 0.1300
@@ -32,7 +35,7 @@ def test_ask_two(self):
def test_fsk(self):
signal = Signal(get_path_for_data_file("fsk.complex"), "FSK-Test")
- signal.modulation_type = 1
+ signal.modulation_type = "FSK"
signal.bit_len = 100
signal.qad_center = 0
@@ -43,7 +46,7 @@ def test_fsk(self):
def test_psk(self):
signal = Signal(get_path_for_data_file("psk_gen_noisy.complex"), "PSK-Test")
- signal.modulation_type = 2
+ signal.modulation_type = "PSK"
signal.bit_len = 300
signal.qad_center = 0.0281
signal.noise_threshold = 0
@@ -52,3 +55,18 @@ def test_psk(self):
proto_analyzer = ProtocolAnalyzer(signal)
proto_analyzer.get_protocol_from_signal()
self.assertEqual(proto_analyzer.plain_bits_str[0], "101100")
+
+ def test_4_fsk(self):
+ bits = array.array("B", [1, 0, 1, 0, 1, 1, 0, 0, 0, 1])
+ parameters = array.array("f", [-20e3, -10e3, 10e3, 20e3])
+ result = modulate_c(bits, 100, "FSK", parameters, 2, 1, 40e3, 0, 1e6, 1000, 0, parameters[0])
+
+ signal = Signal("")
+ signal.iq_array = IQArray(result)
+ signal.bits_per_symbol = 2
+ signal.qad_center = 0
+
+ proto_analyzer = ProtocolAnalyzer(signal)
+ proto_analyzer.get_protocol_from_signal()
+ self.assertEqual(proto_analyzer.plain_bits_str[0], "1010110001")
+
diff --git a/tests/test_generator.py b/tests/test_generator.py
index 3fd6c931f1..18b2197931 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -52,7 +52,7 @@ def test_generation(self):
# Generate Datafile
modulator = gframe.modulators[0]
- modulator.modulation_type = 0
+ modulator.modulation_type = "ASK"
modulator.samples_per_symbol = 300
buffer = gframe.prepare_modulation_buffer(gframe.total_modulated_samples, show_error=False)
modulated_data = gframe.modulate_data(buffer)
diff --git a/tests/test_modulator.py b/tests/test_modulator.py
index 735bfc6718..d7cf3fc968 100644
--- a/tests/test_modulator.py
+++ b/tests/test_modulator.py
@@ -24,12 +24,12 @@ def setUp(self):
def test_ask_fsk_psk_modulation(self):
modulations = ["ASK", "FSK", "PSK"]
- for i, modulation in enumerate(modulations):
+ for modulation in modulations:
modulator = Modulator(modulation)
tmp_dir = QDir.tempPath()
filename = "{0}_mod.complex".format(modulation)
filename = os.path.join(tmp_dir, filename)
- modulator.modulation_type = i
+ modulator.modulation_type = modulation
modulator.samples_per_symbol = self.samples_per_symbol
if modulation == "ASK":
@@ -45,7 +45,7 @@ def test_ask_fsk_psk_modulation(self):
modulator.modulate(self.modulation_data, self.pause).tofile(filename)
signal = Signal(filename, modulation)
- signal.modulation_type = i
+ signal.modulation_type = modulation
signal.bit_len = self.samples_per_symbol
if modulation == "ASK":
signal.qad_center = 0.5
@@ -63,14 +63,14 @@ def test_gfsk(self):
target_file = os.path.join(tempfile.gettempdir(), "test.complex")
modulator = Modulator("gfsk")
- modulator.modulation_type_str = "FSK"
+ modulator.modulation_type = "GFSK"
modulator.samples_per_symbol = 100
modulator.sample_rate = 1e6
modulator.param_for_one = 20e3
modulator.param_for_zero = -10e3
data1 = modulator.modulate([True, False, False, True, False], 9437)
data2 = modulator.modulate([True, False, True], 9845) #, start=len(s))
- data3 = modulator.modulate([True, False, True, False], 8457) #, start=len(s))
+ data3 = modulator.modulate([True, False, True, False], 8458) #, start=len(s))
s = np.concatenate((data1, data2, data3))
s.tofile(target_file)
@@ -81,7 +81,7 @@ def test_gfsk(self):
def test_performance(self):
t = time.time()
modulator = Modulator("Perf")
- modulator.modulation_type = 1
+ modulator.modulation_type = "FSK"
modulator.modulate([True] * 1000, pause=10000000)
elapsed = time.time() - t
self.assertLess(elapsed, 0.5)
diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py
index 1f9c0c1bd5..673a1c72b5 100644
--- a/tests/test_project_manager.py
+++ b/tests/test_project_manager.py
@@ -34,7 +34,7 @@ def test_save_modulations(self):
self.gframe.modulators[0].carrier_amplitude = amplitude
self.gframe.modulators[0].carrier_freq_hz = 1337
self.gframe.modulators[0].carrier_phase_deg = 42
- self.gframe.modulators[0].modulation_type = 1
+ self.gframe.modulators[0].modulation_type = "FSK"
self.gframe.modulators[0].sample_rate = 10 ** 3
self.gframe.modulators.append(Modulator("test 2"))
self.gframe.modulators = self.gframe.modulators[:2] # Take only the first two
@@ -48,7 +48,7 @@ def test_save_modulations(self):
self.assertEqual(loaded_mods[1].name, "test 2")
self.assertEqual(loaded_mods[0].carrier_freq_hz, 1337)
self.assertEqual(loaded_mods[0].carrier_phase_deg, 42)
- self.assertEqual(loaded_mods[0].modulation_type, 1)
+ self.assertEqual(loaded_mods[0].modulation_type, "FSK")
self.assertEqual(loaded_mods[0].sample_rate, 10 ** 3)
self.gframe.modulators.clear()
diff --git a/tests/test_protocol_analyzer.py b/tests/test_protocol_analyzer.py
index 52cc58bd68..bca3e55506 100644
--- a/tests/test_protocol_analyzer.py
+++ b/tests/test_protocol_analyzer.py
@@ -11,7 +11,7 @@
class TestProtocolAnalyzer(unittest.TestCase):
def test_get_bit_sample_pos(self):
signal = Signal(get_path_for_data_file("ASK_mod.complex"), "Bit sample pos test")
- signal.modulation_type = 0
+ signal.modulation_type = "ASK"
signal.bit_len = 100
proto_analyzer = ProtocolAnalyzer(signal)
@@ -41,7 +41,7 @@ def test_fsk_freq_detection(self):
def test_get_rssi_of_message(self):
signal = Signal(get_path_for_data_file("two_participants.coco"), "RSSI-Test")
- signal.modulation_type = 1
+ signal.modulation_type = "FSK"
signal.bit_len = 100
signal.qad_center = -0.0507
diff --git a/tests/test_protocol_sniffer.py b/tests/test_protocol_sniffer.py
index 0d097ae347..a6d82cd2a3 100644
--- a/tests/test_protocol_sniffer.py
+++ b/tests/test_protocol_sniffer.py
@@ -24,7 +24,7 @@ def test_protocol_sniffer(self):
center = 0.0942
noise = 0.1
tolerance = 2
- modulation_type = 1
+ modulation_type = "FSK"
sample_rate = 1e6
device_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME
sniffer = ProtocolSniffer(bit_len=bit_len, center=center, noise=noise, tolerance=tolerance,
diff --git a/tests/test_signal_tab_GUI.py b/tests/test_signal_tab_GUI.py
index cfb736b90c..bb32b0d4a3 100644
--- a/tests/test_signal_tab_GUI.py
+++ b/tests/test_signal_tab_GUI.py
@@ -198,21 +198,6 @@ def test_selection_sync(self):
self.assertAlmostEqual((128440 - 89383) / 1000000,
(frame.ui.gvSignal.view_rect().width()) / 1000000, places=1)
- def test_legend_graphic_view(self):
- self.add_signal_to_form("esaver.coco")
- frame = self.form.signal_tab_controller.signal_frames[0]
-
- self.assertTrue(frame.ui.gvLegend.isHidden())
- frame.ui.cbSignalView.setCurrentIndex(1)
- self.assertFalse(frame.ui.gvLegend.isHidden())
-
- self.assertAlmostEqual(frame.ui.gvLegend.y_sep, -frame.ui.spinBoxCenterOffset.value(), places=4)
-
- frame.ui.spinBoxCenterOffset.setValue(0)
- frame.ui.spinBoxCenterOffset.editingFinished.emit()
-
- self.assertEqual(frame.ui.gvLegend.y_sep, 0)
-
def test_auto_detect_button(self):
self.add_signal_to_form("esaver.coco")
frame = self.form.signal_tab_controller.signal_frames[0]
@@ -244,8 +229,6 @@ def test_demodulated_view(self):
frame.ui.cbSignalView.setCurrentIndex(1)
QApplication.instance().processEvents()
self.assertEqual(frame.ui.gvSignal.scene_type, 1)
- if self.SHOW:
- self.assertTrue(frame.ui.gvLegend.isVisible())
def test_context_menu_text_edit_protocol_view(self):
self.add_signal_to_form("esaver.coco")
diff --git a/tests/test_simulator_dialog.py b/tests/test_simulator_dialog.py
index 198cd452f8..76dec62acd 100644
--- a/tests/test_simulator_dialog.py
+++ b/tests/test_simulator_dialog.py
@@ -86,7 +86,7 @@ def test_set_sniff_parameters(self):
self.assertEqual(simulator.sniffer.signal.noise_threshold_relative, 0.1234)
sniff_settings_widget.ui.combox_sniff_Modulation.setCurrentText("PSK")
- self.assertEqual(simulator.sniffer.signal.modulation_type_str, "PSK")
+ self.assertEqual(simulator.sniffer.signal.modulation_type, "PSK")
decodings = [sniff_settings_widget.ui.comboBox_sniff_encoding.itemText(i) for i in
range(sniff_settings_widget.ui.comboBox_sniff_encoding.count())]
diff --git a/tests/test_util.py b/tests/test_util.py
index 023cff1df7..f9ca02b9c2 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -55,7 +55,7 @@ def test_get_receive_buffer_size(self):
def test_write_pcap(self):
signal = Signal(get_path_for_data_file("ask.complex"), "ASK-Test")
- signal.modulation_type = 0
+ signal.modulation_type = "ASK"
signal.bit_len = 295
signal.qad_center = -0.1667
self.assertEqual(signal.num_samples, 13710)