import sys import serial.tools.list_ports from PySide2.QtWidgets import * from PySide2.QtCore import * from PySide2.QtGui import * from rawprotocol import RawProtocol, RawProtocolWidget from serialbus import SerialBus, SerialTab class MainWindow(QMainWindow): """Главное окно приложения""" def __init__(self): super().__init__() # Создаем низкоуровневый протокол self.raw_protocol = RawProtocol() # Создаем высокоуровневый протокол, передавая ему low-level self.serial_bus = SerialBus(self.raw_protocol) self.init_ui() def init_ui(self): self.setWindowTitle("Терминал") self.setGeometry(100, 100, 800, 600) # Главный виджет и компоновка main_widget = QWidget() main_layout = QVBoxLayout() # Центральный виджет с вкладками self.tab_widget = QTabWidget() # Виджет для RAW протокола (всегда внизу) self.raw_widget = RawProtocolWidget(self.raw_protocol) # Вкладка для серийной шины self.serial_tab = SerialTab(self.serial_bus, self.raw_protocol, self.raw_widget) self.tab_widget.addTab(self.serial_tab, "Серийная шина") main_layout.addWidget(self.tab_widget) main_layout.addWidget(self.raw_widget) main_widget.setLayout(main_layout) self.setCentralWidget(main_widget) # Создание меню self.create_menu() # Создание панели инструментов self.create_toolbar() def create_menu(self): menubar = self.menuBar() # Меню Файл file_menu = menubar.addMenu("Файл") exit_action = QAction("Выход", self) exit_action.triggered.connect(self.close) file_menu.addAction(exit_action) # Меню Помощь help_menu = menubar.addMenu("Помощь") protocol_action = QAction("Информация о протоколе", self) protocol_action.triggered.connect(self.show_protocol_info) help_menu.addAction(protocol_action) def create_toolbar(self): toolbar = self.addToolBar("Подключение") # Выбор COM порта toolbar.addWidget(QLabel("COM порт:")) self.port_combo = QComboBox() self.port_combo.setMinimumWidth(150) self.refresh_ports() toolbar.addWidget(self.port_combo) # Кнопка обновления портов refresh_btn = QToolButton() refresh_btn.setText("⟳") refresh_btn.setToolTip("Обновить список портов") refresh_btn.clicked.connect(self.refresh_ports) toolbar.addWidget(refresh_btn) # Кнопка подключения/отключения self.connect_btn = QPushButton("Подключить") self.connect_btn.clicked.connect(self.toggle_connection) toolbar.addWidget(self.connect_btn) # Индикатор статуса self.status_label = QLabel("Отключено") self.status_label.setStyleSheet("color: red;") toolbar.addWidget(self.status_label) toolbar.addSeparator() # Настройки скорости toolbar.addWidget(QLabel("Скорость:")) self.baud_combo = QComboBox() self.baud_combo.addItems(["9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"]) self.baud_combo.setCurrentText("115200") toolbar.addWidget(self.baud_combo) def refresh_ports(self): """Обновление списка доступных COM портов""" self.port_combo.clear() ports = serial.tools.list_ports.comports() for port in ports: self.port_combo.addItem(f"{port.device} - {port.description}") if not ports: self.port_combo.addItem("Порты не найдены") def toggle_connection(self): """Подключение/отключение от COM порта""" if self.raw_protocol.is_connected: # Отключение self.raw_protocol.disconnect() self.connect_btn.setText("Подключить") self.status_label.setText("Отключено") self.status_label.setStyleSheet("color: red;") # Блокировка элементов управления self.serial_tab.bus_write_btn.setEnabled(False) self.serial_tab.bus_read_btn.setEnabled(False) self.raw_widget.raw_send_btn.setEnabled(False) self.raw_widget.raw_read_btn.setEnabled(False) else: # Подключение port_text = self.port_combo.currentText() if " - " in port_text: port_name = port_text.split(" - ")[0] else: port_name = port_text try: baudrate = int(self.baud_combo.currentText()) if self.raw_protocol.connect(port_name, baudrate): self.connect_btn.setText("Отключить") self.status_label.setText("Подключено") self.status_label.setStyleSheet("color: green;") # Разблокировка элементов управления self.serial_tab.bus_write_btn.setEnabled(True) self.serial_tab.bus_read_btn.setEnabled(True) self.raw_widget.raw_send_btn.setEnabled(True) self.raw_widget.raw_read_btn.setEnabled(True) else: QMessageBox.warning(self, "Ошибка", "Не удалось подключиться к порту") except Exception as e: QMessageBox.warning(self, "Ошибка", f"Ошибка подключения: {e}") def show_protocol_info(self): """Показать информацию о протоколе""" info = """ ИНФОРМАЦИЯ О ПРОТОКОЛЕ: На основе кода контроллера: 1. ФОРМАТ СООБЩЕНИЙ: [адрес][команда][данные][CRC16-IBM] 2. КЛЮЧЕВЫЕ АДРЕСА: - 0x200A: Регистр данных шины (запись) - 0x200B: Регистр управления шиной - 0x200F: Регистр данных шины (чтение) 3. ПРОТОКОЛ ШИНЫ: ЗАПИСЬ: 1. POKE 0x200A <данные> 2. POKE 0x200B 0x80A0 | (адрес << 4) ЧТЕНИЕ: 1. POKE 0x200B 0x00A0 | (адрес << 4) 2. PEEK 0x200F 4. ЧТО НУЖНО УТОЧНИТЬ: - Точные коды команд CMD_RS232_PEEK и CMD_RS232_POKE - Длину полей в сообщениях - Формат ответов от контроллера """ QMessageBox.information(self, "Информация о протоколе", info) def main(): app = QApplication(sys.argv) # Установка стиля app.setStyle("Fusion") window = MainWindow() window.show() sys.exit(app.exec_()) if __name__ == "__main__": main()