Example #1
0
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)
Example #2
0
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)
Example #3
0
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()
Example #4
0
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()
Example #5
0
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
Example #6
0
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()
Example #7
0
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()
Example #8
0
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)
Example #9
0
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)
Example #11
0
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])
Example #13
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()
Example #14
0
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)
Example #15
0
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()
Example #16
0
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()
Example #17
0
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)
Example #18
0
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()
Example #19
0
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()
Example #20
0
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)
Example #21
0
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)