class EndlessSender(object): """ Enter endless send mode for a device and send data if data gets pushed to ringbuffer. """ def __init__(self, backend_handler, name: str): self.__device = VirtualDevice(backend_handler=backend_handler, name=name, mode=Mode.send) self.ringbuffer = RingBuffer( int(constants.CONTINUOUS_BUFFER_SIZE_MB * 10**6) // 8, self.__device.data_type) self.__device.continuous_send_ring_buffer = self.ringbuffer self.__device.is_send_continuous = True @property def device(self) -> VirtualDevice: return self.__device @device.setter def device(self, value: VirtualDevice): self.__device = value self.__device.is_send_continuous = True self.ringbuffer = RingBuffer( int(constants.CONTINUOUS_BUFFER_SIZE_MB * 10**6) // 8, self.__device.data_type) self.__device.continuous_send_ring_buffer = self.ringbuffer @property def device_name(self) -> str: return self.device.name @device_name.setter def device_name(self, value: str): if value != self.device_name: self.device = VirtualDevice( backend_handler=self.device.backend_handler, name=value, mode=Mode.send) def start(self): self.device.num_sending_repeats = 0 self.device.start() def stop(self): self.device.stop("EndlessSender stopped.") def push_data(self, data: np.ndarray): self.ringbuffer.push(data)
class EndlessSender(object): """ Enter endless send mode for a device and send data if data gets pushed to ringbuffer. """ def __init__(self, backend_handler, name: str): self.__device = VirtualDevice(backend_handler=backend_handler, name=name, mode=Mode.send) self.ringbuffer = RingBuffer(int(constants.CONTINUOUS_BUFFER_SIZE_MB * 10 ** 6) // 8) self.__device.continuous_send_ring_buffer = self.ringbuffer self.__device.is_send_continuous = True self.__device.num_sending_repeats = 0 @property def device(self) -> VirtualDevice: return self.__device @device.setter def device(self, value: VirtualDevice): self.__device = value self.__device.is_send_continuous = True self.__device.num_sending_repeats = 0 self.__device.continuous_send_ring_buffer = self.ringbuffer @property def device_name(self) -> str: return self.device.name @device_name.setter def device_name(self, value: str): if value != self.device_name: self.device = VirtualDevice(backend_handler=self.device.backend_handler, name=value, mode=Mode.send) def start(self): self.device.start() def stop(self): self.device.stop("EndlessSender stopped.") def push_data(self, data: np.ndarray): self.ringbuffer.push(data)
class ProtocolSniffer(ProtocolAnalyzer, QObject): """ This class is used for live sniffing a protocol with certain signal parameters. """ started = pyqtSignal() stopped = pyqtSignal() message_sniffed = pyqtSignal() def __init__(self, bit_len: int, center: float, noise: float, tolerance: int, modulation_type: int, device: str, backend_handler: BackendHandler, network_raw_mode=False): signal = Signal("", "LiveSignal") signal.bit_len = bit_len signal.qad_center = center signal.noise_threshold = noise signal.tolerance = tolerance signal.silent_set_modulation_type(modulation_type) ProtocolAnalyzer.__init__(self, signal) QObject.__init__(self, None) self.network_raw_mode = network_raw_mode self.backend_handler = backend_handler self.rcv_device = VirtualDevice(self.backend_handler, device, Mode.receive, resume_on_full_receive_buffer=True, raw_mode=network_raw_mode) self.rcv_device.emit_data_received_signal = True self.rcv_device.data_received.connect(self.on_data_received) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) self.real_time = real_time self.data_cache = [] self.reading_data = False self.adaptive_noise = False self.pause_length = 0 self.store_messages = True self.__sniff_file = "" self.__store_data = True def decoded_to_string(self, view: int, start=0, include_timestamps=True): result = [] for msg in self.messages[start:]: result.append(self.message_to_string(msg, view, include_timestamps)) return "\n".join(result) def message_to_string(self, message: Message, view: int, include_timestamps=True): msg_str_data = [] if include_timestamps: msg_date = datetime.fromtimestamp(message.timestamp) msg_str_data.append(msg_date.strftime("[%Y-%m-%d %H:%M:%S.%f]")) msg_str_data.append( message.view_to_string(view, decoded=True, show_pauses=False)) return " ".join(msg_str_data) @property def sniff_file(self): return self.__sniff_file @sniff_file.setter def sniff_file(self, val): self.__sniff_file = val if self.__sniff_file: self.__store_data = False @property def device_name(self): return self.rcv_device.name @device_name.setter def device_name(self, value: str): if value != self.rcv_device.name: self.rcv_device.free_data() self.rcv_device = VirtualDevice(self.backend_handler, value, Mode.receive, device_ip="192.168.10.2", resume_on_full_receive_buffer=True, raw_mode=self.network_raw_mode) self.rcv_device.emit_data_received_signal = True self.rcv_device.data_received.connect(self.on_data_received) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) def sniff(self): self.rcv_device.start() @pyqtSlot(np.ndarray) def on_data_received(self, data: np.ndarray): if self.rcv_device.is_raw_mode: self.__demodulate_data(data) elif self.rcv_device.backend == Backends.network: # We receive the bits here for bit_str in self.rcv_device.data: msg = Message.from_plain_bits_str(bit_str) msg.decoder = self.decoder self.messages.append(msg) self.message_sniffed.emit() self.rcv_device.free_data() # do not store received bits twice if self.sniff_file and not os.path.isdir(self.sniff_file): plain_bits_str = self.plain_bits_str if plain_bits_str: with open(self.sniff_file, "a") as f: f.write("\n".join(plain_bits_str) + "\n") if not self.__store_data: self.messages.clear() def __demodulate_data(self, data): """ Demodulates received IQ data and adds demodulated bits to messages :param data: :return: """ rssi_squared = np.mean(data.real**2 + data.imag**2) is_above_noise = rssi_squared > self.signal.noise_threshold**2 if self.adaptive_noise and not is_above_noise: self.signal.noise_threshold = 0.9 * self.signal.noise_threshold + 0.1 * np.max( np.abs(data)) if is_above_noise: self.data_cache.append(data) self.pause_length = 0 return else: self.pause_length += len(data) if self.pause_length < 10 * self.signal.bit_len: self.data_cache.append(data) return if len(self.data_cache) == 0: return # clear cache and start a new message self.signal._fulldata = np.concatenate(self.data_cache) self.data_cache.clear() self.signal._qad = None bit_len = 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) bit_data, pauses, bit_sample_pos = self._ppseq_to_bits( ppseq, bit_len, 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, decoder=self.decoder) self.messages.append(message) self.message_sniffed.emit() def stop(self): self.rcv_device.stop("Stopping receiving due to user interaction") def clear(self): self.data_cache.clear() self.messages.clear() def __emit_started(self): self.started.emit() def __emit_stopped(self): if hasattr(self, "stopped"): self.stopped.emit()
class ProtocolSniffer(ProtocolAnalyzer, QObject): """ This class is used for live sniffing a protocol with certain signal parameters. """ started = pyqtSignal() stopped = pyqtSignal() message_sniffed = pyqtSignal(int) BUFFER_SIZE_MB = 100 def __init__(self, samples_per_symbol: int, center: float, center_spacing: float, noise: float, tolerance: int, modulation_type: str, bits_per_symbol: int, device: str, backend_handler: BackendHandler, network_raw_mode=False): signal = Signal("", "LiveSignal") signal.samples_per_symbol = samples_per_symbol signal.center = center signal.center_spacing = center_spacing signal.noise_threshold = noise signal.tolerance = tolerance signal.silent_set_modulation_type(modulation_type) signal.bits_per_symbol = bits_per_symbol ProtocolAnalyzer.__init__(self, signal) QObject.__init__(self, None) self.network_raw_mode = network_raw_mode self.backend_handler = backend_handler self.rcv_device = VirtualDevice(self.backend_handler, device, Mode.receive, resume_on_full_receive_buffer=True, raw_mode=network_raw_mode) signal.iq_array = IQArray(None, self.rcv_device.data_type, 0) self.sniff_thread = Thread(target=self.check_for_data, daemon=True) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) self.__buffer = IQArray(None, np.float32, 0) self.__init_buffer() self.__current_buffer_index = 0 self.reading_data = False self.adaptive_noise = False self.automatic_center = False self.pause_length = 0 self.is_running = False self.store_messages = True self.__sniff_file = "" self.__store_data = True def __add_to_buffer(self, data: np.ndarray): n = len(data) if n + self.__current_buffer_index > len(self.__buffer): n = len(self.__buffer) - self.__current_buffer_index - 1 logger.warning("Buffer of protocol sniffer is full") self.__buffer[self.__current_buffer_index:self.__current_buffer_index + n] = data[:n] self.__current_buffer_index += n def __clear_buffer(self): self.__current_buffer_index = 0 def __buffer_is_full(self): return self.__current_buffer_index >= len(self.__buffer) - 2 def __init_buffer(self): self.__buffer = IQArray(None, self.rcv_device.data_type, int(self.BUFFER_SIZE_MB * 1000 * 1000 / 8)) self.__current_buffer_index = 0 def decoded_to_string(self, view: int, start=0, include_timestamps=True): result = [] for msg in self.messages[start:]: result.append(self.message_to_string(msg, view, include_timestamps)) return "\n".join(result) def message_to_string(self, message: Message, view: int, include_timestamps=True): msg_str_data = [] if include_timestamps: msg_date = datetime.fromtimestamp(message.timestamp) msg_str_data.append(msg_date.strftime("[%Y-%m-%d %H:%M:%S.%f]")) msg_str_data.append( message.view_to_string(view, decoded=True, show_pauses=False)) return " ".join(msg_str_data) @property def sniff_file(self): return self.__sniff_file @sniff_file.setter def sniff_file(self, val): self.__sniff_file = val if self.__sniff_file: self.__store_data = False @property def device_name(self): return self.rcv_device.name @device_name.setter def device_name(self, value: str): if value != self.rcv_device.name: self.rcv_device.free_data() self.rcv_device = VirtualDevice(self.backend_handler, value, Mode.receive, device_ip="192.168.10.2", resume_on_full_receive_buffer=True, raw_mode=self.network_raw_mode) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) self.signal.iq_array = IQArray(None, self.rcv_device.data_type, 0) self.__init_buffer() def sniff(self): self.is_running = True self.rcv_device.start() self.sniff_thread = Thread(target=self.check_for_data, daemon=True) self.sniff_thread.start() def check_for_data(self): old_index = 0 while self.is_running: time.sleep(0.01) if self.rcv_device.is_raw_mode: if old_index <= self.rcv_device.current_index: data = self.rcv_device.data[old_index:self.rcv_device. current_index] else: data = np.concatenate( (self.rcv_device.data[old_index:], self.rcv_device.data[:self.rcv_device.current_index])) old_index = self.rcv_device.current_index self.__demodulate_data(data) elif self.rcv_device.backend == Backends.network: # We receive the bits here for bit_str in self.rcv_device.data: msg = Message.from_plain_bits_str(bit_str) msg.decoder = self.decoder self.messages.append(msg) self.message_sniffed.emit(len(self.messages) - 1) self.rcv_device.free_data() # do not store received bits twice if self.sniff_file and not os.path.isdir(self.sniff_file): plain_bits_str = self.plain_bits_str if plain_bits_str: with open(self.sniff_file, "a") as f: f.write("\n".join(plain_bits_str) + "\n") if not self.__store_data: self.messages.clear() def __demodulate_data(self, data): """ Demodulates received IQ data and adds demodulated bits to messages :param data: :return: """ if len(data) == 0: return power_spectrum = data.real**2.0 + data.imag**2.0 is_above_noise = np.sqrt( np.mean(power_spectrum)) > self.signal.noise_threshold if self.adaptive_noise and not is_above_noise: self.signal.noise_threshold = 0.9 * self.signal.noise_threshold + 0.1 * np.sqrt( np.max(power_spectrum)) if is_above_noise: self.__add_to_buffer(data) self.pause_length = 0 if not self.__buffer_is_full(): return else: self.pause_length += len(data) if self.pause_length < 10 * self.signal.samples_per_symbol: self.__add_to_buffer(data) if not self.__buffer_is_full(): return if self.__current_buffer_index == 0: return # clear cache and start a new message self.signal.iq_array = IQArray( self.__buffer[0:self.__current_buffer_index]) self.__clear_buffer() self.signal._qad = None samples_per_symbol = self.signal.samples_per_symbol if self.automatic_center: self.signal.center = AutoInterpretation.detect_center( self.signal.qad, max_size=150 * samples_per_symbol) ppseq = grab_pulse_lens(self.signal.qad, self.signal.center, self.signal.tolerance, self.signal.modulation_type, self.signal.samples_per_symbol, self.signal.bits_per_symbol, self.signal.center_spacing) bit_data, pauses, bit_sample_pos = self._ppseq_to_bits( ppseq, samples_per_symbol, self.signal.bits_per_symbol, write_bit_sample_pos=False) for bits, pause in zip(bit_data, pauses): message = Message(bits, pause, samples_per_symbol=samples_per_symbol, message_type=self.default_message_type, decoder=self.decoder) self.messages.append(message) self.message_sniffed.emit(len(self.messages) - 1) def stop(self): self.is_running = False self.rcv_device.stop("Stopping receiving due to user interaction") if self.sniff_thread.is_alive(): self.sniff_thread.join(0.1) if self.sniff_thread.is_alive(): logger.error("Sniff thread is still alive") def clear(self): self.__clear_buffer() self.messages.clear() def __emit_started(self): self.started.emit() def __emit_stopped(self): if hasattr(self, "stopped"): self.stopped.emit()
class SpectrumDialogController(SendRecvDialog): files_recorded = pyqtSignal(str) left_click = QtCore.pyqtSignal() right_click = QtCore.pyqtSignal() drag_started = pyqtSignal(QPoint) my_start = pyqtSignal(bool) change_tab = pyqtSignal() un_freaze_scroll = pyqtSignal(bool) freaze_scroll = pyqtSignal(bool) un_freaze_scroll2 = pyqtSignal(bool) freaze_scroll2 = pyqtSignal(bool) def __init__(self, project_manager, parent=None, testing_mode=False): super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) self.project_manager = project_manager self.graphics_view = self.ui.graphicsViewFFT self.update_interval = 1 self.ui.stackedWidget.setCurrentWidget(self.ui.page_spectrum) self.hide_send_ui_items() self.index = '' self.ui.btnSave.hide() self.setWindowTitle("Spectrum Analyzer") self.setWindowIcon(QIcon(":/icons/icons/spectrum.svg")) self.ui.btnStart.setToolTip(self.tr("Старт")) self.ui.btnStop.setToolTip(self.tr("Стоп")) self.ui.btnNuke1.setToolTip( self.tr(" Включення/виключення \nприймачів діапазону 4-6 ГГц")) self.ui.btnNuke2.setToolTip( self.tr(" Включення/виключення \nприймачів діапазону 6-8 ГГц")) self.ui.btnRecordIQ.setToolTip( self.tr("Реєстрація IQ відліків тривалістю до 15 секунд")) self.ui.btnMon.setToolTip( self.tr("Додаткове вікно завантаженності діапазонів")) self.scene_manager = FFTSceneManager(parent=self, graphic_view=self.graphics_view) self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.ui.graphicsViewSpectrogram.setScene(QGraphicsScene()) self.__clear_spectrogram() self.gain_timer = QTimer(self) self.gain_timer.setSingleShot(True) self.if_gain_timer = QTimer(self) self.if_gain_timer.setSingleShot(True) self.bb_gain_timer = QTimer(self) self.bb_gain_timer.setSingleShot(True) self.my_overlap_factor = 0.5 self.my_clear_timer = QTimer(self) self.my_clear_timer.setSingleShot(True) self.old_freq = None self.hide_receive_ui_items() self.create_connects() self.device_settings_widget.update_for_new_device( overwrite_settings=False) self.value1 = [] self.value1.append(20950) self.summ = [] self.tick = 0 self.click = 0 self.my_save = False self.ui.btnSave.setEnabled(False) self.my_start.emit(True) self.bd_freq = '' self.my_monitor_controller = MyMon(parent=self.ui.groupBox) self.ui.groupBox.layout().addWidget(self.my_monitor_controller) self.my_monitor_controller.BarIndex.connect(self.change) self.status_k = 0 self.mymy_freq = None self.chek_freq = 0 self.MyConf = MyConf() self.my_mass_vodopad = [] self.my_monitor_dialog = MyMon_Dialog() self.ui.btnSetting.setChecked(True) self.ui.btnRecordIQ.setEnabled(False) self.ui.btnSetting.setStyleSheet("background-color: green") self.ui.btnMon.clicked.connect(self.MonDialog) self.ui.btnConf.clicked.connect(self.ConfDialog) @pyqtSlot(list) def my_tr(self, data): self.my_monitor_dialog.new_series(data) def MonDialog(self): self.my_monitor_controller.tr_sig_1.connect(self.my_tr) self.my_monitor_controller.tr_sig_2.connect(self.my_tr) self.my_monitor_controller.tr_sig_3.connect(self.my_tr) self.my_monitor_controller.tr_sig_4.connect(self.my_tr) self.my_monitor_dialog.show() def ConfDialog(self): self.MyConf.show() def __clear_spectrogram(self): self.my_mass_vodopad = [] self.ui.graphicsViewSpectrogram.scene().clear() window_size = Spectrogram.DEFAULT_FFT_WINDOW_SIZE self.ui.graphicsViewSpectrogram.scene().setSceneRect( 0, 0, window_size, 20 * window_size) self.spectrogram_y_pos = 0 self.ui.graphicsViewSpectrogram.fitInView( self.ui.graphicsViewSpectrogram.sceneRect()) def __update_spectrogram(self): spectrogram = Spectrogram(self.device.data, overlap_factor=self.my_overlap_factor) spectrogram.data_min = -80 spectrogram.data_max = 10 scene = self.ui.graphicsViewSpectrogram.scene() pixmap = QPixmap.fromImage( spectrogram.create_spectrogram_image(transpose=True)) pixmap_item = scene.addPixmap(pixmap) self.my_mass_vodopad.append(pixmap) pixmap_item.moveBy(0, self.spectrogram_y_pos) self.spectrogram_y_pos += pixmap.height() if self.spectrogram_y_pos >= scene.sceneRect().height(): while sum(map(lambda x: x.height(), self.my_mass_vodopad)) >= 20480: scene.setSceneRect(0, 0, Spectrogram.DEFAULT_FFT_WINDOW_SIZE, self.spectrogram_y_pos) self.ui.graphicsViewSpectrogram.ensureVisible(pixmap_item) scene.removeItem(scene.items().pop(-1)) self.my_mass_vodopad.pop(-1) def _eliminate_graphic_view(self): super()._eliminate_graphic_view() if self.ui.graphicsViewSpectrogram and self.ui.graphicsViewSpectrogram.scene( ) is not None: self.ui.graphicsViewSpectrogram.scene().clear() self.ui.graphicsViewSpectrogram.scene().setParent(None) self.ui.graphicsViewSpectrogram.setScene(None) self.ui.graphicsViewSpectrogram = None @pyqtSlot(int) def my_overlap_factor_func(self, value): if value == 1: self.my_overlap_factor = 0.1 self.on_clear_clicked() elif value == 2: self.my_overlap_factor = 0.5 self.on_clear_clicked() elif value == 3: self.my_overlap_factor = 0.9 self.on_clear_clicked() def save_trigger(self): self.ui.btnSave.setEnabled(False) self.my_save = True def create_connects(self): super().create_connects() self.ui.btnSave.clicked.connect(self.save_trigger) self.graphics_view.my_freq_wheel.connect( self.on_graphics_view_freq_clicked ) #---------- перестраиваеться частота насколько далеко мышка от центральной частоти self.graphics_view.my_wheel_event_freq.connect(self.scroll_freq) self.graphics_view.wheel_event_triggered.connect( self.on_graphics_view_wheel_event_triggered) self.graphics_view.my_freq_to_main.connect(self.my_selecte_freq) self.ui.btnSetting.clicked.connect(self.click_active) self.ui.sliderYscale1.valueChanged.connect( self.device_settings_widget.on_slider_gain_value_changed) self.ui.sliderYscale2.valueChanged.connect(self.my_overlap_factor_func) self.device_settings_widget.ui.sliderGain.valueChanged.connect( self.on_slider_gain_value_changed) self.device_settings_widget.ui.sliderBasebandGain.valueChanged.connect( self.on_slider_baseband_gain_value_changed) self.device_settings_widget.ui.sliderIFGain.valueChanged.connect( self.on_slider_if_gain_value_changed) self.device_settings_widget.ui.spinBoxFreq.valueChanged.connect( self.on_spinbox_frequency_editing_finished) self.device_settings_widget.ui.spinBoxFreq.valueChanged.connect( self.on_clear_changed) self.ui.btnRecordIQ.clicked.connect(self.my_record_long_iq_data) self.gain_timer.timeout.connect( self.device_settings_widget.ui.spinBoxGain.editingFinished.emit) self.if_gain_timer.timeout.connect( self.device_settings_widget.ui.spinBoxIFGain.editingFinished.emit) self.bb_gain_timer.timeout.connect( self.device_settings_widget.ui.spinBoxBasebandGain.editingFinished. emit) self.my_clear_timer.timeout.connect(self.on_clear_clicked) self.ui.btnNuke1.clicked.connect(self.start_Nuke1) self.ui.btnNuke2.clicked.connect(self.start_Nuke2) def my_record_long_iq_data(self): pm = self.project_manager try: self.on_stop_clicked() self.on_clear_clicked() self.r = ReceiveDialog( pm, parent=self, param_of_dev=[self.device.frequency, self.device.gain]) self.r.ui.btnSave.hide() except OSError as e: logger.error(repr(e)) return if self.r.has_empty_device_list: Errors.no_device() self.r.close() return self.r.device_parameters_changed.connect(pm.set_device_parameters) self.r.show() self.r.start_after_close.connect(self.on_start_clicked) def stop_iq_read(self): self.on_stop_clicked() data = self.device.data[:self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix timestamp = datetime.now().strftime("%Y-%m-%d_%H:%M:%S") initial_name = "{0}-{1}-{2}Hz-{3}Sps".format(dev.name, timestamp, big_val(dev.frequency), big_val(dev.sample_rate)) if dev.bandwidth_is_adjustable: initial_name += "-{}Hz.wav".format(big_val(dev.bandwidth)) initial_name = initial_name.replace( Formatter.local_decimal_seperator(), "_").replace("_000", "") FileOperator.save_data(data, initial_name, sample_rate=dev.sample_rate) self.files_recorded.emit(initial_name) self.init_device() self.device.frequency = self.old_freq self.old_freq = None self.on_start_clicked() self.change_tab.emit() def scroll_freq(self, a: int): print(self.device.frequency) if self.ui.btnStop.isEnabled(): if a < 0: self.device_settings_widget.ui.spinBoxFreq.stepDown() else: self.device_settings_widget.ui.spinBoxFreq.stepUp() self.ui.lcdNumber.display(self.real_freq()) name = ['4...5ГГц', '5...6ГГц', '6...7ГГц', '7...8ГГц'] if self.real_freq() > 4000e6 and self.real_freq() < 8000e6: if self.chek_freq - self.real_freq() >= 10e6: self.chek_freq = self.chek_freq - 20e6 if self.my_monitor_controller.check_index[1] - 1 > 0: self.my_monitor_controller.check_index[ 1] = self.my_monitor_controller.check_index[1] - 1 else: new_name = name.index( self.my_monitor_controller.check_index[0]) if new_name != 0: self.my_monitor_controller.check_index = [ name[new_name - 1], 49 ] elif self.real_freq() - self.chek_freq >= 10e6: self.chek_freq = self.chek_freq + 20e6 if self.my_monitor_controller.check_index[1] + 1 < 50: self.my_monitor_controller.check_index[ 1] = self.my_monitor_controller.check_index[1] + 1 else: try: new_name = name.index( self.my_monitor_controller.check_index[0]) except Exception as E: return if new_name != 3: self.my_monitor_controller.check_index = [ name[new_name + 1], 0 ] def click_active(self): if self.ui.btnSetting.isChecked() == False: self.ui.btnSetting.setStyleSheet("background-color: red") self.mymy_freq = None self.scene_manager.scene.my_clear() elif self.ui.btnSetting.isChecked(): self.ui.btnSetting.setStyleSheet("background-color: green") if self.mymy_freq != None: self.record_markered_diapazone(self.mymy_freq) @pyqtSlot(list) def my_selecte_freq(self, my_sel_freq): if self.ui.btnSetting.isChecked(): self.record_markered_diapazone(my_sel_freq) else: self.mymy_freq = my_sel_freq def record_markered_diapazone(self, my_sel_freq): try: bw = abs(my_sel_freq[1] - my_sel_freq[0]) except: return old_freq = self.device.frequency old_gain = self.device.gain self.on_stop_clicked() self.device = VirtualDevice(BackendHandler(), self.selected_device_name, Mode.receive) self.device.frequency = my_sel_freq[0] + bw / 2 sample_rate = 20e6 self.device.sample_rate = sample_rate self.device.bandwidth = bw self.device.start() time.sleep(0.1) while self.device.data[:self.device. current_index].size < 1 * sample_rate: pass self.device.stop('lol_1') data = self.device.data[:self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix timestamp = datetime.now().strftime("%Y-%m-%d_%H:%M:%S") freq = 6800e6 + self.status_k - my_sel_freq[0] + bw / 2 initial_name = "{0}-{1}-{2}Hz-{3}Sps".format(dev.name, timestamp, big_val(freq), big_val(dev.sample_rate)) if dev.bandwidth_is_adjustable: initial_name += "-{}Hz.wav".format(big_val(dev.bandwidth)) initial_name = initial_name.replace( Formatter.local_decimal_seperator(), "_").replace("_000", "") FileOperator.save_data(data, initial_name, sample_rate=sample_rate) self.files_recorded.emit(initial_name) self.init_device() self.device.frequency = old_freq self.device.gain = old_gain self.device.sample_rate = 20e6 self.change_tab.emit() @pyqtSlot(int) def change(self, index): self.ui.btnStart.setEnabled(True) if index >= 100: self.status_k = 2000e6 self.graphics_view.status_k_in_LiveGraphicView = 2000e6 self.graphics_view.scene().status_k = 2000e6 else: self.status_k = 0 self.graphics_view.status_k_in_LiveGraphicView = 0 self.graphics_view.scene().status_k = 0 self.on_stop_clicked() def rng(start, end, div): return range(int(start), int(end), (int(end) - int(start)) // int(div)) TCP_IP = '192.168.0.10' TCP_PORT = 1032 try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) com_index = index b = rng(4010e6, 8010e6, 200) d = {i: b[i] for i in range(len(b))} self.device_settings_widget.ui.labelDCCorrection2.setText( str(int(d[index] / 10e5)) + " МГц") index_input = 2790e6 - index * 20e6 if com_index >= 100: index_input = 2790e6 - (com_index - 100) * 20e6 self.device_settings_widget.ui.spinBoxFreq.setValue(index_input) if com_index < 100: s.send(b'\t\t\t') data = s.recv(10) operation = list(data)[3] operation_send = operation | 128 send_data = [0, 0, 0] send_data.append(operation_send) tcp = bytes(send_data) s.send(tcp) if com_index >= 100: s.send(b'\t\t\t') data = s.recv(10) if data[3] & 128 == 128: operation = list(data)[3] operation_send = operation ^ 128 send_data = [0, 0, 0] send_data.append(operation_send) tcp = bytes(send_data) s.send(tcp) s.close() except IOError as e: if e.errno == ENETUNREACH: print("M lost") QMessageBox.information( self, "Відсутність підключення до мережі", "Зв'язок втрачено. Перевірте мережеве підключення до РКП") else: raise self.chek_freq = self.real_freq() self.ui.lcdNumber.display(self.real_freq()) self.on_start_clicked() def real_freq(self): return 6800e6 + self.status_k - self.device_settings_widget.ui.spinBoxFreq.value( ) def resizeEvent(self, event: QResizeEvent): if self.ui.graphicsViewSpectrogram and self.ui.graphicsViewSpectrogram.sceneRect( ): self.ui.graphicsViewSpectrogram.fitInView( QtCore.QRectF(0.0, 0.0, 1024.0, 20480.0)) def update_view(self): if super().update_view(): x, y = self.device.spectrum if x is None or y is None: return self.scene_manager.scene.frequencies = x self.scene_manager.plot_data = y self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.fitInView(self.graphics_view.sceneRect()) try: self.__update_spectrogram() except MemoryError: self.__clear_spectrogram() self.__update_spectrogram() def init_device(self): self.device = VirtualDevice(self.backend_handler, self.selected_device_name, Mode.spectrum, device_ip="192.168.10.2", parent=self) self._create_device_connects() @pyqtSlot(QWheelEvent) def on_graphics_view_wheel_event_triggered(self, event: QWheelEvent): self.ui.sliderYscale.wheelEvent(event) @pyqtSlot(float) def on_graphics_view_freq_clicked(self, freq: float): pass self.device_settings_widget.ui.spinBoxFreq.setValue(freq) self.device_settings_widget.ui.spinBoxFreq.editingFinished.emit() self.ui.lcdNumber.display(self.real_freq()) @pyqtSlot() def on_spinbox_frequency_editing_finished(self): frequency = self.device_settings_widget.ui.spinBoxFreq.value() self.device.frequency = frequency self.scene_manager.scene.center_freq = frequency @pyqtSlot() def on_start_clicked(self): self.ui.btnConf.setEnabled(False) self.ui.btnRecordIQ.setEnabled(True) super().on_start_clicked() self.device.start() self.on_clear_clicked() self.ui.btnSave.setEnabled(True) self.my_save = False self.summ = [] self.tick = 0 @pyqtSlot() def on_device_started(self): self.ui.graphicsViewSpectrogram.scene().sceneRect() super().on_device_started() self.device_settings_widget.ui.spinBoxPort.setEnabled(False) self.device_settings_widget.ui.lineEditIP.setEnabled(False) self.device_settings_widget.ui.cbDevice.setEnabled(False) self.ui.btnStart.setEnabled(False) self.my_start.emit(False) @pyqtSlot() def on_device_stopped(self): self.ui.btnConf.setEnabled(True) self.ui.btnRecordIQ.setEnabled(False) self.device_settings_widget.ui.spinBoxPort.setEnabled(True) self.device_settings_widget.ui.lineEditIP.setEnabled(True) self.device_settings_widget.ui.cbDevice.setEnabled(True) self.ui.btnStop.setEnabled(False) super().on_device_stopped() self.my_start.emit(True) @pyqtSlot() def on_clear_clicked(self): self.__clear_spectrogram() self.scene_manager.clear_path() self.scene_manager.clear_peak() self.scene_manager.scene.my_clear() # затримка 100 мс при події def on_clear_changed(self): self.my_clear_timer.start(100) @pyqtSlot(int) def on_slider_gain_value_changed(self, value: int): self.gain_timer.start(250) @pyqtSlot(int) def on_slider_if_gain_value_changed(self, value: int): self.if_gain_timer.start(250) @pyqtSlot(int) def on_slider_baseband_gain_value_changed(self, value: int): self.bb_gain_timer.start(250) @pyqtSlot() def kill_thread(self): self.index = 1 self.stop() @pyqtSlot() def kill_thread2(self): self.index2 = 1 self.stop2() def stop(self): if self.index == 1: self.my_ssh1 = My_SSH_Thread() self.my_ssh1.terminate() self.freaze_scroll.emit(True) try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname='192.168.0.9', username=config.USER_NUKE_1, password=config.PASS_NUKE_1, port=22) stdin, stdout, stderr = client.exec_command("ps -x") data = stdout.read() + stderr.read() list_process = str(data).split('\\n') # print(data) for i in list_process: if 'IQRead.py' in i: splt = i.split() client.exec_command("kill {}".format(splt[0])) client.close() self.ui.btnNuke1.setStyleSheet("background-color: red") except IOError as e: if e.errno == ENETUNREACH: pass def stop2(self): if self.index2 == 1: self.my_ssh2 = My_SSH_Thread() self.my_ssh2.terminate() self.freaze_scroll2.emit(True) try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname='192.168.0.132', username=config.USER_NUKE_2, password=config.PASS_NUKE_2, port=22) stdin, stdout, stderr = client.exec_command("ps -x") data = stdout.read() + stderr.read() list_process = str(data).split('\\n') print(data) for i in list_process: if 'IQRead.py' in i: splt = i.split() client.exec_command("kill {}".format(splt[0])) client.close() self.ui.btnNuke2.setStyleSheet("background-color: red") except IOError as e: if e.errno == ENETUNREACH: pass def start_Nuke1(self): if self.ui.btnNuke1.isChecked() == True: self.ui.btnNuke1.setStyleSheet("background-color: green") self.my_ssh = My_SSH_Thread() self.my_ssh.start() self.my_ssh.my_kill.connect(self.kill_thread) # self.my_ssh.terminate() self.un_freaze_scroll.emit(True) else: self.my_ssh.terminate() self.freaze_scroll.emit(True) try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname='192.168.0.9', username=config.USER_NUKE_1, password=config.PASS_NUKE_1, port=22) stdin, stdout, stderr = client.exec_command("ps -x") data = stdout.read() + stderr.read() list_process = str(data).split('\\n') print(data) for i in list_process: if 'IQRead.py' in i: splt = i.split() client.exec_command("kill {}".format(splt[0])) client.close() self.ui.btnNuke1.setStyleSheet("background-color: red") except IOError as e: if e.errno == ENETUNREACH: pass def start_Nuke2(self): if self.ui.btnNuke2.isChecked() == True: self.my_ssh2 = My_SSH_Thread2() self.my_ssh2.start() self.my_ssh2.my_kill2.connect(self.kill_thread2) self.un_freaze_scroll2.emit(True) self.ui.btnNuke2.setStyleSheet("background-color: green") else: self.my_ssh2.terminate() self.freaze_scroll2.emit(True) try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname='192.168.0.132', username=config.USER_NUKE_2, password=config.PASS_NUKE_2, port=22) stdin, stdout, stderr = client.exec_command("ps -x") data = stdout.read() + stderr.read() list_process = str(data).split('\\n') print(data) for i in list_process: if 'IQRead.py' in i: splt = i.split() client.exec_command("kill {}".format(splt[0])) client.close() self.ui.btnNuke2.setStyleSheet("background-color: red") except IOError as e: if e.errno == ENETUNREACH: pass
class SendDialogController(SendRecvDialogController): def __init__(self, freq, samp_rate, bw, gain, device: str, modulated_data, parent=None, testing_mode=False): self.is_tx = True super().__init__(freq, samp_rate, bw, gain, device, parent=parent, testing_mode=testing_mode) self.update_interval = 25 self.graphics_view = self.ui.graphicsViewSend self.ui.stackedWidget.setCurrentIndex(1) self.hide_receive_ui_items() self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.setWindowTitle("Send signal") self.ui.btnStart.setToolTip("Send data") self.ui.btnStop.setToolTip("Stop sending") self.ui.progressBar.setMaximum(len(modulated_data)) self.device_is_sending = False signal = Signal.from_samples(modulated_data, "Modulated Preview", samp_rate) self.scene_manager = SignalSceneManager(signal, parent=self) self.send_indicator = self.scene_manager.scene.addRect( 0, -2, 0, 4, QPen(QColor(Qt.transparent), Qt.FlatCap), QBrush(constants.SEND_INDICATOR_COLOR)) self.send_indicator.stackBefore( self.scene_manager.scene.selection_area) self.scene_manager.init_scene() self.graphics_view.set_signal(signal) self.graphics_view.sample_rate = samp_rate self.init_device() self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.create_connects() def create_connects(self): super().create_connects() self.graphics_view.save_as_clicked.connect( self.on_graphics_view_save_as_clicked) self.scene_manager.signal.data_edited.connect( self.on_signal_data_edited) self.ui.spinBoxNRepeat.editingFinished.connect( self.on_num_repeats_changed) def __update_send_indicator(self, width: int): y, h = self.ui.graphicsViewSend.view_rect().y( ), self.ui.graphicsViewSend.view_rect().height() self.send_indicator.setRect(0, y - h, width, 2 * h + abs(y)) def update_view(self): if super().update_view(): self.__update_send_indicator(self.device.current_index) if not self.device.sending_finished: self.ui.lblCurrentRepeatValue.setText( str(self.device.current_iteration + 1)) else: self.ui.lblCurrentRepeatValue.setText("Done") def init_device(self): device_name = self.ui.cbDevice.currentText() num_repeats = self.ui.spinBoxNRepeat.value() sts = self.scene_manager.signal._fulldata self.device = VirtualDevice(self.backend_handler, device_name, Mode.send, bw=1e6, freq=433.92e6, gain=40, samp_rate=1e6, samples_to_send=sts, device_ip="192.168.10.2", sending_repeats=num_repeats, parent=self) self._create_device_connects() @pyqtSlot() def on_graphics_view_save_as_clicked(self): filename = FileOperator.get_save_file_name("signal.complex") if filename: try: self.scene_manager.signal.save_as(filename) except Exception as e: QMessageBox.critical(self, self.tr("Error saving signal"), e.args[0]) @pyqtSlot() def on_signal_data_edited(self): signal = self.scene_manager.signal self.ui.progressBar.setMaximum(signal.num_samples) self.device.samples_to_send = signal.data self.scene_manager.init_scene() self.ui.graphicsViewSend.redraw_view() @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() if self.ui.progressBar.value() >= self.ui.progressBar.maximum() - 1: self.on_clear_clicked() if self.device_is_sending: self.device.stop("Sending paused by user") else: self.device.start() @pyqtSlot() def on_stop_clicked(self): self.device.stop("Stopped receiving: Stop button clicked") super().on_stop_clicked() self.on_clear_clicked() @pyqtSlot() def on_device_stopped(self): super().on_device_stopped() self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.ui.btnStart.setToolTip("Start sending") self.device_is_sending = False @pyqtSlot() def on_device_started(self): super().on_device_started() self.device_is_sending = True self.ui.btnStart.setEnabled(True) self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-pause")) self.set_device_ui_items_enabled(False) @pyqtSlot() def on_num_repeats_changed(self): self.device.num_sending_repeats = self.ui.spinBoxNRepeat.value() @pyqtSlot() def on_clear_clicked(self): self.__update_send_indicator(0) self.reset()
class ReceiveDialog(RecvDialog): files_recorded = pyqtSignal(list, float) def __init__(self, project_manager, parent=None, testing_mode=False, param_of_dev=[1.8e9, 15]): try: super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) except ValueError: return self.graphics_view = self.ui.graphicsViewReceive self.ui.stackedWidget.setCurrentWidget(self.ui.page_receive) self.hide_send_ui_items() self.already_saved = True self.recorded_files = [] self.setWindowModality(Qt.ApplicationModal) self.setWindowTitle("Реєстрація IQ відліків") self.setWindowIcon(QIcon.fromTheme("media-record")) # set really in on_device_started self.scene_manager = None # type: LiveSceneManager self.create_connects() self.device_settings_widget.update_for_new_device( overwrite_settings=False) self.device.frequency = param_of_dev[0] self.device.gain = param_of_dev[1] self.device.bandwidth = 20e6 self.ui.btnSetting.setEnabled(False) # self.ui.setMaximumSize(QtCore.QSize(400, 40)) def create_connects(self): super().create_connects() self.init_device() self.ui.btnSetting.clicked.connect(self.on_save_clicked) def save_before_close(self): if not self.already_saved and self.device.current_index > 0: msg = QMessageBox(self) msg.setIcon(QMessageBox.Information) msg.setWindowTitle("Збереження сигналу") msg.setText("Бажаєте зберегти записаний сигнал?") okButton = msg.addButton("Так", QMessageBox.ActionRole) okAbort = msg.addButton("Відхилити", QMessageBox.NoRole) msg.addButton("Ні", QMessageBox.RejectRole) msg.exec() if msg.clickedButton() == okButton: self.on_save_clicked() elif msg.clickedButton() == okAbort: return False # reply = QMessageBox.question(self, self.tr("Збереження сигналу"), # self.tr("Бажаєте зберегти записаний сигнал?"), # QMessageBox.Yes | QMessageBox.No | QMessageBox.Abort) # if reply == QMessageBox.Yes: # self.on_save_clicked() # elif reply == QMessageBox.Abort: # return False try: sample_rate = self.device.sample_rate except: sample_rate = 1e6 self.files_recorded.emit(self.recorded_files, sample_rate) return True def update_view(self): if super().update_view(): self.scene_manager.end = self.device.current_index self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() def init_device(self): self.device = VirtualDevice(self.backend_handler, self.selected_device_name, Mode.receive, device_ip="192.168.10.2", parent=self) self._create_device_connects() self.scene_manager = LiveSceneManager(np.array( [], dtype=self.device.data_type), parent=self) self.ui.graphicsViewReceive.Clicable = False # self.graphics_view.Clicable: @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): print('\t\t\t\t', self.device.frequency) time.sleep(0.1) # try: # # except: # print('\t\t\t\t\t123123') # self.device.stop() self.scene_manager.plot_data = self.device.data.real if self.device.data is not None else None super().on_device_started() self.already_saved = False self.ui.btnStart.setEnabled(False) self.set_device_ui_items_enabled(False) @pyqtSlot() def on_clear_clicked(self): self.ui.btnSetting.setEnabled(False) self.scene_manager.clear_path() self.reset() @pyqtSlot() def on_save_clicked(self): data = self.device.data[:self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") initial_name = "{0}-{1}-{2}Hz-{3}Sps".format(dev.name, timestamp, big_val(dev.frequency), big_val(dev.sample_rate)) if dev.bandwidth_is_adjustable: initial_name += "-{}Hz.wav".format(big_val(dev.bandwidth)) initial_name = initial_name.replace( Formatter.local_decimal_seperator(), "_").replace("_000", "") FileOperator.save_data(data, initial_name, sample_rate=20e6, long_record=True) # filename = FileOperator.save_data_dialog(initial_name, data, # sample_rate=dev.sample_rate) # filename = self.recorded_files self.already_saved = True # if filename is not None and filename not in self.recorded_files: # self.recorded_files.append(filename) self.close()
class ReceiveDialog(SendRecvDialog): files_recorded = pyqtSignal(list, float) def __init__(self, project_manager, parent=None, testing_mode=False): try: super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) except ValueError: return self.graphics_view = self.ui.graphicsViewReceive self.ui.stackedWidget.setCurrentWidget(self.ui.page_receive) self.hide_send_ui_items() self.already_saved = True self.recorded_files = [] self.setWindowTitle("Record Signal") self.setWindowIcon(QIcon.fromTheme("media-record")) # set really in on_device_started self.scene_manager = None # type: LiveSceneManager self.create_connects() self.device_settings_widget.on_cb_device_current_index_changed() def create_connects(self): super().create_connects() self.ui.btnSave.clicked.connect(self.on_save_clicked) def save_before_close(self): if not self.already_saved and self.device.current_index > 0: reply = QMessageBox.question(self, self.tr("Save data?"), self.tr("Do you want to save the data you have captured so far?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Abort) if reply == QMessageBox.Yes: self.on_save_clicked() elif reply == QMessageBox.Abort: return False try: sample_rate = self.device.sample_rate except: sample_rate = 1e6 self.files_recorded.emit(self.recorded_files, sample_rate) return True def update_view(self): if super().update_view(): self.scene_manager.end = self.device.current_index self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() def init_device(self): self.device = VirtualDevice(self.backend_handler, self.selected_device_name, Mode.receive, device_ip="192.168.10.2", parent=self) self._create_device_connects() self.scene_manager = LiveSceneManager(np.array([]), parent=self) @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): self.scene_manager.plot_data = self.device.data.real if self.device.data is not None else None super().on_device_started() self.already_saved = False self.ui.btnStart.setEnabled(False) self.set_device_ui_items_enabled(False) @pyqtSlot() def on_clear_clicked(self): self.scene_manager.clear_path() self.reset() @pyqtSlot() def on_save_clicked(self): data = self.device.data[:self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix initial_name = "{0}-{1}Hz-{2}Sps".format(dev.name, big_val(dev.frequency), big_val(dev.sample_rate)) if dev.bandwidth_is_adjustable: initial_name += "-{}Hz".format(big_val(dev.bandwidth)) initial_name = initial_name.replace(Formatter.local_decimal_seperator(), "_").replace("_000", "") filename = FileOperator.save_data_dialog(initial_name + ".complex", data, parent=self) self.already_saved = True if filename is not None and filename not in self.recorded_files: self.recorded_files.append(filename)
class SpectrumDialogController(SendRecvDialogController): def __init__(self, freq, samp_rate, bw, gain, device: str, parent=None, testing_mode=False): self.is_rx = True super().__init__(freq, samp_rate, bw, gain, device, parent=parent, testing_mode=testing_mode) self.graphics_view = self.ui.graphicsViewReceive self.update_interval = 1 self.ui.stackedWidget.setCurrentIndex(0) self.hide_receive_ui_items() self.hide_send_ui_items() self.setWindowTitle("Spectrum analyzer") self.ui.btnStart.setToolTip(self.tr("Start")) self.ui.btnStop.setToolTip(self.tr("Stop")) self.scene_manager = FFTSceneManager(parent=self, graphic_view=self.graphics_view) self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager # do not use network sdr plugin for spectrum analysis index = next((i for i in range(self.ui.cbDevice.count()) if self.ui.cbDevice.itemText(i) == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME), None) if index is not None: self.ui.cbDevice.removeItem(index) self.init_device() self.set_bandwidth_status() self.create_connects() def create_connects(self): super().create_connects() self.graphics_view.freq_clicked.connect( self.on_graphics_view_freq_clicked) def update_view(self): if super().update_view(): x, y = self.device.spectrum if x is None or y is None: return self.scene_manager.scene.frequencies = x self.scene_manager.plot_data = y self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() def init_device(self): device_name = self.ui.cbDevice.currentText() self.device = VirtualDevice(self.backend_handler, device_name, Mode.spectrum, bw=1e6, freq=433.92e6, gain=40, samp_rate=1e6, device_ip="192.168.10.2", parent=self) self._create_device_connects() @pyqtSlot(float) def on_graphics_view_freq_clicked(self, freq: float): self.ui.spinBoxFreq.setValue(freq) self.ui.spinBoxFreq.editingFinished.emit() @pyqtSlot() def on_freq_changed(self): self.device.frequency = self.ui.spinBoxFreq.value() self.scene_manager.scene.center_freq = self.ui.spinBoxFreq.value() self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): super().on_device_started() self.ui.btnClear.setEnabled(False) self.ui.btnStart.setEnabled(False) @pyqtSlot() def on_clear_clicked(self): self.scene_manager.clear_path() self.scene_manager.clear_peak()
class SpectrumDialogController(SendRecvDialog): def __init__(self, project_manager, parent=None, testing_mode=False): super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) self.graphics_view = self.ui.graphicsViewFFT self.update_interval = 1 self.ui.stackedWidget.setCurrentWidget(self.ui.page_spectrum) self.hide_receive_ui_items() self.hide_send_ui_items() self.setWindowTitle("Spectrum Analyzer") self.setWindowIcon(QIcon(":/icons/icons/spectrum.svg")) self.ui.btnStart.setToolTip(self.tr("Start")) self.ui.btnStop.setToolTip(self.tr("Stop")) self.scene_manager = FFTSceneManager(parent=self, graphic_view=self.graphics_view) self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.ui.graphicsViewSpectrogram.setScene(QGraphicsScene()) self.__clear_spectrogram() self.gain_timer = QTimer(self) self.gain_timer.setSingleShot(True) self.if_gain_timer = QTimer(self) self.if_gain_timer.setSingleShot(True) self.bb_gain_timer = QTimer(self) self.bb_gain_timer.setSingleShot(True) self.create_connects() self.device_settings_widget.on_cb_device_current_index_changed() def __clear_spectrogram(self): self.ui.graphicsViewSpectrogram.scene().clear() window_size = Spectrogram.DEFAULT_FFT_WINDOW_SIZE self.ui.graphicsViewSpectrogram.scene().setSceneRect(0, 0, window_size, 20 * window_size) self.spectrogram_y_pos = 0 self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.sceneRect()) def __update_spectrogram(self): spectrogram = Spectrogram(self.device.data) spectrogram.data_min = -80 spectrogram.data_max = 10 scene = self.ui.graphicsViewSpectrogram.scene() pixmap = QPixmap.fromImage(spectrogram.create_spectrogram_image(transpose=True)) pixmap_item = scene.addPixmap(pixmap) pixmap_item.moveBy(0, self.spectrogram_y_pos) self.spectrogram_y_pos += pixmap.height() if self.spectrogram_y_pos >= scene.sceneRect().height(): scene.setSceneRect(0, 0, Spectrogram.DEFAULT_FFT_WINDOW_SIZE, self.spectrogram_y_pos) self.ui.graphicsViewSpectrogram.ensureVisible(pixmap_item) def _eliminate_graphic_view(self): super()._eliminate_graphic_view() if self.ui.graphicsViewSpectrogram and self.ui.graphicsViewSpectrogram.scene() is not None: self.ui.graphicsViewSpectrogram.scene().clear() self.ui.graphicsViewSpectrogram.scene().setParent(None) self.ui.graphicsViewSpectrogram.setScene(None) self.ui.graphicsViewSpectrogram = None def create_connects(self): super().create_connects() self.graphics_view.freq_clicked.connect(self.on_graphics_view_freq_clicked) self.graphics_view.wheel_event_triggered.connect(self.on_graphics_view_wheel_event_triggered) self.device_settings_widget.ui.sliderGain.valueChanged.connect(self.on_slider_gain_value_changed) self.device_settings_widget.ui.sliderBasebandGain.valueChanged.connect( self.on_slider_baseband_gain_value_changed) self.device_settings_widget.ui.sliderIFGain.valueChanged.connect(self.on_slider_if_gain_value_changed) self.device_settings_widget.ui.spinBoxFreq.editingFinished.connect(self.on_spinbox_frequency_editing_finished) self.gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxGain.editingFinished.emit) self.if_gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxIFGain.editingFinished.emit) self.bb_gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxBasebandGain.editingFinished.emit) def resizeEvent(self, event: QResizeEvent): if self.ui.graphicsViewSpectrogram and self.ui.graphicsViewSpectrogram.sceneRect(): self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.sceneRect()) def update_view(self): if super().update_view(): x, y = self.device.spectrum if x is None or y is None: return self.scene_manager.scene.frequencies = x self.scene_manager.plot_data = y self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.fitInView(self.graphics_view.sceneRect()) self.__update_spectrogram() def init_device(self): self.device = VirtualDevice(self.backend_handler, self.selected_device_name, Mode.spectrum, device_ip="192.168.10.2", parent=self) self._create_device_connects() @pyqtSlot(QWheelEvent) def on_graphics_view_wheel_event_triggered(self, event: QWheelEvent): self.ui.sliderYscale.wheelEvent(event) @pyqtSlot(float) def on_graphics_view_freq_clicked(self, freq: float): self.device_settings_widget.ui.spinBoxFreq.setValue(freq) self.device_settings_widget.ui.spinBoxFreq.editingFinished.emit() @pyqtSlot() def on_spinbox_frequency_editing_finished(self): frequency = self.device_settings_widget.ui.spinBoxFreq.value() self.device.frequency = frequency self.scene_manager.scene.center_freq = frequency self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.scene().sceneRect()) super().on_device_started() self.ui.btnClear.setEnabled(True) self.device_settings_widget.ui.spinBoxPort.setEnabled(False) self.device_settings_widget.ui.lineEditIP.setEnabled(False) self.device_settings_widget.ui.cbDevice.setEnabled(False) self.ui.btnStart.setEnabled(False) @pyqtSlot() def on_device_stopped(self): self.device_settings_widget.ui.spinBoxPort.setEnabled(True) self.device_settings_widget.ui.lineEditIP.setEnabled(True) self.device_settings_widget.ui.cbDevice.setEnabled(True) super().on_device_stopped() @pyqtSlot() def on_clear_clicked(self): self.__clear_spectrogram() self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot(int) def on_slider_gain_value_changed(self, value: int): self.gain_timer.start(250) @pyqtSlot(int) def on_slider_if_gain_value_changed(self, value: int): self.if_gain_timer.start(250) @pyqtSlot(int) def on_slider_baseband_gain_value_changed(self, value: int): self.bb_gain_timer.start(250)
class ProtocolSniffer(ProtocolAnalyzer, QObject): """ This class is used for live sniffing a protocol with certain signal parameters. """ started = pyqtSignal() stopped = pyqtSignal() message_sniffed = pyqtSignal(int) 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): signal = Signal("", "LiveSignal") signal.bit_len = bit_len signal.qad_center = center signal.noise_threshold = noise signal.tolerance = tolerance signal.silent_set_modulation_type(modulation_type) ProtocolAnalyzer.__init__(self, signal) QObject.__init__(self, None) self.network_raw_mode = network_raw_mode self.backend_handler = backend_handler self.rcv_device = VirtualDevice(self.backend_handler, device, Mode.receive, resume_on_full_receive_buffer=True, raw_mode=network_raw_mode) self.sniff_thread = Thread(target=self.check_for_data, daemon=True) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) self.__buffer = np.zeros(int(self.BUFFER_SIZE_MB * 1000 * 1000 / 8), dtype=np.complex64) self.__current_buffer_index = 0 self.reading_data = False self.adaptive_noise = False self.automatic_center = False self.pause_length = 0 self.is_running = False self.store_messages = True self.__sniff_file = "" self.__store_data = True def __add_to_buffer(self, data: np.ndarray): n = len(data) if n + self.__current_buffer_index > len(self.__buffer): n = len(self.__buffer) - self.__current_buffer_index - 1 logger.warning("Buffer of protocol sniffer is full") self.__buffer[self.__current_buffer_index:self.__current_buffer_index + n] = data[:n] self.__current_buffer_index += n def __clear_buffer(self): self.__current_buffer_index = 0 def __buffer_is_full(self): return self.__current_buffer_index >= len(self.__buffer) - 2 def decoded_to_string(self, view: int, start=0, include_timestamps=True): result = [] for msg in self.messages[start:]: result.append(self.message_to_string(msg, view, include_timestamps)) return "\n".join(result) def message_to_string(self, message: Message, view: int, include_timestamps=True): msg_str_data = [] if include_timestamps: msg_date = datetime.fromtimestamp(message.timestamp) msg_str_data.append(msg_date.strftime("[%Y-%m-%d %H:%M:%S.%f]")) msg_str_data.append(message.view_to_string(view, decoded=True, show_pauses=False)) return " ".join(msg_str_data) @property def sniff_file(self): return self.__sniff_file @sniff_file.setter def sniff_file(self, val): self.__sniff_file = val if self.__sniff_file: self.__store_data = False @property def device_name(self): return self.rcv_device.name @device_name.setter def device_name(self, value: str): if value != self.rcv_device.name: self.rcv_device.free_data() self.rcv_device = VirtualDevice(self.backend_handler, value, Mode.receive, device_ip="192.168.10.2", resume_on_full_receive_buffer=True, raw_mode=self.network_raw_mode) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) def sniff(self): self.is_running = True self.rcv_device.start() self.sniff_thread = Thread(target=self.check_for_data, daemon=True) self.sniff_thread.start() def check_for_data(self): old_index = 0 while self.is_running: time.sleep(0.01) if self.rcv_device.is_raw_mode: if old_index <= self.rcv_device.current_index: data = self.rcv_device.data[old_index:self.rcv_device.current_index] else: data = np.concatenate((self.rcv_device.data[old_index:], self.rcv_device.data[:self.rcv_device.current_index])) old_index = self.rcv_device.current_index self.__demodulate_data(data) elif self.rcv_device.backend == Backends.network: # We receive the bits here for bit_str in self.rcv_device.data: msg = Message.from_plain_bits_str(bit_str) msg.decoder = self.decoder self.messages.append(msg) self.message_sniffed.emit(len(self.messages) - 1) self.rcv_device.free_data() # do not store received bits twice if self.sniff_file and not os.path.isdir(self.sniff_file): plain_bits_str = self.plain_bits_str if plain_bits_str: with open(self.sniff_file, "a") as f: f.write("\n".join(plain_bits_str) + "\n") if not self.__store_data: self.messages.clear() def __demodulate_data(self, data): """ Demodulates received IQ data and adds demodulated bits to messages :param data: :return: """ if len(data) == 0: return power_spectrum = data.real ** 2 + data.imag ** 2 is_above_noise = np.sqrt(np.mean(power_spectrum)) > self.signal.noise_threshold if self.adaptive_noise and not is_above_noise: self.signal.noise_threshold = 0.9 * self.signal.noise_threshold + 0.1 * np.sqrt(np.max(power_spectrum)) if is_above_noise: self.__add_to_buffer(data) self.pause_length = 0 if not self.__buffer_is_full(): return else: self.pause_length += len(data) if self.pause_length < 10 * self.signal.bit_len: self.__add_to_buffer(data) if not self.__buffer_is_full(): return if self.__current_buffer_index == 0: return # clear cache and start a new message self.signal._fulldata = self.__buffer[0:self.__current_buffer_index] self.__clear_buffer() self.signal._qad = None bit_len = self.signal.bit_len if self.automatic_center: 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) bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, bit_len, 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, decoder=self.decoder) self.messages.append(message) self.message_sniffed.emit(len(self.messages) - 1) def stop(self): self.is_running = False self.rcv_device.stop("Stopping receiving due to user interaction") if self.sniff_thread.is_alive(): self.sniff_thread.join(0.1) if self.sniff_thread.is_alive(): logger.error("Sniff thread is still alive") def clear(self): self.__clear_buffer() self.messages.clear() def __emit_started(self): self.started.emit() def __emit_stopped(self): if hasattr(self, "stopped"): self.stopped.emit()
class SendRecvDialogController(QDialog): files_recorded = pyqtSignal(list) recording_parameters = pyqtSignal(str, str, str, str, str) def __init__(self, freq, samp_rate, bw, gain, device: str, mode: Mode, modulated_data=None, parent=None): super().__init__(parent) self.ui = Ui_SendRecvDialog() self.ui.setupUi(self) self.setAttribute(Qt.WA_DeleteOnClose) self.graphics_view = self.ui.graphicsViewSend if mode == Mode.send else self.ui.graphicsViewReceive self.backend_handler = BackendHandler() if mode == Mode.spectrum: self.update_interval = 1 else: self.update_interval = 50 if mode == Mode.send and modulated_data is None: raise ValueError("I need modulated data to send!") if mode == Mode.receive or mode == Mode.spectrum: self.ui.spinBoxNRepeat.hide() self.ui.labelNRepeat.hide() self.ui.lblCurrentRepeatValue.hide() self.ui.lblRepeatText.hide() self.ui.lSamplesSentText.hide() self.ui.progressBar.hide() self.ui.stackedWidget.setCurrentIndex(0) else: self.ui.stackedWidget.setCurrentIndex(1) if mode == Mode.send or mode == Mode.spectrum: self.ui.lSamplesCaptured.hide() self.ui.lSamplesCapturedText.hide() self.ui.lSignalSize.hide() self.ui.lSignalSizeText.hide() self.ui.lTime.hide() self.ui.lTimeText.hide() self.ui.btnSave.hide() if mode == Mode.spectrum: self.setWindowTitle("Spectrum analyzer") if mode == Mode.send: self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.setWindowTitle("Send signal") self.ui.btnStart.setToolTip("Send data") self.ui.btnStop.setToolTip("Stop sending") self.ui.progressBar.setMaximum(len(modulated_data)) self.device_is_sending = False self.ui.btnStop.setEnabled(False) self.ui.btnClear.setEnabled(False) self.ui.btnSave.setEnabled(False) self.start = 0 self.already_saved = True self.bw_sr_are_locked = constants.SETTINGS.value("lock_bandwidth_sample_rate", True, bool) self.ui.spinBoxFreq.setValue(freq) self.ui.spinBoxSampleRate.setValue(samp_rate) self.ui.spinBoxBandwidth.setValue(bw) self.ui.spinBoxGain.setValue(gain) self.ui.spinBoxNRepeat.setValue(constants.SETTINGS.value('num_sending_repeats', 1, type=int)) self.ui.cbDevice.clear() items = [] for device_name in self.backend_handler.DEVICE_NAMES: dev = self.backend_handler.device_backends[device_name.lower()] if mode == Mode.send and dev.is_enabled and dev.supports_tx: items.append(device_name) elif mode in (Mode.receive, Mode.spectrum) and dev.is_enabled and dev.supports_rx: items.append(device_name) if mode == Mode.send and PluginManager().is_plugin_enabled("NetworkSDRInterface"): items.append(NetworkSDRInterfacePlugin.NETWORK_SDR_NAME) self.ui.cbDevice.addItems(items) if device in items: self.ui.cbDevice.setCurrentIndex(items.index(device)) dev_name = self.ui.cbDevice.currentText() nrep = self.ui.spinBoxNRepeat.value() self.device = VirtualDevice(self.backend_handler, dev_name, mode, bw, freq, gain, samp_rate, samples_to_send=modulated_data, device_ip=self.ui.lineEditIP.text(), sending_repeats=nrep, parent=self) self.ui.lineEditIP.setVisible(dev_name == "USRP") self.ui.labelIP.setVisible(dev_name == "USRP") self.recorded_files = [] self.timer = QTimer(self) if mode == Mode.receive: self.scene_manager = LiveSceneManager(np.array([]), parent=self) # set really in on_device_started elif mode == Mode.send: signal = Signal.from_samples(modulated_data, "Modulated Preview", samp_rate) self.scene_manager = SignalSceneManager(signal, parent=self) self.send_indicator = self.scene_manager.scene.addRect(0, -2, 0, 4, QPen(QColor(Qt.transparent), Qt.FlatCap), QBrush(constants.SEND_INDICATOR_COLOR)) self.send_indicator.stackBefore(self.scene_manager.scene.selection_area) self.scene_manager.init_scene() self.graphics_view.set_signal(signal) self.graphics_view.sample_rate = samp_rate else: self.scene_manager = FFTSceneManager(parent=self, graphic_view=self.graphics_view) self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])" ipRegex = QRegExp("^" + ipRange + "\\." + ipRange + "\\." + ipRange + "\\." + ipRange + "$") self.ui.lineEditIP.setValidator(QRegExpValidator(ipRegex)) self.create_connects() self.ui.btnLockBWSR.setChecked(self.bw_sr_are_locked) self.on_btn_lock_bw_sr_clicked() @property def mode(self): return self.device.mode @property def has_empty_device_list(self): return self.ui.cbDevice.count() == 0 def create_connects(self): self.ui.btnStart.clicked.connect(self.on_start_clicked) self.ui.btnStop.clicked.connect(self.on_stop_clicked) self.ui.btnClear.clicked.connect(self.on_clear_clicked) self.ui.btnSave.clicked.connect(self.on_save_clicked) self.__create_device_connects() self.timer.timeout.connect(self.update_view) self.ui.spinBoxSampleRate.editingFinished.connect(self.on_sample_rate_changed) self.ui.spinBoxGain.editingFinished.connect(self.on_gain_changed) self.ui.spinBoxFreq.editingFinished.connect(self.on_freq_changed) self.ui.spinBoxBandwidth.editingFinished.connect(self.on_bw_changed) self.ui.lineEditIP.editingFinished.connect(self.on_usrp_ip_changed) self.ui.cbDevice.currentIndexChanged.connect(self.on_selected_device_changed) self.ui.spinBoxNRepeat.editingFinished.connect(self.on_num_repeats_changed) self.ui.sliderYscale.valueChanged.connect(self.on_slideyscale_value_changed) if hasattr(self.graphics_view, "freq_clicked"): self.graphics_view.freq_clicked.connect(self.on_graphics_view_freq_clicked) if hasattr(self.graphics_view, "save_as_clicked"): self.graphics_view.save_as_clicked.connect(self.on_graphics_view_save_as_clicked) if hasattr(self.scene_manager, "signal"): self.scene_manager.signal.data_edited.connect(self.on_signal_data_edited) self.ui.btnLockBWSR.clicked.connect(self.on_btn_lock_bw_sr_clicked) def __create_device_connects(self): self.device.stopped.connect(self.on_device_stopped) self.device.started.connect(self.on_device_started) self.device.sender_needs_restart.connect(self.__restart_device_thread) def __update_send_indicator(self, width: int): y, h = self.ui.graphicsViewSend.view_rect().y(), self.ui.graphicsViewSend.view_rect().height() self.send_indicator.setRect(0, y - h, width, 2 * h + abs(y)) @pyqtSlot() def on_sample_rate_changed(self): self.device.sample_rate = self.ui.spinBoxSampleRate.value() if self.bw_sr_are_locked: self.ui.spinBoxBandwidth.setValue(self.ui.spinBoxSampleRate.value()) self.device.bandwidth = self.ui.spinBoxBandwidth.value() @pyqtSlot() def on_freq_changed(self): self.device.frequency = self.ui.spinBoxFreq.value() if self.mode == Mode.spectrum: self.scene_manager.scene.center_freq = self.ui.spinBoxFreq.value() self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot() def on_bw_changed(self): self.device.bandwidth = self.ui.spinBoxBandwidth.value() if self.bw_sr_are_locked: self.ui.spinBoxSampleRate.setValue(self.ui.spinBoxBandwidth.value()) self.device.sample_rate = self.ui.spinBoxSampleRate.value() @pyqtSlot() def on_usrp_ip_changed(self): self.device.ip = self.ui.lineEditIP.text() @pyqtSlot() def on_gain_changed(self): self.device.gain = self.ui.spinBoxGain.value() @pyqtSlot() def on_selected_device_changed(self): dev_name = self.ui.cbDevice.currentText() if dev_name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.ui.cbDevice.blockSignals(True) self.ui.cbDevice.setCurrentText(self.device.name) self.ui.cbDevice.blockSignals(False) Errors.network_sdr_send_is_elsewhere() return nrep = self.ui.spinBoxNRepeat.value() sts = self.device.samples_to_send self.device.free_data() # gc.collect() # Cant do GC here, because the SencRecvDialog itself would be deleted (see https://github.com/jopohl/urh/issues/83) self.device = VirtualDevice(self.backend_handler, dev_name, self.device.mode, self.device.bandwidth, self.device.frequency, self.device.gain, self.device.sample_rate, sts, self.device.ip, nrep, self) self.__create_device_connects() if hasattr(self.scene_manager, "plot_data"): del self.scene_manager.plot_data if self.mode == Mode.receive: self.scene_manager = LiveSceneManager(np.array([]), parent=self) self.graphics_view.scene_manager = self.scene_manager self.graphics_view.setScene(self.scene_manager.scene) self.ui.lineEditIP.setVisible(dev_name == "USRP") self.ui.labelIP.setVisible(dev_name == "USRP") @pyqtSlot() def on_start_clicked(self): if self.mode == Mode.send: if self.ui.progressBar.value() >= self.ui.progressBar.maximum() - 1: self.on_clear_clicked() self.ui.spinBoxFreq.editingFinished.emit() self.ui.lineEditIP.editingFinished.emit() self.ui.spinBoxBandwidth.editingFinished.emit() self.ui.spinBoxSampleRate.editingFinished.emit() self.ui.spinBoxNRepeat.editingFinished.emit() if self.mode == Mode.send and self.device_is_sending: self.device.stop("Sending paused by user") else: self.device.start() @pyqtSlot() def on_num_repeats_changed(self): if not self.ui.spinBoxNRepeat.isVisible(): return self.device.num_sending_repeats = self.ui.spinBoxNRepeat.value() @pyqtSlot() def on_stop_clicked(self): self.device.stop("Stopped receiving: Stop button clicked") if self.mode == Mode.send: self.on_clear_clicked() @pyqtSlot() def on_device_stopped(self): self.graphics_view.capturing_data = False if self.mode == Mode.send: self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.ui.btnStart.setToolTip("Start sending") self.device_is_sending = False else: self.ui.btnStart.setEnabled(True) self.ui.btnStop.setEnabled(False) self.ui.btnClear.setEnabled(True) self.ui.btnSave.setEnabled(self.device.current_index > 0) self.ui.spinBoxSampleRate.setEnabled(True) self.ui.spinBoxFreq.setEnabled(True) self.ui.lineEditIP.setEnabled(True) self.ui.spinBoxBandwidth.setEnabled(True) self.ui.spinBoxGain.setEnabled(True) self.ui.cbDevice.setEnabled(True) self.ui.spinBoxNRepeat.setEnabled(True) self.timer.stop() self.scene_manager.set_text("") self.update_view() @pyqtSlot() def on_device_started(self): if self.mode == Mode.receive: self.scene_manager.plot_data = self.device.data.real if self.device.data is not None else None self.ui.txtEditErrors.clear() self.scene_manager.set_text("Waiting for device..") self.graphics_view.capturing_data = True self.ui.btnSave.setEnabled(False) if self.mode == Mode.send: self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-pause")) self.ui.btnStart.setToolTip("Pause sending") self.device_is_sending = True else: self.ui.btnStart.setEnabled(False) self.ui.btnClear.setEnabled(self.mode == Mode.spectrum) self.ui.spinBoxNRepeat.setEnabled(False) self.ui.btnStop.setEnabled(True) if self.mode != Mode.spectrum: self.ui.spinBoxSampleRate.setDisabled(True) self.ui.spinBoxFreq.setDisabled(True) self.ui.spinBoxGain.setDisabled(True) self.ui.spinBoxBandwidth.setDisabled(True) self.ui.lineEditIP.setDisabled(True) self.ui.cbDevice.setDisabled(True) self.timer.start(self.update_interval) self.already_saved = False def update_view(self): txt = self.ui.txtEditErrors.toPlainText() new_errors = self.device.read_errors() if "No devices found for" in new_errors: self.device.stop_on_error("Could not establish connection to USRP") Errors.usrp_ip_not_found() self.on_clear_clicked() elif "FATAL: No supported devices found" in new_errors or \ "HACKRF_ERROR_NOT_FOUND" in new_errors or \ "HACKRF_ERROR_LIBUSB" in new_errors: self.device.stop_on_error("Could not establish connection to HackRF") Errors.hackrf_not_found() self.on_clear_clicked() elif "No module named gnuradio" in new_errors: self.device.stop_on_error("Did not find gnuradio.") Errors.gnuradio_not_installed() self.on_clear_clicked() elif "Address already in use" in new_errors: self.__restart_device_thread() if len(new_errors) > 1: self.ui.txtEditErrors.setPlainText(txt + new_errors) self.ui.progressBar.setValue(self.device.current_index) self.ui.lSamplesCaptured.setText("{0:n}".format(self.device.current_index)) self.ui.lSignalSize.setText("{0:n}".format((8 * self.device.current_index) / (1024 ** 2))) self.ui.lTime.setText(locale.format_string("%.2f", self.device.current_index / self.device.sample_rate)) if not self.device.sending_finished: self.ui.lblCurrentRepeatValue.setText(str(self.device.current_iteration + 1)) else: self.ui.lblCurrentRepeatValue.setText("Done") if self.device.current_index == 0: return if self.mode == Mode.receive: self.scene_manager.end = self.device.current_index elif self.mode == Mode.spectrum: x, y = self.device.spectrum if x is None or y is None: return self.scene_manager.scene.frequencies = x self.scene_manager.plot_data = y elif self.mode == Mode.send: self.__update_send_indicator(self.device.current_index) return self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() def __restart_device_thread(self): self.device.stop("Restarting with new port") QApplication.processEvents() self.device.port = random.randint(1024, 65536) logger.info("Retry with port " + str(self.device.port)) self.device.start() QApplication.processEvents() @pyqtSlot() def on_clear_clicked(self): if self.mode == Mode.send: self.__update_send_indicator(0) else: self.scene_manager.clear_path() if self.mode in (Mode.send, Mode.receive): self.ui.txtEditErrors.clear() self.device.current_index = 0 self.device.current_iteration = 0 self.ui.lSamplesCaptured.setText("0") self.ui.lSignalSize.setText("0") self.ui.lTime.setText("0") self.ui.lblCurrentRepeatValue.setText("-") self.scene_manager.set_text("") self.ui.progressBar.setValue(0) self.ui.btnClear.setEnabled(False) self.ui.btnSave.setEnabled(False) elif self.mode == Mode.spectrum: self.scene_manager.clear_peak() @pyqtSlot() def on_save_clicked(self): data = self.device.data[:self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix initial_name = "{0} {1}Hz {2}Sps {3}Hz.complex".format(dev.name, big_val(dev.frequency), big_val(dev.sample_rate), big_val(dev.bandwidth)).replace( Formatter.local_decimal_seperator(), "_").replace("_000", "") filename = FileOperator.save_data_dialog(initial_name, data, parent=self) self.already_saved = True if filename is not None and filename not in self.recorded_files: self.recorded_files.append(filename) def closeEvent(self, event: QCloseEvent): if self.device.backend == Backends.network: event.accept() return self.device.stop("Dialog closed. Killing recording process.") if self.mode == Mode.receive and not self.already_saved and self.device.current_index > 0: reply = QMessageBox.question(self, self.tr("Save data?"), self.tr("Do you want to save the data you have captured so far?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Abort) if reply == QMessageBox.Yes: self.on_save_clicked() elif reply == QMessageBox.Abort: event.ignore() return time.sleep(0.1) if self.device.backend != Backends.none: self.device.cleanup() self.files_recorded.emit(self.recorded_files) self.recording_parameters.emit(str(self.device.frequency), str(self.device.sample_rate), str(self.device.bandwidth), str(self.device.gain), str(self.device.name)) event.accept() @pyqtSlot() def on_btn_lock_bw_sr_clicked(self): self.bw_sr_are_locked = self.ui.btnLockBWSR.isChecked() constants.SETTINGS.setValue("lock_bandwidth_sample_rate", self.bw_sr_are_locked) if self.bw_sr_are_locked: self.ui.btnLockBWSR.setIcon(QIcon(":/icons/data/icons/lock.svg")) else: self.ui.btnLockBWSR.setIcon(QIcon(":/icons/data/icons/unlock.svg")) @pyqtSlot(int) def on_slideyscale_value_changed(self, new_value: int): # Scale Up = Top Half, Scale Down = Lower Half middle = int((self.ui.sliderYscale.maximum() + 1 - self.ui.sliderYscale.minimum()) / 2) scale_up = new_value >= middle current_factor = self.graphics_view.sceneRect().height() / self.graphics_view.view_rect().height() scale_factor = (new_value + 1 - middle) / current_factor if scale_up else current_factor / new_value if scale_factor > 0: self.graphics_view.scale(1, scale_factor) @pyqtSlot(float) def on_graphics_view_freq_clicked(self, freq: float): self.ui.spinBoxFreq.setValue(freq) self.ui.spinBoxFreq.editingFinished.emit() @pyqtSlot() def on_signal_data_edited(self): signal = self.scene_manager.signal self.ui.progressBar.setMaximum(signal.num_samples) self.device.samples_to_send = signal.data self.scene_manager.init_scene() self.ui.graphicsViewSend.redraw_view() @pyqtSlot() def on_graphics_view_save_as_clicked(self): filename = FileOperator.get_save_file_name("signal.complex", parent=self) if filename: try: self.scene_manager.signal.save_as(filename) except Exception as e: QMessageBox.critical(self, self.tr("Error saving signal"), e.args[0])
class SendDialog(SendRecvDialog): def __init__(self, project_manager, modulated_data, modulation_msg_indices=None, continuous_send_mode=False, parent=None, testing_mode=False): super().__init__(project_manager, is_tx=True, continuous_send_mode=continuous_send_mode, parent=parent, testing_mode=testing_mode) self.graphics_view = self.ui.graphicsViewSend self.ui.stackedWidget.setCurrentWidget(self.ui.page_send) self.hide_receive_ui_items() self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.setWindowTitle("Send Signal") self.setWindowIcon(QIcon.fromTheme("media-playback-start")) self.ui.btnStart.setToolTip("Send data") self.ui.btnStop.setToolTip("Stop sending") self.device_is_sending = False self.modulation_msg_indices = modulation_msg_indices if self.modulation_msg_indices is not None: self.ui.progressBarMessage.setMaximum(len(self.modulation_msg_indices)) else: self.ui.progressBarMessage.hide() self.ui.labelCurrentMessage.hide() if modulated_data is not None: # modulated_data is none in continuous send mode self.ui.progressBarSample.setMaximum(len(modulated_data)) samp_rate = self.device_settings_widget.ui.spinBoxSampleRate.value() signal = Signal.from_samples(modulated_data, "Modulated Preview", samp_rate) self.scene_manager = SignalSceneManager(signal, parent=self) self.send_indicator = self.scene_manager.scene.addRect(0, -2, 0, 4, QPen(QColor(Qt.transparent), 0), QBrush(constants.SEND_INDICATOR_COLOR)) self.send_indicator.stackBefore(self.scene_manager.scene.selection_area) self.scene_manager.init_scene() self.graphics_view.set_signal(signal) self.graphics_view.sample_rate = samp_rate self.create_connects() self.device_settings_widget.update_for_new_device(overwrite_settings=False) def create_connects(self): super().create_connects() self.graphics_view.save_as_clicked.connect(self.on_graphics_view_save_as_clicked) self.scene_manager.signal.data_edited.connect(self.on_signal_data_edited) def _update_send_indicator(self, width: int): y, h = self.ui.graphicsViewSend.view_rect().y(), self.ui.graphicsViewSend.view_rect().height() self.send_indicator.setRect(0, y - h, width, 2 * h + abs(y)) def set_current_message_progress_bar_value(self, current_sample: int): if self.modulation_msg_indices is not None: msg_index = next((i for i, sample in enumerate(self.modulation_msg_indices) if sample >= current_sample), len(self.modulation_msg_indices)) self.ui.progressBarMessage.setValue(msg_index + 1) def update_view(self): if super().update_view(): self._update_send_indicator(self.device.current_index) self.ui.progressBarSample.setValue(self.device.current_index) self.set_current_message_progress_bar_value(self.device.current_index) if not self.device.sending_finished: self.ui.lblCurrentRepeatValue.setText(str(self.device.current_iteration + 1)) else: self.ui.btnStop.click() self.ui.lblCurrentRepeatValue.setText("Sending finished") def init_device(self): device_name = self.selected_device_name num_repeats = self.device_settings_widget.ui.spinBoxNRepeat.value() sts = self.scene_manager.signal._fulldata self.device = VirtualDevice(self.backend_handler, device_name, Mode.send, samples_to_send=sts, device_ip="192.168.10.2", sending_repeats=num_repeats, parent=self) self._create_device_connects() @pyqtSlot() def on_graphics_view_save_as_clicked(self): filename = FileOperator.get_save_file_name("signal.complex") if filename: try: try: self.scene_manager.signal.sample_rate = self.device.sample_rate except Exception as e: logger.exception(e) self.scene_manager.signal.save_as(filename) except Exception as e: QMessageBox.critical(self, self.tr("Error saving signal"), e.args[0]) @pyqtSlot() def on_signal_data_edited(self): signal = self.scene_manager.signal self.ui.progressBarSample.setMaximum(signal.num_samples) self.device.samples_to_send = signal.data self.scene_manager.init_scene() self.ui.graphicsViewSend.redraw_view() @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() if self.ui.progressBarSample.value() >= self.ui.progressBarSample.maximum() - 1: self.on_clear_clicked() if self.device_is_sending: self.device.stop("Sending paused by user") else: self.device.start() @pyqtSlot() def on_stop_clicked(self): super().on_stop_clicked() self.on_clear_clicked() @pyqtSlot() def on_device_stopped(self): super().on_device_stopped() self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.ui.btnStart.setText("Start") self.ui.btnStart.setToolTip("Start sending") self.device_is_sending = False @pyqtSlot() def on_device_started(self): super().on_device_started() self.device_is_sending = True self.ui.btnStart.setEnabled(True) self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-pause")) self.ui.btnStart.setText("Pause") self.set_device_ui_items_enabled(False) @pyqtSlot() def on_clear_clicked(self): self._update_send_indicator(0) self.reset()
class SpectrumDialogController(SendRecvDialog): def __init__(self, project_manager, parent=None, testing_mode=False): super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) self.graphics_view = self.ui.graphicsViewFFT self.update_interval = 1 self.ui.stackedWidget.setCurrentWidget(self.ui.page_spectrum) self.hide_receive_ui_items() self.hide_send_ui_items() self.setWindowTitle("Spectrum Analyzer") self.setWindowIcon(QIcon(":/icons/icons/spectrum.svg")) self.ui.btnStart.setToolTip(self.tr("Start")) self.ui.btnStop.setToolTip(self.tr("Stop")) self.scene_manager = FFTSceneManager(parent=self, graphic_view=self.graphics_view) self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.ui.graphicsViewSpectrogram.setScene(QGraphicsScene()) self.__clear_spectrogram() self.init_device() self.device_settings_widget.set_bandwidth_status() self.gain_timer = QTimer() self.gain_timer.setSingleShot(True) self.if_gain_timer = QTimer() self.if_gain_timer.setSingleShot(True) self.bb_gain_timer = QTimer() self.bb_gain_timer.setSingleShot(True) self.create_connects() def __clear_spectrogram(self): self.ui.graphicsViewSpectrogram.scene().clear() window_size = Spectrogram.DEFAULT_FFT_WINDOW_SIZE self.ui.graphicsViewSpectrogram.scene().setSceneRect(0, 0, window_size, 20 * window_size) self.spectrogram_y_pos = 0 self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.sceneRect()) def __update_spectrogram(self): spectrogram = Spectrogram(self.device.data) spectrogram.data_min = -80 spectrogram.data_max = 10 scene = self.ui.graphicsViewSpectrogram.scene() pixmap = QPixmap.fromImage(spectrogram.create_spectrogram_image(transpose=True)) scene.addPixmap(pixmap).moveBy(0, self.spectrogram_y_pos) self.spectrogram_y_pos += pixmap.height() if self.spectrogram_y_pos >= scene.sceneRect().height(): scene.setSceneRect(0, 0, Spectrogram.DEFAULT_FFT_WINDOW_SIZE, self.spectrogram_y_pos) self.ui.graphicsViewSpectrogram.verticalScrollBar().setValue( self.ui.graphicsViewSpectrogram.verticalScrollBar().maximum()) def _eliminate_graphic_view(self): super()._eliminate_graphic_view() if self.ui.graphicsViewSpectrogram.scene() is not None: self.ui.graphicsViewSpectrogram.scene().clear() self.ui.graphicsViewSpectrogram.scene().setParent(None) self.ui.graphicsViewSpectrogram.setScene(None) self.ui.graphicsViewSpectrogram = None def create_connects(self): super().create_connects() self.graphics_view.freq_clicked.connect(self.on_graphics_view_freq_clicked) self.graphics_view.wheel_event_triggered.connect(self.on_graphics_view_wheel_event_triggered) self.device_settings_widget.ui.sliderGain.valueChanged.connect(self.on_slider_gain_value_changed) self.device_settings_widget.ui.sliderBasebandGain.valueChanged.connect(self.on_slider_baseband_gain_value_changed) self.device_settings_widget.ui.sliderIFGain.valueChanged.connect(self.on_slider_if_gain_value_changed) self.device_settings_widget.ui.spinBoxFreq.editingFinished.connect(self.on_spinbox_frequency_editing_finished) self.gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxGain.editingFinished.emit) self.if_gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxIFGain.editingFinished.emit) self.bb_gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxBasebandGain.editingFinished.emit) def resizeEvent(self, event: QResizeEvent): if self.ui.graphicsViewSpectrogram and self.ui.graphicsViewSpectrogram.sceneRect(): self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.sceneRect()) def update_view(self): if super().update_view(): x, y = self.device.spectrum if x is None or y is None: return self.scene_manager.scene.frequencies = x self.scene_manager.plot_data = y self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.fitInView(self.graphics_view.sceneRect()) self.__update_spectrogram() def init_device(self): self.device = VirtualDevice(self.backend_handler, self.selected_device_name, Mode.spectrum, device_ip="192.168.10.2", parent=self) self._create_device_connects() @pyqtSlot(QWheelEvent) def on_graphics_view_wheel_event_triggered(self, event: QWheelEvent): self.ui.sliderYscale.wheelEvent(event) @pyqtSlot(float) def on_graphics_view_freq_clicked(self, freq: float): self.device_settings_widget.ui.spinBoxFreq.setValue(freq) self.device_settings_widget.ui.spinBoxFreq.editingFinished.emit() @pyqtSlot() def on_spinbox_frequency_editing_finished(self): frequency = self.device_settings_widget.ui.spinBoxFreq.value() self.device.frequency = frequency self.scene_manager.scene.center_freq = frequency self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.scene().sceneRect()) super().on_device_started() self.ui.btnClear.setEnabled(True) self.device_settings_widget.ui.spinBoxPort.setEnabled(False) self.device_settings_widget.ui.lineEditIP.setEnabled(False) self.ui.btnStart.setEnabled(False) @pyqtSlot() def on_clear_clicked(self): self.__clear_spectrogram() self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot(int) def on_slider_gain_value_changed(self, value: int): self.gain_timer.start(250) @pyqtSlot(int) def on_slider_if_gain_value_changed(self, value: int): self.if_gain_timer.start(250) @pyqtSlot(int) def on_slider_baseband_gain_value_changed(self, value: int): self.bb_gain_timer.start(250)
class SendDialog(SendRecvDialog): def __init__(self, project_manager, modulated_data, modulation_msg_indices=None, parent=None, testing_mode=False): super().__init__(project_manager, is_tx=True, parent=parent, testing_mode=testing_mode) self.graphics_view = self.ui.graphicsViewSend self.ui.stackedWidget.setCurrentWidget(self.ui.page_send) self.hide_receive_ui_items() self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.setWindowTitle("Send Signal") self.setWindowIcon(QIcon.fromTheme("media-playback-start")) self.ui.btnStart.setToolTip("Send data") self.ui.btnStop.setToolTip("Stop sending") self.device_is_sending = False self.modulation_msg_indices = modulation_msg_indices if self.modulation_msg_indices is not None: self.ui.progressBarMessage.setMaximum( len(self.modulation_msg_indices)) else: self.ui.progressBarMessage.hide() self.ui.labelCurrentMessage.hide() if modulated_data is not None: # modulated_data is none in continuous send mode self.ui.progressBarSample.setMaximum(len(modulated_data)) samp_rate = self.device_settings_widget.ui.spinBoxSampleRate.value( ) signal = Signal.from_samples(modulated_data, "Modulated Preview", samp_rate) self.scene_manager = SignalSceneManager(signal, parent=self) self.send_indicator = self.scene_manager.scene.addRect( 0, -2, 0, 4, QPen(QColor(Qt.transparent), Qt.FlatCap), QBrush(constants.SEND_INDICATOR_COLOR)) self.send_indicator.stackBefore( self.scene_manager.scene.selection_area) self.scene_manager.init_scene() self.graphics_view.set_signal(signal) self.graphics_view.sample_rate = samp_rate self.init_device() self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.create_connects() def create_connects(self): super().create_connects() self.graphics_view.save_as_clicked.connect( self.on_graphics_view_save_as_clicked) self.scene_manager.signal.data_edited.connect( self.on_signal_data_edited) def _update_send_indicator(self, width: int): y, h = self.ui.graphicsViewSend.view_rect().y( ), self.ui.graphicsViewSend.view_rect().height() self.send_indicator.setRect(0, y - h, width, 2 * h + abs(y)) def set_current_message_progress_bar_value(self, current_sample: int): if self.modulation_msg_indices is not None: msg_index = next( (i for i, sample in enumerate(self.modulation_msg_indices) if sample >= current_sample), len(self.modulation_msg_indices)) self.ui.progressBarMessage.setValue(msg_index + 1) def update_view(self): if super().update_view(): self._update_send_indicator(self.device.current_index) self.ui.progressBarSample.setValue(self.device.current_index) self.set_current_message_progress_bar_value( self.device.current_index) if not self.device.sending_finished: self.ui.lblCurrentRepeatValue.setText( str(self.device.current_iteration + 1)) else: self.ui.lblCurrentRepeatValue.setText("Done") def init_device(self): device_name = self.selected_device_name num_repeats = self.device_settings_widget.ui.spinBoxNRepeat.value() sts = self.scene_manager.signal._fulldata self.device = VirtualDevice(self.backend_handler, device_name, Mode.send, samples_to_send=sts, device_ip="192.168.10.2", sending_repeats=num_repeats, parent=self) self._create_device_connects() @pyqtSlot() def on_graphics_view_save_as_clicked(self): filename = FileOperator.get_save_file_name("signal.complex") if filename: try: self.scene_manager.signal.save_as(filename) except Exception as e: QMessageBox.critical(self, self.tr("Error saving signal"), e.args[0]) @pyqtSlot() def on_signal_data_edited(self): signal = self.scene_manager.signal self.ui.progressBarSample.setMaximum(signal.num_samples) self.device.samples_to_send = signal.data self.scene_manager.init_scene() self.ui.graphicsViewSend.redraw_view() @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() if self.ui.progressBarSample.value( ) >= self.ui.progressBarSample.maximum() - 1: self.on_clear_clicked() if self.device_is_sending: self.device.stop("Sending paused by user") else: self.device.start() @pyqtSlot() def on_stop_clicked(self): super().on_stop_clicked() self.on_clear_clicked() @pyqtSlot() def on_device_stopped(self): super().on_device_stopped() self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-start")) self.ui.btnStart.setText("Start") self.ui.btnStart.setToolTip("Start sending") self.device_is_sending = False @pyqtSlot() def on_device_started(self): super().on_device_started() self.device_is_sending = True self.ui.btnStart.setEnabled(True) self.ui.btnStart.setIcon(QIcon.fromTheme("media-playback-pause")) self.ui.btnStart.setText("Pause") self.set_device_ui_items_enabled(False) @pyqtSlot() def on_clear_clicked(self): self._update_send_indicator(0) self.reset()
class ProtocolSniffer(ProtocolAnalyzer, QObject): """ This class is used for live sniffing a protocol with certain signal parameters. """ started = pyqtSignal() stopped = pyqtSignal() def __init__(self, bit_len: int, center: float, noise: float, tolerance: int, modulation_type: int, sample_rate: float, freq: float, gain: int, bandwidth: float, device: str, usrp_ip="192.168.10.2"): signal = Signal("", "LiveSignal") signal.bit_len = bit_len signal.qad_center = center signal.noise_threshold = noise signal.tolerance = tolerance signal.silent_set_modulation_type(modulation_type) ProtocolAnalyzer.__init__(self, signal) QObject.__init__(self, None) self.backend_handler = BackendHandler() self.rcv_device = VirtualDevice(self.backend_handler, device, Mode.receive, bandwidth, freq, gain, sample_rate, device_ip=usrp_ip, is_ringbuffer=True) self.rcv_device.index_changed.connect(self.on_rcv_thread_index_changed) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) self.rcv_timer = QTimer() self.rcv_timer.setInterval(1000) self.rcv_timer.timeout.connect(self.on_rcv_timer_timeout) self.rel_symbol_len = self._read_symbol_len() self.data_cache = [] self.conseq_non_data = 0 self.reading_data = False self.store_messages = True self.__sniff_file = "" self.__store_data = True def plain_to_string(self, view: int, show_pauses=True, start=0) -> str: """ :param start: First message to begin with :param show_pauses: Show pauses in output? :param view: 0 - Bits ## 1 - Hex ## 2 - ASCII """ return '\n'.join( msg.view_to_string(view, False, show_pauses) for msg in self.messages[start:]) @property def sniff_file(self): return self.__sniff_file @sniff_file.setter def sniff_file(self, val): self.__sniff_file = val if self.__sniff_file: self.__store_data = False @property def device_name(self): return self.rcv_device.name @device_name.setter def device_name(self, value: str): if value != self.rcv_device.name: self.rcv_device.free_data() self.rcv_device = VirtualDevice(self.backend_handler, value, self.rcv_device.mode, bw=1e6, freq=433.92e6, gain=20, samp_rate=1e6, device_ip="192.168.10.2", is_ringbuffer=True) self.rcv_device.index_changed.connect( self.on_rcv_thread_index_changed) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) @property def usrp_ip(self): return self.rcv_device.ip @usrp_ip.setter def usrp_ip(self, value: str): self.rcv_device.ip = value def sniff(self): self.rcv_device.start() self.rcv_timer.start() @pyqtSlot(int, int) def on_rcv_thread_index_changed(self, old_index, new_index): old_nmsgs = len(self.messages) if self.rcv_device.backend in (Backends.native, Backends.grc): self.__demodulate_data(self.rcv_device.data[old_index:new_index]) elif self.rcv_device.backend == Backends.network: # We receive the bits here for bit_str in self.rcv_device.data: self.messages.append(Message.from_plain_bits_str(bit_str, {})) self.rcv_device.free_data() # do not store received bits twice self.qt_signals.data_sniffed.emit(old_nmsgs) if self.sniff_file and not os.path.isdir(self.sniff_file): # Write Header if not os.path.isfile(self.sniff_file): with open(self.sniff_file, "w") as f: f.write("PROTOCOL:\n\n") with open(self.sniff_file, "a") as myfile: if self.plain_bits_str: myfile.write("\n") myfile.write("\n".join(self.plain_bits_str)) if not self.__store_data: self.messages[:] = [] def __demodulate_data(self, data): """ Demodulates received IQ data and adds demodulated bits to messages :param data: :return: """ signal = self.signal if self.__are_bits_in_data(data): self.reading_data = True elif self.conseq_non_data == 5: self.reading_data = False self.conseq_non_data = 0 else: self.conseq_non_data += 1 if self.reading_data: self.data_cache.append(data) return elif len(self.data_cache) == 0: return signal._fulldata = np.concatenate(self.data_cache) del self.data_cache[:] signal._qad = None bit_len = signal.bit_len ppseq = grab_pulse_lens(signal.qad, signal.qad_center, signal.tolerance, signal.modulation_type) bit_data, pauses, bit_sample_pos = self._ppseq_to_bits( ppseq, bit_len, self.rel_symbol_len) i = 0 first_msg = True for bits, pause in zip(bit_data, pauses): if first_msg or self.messages[-1].pause > 8 * bit_len: # Create new Message middle_bit_pos = bit_sample_pos[i][int(len(bits) / 2)] start, end = middle_bit_pos, middle_bit_pos + bit_len rssi = np.mean(np.abs(signal._fulldata[start:end])) message = Message(bits, pause, bit_len=bit_len, rssi=rssi, message_type=self.default_message_type) self.messages.append(message) first_msg = False else: # Append to last message message = self.messages[-1] nzeros = int(np.round(message.pause / bit_len)) message.plain_bits.extend([False] * nzeros) message.plain_bits.extend(bits) message.pause = pause i += 1 def __are_bits_in_data(self, data): signal = self.signal signal._fulldata = data signal._qad = None bit_len = signal.bit_len ppseq = grab_pulse_lens(signal.qad, signal.qad_center, signal.tolerance, signal.modulation_type) bit_data, pauses, _ = self._ppseq_to_bits(ppseq, bit_len, self.rel_symbol_len) return bool(bit_data) def stop(self): self.rcv_timer.stop() self.rcv_device.stop("Stopping receiving due to user interaction") QApplication.processEvents() time.sleep(0.1) def clear(self): del self.data_cache[:] del self.messages[:] def on_rcv_timer_timeout(self): new_errors = self.rcv_device.read_errors() self.qt_signals.sniff_device_errors_changed.emit(new_errors) if "No devices found for" in new_errors: self.rcv_device.stop("Could not establish connection to USRP") Errors.usrp_ip_not_found() self.stop() elif "FATAL: No supported devices found" in new_errors or \ "HACKRF_ERROR_NOT_FOUND" in new_errors: self.rcv_device.stop("Could not establish connection to HackRF") Errors.hackrf_not_found() self.stop() elif "No module named gnuradio" in new_errors: self.rcv_device.stop("Did not find gnuradio.") Errors.gnuradio_not_installed() self.stop() elif "Address already in use" in new_errors: self.rcv_device.port += 1 self.stop() self.sniff() def __emit_started(self): self.started.emit() def __emit_stopped(self): self.stopped.emit()
class SpectrumDialogController(SendRecvDialogController): def __init__(self, project_manager, parent=None, testing_mode=False): super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) self.graphics_view = self.ui.graphicsViewReceive self.update_interval = 1 self.ui.stackedWidget.setCurrentIndex(0) self.hide_receive_ui_items() self.hide_send_ui_items() self.setWindowTitle("Spectrum analyzer") self.ui.btnStart.setToolTip(self.tr("Start")) self.ui.btnStop.setToolTip(self.tr("Stop")) self.scene_manager = FFTSceneManager(parent=self, graphic_view=self.graphics_view) self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.init_device() self.set_bandwidth_status() self.gain_timer = QTimer() self.gain_timer.setSingleShot(True) self.gain_timer.timeout.connect(self.ui.spinBoxGain.editingFinished.emit) self.if_gain_timer = QTimer() self.if_gain_timer.setSingleShot(True) self.if_gain_timer.timeout.connect(self.ui.spinBoxIFGain.editingFinished.emit) self.bb_gain_timer = QTimer() self.bb_gain_timer.setSingleShot(True) self.bb_gain_timer.timeout.connect(self.ui.spinBoxBasebandGain.editingFinished.emit) self.create_connects() def create_connects(self): super().create_connects() self.graphics_view.freq_clicked.connect(self.on_graphics_view_freq_clicked) def update_view(self): if super().update_view(): x, y = self.device.spectrum if x is None or y is None: return self.scene_manager.scene.frequencies = x self.scene_manager.plot_data = y self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() def init_device(self): device_name = self.ui.cbDevice.currentText() self.device = VirtualDevice(self.backend_handler, device_name, Mode.spectrum, device_ip="192.168.10.2", parent=self) self._create_device_connects() @pyqtSlot(float) def on_graphics_view_freq_clicked(self, freq: float): self.ui.spinBoxFreq.setValue(freq) self.ui.spinBoxFreq.editingFinished.emit() @pyqtSlot() def on_spinbox_frequency_editing_finished(self): self.device.frequency = self.ui.spinBoxFreq.value() self.scene_manager.scene.center_freq = self.ui.spinBoxFreq.value() self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): super().on_device_started() self.ui.btnClear.setEnabled(True) self.ui.spinBoxPort.setEnabled(False) self.ui.lineEditIP.setEnabled(False) self.ui.btnStart.setEnabled(False) @pyqtSlot() def on_clear_clicked(self): self.scene_manager.clear_path() self.scene_manager.clear_peak() @pyqtSlot(int) def on_slider_gain_value_changed(self, value: int): super().on_slider_gain_value_changed(value) self.gain_timer.start(250) @pyqtSlot(int) def on_slider_if_gain_value_changed(self, value: int): super().on_slider_if_gain_value_changed(value) self.if_gain_timer.start(250) @pyqtSlot(int) def on_slider_baseband_gain_value_changed(self, value: int): super().on_slider_baseband_gain_value_changed(value) self.bb_gain_timer.start(250)
class ProtocolSniffer(ProtocolAnalyzer, QObject): """ This class is used for live sniffing a protocol with certain signal parameters. """ started = pyqtSignal() stopped = pyqtSignal() def __init__(self, bit_len: int, center: float, noise: float, tolerance: int, modulation_type: int, device: str, backend_handler: BackendHandler): signal = Signal("", "LiveSignal") signal.bit_len = bit_len signal.qad_center = center signal.noise_threshold = noise signal.tolerance = tolerance signal.silent_set_modulation_type(modulation_type) ProtocolAnalyzer.__init__(self, signal) QObject.__init__(self, None) self.backend_handler = backend_handler self.rcv_device = VirtualDevice(self.backend_handler, device, Mode.receive, is_ringbuffer=False, raw_mode=False) self.rcv_device.index_changed.connect(self.on_rcv_thread_index_changed) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) self.data_cache = [] self.conseq_non_data = 0 self.reading_data = False self.store_messages = True self.__sniff_file = "" self.__store_data = True def decoded_to_string(self, view: int, start=0): return '\n'.join( msg.view_to_string(view, decoded=True, show_pauses=False) for msg in self.messages[start:]) @property def sniff_file(self): return self.__sniff_file @sniff_file.setter def sniff_file(self, val): self.__sniff_file = val if self.__sniff_file: self.__store_data = False @property def device_name(self): return self.rcv_device.name @device_name.setter def device_name(self, value: str): if value != self.rcv_device.name: self.rcv_device.free_data() self.rcv_device = VirtualDevice(self.backend_handler, value, Mode.receive, device_ip="192.168.10.2", is_ringbuffer=False, raw_mode=False) self.rcv_device.index_changed.connect( self.on_rcv_thread_index_changed) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) def sniff(self): self.rcv_device.start() @pyqtSlot(int, int) def on_rcv_thread_index_changed(self, old_index, new_index): old_nmsgs = len(self.messages) if self.rcv_device.backend in (Backends.native, Backends.grc): if old_index == new_index: return self.__demodulate_data(self.rcv_device.data[old_index:new_index]) elif self.rcv_device.backend == Backends.network: # We receive the bits here for bit_str in self.rcv_device.data: msg = Message.from_plain_bits_str(bit_str) msg.decoder = self.decoder self.messages.append(msg) self.rcv_device.free_data() # do not store received bits twice self.qt_signals.data_sniffed.emit(old_nmsgs) if self.sniff_file and not os.path.isdir(self.sniff_file): with open(self.sniff_file, "a") as myfile: myfile.write("\n".join(self.plain_bits_str)) if not self.__store_data: self.messages.clear() def __demodulate_data(self, data): """ Demodulates received IQ data and adds demodulated bits to messages :param data: :return: """ if self.__are_bits_in_data(data): self.reading_data = True elif self.conseq_non_data == 5: self.reading_data = False self.conseq_non_data = 0 else: self.conseq_non_data += 1 if self.reading_data: self.data_cache.append(data) return elif len(self.data_cache) == 0: return self.signal._fulldata = np.concatenate(self.data_cache) self.data_cache.clear() self.signal._qad = None bit_len = self.signal.bit_len ppseq = grab_pulse_lens(self.signal.qad, self.signal.qad_center, self.signal.tolerance, self.signal.modulation_type) bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, bit_len) i = 0 first_msg = True for bits, pause in zip(bit_data, pauses): if first_msg or self.messages[-1].pause > 8 * bit_len: # Create new Message middle_bit_pos = bit_sample_pos[i][int(len(bits) / 2)] start, end = middle_bit_pos, middle_bit_pos + bit_len rssi = np.mean(np.abs(self.signal._fulldata[start:end])) message = Message(bits, pause, bit_len=bit_len, rssi=rssi, message_type=self.default_message_type, decoder=self.decoder) self.messages.append(message) first_msg = False else: # Append to last message message = self.messages[-1] nzeros = int(np.round(message.pause / bit_len)) message.plain_bits.extend([False] * nzeros) message.plain_bits.extend(bits) message.pause = pause i += 1 def __are_bits_in_data(self, data): self.signal._fulldata = data self.signal._qad = None bit_len = self.signal.bit_len ppseq = grab_pulse_lens(self.signal.qad, self.signal.qad_center, self.signal.tolerance, self.signal.modulation_type) bit_data, pauses, _ = self._ppseq_to_bits(ppseq, bit_len) return bool(bit_data) def stop(self): self.rcv_device.stop("Stopping receiving due to user interaction") def clear(self): self.data_cache.clear() self.messages.clear() def __emit_started(self): self.started.emit() def __emit_stopped(self): self.stopped.emit()
class ProtocolSniffer(ProtocolAnalyzer, QObject): """ This class is used for live sniffing a protocol with certain signal parameters. """ started = pyqtSignal() stopped = pyqtSignal() def __init__(self, bit_len: int, center: float, noise: float, tolerance: int, modulation_type: int, device: str, backend_handler: BackendHandler): signal = Signal("", "LiveSignal") signal.bit_len = bit_len signal.qad_center = center signal.noise_threshold = noise signal.tolerance = tolerance signal.silent_set_modulation_type(modulation_type) ProtocolAnalyzer.__init__(self, signal) QObject.__init__(self, None) self.backend_handler = backend_handler self.rcv_device = VirtualDevice(self.backend_handler, device, Mode.receive, resume_on_full_receive_buffer=True, raw_mode=False) self.rcv_device.index_changed.connect(self.on_rcv_thread_index_changed) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) self.data_cache = [] self.conseq_non_data = 0 self.reading_data = False self.store_messages = True self.__sniff_file = "" self.__store_data = True def decoded_to_string(self, view: int, start=0): return '\n'.join(msg.view_to_string(view, decoded=True, show_pauses=False) for msg in self.messages[start:]) @property def sniff_file(self): return self.__sniff_file @sniff_file.setter def sniff_file(self, val): self.__sniff_file = val if self.__sniff_file: self.__store_data = False @property def device_name(self): return self.rcv_device.name @device_name.setter def device_name(self, value: str): if value != self.rcv_device.name: self.rcv_device.free_data() self.rcv_device = VirtualDevice(self.backend_handler, value, Mode.receive, device_ip="192.168.10.2", resume_on_full_receive_buffer=True, raw_mode=False) self.rcv_device.index_changed.connect(self.on_rcv_thread_index_changed) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) def sniff(self): self.rcv_device.start() @pyqtSlot(int, int) def on_rcv_thread_index_changed(self, old_index, new_index): old_nmsgs = len(self.messages) if self.rcv_device.backend in (Backends.native, Backends.grc): if old_index == new_index: return self.__demodulate_data(self.rcv_device.data[old_index:new_index]) elif self.rcv_device.backend == Backends.network: # We receive the bits here for bit_str in self.rcv_device.data: msg = Message.from_plain_bits_str(bit_str) msg.decoder = self.decoder self.messages.append(msg) self.rcv_device.free_data() # do not store received bits twice self.qt_signals.data_sniffed.emit(old_nmsgs) if self.sniff_file and not os.path.isdir(self.sniff_file): with open(self.sniff_file, "a") as myfile: myfile.write("\n".join(self.plain_bits_str)) if not self.__store_data: self.messages.clear() def __demodulate_data(self, data): """ Demodulates received IQ data and adds demodulated bits to messages :param data: :return: """ if self.__are_bits_in_data(data): self.reading_data = True elif self.conseq_non_data == 5: self.reading_data = False self.conseq_non_data = 0 else: self.conseq_non_data += 1 if self.reading_data: self.data_cache.append(data) return elif len(self.data_cache) == 0: return self.signal._fulldata = np.concatenate(self.data_cache) self.data_cache.clear() self.signal._qad = None bit_len = self.signal.bit_len ppseq = grab_pulse_lens(self.signal.qad, self.signal.qad_center, self.signal.tolerance, self.signal.modulation_type) bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, bit_len) i = 0 first_msg = True for bits, pause in zip(bit_data, pauses): if first_msg or self.messages[-1].pause > 8 * bit_len: # Create new Message middle_bit_pos = bit_sample_pos[i][int(len(bits) / 2)] start, end = middle_bit_pos, middle_bit_pos + bit_len rssi = np.mean(np.abs(self.signal._fulldata[start:end])) message = Message(bits, pause, bit_len=bit_len, rssi=rssi, message_type=self.default_message_type, decoder=self.decoder) self.messages.append(message) first_msg = False else: # Append to last message message = self.messages[-1] nzeros = int(np.round(message.pause / bit_len)) message.plain_bits.extend([False] * nzeros) message.plain_bits.extend(bits) message.pause = pause i += 1 def __are_bits_in_data(self, data): self.signal._fulldata = data self.signal._qad = None bit_len = self.signal.bit_len ppseq = grab_pulse_lens(self.signal.qad, self.signal.qad_center, self.signal.tolerance, self.signal.modulation_type) bit_data, pauses, _ = self._ppseq_to_bits(ppseq, bit_len) return bool(bit_data) def stop(self): self.rcv_device.stop("Stopping receiving due to user interaction") def clear(self): self.data_cache.clear() self.messages.clear() def __emit_started(self): self.started.emit() def __emit_stopped(self): self.stopped.emit()
class ReceiveDialogController(SendRecvDialogController): files_recorded = pyqtSignal(list) def __init__(self, project_manager, parent=None, testing_mode=False): try: super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) except ValueError: return self.graphics_view = self.ui.graphicsViewReceive self.ui.stackedWidget.setCurrentWidget(self.ui.page_receive) self.hide_send_ui_items() self.already_saved = True self.recorded_files = [] # set really in on_device_started self.scene_manager = None # type: LiveSceneManager self.init_device() self.set_bandwidth_status() self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.create_connects() def create_connects(self): super().create_connects() self.ui.btnSave.clicked.connect(self.on_save_clicked) def save_before_close(self): if not self.already_saved and self.device.current_index > 0: reply = QMessageBox.question(self, self.tr("Save data?"), self.tr("Do you want to save the data you have captured so far?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Abort) if reply == QMessageBox.Yes: self.on_save_clicked() elif reply == QMessageBox.Abort: return False self.files_recorded.emit(self.recorded_files) return True def update_view(self): if super().update_view(): self.scene_manager.end = self.device.current_index self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() def init_device(self): device_name = self.ui.cbDevice.currentText() self.device = VirtualDevice(self.backend_handler, device_name, Mode.receive, device_ip="192.168.10.2", parent=self) self._create_device_connects() self.scene_manager = LiveSceneManager(np.array([]), parent=self) @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): self.scene_manager.plot_data = self.device.data.real if self.device.data is not None else None super().on_device_started() self.already_saved = False self.ui.btnStart.setEnabled(False) self.set_device_ui_items_enabled(False) @pyqtSlot() def on_clear_clicked(self): self.scene_manager.clear_path() self.reset() @pyqtSlot() def on_save_clicked(self): data = self.device.data[:self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix initial_name = "{0}-{1}Hz-{2}Sps".format(dev.name, big_val(dev.frequency), big_val(dev.sample_rate)) if dev.bandwidth_is_adjustable: initial_name += "-{}Hz".format(big_val(dev.bandwidth)) initial_name = initial_name.replace(Formatter.local_decimal_seperator(), "_").replace("_000", "") filename = FileOperator.save_data_dialog(initial_name + ".complex", data, parent=self) self.already_saved = True if filename is not None and filename not in self.recorded_files: self.recorded_files.append(filename)
class ReceiveDialogController(SendRecvDialogController): files_recorded = pyqtSignal(list) def __init__(self, freq, samp_rate, bw, gain, device: str, parent=None, testing_mode=False): self.is_rx = True try: super().__init__(freq, samp_rate, bw, gain, device, parent=parent, testing_mode=testing_mode) except ValueError: return self.update_interval = 25 self.graphics_view = self.ui.graphicsViewReceive self.ui.stackedWidget.setCurrentIndex(0) self.hide_send_ui_items() self.already_saved = True self.recorded_files = [] # set really in on_device_started self.scene_manager = None # type: LiveSceneManager self.init_device() self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager self.create_connects() def create_connects(self): super().create_connects() self.ui.btnSave.clicked.connect(self.on_save_clicked) def save_before_close(self): if not self.already_saved and self.device.current_index > 0: reply = QMessageBox.question( self, self.tr("Save data?"), self.tr( "Do you want to save the data you have captured so far?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Abort) if reply == QMessageBox.Yes: self.on_save_clicked() elif reply == QMessageBox.Abort: return False self.files_recorded.emit(self.recorded_files) return True def update_view(self): if super().update_view(): self.scene_manager.end = self.device.current_index self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() def init_device(self): device_name = self.ui.cbDevice.currentText() if self.device: self.device.free_data() # Can't perform gc.collect() here, because the dialog itself would be deleted # see https://github.com/jopohl/urh/issues/83 # gc.collect() self.device = VirtualDevice(self.backend_handler, device_name, Mode.receive, bw=1e6, freq=433.92e6, gain=40, samp_rate=1e6, device_ip="192.168.10.2", parent=self) self._create_device_connects() self.scene_manager = LiveSceneManager(np.array([]), parent=self) @pyqtSlot() def on_start_clicked(self): super().on_start_clicked() self.device.start() @pyqtSlot() def on_device_started(self): self.scene_manager.plot_data = self.device.data.real if self.device.data is not None else None super().on_device_started() self.already_saved = False self.ui.btnStart.setEnabled(False) self.set_device_ui_items_enabled(False) @pyqtSlot() def on_clear_clicked(self): self.scene_manager.clear_path() self.reset() @pyqtSlot() def on_save_clicked(self): data = self.device.data[:self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix initial_name = "{0} {1}Hz {2}Sps {3}Hz.complex".format( dev.name, big_val(dev.frequency), big_val(dev.sample_rate), big_val(dev.bandwidth)).replace( Formatter.local_decimal_seperator(), "_").replace("_000", "") filename = FileOperator.save_data_dialog(initial_name, data, parent=self) self.already_saved = True if filename is not None and filename not in self.recorded_files: self.recorded_files.append(filename)