Files
templates/python/pysetterminal/mainterm.py

210 lines
7.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import sys
from PySide6.QtSerialPort import QSerialPortInfo
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
from pysetterminal.rawprotocol import RawProtocol, RawProtocolWidget
from pysetterminal.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 = QSerialPortInfo.availablePorts()
for port in ports:
self.port_combo.addItem(f"{port.portName()} - {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 closeEvent(self, event):
self.serial_tab.stop_macro()
self.raw_protocol.cancel_async()
self.raw_protocol.disconnect()
super().closeEvent(event)
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()