|
|
@@ -0,0 +1,207 @@
|
|
|
+import numpy as np
|
|
|
+from matplotlib.figure import Figure
|
|
|
+import socket
|
|
|
+import msgpack
|
|
|
+from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QHBoxLayout, QMessageBox
|
|
|
+from PySide6.QtWidgets import QDialog, QFormLayout, QLineEdit, QLabel, QComboBox, QSpinBox, QToolButton, QFileDialog
|
|
|
+from PySide6.QtCore import QTimer
|
|
|
+from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
|
|
+from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
|
|
|
+from PySide6.QtWidgets import QSizePolicy
|
|
|
+import json
|
|
|
+
|
|
|
+class MplCanvas(FigureCanvas):
|
|
|
+ def __init__(self, parent=None, width=5, height=4, dpi=100):
|
|
|
+ self.fig = Figure(figsize=(width, height), dpi=dpi, facecolor='grey')
|
|
|
+ super().__init__(self.fig)
|
|
|
+ self.setParent(parent)
|
|
|
+ self.axes = self.fig.add_subplot(111)
|
|
|
+ # Построим простой график
|
|
|
+ self.axes.plot([0, 1, 2, 3], [10, 1, 20, 3])
|
|
|
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
|
+
|
|
|
+class SDRClient(QMainWindow):
|
|
|
+ def __init__(self):
|
|
|
+ super().__init__()
|
|
|
+ # Параметры подключения к серверу
|
|
|
+ self.server_ip = '127.0.0.1'
|
|
|
+ self.server_port = 5003
|
|
|
+ self.sock = None
|
|
|
+ # Параметры для отрисовки
|
|
|
+ self.channel_data = {
|
|
|
+ 'time': np.array([]),
|
|
|
+ 'channel_g': np.array([]),
|
|
|
+ 'channel_rf': np.array([]),
|
|
|
+ 'channel_adc_ttl': np.array([]),
|
|
|
+ 'channel_rf_ttl': np.array([])
|
|
|
+ }
|
|
|
+
|
|
|
+ # Настройка окна
|
|
|
+ self.setWindowTitle("SDR Client")
|
|
|
+ self.setGeometry(100, 100, 1280, 720)
|
|
|
+ self.central_widget = QWidget()
|
|
|
+ self.setCentralWidget(self.central_widget)
|
|
|
+
|
|
|
+ self.layout = QHBoxLayout()
|
|
|
+
|
|
|
+ self.plot_layout = QVBoxLayout()
|
|
|
+ self.menu_layout = QVBoxLayout()
|
|
|
+ self.layout.addLayout(self.menu_layout)
|
|
|
+ self.layout.addLayout(self.plot_layout)
|
|
|
+
|
|
|
+ self.central_widget.setLayout(self.layout)
|
|
|
+
|
|
|
+ self.command_layout = QHBoxLayout()
|
|
|
+ self.plot_layout.addLayout(self.command_layout)
|
|
|
+
|
|
|
+ self.add_event_button = QPushButton("Add Event")
|
|
|
+ self.command_layout.addWidget(self.add_event_button)
|
|
|
+ self.add_rfwave_button = QPushButton("Add RF Wave")
|
|
|
+ self.command_layout.addWidget(self.add_rfwave_button)
|
|
|
+ self.run_event_list_button = QPushButton("Run Event List")
|
|
|
+ self.command_layout.addWidget(self.run_event_list_button)
|
|
|
+ self.clear_event_list_button = QPushButton("Clear Event List")
|
|
|
+ self.command_layout.addWidget(self.clear_event_list_button)
|
|
|
+
|
|
|
+ self.plot_canvas = MplCanvas(self, width=5, height=4, dpi=100)
|
|
|
+ #self.plot_canvas.setSizePolicy(self.plot_widget.sizePolicy())
|
|
|
+ self.plot_layout.addWidget(self.plot_canvas, stretch=1)
|
|
|
+
|
|
|
+ toolbar = NavigationToolbar(self.plot_canvas, self)
|
|
|
+ self.plot_layout.addWidget(toolbar, stretch=1)
|
|
|
+
|
|
|
+ self.connect_button = QPushButton("Connect to SDR")
|
|
|
+ self.connect_button.setMinimumSize(200, 50)
|
|
|
+ self.disconnect_button = QPushButton("Disconnect")
|
|
|
+ self.disconnect_button.setMinimumSize(200, 50)
|
|
|
+ self.settings_button = QPushButton("Settings")
|
|
|
+ self.settings_button.setMinimumSize(200, 50)
|
|
|
+ self.recv_sim_data_button = QPushButton("Receive Sim Data")
|
|
|
+ self.recv_sim_data_button.setMinimumSize(200, 50)
|
|
|
+
|
|
|
+ self.menu_layout.addWidget(self.connect_button)
|
|
|
+ self.menu_layout.addWidget(self.disconnect_button)
|
|
|
+ self.menu_layout.addWidget(self.settings_button)
|
|
|
+ self.menu_layout.addWidget(self.recv_sim_data_button)
|
|
|
+
|
|
|
+ self.connect_button.clicked.connect(self.connect_to_server)
|
|
|
+ self.disconnect_button.clicked.connect(self.disconnect_from_server)
|
|
|
+ self.add_event_button.clicked.connect(self.add_event_dialog)
|
|
|
+
|
|
|
+ def connect_to_server(self):
|
|
|
+ try:
|
|
|
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
+ self.sock.connect((self.server_ip, self.server_port))
|
|
|
+ print(f"Connected to SDR server at {self.server_ip}:{self.server_port}")
|
|
|
+ except Exception as e:
|
|
|
+ print(f"Failed to connect to server: {e}")
|
|
|
+ QMessageBox.critical(self, "Connection Error", f"Failed to connect to server: {e}")
|
|
|
+ self.sock = None
|
|
|
+
|
|
|
+ def disconnect_from_server(self):
|
|
|
+ if self.sock:
|
|
|
+ self.sock.close()
|
|
|
+ self.sock = None
|
|
|
+ QMessageBox.information(self, "Disconnected", "Successfully disconnected from SDR server")
|
|
|
+ print("Disconnected from SDR server")
|
|
|
+
|
|
|
+ def add_event_dialog(self):
|
|
|
+ #if not self.sock:
|
|
|
+ # QMessageBox.warning(self, "Not Connected", "Please connect to the SDR server first")
|
|
|
+ # return False
|
|
|
+ add_event_dialog = QDialog(self)
|
|
|
+ add_event_dialog.setWindowTitle("Add Event")
|
|
|
+ layout = QFormLayout()
|
|
|
+
|
|
|
+ labels = ["Start Time (ticks)", "Duration (ticks)", "Waveform Type", "time_front_rf_ttl (ticks)", "time_back_rf_ttl (ticks)", "time_front_adc_ttl (ticks)", "time_back_adc_ttl (ticks)", "time_start_rf (ticks)", "time_end_rf (ticks)", "rf_freq (Hz)"]
|
|
|
+ self.event_inputs = {}
|
|
|
+ for label in labels:
|
|
|
+ if label == "Waveform Type":
|
|
|
+ combo = QComboBox()
|
|
|
+ combo.addItems(["sine", "square", "triangle"])
|
|
|
+ layout.addRow(QLabel(label), combo)
|
|
|
+ self.event_inputs[label] = combo
|
|
|
+ else:
|
|
|
+ line_edit = QLineEdit()
|
|
|
+ layout.addRow(QLabel(label), line_edit)
|
|
|
+ self.event_inputs[label] = line_edit
|
|
|
+
|
|
|
+ submit_button = QPushButton("Submit")
|
|
|
+ layout.addWidget(submit_button)
|
|
|
+
|
|
|
+ load_event_list_button = QPushButton("Load Event List")
|
|
|
+ layout.addWidget(load_event_list_button)
|
|
|
+
|
|
|
+ submit_button.clicked.connect(self.submit_event)
|
|
|
+ load_event_list_button.clicked.connect(self.load_event_list)
|
|
|
+
|
|
|
+ add_event_dialog.setLayout(layout)
|
|
|
+ add_event_dialog.exec()
|
|
|
+
|
|
|
+ def submit_event(self):
|
|
|
+ try:
|
|
|
+ event_data = {
|
|
|
+ "time": int(self.event_inputs["Start Time (ticks)"].text()),
|
|
|
+ "duration": int(self.event_inputs["Duration (ticks)"].text()),
|
|
|
+ "wave": self.event_inputs["Waveform Type"].currentText(),
|
|
|
+ "time_front_rf_trigger": int(self.event_inputs["time_front_rf_ttl (ticks)"].text()),
|
|
|
+ "time_back_rf_trigger": int(self.event_inputs["time_back_rf_ttl (ticks)"].text()),
|
|
|
+ "time_front_adc_trigger": int(self.event_inputs["time_front_adc_ttl (ticks)"].text()),
|
|
|
+ "time_back_adc_trigger": int(self.event_inputs["time_back_adc_ttl (ticks)"].text()),
|
|
|
+ "rf_start": int(self.event_inputs["time_start_rf (ticks)"].text()),
|
|
|
+ "rf_end": int(self.event_inputs["time_end_rf (ticks)"].text()),
|
|
|
+ "carrier_freq": float(self.event_inputs["rf_freq (Hz)"].text())
|
|
|
+ }
|
|
|
+ msg = msgpack.packb({"command": 0x10, "data": event_data})
|
|
|
+ self.sock.sendall(msg)
|
|
|
+ print("Event added successfully")
|
|
|
+ QMessageBox.information(self, "Success", "Event added successfully")
|
|
|
+ self.add_event_dialog.close()
|
|
|
+ except Exception as e:
|
|
|
+ print(f"Failed to add event: {e}")
|
|
|
+ QMessageBox.critical(self, "Error", f"Failed to add event: {e}")
|
|
|
+
|
|
|
+ def load_event_list(self):
|
|
|
+ file_dialog = QFileDialog(self)
|
|
|
+ file_dialog.setNameFilter("JSON Files (*.json)")
|
|
|
+ if file_dialog.exec():
|
|
|
+ selected_file = file_dialog.selectedFiles()[0]
|
|
|
+ try:
|
|
|
+ with open(selected_file, 'r') as f:
|
|
|
+ event_list = json.load(f)
|
|
|
+ for event_data in event_list:
|
|
|
+ msg = {
|
|
|
+ "magic": 0xAA,
|
|
|
+ "cmd": 0x10,
|
|
|
+ "time": event_data["time"],
|
|
|
+ "duration": event_data["duration"],
|
|
|
+ "wave": event_data["wave"],
|
|
|
+ "time_front_rf_trigger": event_data["time_front_rf_trigger"],
|
|
|
+ "time_back_rf_trigger": event_data["time_back_rf_trigger"],
|
|
|
+ "time_front_adc_trigger": event_data["time_front_adc_trigger"],
|
|
|
+ "time_back_adc_trigger": event_data["time_back_adc_trigger"],
|
|
|
+ "rf_start": event_data["rf_start"],
|
|
|
+ "rf_end": event_data["rf_end"],
|
|
|
+ "carrier_freq": event_data["carrier_freq"]
|
|
|
+ }
|
|
|
+ packed_msg = msgpack.packb(msg, use_bin_type=True)
|
|
|
+ self.sock.sendall(packed_msg)
|
|
|
+ resp = self.sock.recv(1024)
|
|
|
+ if not resp:
|
|
|
+ raise Exception("No response from server")
|
|
|
+ unpacked_resp = msgpack.unpackb(resp, raw=False)
|
|
|
+ if unpacked_resp["cmd"] != 0xFE and unpacked_resp["code"] != 0x00000010:
|
|
|
+ raise Exception(f"Server error: {unpacked_resp['message']}")
|
|
|
+ print("Event list loaded successfully")
|
|
|
+ QMessageBox.information(self, "Success", "Event list loaded successfully")
|
|
|
+ self.add_event_dialog.close()
|
|
|
+ except Exception as e:
|
|
|
+ print(f"Failed to load event list: {e}")
|
|
|
+ QMessageBox.critical(self, "Error", f"Failed to load event list: {e}")
|
|
|
+
|
|
|
+app = QApplication([])
|
|
|
+client = SDRClient()
|
|
|
+client.show()
|
|
|
+#plt.ion() # Enable interactive mode for plotting
|
|
|
+#plt.show()
|
|
|
+app.exec()
|